Skip to content

Commit

Permalink
add required signers
Browse files Browse the repository at this point in the history
  • Loading branch information
mkv-vcm committed Oct 12, 2021
1 parent 399f99d commit feb80a6
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/errors/invalidDataReason.ts
Expand Up @@ -135,6 +135,9 @@ export enum InvalidDataReason {
SCRIPT_DATA_HASH_WRONG_LENGTH = "script data hash not 32 long",

COLLATERALS_NOT_ARRAY = "collaterals not an array",

REQUIRED_SIGNERS_NOT_ARRAY = "required signers not an array",
VKEY_WRONG_LENGTH = "vkey not 32 long",

SIGN_MODE_UNKNOWN = "unknown signing mode",

Expand Down
4 changes: 4 additions & 0 deletions src/interactions/serialization/txInit.ts
Expand Up @@ -34,6 +34,9 @@ export function serializeTxInit(
const collateralsBuffer = getCompatibility(version).supportsAlonso
? uint32_to_buf(tx.collaterals.length as Uint32_t)
: Buffer.from([])
const requiredSignersBuffer = getCompatibility(version).supportsAlonso
? uint32_to_buf(tx.requiredSigners.length as Uint32_t)
: Buffer.from([])

return Buffer.concat([
uint8_to_buf(tx.network.networkId),
Expand All @@ -50,5 +53,6 @@ export function serializeTxInit(
uint32_to_buf(tx.withdrawals.length as Uint32_t),
uint32_to_buf(numWitnesses as Uint32_t),
collateralsBuffer,
requiredSignersBuffer,
])
}
6 changes: 5 additions & 1 deletion src/interactions/serialization/txOther.ts
@@ -1,5 +1,5 @@
import { InvalidDataReason } from "../../errors/invalidDataReason"
import type { Int64_str, ParsedAssetGroup, ParsedInput, ParsedToken, ParsedWithdrawal, ScriptDataHash, Uint32_t, Uint64_str, ValidBIP32Path, Version } from "../../types/internal"
import type { Int64_str, ParsedAssetGroup, ParsedInput, ParsedToken, ParsedVKey, ParsedWithdrawal, ScriptDataHash, Uint32_t, Uint64_str, ValidBIP32Path, Version } from "../../types/internal"
import { StakeCredentialType } from "../../types/internal"
import { assert } from "../../utils/assert"
import { hex_to_buf, path_to_buf, stake_credential_to_buf,uint32_to_buf, uint64_to_buf } from "../../utils/serialize"
Expand Down Expand Up @@ -90,3 +90,7 @@ export function serializeMintBasicParams(mint: Array<ParsedAssetGroup<Int64_str>
export function serializeScriptDataHash(scriptDataHash: ScriptDataHash) {
return hex_to_buf(scriptDataHash)
}

export function serializeVKey(vkey: ParsedVKey) {
return hex_to_buf(vkey)
}
26 changes: 23 additions & 3 deletions src/interactions/signTx.ts
@@ -1,5 +1,5 @@
import { DeviceVersionUnsupported } from "../errors"
import type { Int64_str, ParsedAssetGroup, ParsedCertificate, ParsedInput, ParsedOutput, ParsedSigningRequest, ParsedTransaction, ParsedTxAuxiliaryData, ParsedWithdrawal, ScriptDataHash, Uint64_str, ValidBIP32Path, Version } from "../types/internal"
import type { Int64_str, ParsedAssetGroup, ParsedCertificate, ParsedInput, ParsedOutput, ParsedSigningRequest, ParsedTransaction, ParsedTxAuxiliaryData, ParsedVKey, ParsedWithdrawal, ScriptDataHash, Uint64_str, ValidBIP32Path, Version } from "../types/internal"
import { StakeCredentialType } from "../types/internal"
import { CertificateType, ED25519_SIGNATURE_LENGTH, PoolOwnerType, TX_HASH_LENGTH } from "../types/internal"
import type { SignedTransactionData, TxAuxiliaryDataSupplement} from "../types/public"
Expand All @@ -16,7 +16,7 @@ import { serializeFinancials, serializePoolInitialParams, serializePoolInitialPa
import { serializeTxAuxiliaryData } from "./serialization/txAuxiliaryData"
import { serializeTxCertificate } from "./serialization/txCertificate"
import { serializeTxInit } from "./serialization/txInit"
import { serializeAssetGroup, serializeMintBasicParams, serializeToken, serializeTxFee, serializeTxInput, serializeTxTtl, serializeTxValidityStart, serializeTxWithdrawal, serializeTxWitnessRequest, serializeScriptDataHash } from "./serialization/txOther"
import { serializeAssetGroup, serializeMintBasicParams, serializeToken, serializeTxFee, serializeTxInput, serializeTxTtl, serializeTxValidityStart, serializeTxWithdrawal, serializeTxWitnessRequest, serializeScriptDataHash, serializeVKey } from "./serialization/txOther"
import { serializeTxOutputBasicParams } from "./serialization/txOutput"

const enum P1 {
Expand All @@ -33,6 +33,7 @@ const enum P1 {
STAGE_MINT = 0x0b,
STAGE_SCRIPT_DATA_HASH = 0x0c,
STAGE_COLLATERALS = 0x0d,
STAGE_REQUIRED_SIGNERS = 0x0e,
STAGE_WITNESSES = 0x0f,
}

Expand Down Expand Up @@ -513,6 +514,21 @@ function* signTx_addCollateral(
})
}

function* signTx_addRequiredSigner(
vkey: ParsedVKey
): Interaction<void> {
const enum P2 {
UNUSED = 0x00,
}

yield send({
p1: P1.STAGE_REQUIRED_SIGNERS,
p2: P2.UNUSED,
data: serializeVKey(vkey),
expectedResponseLength: 0,
})
}

function* signTx_awaitConfirm(
): Interaction<{ txHashHex: string; }> {
const enum P2 {
Expand Down Expand Up @@ -664,7 +680,7 @@ function ensureRequestSupportedByAppVersion(version: Version, request: ParsedSig
}

if (!getCompatibility(version).supportsAlonso) {
if (request?.tx?.scriptDataHashHex || request?.tx.collaterals.length != 0) {
if (request?.tx?.scriptDataHashHex || request?.tx.collaterals.length != 0 || request?.tx.requiredSigners.length != 0) {
throw new DeviceVersionUnsupported(`Alonso not supported by Ledger app version ${version}.`)
}
}
Expand Down Expand Up @@ -753,6 +769,10 @@ export function* signTransaction(version: Version, request: ParsedSigningRequest
yield* signTx_addCollateral(input)
}

for (const input of tx.requiredSigners) {
yield* signTx_addRequiredSigner(input)
}

// confirm
const { txHashHex } = yield* signTx_awaitConfirm()

Expand Down
8 changes: 6 additions & 2 deletions src/parsing/transaction.ts
@@ -1,6 +1,6 @@
import { InvalidData } from "../errors"
import { InvalidDataReason } from "../errors/invalidDataReason"
import { OutputDestination, ParsedAssetGroup, ParsedCertificate, ParsedInput, ParsedOutput, ParsedSigningRequest, ParsedToken, ParsedTransaction, ParsedWithdrawal } from "../types/internal"
import { OutputDestination, ParsedAssetGroup, ParsedCertificate, ParsedInput, ParsedOutput, ParsedSigningRequest, ParsedToken, ParsedTransaction, ParsedWithdrawal, VKEY_LENGTH } from "../types/internal"
import { StakeCredentialType } from "../types/internal"
import { ASSET_NAME_LENGTH_MAX, CertificateType, SpendingDataSourceType, TOKEN_POLICY_LENGTH, TX_HASH_LENGTH, SCRIPT_DATA_HASH_LENGTH } from "../types/internal"
import type {
Expand Down Expand Up @@ -144,6 +144,9 @@ export function parseTransaction(tx: Transaction): ParsedTransaction {
validate(isArray(tx.collaterals ?? []), InvalidDataReason.COLLATERALS_NOT_ARRAY)
const collaterals = (tx.collaterals ?? []).map(inp => parseTxInput(inp))

validate(isArray(tx.requiredSigners ?? []), InvalidDataReason.REQUIRED_SIGNERS_NOT_ARRAY)
const requiredSigners = (tx.requiredSigners ?? []).map(vkey => parseHexStringOfLength(vkey, VKEY_LENGTH, InvalidDataReason.VKEY_WRONG_LENGTH))

return {
network,
inputs,
Expand All @@ -156,7 +159,8 @@ export function parseTransaction(tx: Transaction): ParsedTransaction {
fee,
mint,
scriptDataHashHex: scriptDataHash,
collaterals
collaterals,
requiredSigners,
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/types/internal.ts
Expand Up @@ -31,6 +31,7 @@ export const REWARD_ACCOUNT_HEX_LENGTH = 29
export const ED25519_SIGNATURE_LENGTH = 64
export const SCRIPT_DATA_HASH_LENGTH = 32
export const DATUM_HASH_LENGTH = 32
export const VKEY_LENGTH = 32

export const enum StakeCredentialType {
KEY_PATH = 0,
Expand Down Expand Up @@ -118,6 +119,7 @@ export type ParsedTransaction = {
mint: Array<ParsedAssetGroup<Int64_str>> | null
scriptDataHashHex: ScriptDataHash | null
collaterals: ParsedInput[]
requiredSigners: ParsedVKey[]
}

export type ParsedSigningRequest = {
Expand All @@ -141,12 +143,13 @@ export type ParsedWithdrawal = {

export type ScriptDataHash = FixlenHexString<typeof SCRIPT_DATA_HASH_LENGTH>

export type ParsedVKey = FixlenHexString<typeof VKEY_LENGTH>

export type ParsedMargin = {
numerator: Uint64_str,
denominator: Uint64_str
}


export type ParsedPoolParams = {
poolKey: ParsedPoolKey,
vrfHashHex: FixlenHexString<typeof VRF_KEY_HASH_LENGTH>,
Expand Down
4 changes: 4 additions & 0 deletions src/types/public.ts
Expand Up @@ -1069,6 +1069,10 @@ export type Transaction = {
* Collaterals (if any)
*/
collaterals?: Array<TxInput> | null,
/**
* Required Signers by key (if any)
*/
requiredSigners?: Array<string> | null,
}

/**
Expand Down
26 changes: 26 additions & 0 deletions test/integration/__fixtures__/signTx.ts
Expand Up @@ -1074,6 +1074,32 @@ export const testsShelleyNoCertificates: TestcaseShelley[] = [
auxiliaryDataSupplement: null,
},
},
{
testname: "Sign tx with required signers",
tx: {
...shelleyBase,
outputs: [],
requiredSigners: [
"fea6646c67fb467f8a5425e9c752e1e262b0420ba4b638f39514049a54ca5330",
"eea6646c67fb467f8a5425e9c752e1e262b0420ba4b638f39514049a54ca5330"
],
},
signingMode: TransactionSigningMode.ORDINARY_TRANSACTION,
additionalWitnessPaths: [],
txBody: "a600818258203b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b700018002182a030a0e825820fea6646c67fb467f8a5425e9c752e1e262b0420ba4b638f39514049a54ca53305820eea6646c67fb467f8a5425e9c752e1e262b0420ba4b638f39514049a54ca53300f01",
result: {
txHashHex:
"c80e96df14dabe295b9a089aa5e25bfb09daf7a9a0ffa8b2b90f83e92e5cc3d7",
witnesses: [
{
path: str_to_path("1852'/1815'/0'/0/0"),
witnessSignatureHex:
"8c3f85a2b7e9d462970c7817b33850d817fff5969852616396a561ee9ceaa5c626340852fbadb6dce2df373ecb6d2dc2a884f90c08c0162cbad106a057bc4909",
},
],
auxiliaryDataSupplement: null,
},
},
]

export const testsShelleyWithCertificates: TestcaseShelley[] = [
Expand Down

0 comments on commit feb80a6

Please sign in to comment.