From 2136fff172601eeb4ac70ee85b79fbe5067da0fa Mon Sep 17 00:00:00 2001 From: Simon Vutov Date: Tue, 16 Sep 2025 10:04:58 -0400 Subject: [PATCH 01/34] feat(sdk-coin-hbar): token enablement transaction verification - Add validation functions for transaction structure, amount, account ID, token name, and transaction type - Integrate token enablement validation into verifyTransaction method - Add test coverage for all validation scenarios TICKET: WP-5746 --- modules/sdk-coin-hbar/src/hbar.ts | 241 +++++++++++++++++++- modules/sdk-coin-hbar/src/lib/index.ts | 1 + modules/sdk-coin-hbar/test/unit/hbar.ts | 278 +++++++++++++++++++++++- 3 files changed, 515 insertions(+), 5 deletions(-) diff --git a/modules/sdk-coin-hbar/src/hbar.ts b/modules/sdk-coin-hbar/src/hbar.ts index 58d4f5b788..76f4d91754 100644 --- a/modules/sdk-coin-hbar/src/hbar.ts +++ b/modules/sdk-coin-hbar/src/hbar.ts @@ -28,7 +28,7 @@ import { import { BigNumber } from 'bignumber.js'; import * as stellar from 'stellar-sdk'; import { SeedValidator } from './seedValidator'; -import { KeyPair as HbarKeyPair, TransactionBuilderFactory, Transaction } from './lib'; +import { KeyPair as HbarKeyPair, TransactionBuilderFactory, Transaction, Recipient as HederaRecipient } from './lib'; import * as Utils from './lib/utils'; import * as _ from 'lodash'; import { @@ -39,6 +39,31 @@ import { Hbar as HbarUnit, } from '@hashgraph/sdk'; import { PUBLIC_KEY_PREFIX } from './lib/keyPair'; + +// Hedera-specific transaction data interface for raw transaction validation +interface HederaRawTransactionData { + id?: string; + from?: string; + fee?: number; + startTime?: string; + validDuration?: string; + node?: string; + memo?: string; + amount?: string; + instructionsData?: { + type?: string; + accountId?: string; + params?: { + accountId?: string; + tokenNames?: string[]; + recipients?: Array<{ + address: string; + amount: string; + tokenName?: string; + }>; + }; + }; +} export interface HbarSignTransactionOptions extends SignTransactionOptions { txPrebuild: TransactionPrebuild; prv: string; @@ -224,10 +249,202 @@ export class Hbar extends BaseCoin { return Utils.isSameBaseAddress(address, baseAddress); } + /** + * Verify a token enablement transaction with strict validation + * @param txHex - The transaction hex to verify + * @param expectedToken - Object containing tokenId (preferred) or tokenName + * @param expectedAccountId - The expected account ID that will enable the token + * @throws Error if the transaction is not a valid token enablement transaction + */ + async verifyTokenEnablementTransaction( + txHex: string, + expectedToken: { tokenId?: string; tokenName?: string }, + expectedAccountId: string + ): Promise { + if (!txHex || !expectedAccountId || (!expectedToken.tokenId && !expectedToken.tokenName)) { + const missing: string[] = []; + if (!txHex) missing.push('txHex'); + if (!expectedAccountId) missing.push('expectedAccountId'); + if (!expectedToken.tokenId && !expectedToken.tokenName) missing.push('expectedToken.tokenId|tokenName'); + throw new Error(`Missing required parameters: ${missing.join(', ')}`); + } + + try { + const transaction = new Transaction(coins.get(this.getChain())); + transaction.fromRawTransaction(txHex); + const raw = transaction.toJson(); + + const explainedTx = await this.explainTransaction({ txHex }); + + this.validateTxStructureStrict(explainedTx); + this.validateNoTransfers(raw); + this.validateAccountIdMatches(explainedTx, raw, expectedAccountId); + this.validateTokenEnablementTarget(explainedTx, raw, expectedToken); + this.validateAssociateInstructionOnly(raw); + this.validateTxHexAgainstExpected(txHex, expectedToken, expectedAccountId); + } catch (error) { + throw new Error(`Invalid token enablement transaction: ${error.message}`); + } + } + + private validateTxStructureStrict(ex: TransactionExplanation): void { + if (!ex.outputs || ex.outputs.length === 0) { + throw new Error('Invalid token enablement transaction: missing required token association output'); + } + if (ex.outputs.length !== 1) { + throw new Error(`Expected exactly 1 output, got ${ex.outputs.length}`); + } + const out0 = ex.outputs[0]; + if (out0.amount !== '0') { + throw new Error(`Expected output amount '0', got ${out0.amount}`); + } + } + + private validateNoTransfers(raw: HederaRawTransactionData): void { + if (raw.instructionsData?.params?.recipients?.length && raw.instructionsData.params.recipients.length > 0) { + const hasNonZeroTransfers = raw.instructionsData.params.recipients.some( + (recipient: HederaRecipient) => recipient.amount && recipient.amount !== '0' + ); + if (hasNonZeroTransfers) { + throw new Error('Transaction contains transfers; not a pure token enablement.'); + } + } + + if (raw.amount && raw.amount !== '0') { + throw new Error('Transaction contains transfers; not a pure token enablement.'); + } + } + + private validateAccountIdMatches( + ex: TransactionExplanation, + raw: HederaRawTransactionData, + expectedAccountId: string + ): void { + if (ex.outputs && ex.outputs.length > 0) { + const out0 = ex.outputs[0]; + const normalizedOutput = Utils.getAddressDetails(out0.address).address; + const normalizedExpected = Utils.getAddressDetails(expectedAccountId).address; + if (normalizedOutput !== normalizedExpected) { + throw new Error(`Expected account ${expectedAccountId}, got ${out0.address}`); + } + } + + const assocAcct = raw.instructionsData?.params?.accountId; + if (assocAcct) { + const normalizedAssoc = Utils.getAddressDetails(assocAcct).address; + const normalizedExpected = Utils.getAddressDetails(expectedAccountId).address; + if (normalizedAssoc !== normalizedExpected) { + throw new Error(`Associate account ${assocAcct} does not match expected ${expectedAccountId}`); + } + } + } + + private validateTokenEnablementTarget( + ex: TransactionExplanation, + raw: HederaRawTransactionData, + expected: { tokenId?: string; tokenName?: string } + ): void { + if (ex.outputs && ex.outputs.length > 0) { + const out0 = ex.outputs[0]; + const explainedName = out0.tokenName; + + if (expected.tokenName) { + if (explainedName !== expected.tokenName) { + throw new Error(`Expected token name ${expected.tokenName}, got ${explainedName}`); + } + } + + if (expected.tokenId && explainedName) { + const actualTokenId = Utils.getHederaTokenIdFromName(explainedName); + if (!actualTokenId) { + throw new Error(`Unable to resolve tokenId for token name ${explainedName}`); + } + if (actualTokenId !== expected.tokenId) { + throw new Error( + `Expected tokenId ${expected.tokenId}, but transaction contains tokenId ${actualTokenId} (${explainedName})` + ); + } + } + } else { + throw new Error('Transaction missing token information in outputs'); + } + + const tokenNames = raw.instructionsData?.params?.tokenNames || []; + if (tokenNames.length !== 1) { + throw new Error(`Expected exactly 1 token to associate, got ${tokenNames.length}`); + } + } + + private validateTxHexAgainstExpected( + txHex: string, + expectedToken: { tokenId?: string; tokenName?: string }, + expectedAccountId: string + ): void { + const transaction = new Transaction(coins.get(this.getChain())); + transaction.fromRawTransaction(txHex); + + const txBody = transaction.txBody; + if (!txBody.tokenAssociate) { + throw new Error('Transaction is not a TokenAssociate transaction'); + } + + const actualAccountId = Utils.stringifyAccountId(txBody.tokenAssociate.account!); + const normalizedActual = Utils.getAddressDetails(actualAccountId).address; + const normalizedExpected = Utils.getAddressDetails(expectedAccountId).address; + if (normalizedActual !== normalizedExpected) { + throw new Error(`TxHex account ${actualAccountId} does not match expected ${expectedAccountId}`); + } + + const actualTokens = txBody.tokenAssociate.tokens || []; + if (actualTokens.length !== 1) { + throw new Error(`TxHex contains ${actualTokens.length} tokens, expected exactly 1`); + } + + const actualTokenId = Utils.stringifyTokenId(actualTokens[0]); + + if (expectedToken.tokenId) { + if (actualTokenId !== expectedToken.tokenId) { + throw new Error(`TxHex tokenId ${actualTokenId} does not match expected ${expectedToken.tokenId}`); + } + } + + if (expectedToken.tokenName) { + const expectedTokenId = Utils.getHederaTokenIdFromName(expectedToken.tokenName); + if (!expectedTokenId) { + throw new Error(`Unable to resolve tokenId for expected token name ${expectedToken.tokenName}`); + } + if (actualTokenId !== expectedTokenId) { + throw new Error( + `TxHex tokenId ${actualTokenId} does not match expected tokenId ${expectedTokenId} for token ${expectedToken.tokenName}` + ); + } + } + } + + private validateAssociateInstructionOnly(raw: HederaRawTransactionData): void { + const instructionType = String(raw.instructionsData?.type || '').toLowerCase(); + + if ( + instructionType === 'contractexecute' || + instructionType === 'contractcall' || + instructionType === 'precompile' + ) { + throw new Error(`Contract-based token association not allowed for blind enablement; got ${instructionType}`); + } + + const isNativeAssociate = + instructionType === 'tokenassociate' || instructionType === 'associate' || instructionType === 'associate_token'; + if (!isNativeAssociate) { + throw new Error( + `Only native TokenAssociate is allowed for blind enablement; got ${instructionType || 'unknown'}` + ); + } + } + async verifyTransaction(params: HbarVerifyTransactionOptions): Promise { // asset name to transfer amount map const coinConfig = coins.get(this.getChain()); - const { txParams: txParams, txPrebuild: txPrebuild, memo: memo } = params; + const { txParams, txPrebuild, memo, verification } = params; const transaction = new Transaction(coinConfig); if (!txPrebuild.txHex) { throw new Error('missing required tx prebuild property txHex'); @@ -245,6 +462,26 @@ export class Hbar extends BaseCoin { throw new Error('missing required tx params property recipients'); } + if (txParams.type === 'enabletoken' && verification?.verifyTokenEnablement) { + const r0 = txParams.recipients[0]; + const expectedToken: { tokenId?: string; tokenName?: string } = {}; + + if (r0.tokenName) { + expectedToken.tokenName = r0.tokenName; + const tokenId = Utils.getHederaTokenIdFromName(r0.tokenName); + if (tokenId) { + expectedToken.tokenId = tokenId; + } + } + + if (!expectedToken.tokenName && !expectedToken.tokenId) { + throw new Error('Token enablement request missing token information'); + } + + await this.verifyTokenEnablementTransaction(txPrebuild.txHex, expectedToken, r0.address); + return true; + } + // for enabletoken, recipient output amount is 0 const recipients = txParams.recipients.map((recipient) => ({ ...recipient, diff --git a/modules/sdk-coin-hbar/src/lib/index.ts b/modules/sdk-coin-hbar/src/lib/index.ts index 9b7a50c0c2..1fc57fda27 100644 --- a/modules/sdk-coin-hbar/src/lib/index.ts +++ b/modules/sdk-coin-hbar/src/lib/index.ts @@ -7,4 +7,5 @@ export { TransferBuilder } from './transferBuilder'; export { CoinTransferBuilder } from './coinTransferBuilder'; export { TokenTransferBuilder } from './tokenTransferBuilder'; export { TokenAssociateBuilder } from './tokenAssociateBuilder'; +export { Recipient } from './iface'; export { Utils }; diff --git a/modules/sdk-coin-hbar/test/unit/hbar.ts b/modules/sdk-coin-hbar/test/unit/hbar.ts index 0b0b3a142a..8350ebb693 100644 --- a/modules/sdk-coin-hbar/test/unit/hbar.ts +++ b/modules/sdk-coin-hbar/test/unit/hbar.ts @@ -1,13 +1,14 @@ import assert from 'assert'; import * as _ from 'lodash'; +import nock from 'nock'; import Sinon, { SinonStub } from 'sinon'; import { randomBytes } from 'crypto'; import { BigNumber } from 'bignumber.js'; import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test'; import { BitGoAPI, encrypt } from '@bitgo/sdk-api'; +import { common, Wallet } from '@bitgo/sdk-core'; import { TxData, Transfer } from '../../src/lib/iface'; -import { Wallet } from '@bitgo/sdk-core'; import * as TestData from '../fixtures/hbar'; import { Hbar, Thbar, KeyPair, HbarToken } from '../../src'; @@ -364,6 +365,7 @@ describe('Hedera Hashgraph:', function () { const txParams = newTxParams(); const txPrebuild = newTxPrebuild(); txPrebuild.txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + txParams.type = 'enabletoken'; txParams.recipients = [ { address: '0.0.81320', @@ -376,6 +378,7 @@ describe('Hedera Hashgraph:', function () { txPrebuild, memo, wallet: walletObj, + verification: { verifyTokenEnablement: true }, } as any); validTransaction.should.equal(true); }); @@ -384,6 +387,7 @@ describe('Hedera Hashgraph:', function () { const txParams = newTxParams(); const txPrebuild = newTxPrebuild(); txPrebuild.txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + txParams.type = 'enabletoken'; txParams.recipients = [ { address: '0.0.81321', @@ -392,8 +396,14 @@ describe('Hedera Hashgraph:', function () { }, ]; await basecoin - .verifyTransaction({ txParams, txPrebuild, memo, wallet: walletObj } as any) - .should.be.rejectedWith('Tx outputs does not match with expected txParams recipients'); + .verifyTransaction({ + txParams, + txPrebuild, + memo, + wallet: walletObj, + verification: { verifyTokenEnablement: true }, + } as any) + .should.be.rejectedWith('Invalid token enablement transaction: Expected account 0.0.81321, got 0.0.81320'); }); it('should verify token transfer transaction', async function () { @@ -484,6 +494,7 @@ describe('Hedera Hashgraph:', function () { const txParams = newTxParams(); const txPrebuild = newTxPrebuild(); txPrebuild.txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + txParams.type = 'enabletoken'; txParams.recipients = [ { address: '0.0.81320?memoId=1', @@ -496,11 +507,272 @@ describe('Hedera Hashgraph:', function () { txPrebuild, memo, wallet: walletObj, + verification: { verifyTokenEnablement: true }, } as any); validTransaction.should.equal(true); }); }); + describe('Verify Token Enablement Transaction:', () => { + it('should verify a valid token enablement transaction with tokenName', async function () { + const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + const expectedToken = { tokenName: 'thbar:usdc' }; + const expectedAccountId = '0.0.81320'; + + await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId); + }); + + it('should verify a valid token enablement transaction with tokenId', async function () { + const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + const expectedToken = { tokenId: '0.0.429274' }; // Actual tokenId for thbar:usdc + const expectedAccountId = '0.0.81320'; + + await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId); + }); + + it('should fail when txHex is missing', async function () { + await basecoin + .verifyTokenEnablementTransaction('', { tokenName: 'thbar:usdc' }, '0.0.81320') + .should.be.rejectedWith('Missing required parameters: txHex'); + }); + + it('should fail when expectedAccountId is missing', async function () { + await basecoin + .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, { tokenName: 'thbar:usdc' }, '') + .should.be.rejectedWith('Missing required parameters: expectedAccountId'); + }); + + it('should fail when wallet platform sends spoofed transaction hex for token enablement', async function () { + // Create a valid transaction response structure from wallet platform with spoofed txHex + // The txHex looks like valid hex but contains malicious/invalid transaction data + const spoofedTxHex = '0a0c0a080800100018a8fb0410130a0c0a080800100018d5d0041014'; // Valid hex but invalid transaction + + // Mock the API endpoints that will be called during token enablement + const bgUrl = common.Environments['mock'].uri; + + // Mock the key endpoint needed for signing + nock(bgUrl) + .post('/api/v2/thbar/key/5b3424f91bf34993006eae94') + .reply(200, [ + { + encryptedPrv: 'fakePrv', + }, + ]); + + // Mock the prebuild API response to return spoofed txHex + nock(bgUrl) + .post('/api/v2/thbar/wallet/5b34252f1bf34993006eae96/tx/build') + .reply(200, { + txHex: spoofedTxHex, + txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2', + recipients: [ + { + address: '0.0.81320', + amount: '0', // Valid amount for token enablement + }, + ], + coin: 'thbar', + feeInfo: { + size: 1000, + fee: 1160407, + feeRate: 1160407, + }, + }); + + // This should fail because the spoofed transaction hex contains invalid transaction data + // The verification logic should catch this when trying to validate the transaction + await assert.rejects( + async () => { + // Test the verification directly instead of going through the wallet flow + await basecoin.verifyTokenEnablementTransaction(spoofedTxHex, { tokenName: 'thbar:usdc' }, '0.0.81320'); + }, + (error: any) => { + // The error should indicate that the transaction is invalid + return error.message.includes('Invalid token enablement transaction'); + } + ); + }); + + it('should fail when both tokenId and tokenName are missing', async function () { + await basecoin + .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, {}, '0.0.81320') + .should.be.rejectedWith('Missing required parameters: expectedToken.tokenId|tokenName'); + }); + + it('should fail when token name does not match', async function () { + await basecoin + .verifyTokenEnablementTransaction( + TestData.UNSIGNED_TOKEN_ASSOCIATE, + { tokenName: 'thbar:wrongtoken' }, + '0.0.81320' + ) + .should.be.rejectedWith(/Expected token name thbar:wrongtoken, got thbar:usdc/); + }); + + it('should fail when account ID does not match', async function () { + await basecoin + .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_ASSOCIATE, { tokenName: 'thbar:usdc' }, '0.0.99999') + .should.be.rejectedWith(/Expected account 0.0.99999, got 0.0.81320/); + }); + + it('should fail when transaction is not a token enablement (has non-zero amount)', async function () { + // Use a regular transfer transaction which has non-zero amount + await basecoin + .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_TRANSFER, { tokenName: 'thbar:usdc' }, '0.0.81320') + .should.be.rejectedWith(/Expected output amount '0'/); + }); + + it('should fail when transaction type is not tokenAssociate', async function () { + // Use a regular transfer transaction which is not tokenAssociate + // This will fail on amount validation first, but that's expected behavior + await basecoin + .verifyTokenEnablementTransaction(TestData.UNSIGNED_TOKEN_TRANSFER, { tokenName: 'thbar:usdc' }, '0.0.81320') + .should.be.rejectedWith(/Expected output amount '0'/); + }); + + it('should validate transaction type for valid token associate transaction', async function () { + // This test ensures the transaction type validation works for valid token associate transactions + const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + const expectedToken = { tokenName: 'thbar:usdc' }; + const expectedAccountId = '0.0.81320'; + + await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId); + }); + + it('should fail with invalid transaction hex', async function () { + await basecoin + .verifyTokenEnablementTransaction('invalid_hex', { tokenName: 'thbar:usdc' }, '0.0.81320') + .should.be.rejectedWith(/Invalid token enablement transaction/); + }); + + it('should fail when txHex contains wrong tokenId compared to expected', async function () { + // This test ensures direct txHex validation catches spoofed tokenIds + const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + const wrongTokenId = '0.0.999999'; // Wrong tokenId + const expectedAccountId = '0.0.81320'; + + await basecoin + .verifyTokenEnablementTransaction(txHex, { tokenId: wrongTokenId }, expectedAccountId) + .should.be.rejectedWith( + new RegExp(`Expected tokenId ${_.escapeRegExp(wrongTokenId)}, but transaction contains tokenId`) + ); + }); + + it('should fail when txHex contains wrong accountId compared to expected', async function () { + // This test ensures direct txHex validation catches spoofed accountIds + const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + const expectedToken = { tokenName: 'thbar:usdc' }; + const wrongAccountId = '0.0.999999'; // Wrong accountId + + await basecoin + .verifyTokenEnablementTransaction(txHex, expectedToken, wrongAccountId) + .should.be.rejectedWith(new RegExp(`Expected account ${_.escapeRegExp(wrongAccountId)}, got`)); + }); + + it('should pass verification for valid token enablement transaction without throwing error', async function () { + // This test ensures that a valid token enablement transaction passes all validations + const txHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + const expectedToken = { tokenName: 'thbar:usdc' }; + const expectedAccountId = '0.0.81320'; + + // This should complete without throwing any errors + await basecoin.verifyTokenEnablementTransaction(txHex, expectedToken, expectedAccountId); + + // If we reach this point, the test passed + assert.ok(true, 'Valid token enablement transaction should not throw any errors'); + }); + + it('should successfully complete sendTokenEnablements with valid transaction response from wallet platform', async function () { + const validTxHex = TestData.UNSIGNED_TOKEN_ASSOCIATE; + + const wallet = { + id: () => '5b34252f1bf34993006eae96', + coin: () => 'thbar', + prebuildTransaction: async () => ({ + txHex: validTxHex, // Valid token associate transaction + txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2', + recipients: [{ address: '0.0.81320', amount: '0' }], + coin: 'thbar', + feeInfo: { size: 1000, fee: 1160407, feeRate: 1160407 }, + }), + sendTokenEnablements: async (params: any) => { + const txPrebuild = await wallet.prebuildTransaction(); + await basecoin.verifyTransaction({ + txParams: { + type: 'enabletoken', + recipients: [{ address: '0.0.81320', amount: '0', tokenName: 'thbar:usdc' }], + }, + txPrebuild, + verification: { verifyTokenEnablement: true }, + }); + + return { + success: [{ txid: txPrebuild.txid, status: 'success' }], + failure: [], + }; + }, + }; + + await wallet.sendTokenEnablements({ + recipients: [{ address: '0.0.81320', tokenName: 'thbar:usdc' }], + }); + + assert.ok( + true, + 'Valid token enablement transaction should complete successfully through sendTokenEnablements flow' + ); + }); + + it('should detect spoofed transaction hex through sendTokenEnablements flow', async function () { + // Use a valid transfer transaction hex instead of a token associate transaction + // This will parse correctly but fail validation because it's not a token associate transaction + const spoofedTxHex = TestData.UNSIGNED_TOKEN_TRANSFER; // Valid transfer transaction, not token associate + + // Create a wallet mock for the sendTokenEnablements flow + const wallet = { + id: () => '5b34252f1bf34993006eae96', + coin: () => 'thbar', + prebuildTransaction: async () => ({ + txHex: spoofedTxHex, + txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2', + recipients: [{ address: '0.0.81320', amount: '0' }], + coin: 'thbar', + feeInfo: { size: 1000, fee: 1160407, feeRate: 1160407 }, + }), + sendTokenEnablements: async (params: any) => { + // This should trigger the verification and fail + const txPrebuild = await wallet.prebuildTransaction(); + return basecoin.verifyTransaction({ + txParams: { + type: 'enabletoken', + recipients: [{ address: '0.0.81320', amount: '0', tokenName: 'thbar:usdc' }], + }, + txPrebuild, + verification: { verifyTokenEnablement: true }, + }); + }, + }; + + // This should fail because the spoofed transaction hex contains a transfer transaction, not a token associate + await assert.rejects( + async () => { + await wallet.sendTokenEnablements({ + recipients: [{ address: '0.0.81320', tokenName: 'thbar:usdc' }], + }); + }, + (error: any) => { + // The error should indicate that the transaction is invalid for token enablement + return ( + error.message.includes('Invalid token enablement transaction') || + error.message.includes('Token enablement transaction missing tokenId') || + error.message.includes("Expected output amount '0'") || + error.message.includes('Transaction is not a TokenAssociate transaction') + ); + } + ); + }); + }); + describe('Sign Message', () => { it('should be performed', async () => { const keyPair = new KeyPair(); From 4930f7ac14ca7050c77bb46448340300116e81ab Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Mon, 13 Oct 2025 10:07:38 +0200 Subject: [PATCH 02/34] feat(secp256k1): export factory functions Export ECPairFactory and BIP32Factory to support reuse of factories with different ecc implementations. Issue: BTC-2668 Co-authored-by: llm-git --- modules/secp256k1/src/index.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/secp256k1/src/index.ts b/modules/secp256k1/src/index.ts index fb1aa6a129..7eafbdb717 100644 --- a/modules/secp256k1/src/index.ts +++ b/modules/secp256k1/src/index.ts @@ -176,4 +176,16 @@ const ECPair: ECPairAPI = ECPairFactory(ecc); const bip32: BIP32API = BIP32Factory(ecc); const musig: MuSig = MuSigFactory(crypto); -export { ecc, ECPair, ECPairAPI, ECPairInterface, bip32, BIP32API, BIP32Interface, musig, MuSig }; +export { + ecc, + ECPair, + ECPairAPI, + ECPairFactory, + ECPairInterface, + bip32, + BIP32API, + BIP32Factory, + BIP32Interface, + musig, + MuSig, +}; From b1ae0fc7e52b83677e228a236b4f8e0844fd9b6f Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Fri, 10 Oct 2025 16:38:25 +0200 Subject: [PATCH 03/34] feat(abstract-utxo): use secp256k1 for bip32 operations Replace uses of `utxo-lib` bip32 functionality with direct imports from `@bitgo/secp256k1`. This change maintains compatibility while using the preferred library for BIP32 operations. Issue: BTC-2668 Co-authored-by: llm-git --- modules/abstract-utxo/package.json | 1 + modules/abstract-utxo/src/abstractUtxoCoin.ts | 6 +++--- modules/abstract-utxo/src/descriptor/builder/parse.ts | 5 ++--- .../src/descriptor/createWallet/createDescriptorWallet.ts | 6 +++--- modules/abstract-utxo/src/keychains.ts | 8 ++++---- .../src/offlineVault/OfflineVaultHalfSigned.ts | 4 ++-- .../src/offlineVault/OfflineVaultSignable.ts | 8 ++++---- modules/abstract-utxo/src/recovery/crossChainRecovery.ts | 2 +- .../src/transaction/fixedScript/explainTransaction.ts | 5 +++-- .../src/transaction/fixedScript/signTransaction.ts | 3 ++- modules/abstract-utxo/src/transaction/signTransaction.ts | 2 +- modules/abstract-utxo/src/verifyKey.ts | 2 +- modules/utxo-core/package.json | 1 + modules/utxo-core/src/bip32utils.ts | 2 +- modules/utxo-core/src/descriptor/psbt/sign.ts | 4 ++-- modules/utxo-core/src/testutil/descriptor/descriptors.ts | 2 +- modules/utxo-core/src/testutil/key.utils.ts | 4 ++-- modules/utxo-core/test/bip32utils.ts | 3 ++- modules/utxo-core/test/paygo/psbt/payGoAddressProof.ts | 3 ++- 19 files changed, 38 insertions(+), 33 deletions(-) diff --git a/modules/abstract-utxo/package.json b/modules/abstract-utxo/package.json index d8f8af1572..f64210b2a4 100644 --- a/modules/abstract-utxo/package.json +++ b/modules/abstract-utxo/package.json @@ -42,6 +42,7 @@ ] }, "dependencies": { + "@bitgo/secp256k1": "^1.5.0", "@bitgo/blockapis": "^1.12.0", "@bitgo/sdk-api": "^1.70.1", "@bitgo/sdk-core": "^36.12.0", diff --git a/modules/abstract-utxo/src/abstractUtxoCoin.ts b/modules/abstract-utxo/src/abstractUtxoCoin.ts index a258c44eb7..d3368f686e 100644 --- a/modules/abstract-utxo/src/abstractUtxoCoin.ts +++ b/modules/abstract-utxo/src/abstractUtxoCoin.ts @@ -3,7 +3,8 @@ import { randomBytes } from 'crypto'; import _ from 'lodash'; import * as utxolib from '@bitgo/utxo-lib'; -import { bip32, bitgo, getMainnet, isMainnet, isTestnet } from '@bitgo/utxo-lib'; +import { bip32 } from '@bitgo/secp256k1'; +import { bitgo, getMainnet, isMainnet, isTestnet } from '@bitgo/utxo-lib'; import { AddressCoinSpecific, AddressTypeChainMismatchError, @@ -46,7 +47,6 @@ import { Wallet, isValidPrv, isValidXprv, - bitcoin, } from '@bitgo/sdk-core'; import { @@ -1160,7 +1160,7 @@ export abstract class AbstractUtxoCoin extends BaseCoin { throw new Error('invalid private key'); } if (publicKey) { - const genPubKey = bitcoin.HDNode.fromBase58(prv).neutered().toBase58(); + const genPubKey = bip32.fromBase58(prv).neutered().toBase58(); if (genPubKey !== publicKey) { throw new Error('public key does not match private key'); } diff --git a/modules/abstract-utxo/src/descriptor/builder/parse.ts b/modules/abstract-utxo/src/descriptor/builder/parse.ts index 8b6a120693..ca5c6f8fbc 100644 --- a/modules/abstract-utxo/src/descriptor/builder/parse.ts +++ b/modules/abstract-utxo/src/descriptor/builder/parse.ts @@ -1,5 +1,4 @@ -import { BIP32Interface } from '@bitgo/utxo-lib'; -import * as utxolib from '@bitgo/utxo-lib'; +import { BIP32Interface, bip32 } from '@bitgo/secp256k1'; import { Descriptor } from '@bitgo/wasm-miniscript'; import { DescriptorBuilder, getDescriptorFromBuilder } from './builder'; @@ -55,7 +54,7 @@ function parseMulti(node: unknown): { }); return { threshold, - keys: keyWithPath.map((k) => utxolib.bip32.fromBase58(k.xpub)), + keys: keyWithPath.map((k) => bip32.fromBase58(k.xpub)), path: paths[0], }; } diff --git a/modules/abstract-utxo/src/descriptor/createWallet/createDescriptorWallet.ts b/modules/abstract-utxo/src/descriptor/createWallet/createDescriptorWallet.ts index a6aeefdea7..a98320fee2 100644 --- a/modules/abstract-utxo/src/descriptor/createWallet/createDescriptorWallet.ts +++ b/modules/abstract-utxo/src/descriptor/createWallet/createDescriptorWallet.ts @@ -1,5 +1,5 @@ import { BitGoAPI } from '@bitgo/sdk-api'; -import * as utxolib from '@bitgo/utxo-lib'; +import { bip32 } from '@bitgo/secp256k1'; import { Wallet } from '@bitgo/sdk-core'; import { AbstractUtxoCoin } from '../../abstractUtxoCoin'; @@ -56,12 +56,12 @@ export async function createDescriptorWalletWithWalletPassphrase( if (!userKeychain.prv) { throw new Error('Missing private key'); } - const userKey = utxolib.bip32.fromBase58(userKeychain.prv); + const userKey = bip32.fromBase58(userKeychain.prv); const cosigners = [backupKeychain, bitgoKeychain].map((keychain) => { if (!keychain.pub) { throw new Error('Missing public key'); } - return utxolib.bip32.fromBase58(keychain.pub); + return bip32.fromBase58(keychain.pub); }); return createDescriptorWallet(bitgo, coin, { ...params, diff --git a/modules/abstract-utxo/src/keychains.ts b/modules/abstract-utxo/src/keychains.ts index b23d08dd40..e0e945063e 100644 --- a/modules/abstract-utxo/src/keychains.ts +++ b/modules/abstract-utxo/src/keychains.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import * as t from 'io-ts'; -import * as utxolib from '@bitgo/utxo-lib'; +import { BIP32Interface, bip32 } from '@bitgo/secp256k1'; import { IRequestTracer, IWallet, KeyIndices, promiseProps, Triple } from '@bitgo/sdk-core'; import { AbstractUtxoCoin } from './abstractUtxoCoin'; @@ -48,12 +48,12 @@ export function toKeychainTriple(keychains: UtxoNamedKeychains): Triple | Triple -): Triple { +): Triple { if (Array.isArray(keychains)) { return keychains.map((keychain: { pub: string } | string) => { const v = typeof keychain === 'string' ? keychain : keychain.pub; - return utxolib.bip32.fromBase58(v); - }) as Triple; + return bip32.fromBase58(v); + }) as Triple; } return toBip32Triple(toKeychainTriple(keychains)); diff --git a/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts b/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts index a53206b8f4..e7c8d624e8 100644 --- a/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts +++ b/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts @@ -1,5 +1,5 @@ +import { BIP32Interface, bip32 } from '@bitgo/secp256k1'; import * as utxolib from '@bitgo/utxo-lib'; -import { BIP32Interface } from '@bitgo/utxo-lib'; import { BaseCoin } from '@bitgo/sdk-core'; import { getNetworkFromChain } from '../names'; @@ -23,7 +23,7 @@ export function createHalfSigned( ): OfflineVaultHalfSigned { const network = getNetworkFromChain(coin); if (typeof prv === 'string') { - prv = utxolib.bip32.fromBase58(prv); + prv = bip32.fromBase58(prv); } prv = BaseCoin.deriveKeyWithSeedBip32(prv, derivationId).key; if (!OfflineVaultSignable.is(tx)) { diff --git a/modules/abstract-utxo/src/offlineVault/OfflineVaultSignable.ts b/modules/abstract-utxo/src/offlineVault/OfflineVaultSignable.ts index e3fcc4fb89..da7108997c 100644 --- a/modules/abstract-utxo/src/offlineVault/OfflineVaultSignable.ts +++ b/modules/abstract-utxo/src/offlineVault/OfflineVaultSignable.ts @@ -1,4 +1,4 @@ -import * as utxolib from '@bitgo/utxo-lib'; +import { BIP32Interface, bip32 } from '@bitgo/secp256k1'; import { Triple } from '@bitgo/sdk-core'; import * as t from 'io-ts'; @@ -28,8 +28,8 @@ export type OfflineVaultUnsigned = t.TypeOf; type WithXpub = { xpub: string }; type NamedKeys = { user: WithXpub; backup: WithXpub; bitgo: WithXpub }; -export function toKeyTriple(xpubs: NamedKeys): Triple { +export function toKeyTriple(xpubs: NamedKeys): Triple { return [xpubs.user.xpub, xpubs.backup.xpub, xpubs.bitgo.xpub].map((xpub) => - utxolib.bip32.fromBase58(xpub) - ) as Triple; + bip32.fromBase58(xpub) + ) as Triple; } diff --git a/modules/abstract-utxo/src/recovery/crossChainRecovery.ts b/modules/abstract-utxo/src/recovery/crossChainRecovery.ts index 2a1c36e0e5..a09eccebbc 100644 --- a/modules/abstract-utxo/src/recovery/crossChainRecovery.ts +++ b/modules/abstract-utxo/src/recovery/crossChainRecovery.ts @@ -1,5 +1,5 @@ import * as utxolib from '@bitgo/utxo-lib'; -import { bip32, BIP32Interface } from '@bitgo/utxo-lib'; +import { BIP32Interface, bip32 } from '@bitgo/secp256k1'; import { Dimensions } from '@bitgo/unspents'; import { BitGoBase, IWallet, Keychain, Triple, Wallet } from '@bitgo/sdk-core'; import { decrypt } from '@bitgo/sdk-api'; diff --git a/modules/abstract-utxo/src/transaction/fixedScript/explainTransaction.ts b/modules/abstract-utxo/src/transaction/fixedScript/explainTransaction.ts index 21130ea2d6..ac568931f7 100644 --- a/modules/abstract-utxo/src/transaction/fixedScript/explainTransaction.ts +++ b/modules/abstract-utxo/src/transaction/fixedScript/explainTransaction.ts @@ -1,6 +1,7 @@ import * as utxolib from '@bitgo/utxo-lib'; import { bip322 } from '@bitgo/utxo-core'; -import { bip32, BIP32Interface, bitgo } from '@bitgo/utxo-lib'; +import { BIP32Interface, bip32 } from '@bitgo/secp256k1'; +import { bitgo } from '@bitgo/utxo-lib'; import { Triple } from '@bitgo/sdk-core'; import * as utxocore from '@bitgo/utxo-core'; @@ -302,7 +303,7 @@ export function explainPsbt sum + getNewSignatureCountForInput(signatures), 0); } -type Key = Buffer | utxolib.BIP32Interface | utxolib.ECPairInterface; +type Key = Buffer | BIP32Interface | ECPairInterface; /** Convenience function to sign a PSBT with a key */ export function signWithKey(psbt: WasmPsbt, key: Key): SignPsbtResult { diff --git a/modules/utxo-core/src/testutil/descriptor/descriptors.ts b/modules/utxo-core/src/testutil/descriptor/descriptors.ts index 09144f8ecd..21a58501bf 100644 --- a/modules/utxo-core/src/testutil/descriptor/descriptors.ts +++ b/modules/utxo-core/src/testutil/descriptor/descriptors.ts @@ -1,7 +1,7 @@ import assert from 'assert'; +import { bip32, BIP32Interface } from '@bitgo/secp256k1'; import { Miniscript, Descriptor, ast } from '@bitgo/wasm-miniscript'; -import { bip32, BIP32Interface } from '@bitgo/utxo-lib'; import { DescriptorMap, PsbtParams } from '../../descriptor'; import { getKeyTriple, Triple, KeyTriple } from '../key.utils'; diff --git a/modules/utxo-core/src/testutil/key.utils.ts b/modules/utxo-core/src/testutil/key.utils.ts index e526099dce..ebea557b74 100644 --- a/modules/utxo-core/src/testutil/key.utils.ts +++ b/modules/utxo-core/src/testutil/key.utils.ts @@ -1,7 +1,7 @@ import * as crypto from 'crypto'; +import { bip32, BIP32Interface } from '@bitgo/secp256k1'; import * as utxolib from '@bitgo/utxo-lib'; -import { BIP32Interface } from '@bitgo/utxo-lib'; export type Triple = [T, T, T]; @@ -13,7 +13,7 @@ export type KeyTriple = Triple; */ export function getKey(seed?: string): BIP32Interface { const finalSeed = seed === undefined ? crypto.randomBytes(32) : crypto.createHash('sha256').update(seed).digest(); - return utxolib.bip32.fromSeed(finalSeed); + return bip32.fromSeed(finalSeed); } /** diff --git a/modules/utxo-core/test/bip32utils.ts b/modules/utxo-core/test/bip32utils.ts index 0f5b94b088..f322eb013a 100644 --- a/modules/utxo-core/test/bip32utils.ts +++ b/modules/utxo-core/test/bip32utils.ts @@ -1,6 +1,7 @@ import * as crypto from 'crypto'; import * as assert from 'assert'; +import { bip32 } from '@bitgo/secp256k1'; import * as utxolib from '@bitgo/utxo-lib'; import { signMessage, verifyMessage } from '../src/bip32utils'; @@ -10,7 +11,7 @@ describe('bip32utils', function () { return Array.from({ length }).map((_, i) => crypto.createHash('sha256').update(`${i}`).digest()); } it('signMessage/verifyMessage', function () { - const keys = getSeedBuffers(4).map((seed) => utxolib.bip32.fromSeed(seed)); + const keys = getSeedBuffers(4).map((seed) => bip32.fromSeed(seed)); const messages = ['hello', 'goodbye', Buffer.from('\x01\x02\x03'), Buffer.from('')]; keys.forEach((key) => { messages.forEach((message) => { diff --git a/modules/utxo-core/test/paygo/psbt/payGoAddressProof.ts b/modules/utxo-core/test/paygo/psbt/payGoAddressProof.ts index 1bd8518f78..15ecc1aff3 100644 --- a/modules/utxo-core/test/paygo/psbt/payGoAddressProof.ts +++ b/modules/utxo-core/test/paygo/psbt/payGoAddressProof.ts @@ -1,6 +1,7 @@ import assert from 'assert'; import crypto from 'crypto'; +import { bip32 } from '@bitgo/secp256k1'; import * as utxolib from '@bitgo/utxo-lib'; import { decodeProprietaryKey } from 'bip174/src/lib/proprietaryKeyVal'; import { KeyValue } from 'bip174/src/lib/interfaces'; @@ -19,7 +20,7 @@ import { NIL_UUID } from '../../../src/paygo/attestation'; // To construct our PSBTs export const network = utxolib.networks.bitcoin; -const keys = [1, 2, 3].map((v) => utxolib.bip32.fromSeed(Buffer.alloc(16, `test/2/${v}`), network)); +const keys = [1, 2, 3].map((v) => bip32.fromSeed(Buffer.alloc(16, `test/2/${v}`), network)); const rootWalletKeys = new utxolib.bitgo.RootWalletKeys([keys[0], keys[1], keys[2]]); // PSBT INPUTS AND OUTPUTS From ceed183bf78e70816c05801091e56eb936d9e03b Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Fri, 10 Oct 2025 17:38:00 +0200 Subject: [PATCH 04/34] feat(utxo-lib): use @bitgo/secp256k1 instead of internal noble_ecc Replace internal noble_ecc wrapper with direct imports from @bitgo/secp256k1. This removes redundant code while maintaining the same functionality. Deprecated exports are preserved for backward compatibility. Issue: BTC-2668 Co-authored-by: llm-git --- modules/utxo-lib/package.json | 7 +- modules/utxo-lib/src/bitgo/Musig2.ts | 2 +- modules/utxo-lib/src/bitgo/UtxoPsbt.ts | 2 +- modules/utxo-lib/src/bitgo/keyutil.ts | 3 +- .../utxo-lib/src/bitgo/legacysafe/index.ts | 2 +- modules/utxo-lib/src/bitgo/outputScripts.ts | 2 +- modules/utxo-lib/src/bitgo/signature.ts | 5 +- modules/utxo-lib/src/bitgo/wallet/Psbt.ts | 2 +- .../utxo-lib/src/bitgo/wallet/WalletKeys.ts | 2 +- .../src/bitgo/wallet/WalletUnspentSigner.ts | 2 +- .../src/bitgo/wallet/psbt/PsbtOutputs.ts | 2 +- .../src/bitgo/wallet/psbt/RootNodes.ts | 3 +- modules/utxo-lib/src/index.ts | 19 +- modules/utxo-lib/src/noble_ecc.ts | 178 ------------------ modules/utxo-lib/src/payments/p2tr.ts | 10 +- modules/utxo-lib/src/taproot.ts | 2 +- .../src/templates/taprootnofn/output.ts | 2 +- modules/utxo-lib/src/testutil/keys.ts | 3 +- modules/utxo-lib/src/testutil/mock.ts | 9 +- modules/utxo-lib/src/transaction_builder.ts | 2 +- modules/utxo-lib/test/bitgo/keyutil.ts | 3 +- .../utxo-lib/test/bitgo/psbt/Musig2Util.ts | 3 +- .../test/bitgo/psbt/SignVerifyPsbtAndTx.ts | 2 +- modules/utxo-lib/test/bitgo/signature.ts | 2 +- .../utxo-lib/test/bitgo/signatureModify.ts | 3 +- .../generate/outputScripts.util.ts | 2 +- .../test/integration_local_rpc/parse.ts | 2 +- modules/utxo-lib/test/taproot.spec.ts | 4 +- modules/utxo-lib/test/transaction_util.ts | 2 +- 29 files changed, 49 insertions(+), 233 deletions(-) delete mode 100644 modules/utxo-lib/src/noble_ecc.ts diff --git a/modules/utxo-lib/package.json b/modules/utxo-lib/package.json index be80d24c22..534fd3df6c 100644 --- a/modules/utxo-lib/package.json +++ b/modules/utxo-lib/package.json @@ -47,19 +47,14 @@ ], "dependencies": { "@bitgo/blake2b": "^3.2.4", + "@bitgo/secp256k1": "^1.5.0", "@brandonblack/musig": "^0.0.1-alpha.0", - "@noble/curves": "1.8.1", - "@noble/secp256k1": "1.6.3", "bech32": "^2.0.0", "bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4", - "bip32": "^3.0.1", "bitcoin-ops": "^1.3.0", "bitcoinjs-lib": "npm:@bitgo-forks/bitcoinjs-lib@7.1.0-master.11", "bs58check": "^2.1.2", "cashaddress": "^1.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ecpair": "npm:@bitgo/ecpair@2.1.0-rc.0", "fastpriorityqueue": "^0.7.1", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2" diff --git a/modules/utxo-lib/src/bitgo/Musig2.ts b/modules/utxo-lib/src/bitgo/Musig2.ts index 80314308cf..23e922c7f5 100644 --- a/modules/utxo-lib/src/bitgo/Musig2.ts +++ b/modules/utxo-lib/src/bitgo/Musig2.ts @@ -7,7 +7,7 @@ import { checkXOnlyPublicKey, toXOnlyPublicKey, } from './outputScripts'; -import { ecc, musig } from '../noble_ecc'; +import { ecc, musig } from '@bitgo/secp256k1'; import { Tuple } from './types'; import { calculateTapTweak, tapTweakPubkey } from '../taproot'; import { Transaction } from '../index'; diff --git a/modules/utxo-lib/src/bitgo/UtxoPsbt.ts b/modules/utxo-lib/src/bitgo/UtxoPsbt.ts index f2438b6174..fa37aa25ac 100644 --- a/modules/utxo-lib/src/bitgo/UtxoPsbt.ts +++ b/modules/utxo-lib/src/bitgo/UtxoPsbt.ts @@ -10,9 +10,9 @@ import { import { checkForInput } from 'bip174/src/lib/utils'; import { BufferWriter, varuint } from 'bitcoinjs-lib/src/bufferutils'; import { SessionKey } from '@brandonblack/musig'; -import { BIP32Factory, BIP32Interface } from 'bip32'; import * as bs58check from 'bs58check'; import { decodeProprietaryKey, encodeProprietaryKey } from 'bip174/src/lib/proprietaryKeyVal'; +import { BIP32Factory, BIP32Interface } from '@bitgo/secp256k1'; import { taproot, diff --git a/modules/utxo-lib/src/bitgo/keyutil.ts b/modules/utxo-lib/src/bitgo/keyutil.ts index d92fc7a1a2..da2b0a4ea6 100644 --- a/modules/utxo-lib/src/bitgo/keyutil.ts +++ b/modules/utxo-lib/src/bitgo/keyutil.ts @@ -1,7 +1,6 @@ -import { ECPairInterface } from 'ecpair'; import * as bs58check from 'bs58check'; import { Network } from '../networks'; -import { bip32, ECPair } from '../noble_ecc'; +import { bip32, ECPair, ECPairInterface } from '@bitgo/secp256k1'; /** * Create an ECPair from the raw private key bytes diff --git a/modules/utxo-lib/src/bitgo/legacysafe/index.ts b/modules/utxo-lib/src/bitgo/legacysafe/index.ts index 24ce4dac3a..f65e020645 100644 --- a/modules/utxo-lib/src/bitgo/legacysafe/index.ts +++ b/modules/utxo-lib/src/bitgo/legacysafe/index.ts @@ -5,7 +5,7 @@ * */ import * as assert from 'assert'; -import { ecc as eccLib } from '../../noble_ecc'; +import { ecc as eccLib } from '@bitgo/secp256k1'; import { isBitcoin, Network } from '../../networks'; import { isTriple } from '../types'; import * as bitcoinjs from 'bitcoinjs-lib'; diff --git a/modules/utxo-lib/src/bitgo/outputScripts.ts b/modules/utxo-lib/src/bitgo/outputScripts.ts index 2f9b9aa212..831beade3e 100644 --- a/modules/utxo-lib/src/bitgo/outputScripts.ts +++ b/modules/utxo-lib/src/bitgo/outputScripts.ts @@ -7,7 +7,7 @@ import * as taproot from '../taproot'; import { isTriple, Triple, Tuple } from './types'; -import { ecc as eccLib } from '../noble_ecc'; +import { ecc as eccLib } from '@bitgo/secp256k1'; import { getDepthFirstTaptree, getTweakedOutputKey } from '../taproot'; export { scriptTypeForChain } from './wallet/chains'; diff --git a/modules/utxo-lib/src/bitgo/signature.ts b/modules/utxo-lib/src/bitgo/signature.ts index 100b948302..680319ac97 100644 --- a/modules/utxo-lib/src/bitgo/signature.ts +++ b/modules/utxo-lib/src/bitgo/signature.ts @@ -1,6 +1,5 @@ -import { BIP32Interface } from 'bip32'; - import { Transaction, taproot, TxOutput, ScriptSignature } from 'bitcoinjs-lib'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { UtxoTransaction } from './UtxoTransaction'; import { UtxoTransactionBuilder } from './UtxoTransactionBuilder'; @@ -15,7 +14,7 @@ import { } from './outputScripts'; import { Triple } from './types'; import { getMainnet, Network, networks } from '../networks'; -import { ecc as eccLib } from '../noble_ecc'; +import { ecc as eccLib } from '@bitgo/secp256k1'; import { parseSignatureScript2Of3 } from './parseInput'; import { getTaprootOutputKey } from '../taproot'; diff --git a/modules/utxo-lib/src/bitgo/wallet/Psbt.ts b/modules/utxo-lib/src/bitgo/wallet/Psbt.ts index 5a2bad2c4a..ef6ff7b32b 100644 --- a/modules/utxo-lib/src/bitgo/wallet/Psbt.ts +++ b/modules/utxo-lib/src/bitgo/wallet/Psbt.ts @@ -2,8 +2,8 @@ import * as assert from 'assert'; import { GlobalXpub, PartialSig, PsbtInput, TapScriptSig } from 'bip174/src/lib/interfaces'; import { checkForInput } from 'bip174/src/lib/utils'; -import { BIP32Interface } from 'bip32'; import * as bs58check from 'bs58check'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { UtxoPsbt } from '../UtxoPsbt'; import { Psbt } from '../../'; import { UtxoTransaction } from '../UtxoTransaction'; diff --git a/modules/utxo-lib/src/bitgo/wallet/WalletKeys.ts b/modules/utxo-lib/src/bitgo/wallet/WalletKeys.ts index 875750ab78..f76f742f90 100644 --- a/modules/utxo-lib/src/bitgo/wallet/WalletKeys.ts +++ b/modules/utxo-lib/src/bitgo/wallet/WalletKeys.ts @@ -9,7 +9,7 @@ * Since we never use other derivations for utxo address scripts, the classes defined here only * allow exactly one level of derivation. */ -import { BIP32Interface } from 'bip32'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { Triple } from '../types'; diff --git a/modules/utxo-lib/src/bitgo/wallet/WalletUnspentSigner.ts b/modules/utxo-lib/src/bitgo/wallet/WalletUnspentSigner.ts index 82e5cc4d9d..d3e186f386 100644 --- a/modules/utxo-lib/src/bitgo/wallet/WalletUnspentSigner.ts +++ b/modules/utxo-lib/src/bitgo/wallet/WalletUnspentSigner.ts @@ -1,4 +1,4 @@ -import { BIP32Interface } from 'bip32'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { DerivedWalletKeys, eqPublicKey, RootWalletKeys, WalletKeys } from './WalletKeys'; import { Triple } from '../types'; diff --git a/modules/utxo-lib/src/bitgo/wallet/psbt/PsbtOutputs.ts b/modules/utxo-lib/src/bitgo/wallet/psbt/PsbtOutputs.ts index 92d34dfd69..299adefeaf 100644 --- a/modules/utxo-lib/src/bitgo/wallet/psbt/PsbtOutputs.ts +++ b/modules/utxo-lib/src/bitgo/wallet/psbt/PsbtOutputs.ts @@ -5,9 +5,9 @@ import { isBufferArray, Triple } from '../../types'; import { createOutputScript2of3, scriptTypes2Of3 } from '../../outputScripts'; import { UtxoPsbt } from '../../UtxoPsbt'; -import { BIP32Interface } from 'bip32'; import { checkForOutput } from 'bip174/src/lib/utils'; import { PsbtOutput } from 'bip174/src/lib/interfaces'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { getSortedRootNodes } from './RootNodes'; /** diff --git a/modules/utxo-lib/src/bitgo/wallet/psbt/RootNodes.ts b/modules/utxo-lib/src/bitgo/wallet/psbt/RootNodes.ts index 95a8bd73d3..ff0f8b5c35 100644 --- a/modules/utxo-lib/src/bitgo/wallet/psbt/RootNodes.ts +++ b/modules/utxo-lib/src/bitgo/wallet/psbt/RootNodes.ts @@ -7,8 +7,7 @@ import * as bs58check from 'bs58check'; import { UtxoPsbt } from '../../UtxoPsbt'; import { isTriple, Triple } from '../../types'; -import { BIP32Factory, BIP32Interface } from 'bip32'; -import { ecc as eccLib } from '../../../noble_ecc'; +import { BIP32Factory, BIP32Interface, ecc as eccLib } from '@bitgo/secp256k1'; import { ParsedScriptType2Of3 } from '../../parseInput'; import { Network } from '../../../networks'; import { createOutputScript2of3 } from '../../outputScripts'; diff --git a/modules/utxo-lib/src/index.ts b/modules/utxo-lib/src/index.ts index 1383bd6515..acf0535137 100644 --- a/modules/utxo-lib/src/index.ts +++ b/modules/utxo-lib/src/index.ts @@ -14,7 +14,24 @@ export * as taproot from './taproot'; export * as testutil from './testutil'; -export * from './noble_ecc'; +import { bip32, BIP32API, BIP32Interface, ecc, ECPair, ECPairInterface, ECPairAPI } from '@bitgo/secp256k1'; + +export { + // @deprecated use import { bip32 } from '@bitgo/secp256k1' instead + bip32, + // @deprecated use import { BIP32API } from '@bitgo/secp256k1' instead + BIP32API, + // @deprecated use import { BIP32Interface } from '@bitgo/secp256k1' instead + BIP32Interface, + // @deprecated use import { ecc } from '@bitgo/secp256k1' instead + ecc, + // @deprecated use import { ECPair } from '@bitgo/secp256k1' instead + ECPair, + // @deprecated use import { ECPairAPI } from '@bitgo/secp256k1' instead + ECPairAPI, + // @deprecated use import { ECPairInterface } from '@bitgo/secp256k1' instead + ECPairInterface, +}; export * as p2trPayments from './payments'; diff --git a/modules/utxo-lib/src/noble_ecc.ts b/modules/utxo-lib/src/noble_ecc.ts deleted file mode 100644 index 4e97e1a3f8..0000000000 --- a/modules/utxo-lib/src/noble_ecc.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { ECPairAPI, ECPairFactory, ECPairInterface } from 'ecpair'; -import * as necc from '@noble/secp256k1'; -import { BIP32API, BIP32Factory, BIP32Interface } from 'bip32'; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore base_crypto is exported as a subPath export, ignoring since compiler complains about importing like this -import * as baseCrypto from '@brandonblack/musig/base_crypto'; -import { MuSig, MuSigFactory } from '@brandonblack/musig'; -const createHmac = require('create-hmac'); -const createHash = require('create-hash'); - -necc.utils.sha256Sync = (...messages: Uint8Array[]): Uint8Array => { - const sha256 = createHash('sha256'); - for (const message of messages) sha256.update(message); - return sha256.digest(); -}; - -necc.utils.hmacSha256Sync = (key: Uint8Array, ...messages: Uint8Array[]): Uint8Array => { - const hash = createHmac('sha256', Buffer.from(key)); - messages.forEach((m) => hash.update(m)); - return Uint8Array.from(hash.digest()); -}; - -const defaultTrue = (param?: boolean): boolean => param !== false; - -function throwToNull(fn: () => Type): Type | null { - try { - return fn(); - } catch (e) { - return null; - } -} - -function isPoint(p: Uint8Array, xOnly: boolean): boolean { - if ((p.length === 32) !== xOnly) return false; - try { - return !!necc.Point.fromHex(p); - } catch (e) { - return false; - } -} - -function toBigInt(b: Uint8Array | Buffer): bigint { - const buff = Buffer.from(b); - if (buff.length !== 32) { - throw new Error('Invalid size ${buff.length}'); - } - return BigInt(`0x${buff.toString('hex')}`); -} - -const ecc = { - isPoint: (p: Uint8Array): boolean => isPoint(p, false), - isPrivate: (d: Uint8Array): boolean => necc.utils.isValidPrivateKey(d), - isXOnlyPoint: (p: Uint8Array): boolean => isPoint(p, true), - - xOnlyPointAddTweak: (p: Uint8Array, tweak: Uint8Array): { parity: 0 | 1; xOnlyPubkey: Uint8Array } | null => - throwToNull(() => { - const P = necc.utils.pointAddScalar(p, tweak, true); - const parity = P[0] % 2 === 1 ? 1 : 0; - return { parity, xOnlyPubkey: P.slice(1) }; - }), - - pointFromScalar: (sk: Uint8Array, compressed?: boolean): Uint8Array | null => - throwToNull(() => necc.getPublicKey(sk, defaultTrue(compressed))), - - pointCompress: (p: Uint8Array, compressed?: boolean): Uint8Array => { - return necc.Point.fromHex(p).toRawBytes(defaultTrue(compressed)); - }, - - pointMultiply: (a: Uint8Array, tweak: Uint8Array, compressed?: boolean): Uint8Array | null => - throwToNull(() => necc.utils.pointMultiply(a, tweak, defaultTrue(compressed))), - - pointAdd: (a: Uint8Array, b: Uint8Array, compressed?: boolean): Uint8Array | null => - throwToNull(() => { - const A = necc.Point.fromHex(a); - const B = necc.Point.fromHex(b); - return A.add(B).toRawBytes(defaultTrue(compressed)); - }), - - pointAddScalar: (p: Uint8Array, tweak: Uint8Array, compressed?: boolean): Uint8Array | null => - throwToNull(() => necc.utils.pointAddScalar(p, tweak, defaultTrue(compressed))), - - privateAdd: (d: Uint8Array, tweak: Uint8Array): Uint8Array | null => - throwToNull(() => { - const res = necc.utils.privateAdd(d, tweak); - // tiny-secp256k1 returns null rather than allowing a 0 private key to be returned - // ECPair.testEcc() requires that behavior. - if (res?.every((i) => i === 0)) return null; - return res; - }), - - privateNegate: (d: Uint8Array): Uint8Array => necc.utils.privateNegate(d), - - sign: (h: Uint8Array, d: Uint8Array, e?: Uint8Array): Uint8Array => { - return necc.signSync(h, d, { der: false, extraEntropy: e }); - }, - - signSchnorr: (h: Uint8Array, d: Uint8Array, e: Uint8Array = Buffer.alloc(32, 0x00)): Uint8Array => { - return necc.schnorr.signSync(h, d, e); - }, - - verify: (h: Uint8Array, Q: Uint8Array, signature: Uint8Array, strict?: boolean): boolean => { - return necc.verify(signature, h, Q, { strict }); - }, - - verifySchnorr: (h: Uint8Array, Q: Uint8Array, signature: Uint8Array): boolean => { - return necc.schnorr.verifySync(signature, h, Q); - }, -}; - -const crypto = { - ...baseCrypto, - pointMultiplyUnsafe(p: Uint8Array, a: Uint8Array, compress: boolean): Uint8Array | null { - try { - const product = necc.Point.fromHex(p).multiplyAndAddUnsafe(necc.Point.ZERO, toBigInt(a), BigInt(1)); - if (!product) return null; - return product.toRawBytes(compress); - } catch { - return null; - } - }, - pointMultiplyAndAddUnsafe(p1: Uint8Array, a: Uint8Array, p2: Uint8Array, compress: boolean): Uint8Array | null { - try { - const p2p = necc.Point.fromHex(p2); - const p = necc.Point.fromHex(p1).multiplyAndAddUnsafe(p2p, toBigInt(a), BigInt(1)); - if (!p) return null; - return p.toRawBytes(compress); - } catch { - return null; - } - }, - pointAdd(a: Uint8Array, b: Uint8Array, compress: boolean): Uint8Array | null { - try { - return necc.Point.fromHex(a).add(necc.Point.fromHex(b)).toRawBytes(compress); - } catch { - return null; - } - }, - pointAddTweak(p: Uint8Array, tweak: Uint8Array, compress: boolean): Uint8Array | null { - try { - const P = necc.Point.fromHex(p); - const t = baseCrypto.readSecret(tweak); - const Q = necc.Point.BASE.multiplyAndAddUnsafe(P, t, BigInt(1)); - if (!Q) throw new Error('Tweaked point at infinity'); - return Q.toRawBytes(compress); - } catch { - return null; - } - }, - pointCompress(p: Uint8Array, compress = true): Uint8Array { - return necc.Point.fromHex(p).toRawBytes(compress); - }, - liftX(p: Uint8Array): Uint8Array | null { - try { - return necc.Point.fromHex(p).toRawBytes(false); - } catch { - return null; - } - }, - getPublicKey(s: Uint8Array, compress: boolean): Uint8Array | null { - try { - return necc.getPublicKey(s, compress); - } catch { - return null; - } - }, - taggedHash: necc.utils.taggedHashSync, - sha256(...messages: Uint8Array[]): Uint8Array { - const sha256 = createHash('sha256'); - for (const message of messages) sha256.update(message); - return sha256.digest(); - }, -}; - -const ECPair: ECPairAPI = ECPairFactory(ecc); -const bip32: BIP32API = BIP32Factory(ecc); -const musig: MuSig = MuSigFactory(crypto); - -export { ecc, ECPair, ECPairAPI, ECPairInterface, bip32, BIP32API, BIP32Interface, musig, MuSig }; diff --git a/modules/utxo-lib/src/payments/p2tr.ts b/modules/utxo-lib/src/payments/p2tr.ts index 80005c6f26..b47c3b8afb 100644 --- a/modules/utxo-lib/src/payments/p2tr.ts +++ b/modules/utxo-lib/src/payments/p2tr.ts @@ -4,8 +4,7 @@ import { networks } from '../networks'; import { script as bscript, Payment, PaymentOpts, lazy } from 'bitcoinjs-lib'; import * as taproot from '../taproot'; -import { musig } from '../noble_ecc'; -import { secp256k1 as necc } from '@noble/curves/secp256k1'; +import { musig, ecc } from '@bitgo/secp256k1'; const typef = require('typeforce'); const OPS = bscript.OPS; @@ -22,12 +21,7 @@ const H = Buffer.from('50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ac const EMPTY_BUFFER = Buffer.alloc(0); function isPlainPubkey(pubKey: Uint8Array): boolean { - if (pubKey.length !== 33) return false; - try { - return !!necc.ProjectivePoint.fromHex(pubKey); - } catch (e) { - return false; - } + return ecc.isPoint(pubKey); } function isPlainPubkeys(pubkeys: Buffer[]) { diff --git a/modules/utxo-lib/src/taproot.ts b/modules/utxo-lib/src/taproot.ts index 7d6de52249..f1657ecd73 100644 --- a/modules/utxo-lib/src/taproot.ts +++ b/modules/utxo-lib/src/taproot.ts @@ -6,7 +6,7 @@ import { TapTree as PsbtTapTree, TapLeaf as PsbtTapLeaf } from 'bip174/src/lib/i import assert = require('assert'); import FastPriorityQueue = require('fastpriorityqueue'); import { script as bscript, crypto as bcrypto, payments as bpayments } from 'bitcoinjs-lib'; -import { ecc as eccLib } from './noble_ecc'; +import { ecc as eccLib } from '@bitgo/secp256k1'; const varuint = require('varuint-bitcoin'); /** diff --git a/modules/utxo-lib/src/templates/taprootnofn/output.ts b/modules/utxo-lib/src/templates/taprootnofn/output.ts index 6c6e7cae63..0fabb3bd4d 100644 --- a/modules/utxo-lib/src/templates/taprootnofn/output.ts +++ b/modules/utxo-lib/src/templates/taprootnofn/output.ts @@ -3,7 +3,7 @@ import { Stack } from '../../'; import { script as bscript } from '../../'; import { opcodes } from '../../'; -import { ecc } from '../../noble_ecc'; +import { ecc } from '@bitgo/secp256k1'; export function check(script: Buffer | Stack, allowIncomplete?: boolean): boolean { const chunks = bscript.decompile(script) as Stack; diff --git a/modules/utxo-lib/src/testutil/keys.ts b/modules/utxo-lib/src/testutil/keys.ts index cb305e7e4a..25eae045bb 100644 --- a/modules/utxo-lib/src/testutil/keys.ts +++ b/modules/utxo-lib/src/testutil/keys.ts @@ -1,9 +1,8 @@ -import { BIP32API, BIP32Factory, BIP32Interface } from 'bip32'; import * as crypto from 'crypto'; import { Triple } from '../bitgo/types'; import { RootWalletKeys } from '../bitgo/wallet/WalletKeys'; -import { ecc, ECPair, ECPairInterface } from '../noble_ecc'; +import { BIP32API, BIP32Factory, BIP32Interface, ecc, ECPair, ECPairInterface } from '@bitgo/secp256k1'; import { networks } from '../networks'; const bip32: BIP32API = BIP32Factory(ecc); diff --git a/modules/utxo-lib/src/testutil/mock.ts b/modules/utxo-lib/src/testutil/mock.ts index fcfbe5a323..21ac8e5491 100644 --- a/modules/utxo-lib/src/testutil/mock.ts +++ b/modules/utxo-lib/src/testutil/mock.ts @@ -1,6 +1,5 @@ import { ok as assert } from 'assert'; -import { BIP32Interface } from 'bip32'; -import * as noble from '@noble/secp256k1'; +import { BIP32Interface } from '@bitgo/secp256k1'; import * as utxolib from '..'; import { getMainnet, Network, networks } from '../networks'; @@ -56,11 +55,7 @@ export function mockPrevTx( }); // Don't require the prevTx for signing and finalizing for non-segwit input utxolib.bitgo.withUnsafeNonSegwit(psbtFromNetwork, () => { - psbtFromNetwork.signInput(0, { - publicKey: pubkey, - sign: (hash: Buffer, lowR?: boolean) => - Buffer.from(noble.signSync(hash, keypair.privateKey as Buffer, { canonical: !lowR, der: false })), - }); + psbtFromNetwork.signInput(0, keypair); psbtFromNetwork.validateSignaturesOfAllInputs(); psbtFromNetwork.finalizeAllInputs(); }); diff --git a/modules/utxo-lib/src/transaction_builder.ts b/modules/utxo-lib/src/transaction_builder.ts index 1cf67d601f..a57c0c11e0 100644 --- a/modules/utxo-lib/src/transaction_builder.ts +++ b/modules/utxo-lib/src/transaction_builder.ts @@ -11,7 +11,7 @@ import { script as bscript } from './'; import { opcodes as ops } from './'; import { taproot } from './'; import { TxOutput, Transaction } from './'; -import { ECPair, ecc as eccLib } from './noble_ecc'; +import { ECPair, ecc as eccLib } from '@bitgo/secp256k1'; export interface Signer { privateKey?: Buffer; diff --git a/modules/utxo-lib/test/bitgo/keyutil.ts b/modules/utxo-lib/test/bitgo/keyutil.ts index 01cdbcd9ac..ddfca1ae0f 100644 --- a/modules/utxo-lib/test/bitgo/keyutil.ts +++ b/modules/utxo-lib/test/bitgo/keyutil.ts @@ -3,13 +3,12 @@ import { networks } from '../../src'; const assert = require('assert'); const crypto = require('crypto'); -import { ECPairInterface } from 'ecpair'; import { convertExtendedKeyNetwork, privateKeyBufferFromECPair, privateKeyBufferToECPair, } from '../../src/bitgo/keyutil'; -import { bip32, ECPair } from '../../src/noble_ecc'; +import { bip32, ECPair, ECPairInterface } from '@bitgo/secp256k1'; describe('privateKeyBufferFromECPair', function () { it('pads short private keys', function () { diff --git a/modules/utxo-lib/test/bitgo/psbt/Musig2Util.ts b/modules/utxo-lib/test/bitgo/psbt/Musig2Util.ts index 591c365379..80c0413242 100644 --- a/modules/utxo-lib/test/bitgo/psbt/Musig2Util.ts +++ b/modules/utxo-lib/test/bitgo/psbt/Musig2Util.ts @@ -32,8 +32,7 @@ import { toXOnlyPublicKey, } from '../../../src/bitgo/outputScripts'; import { mockWalletUnspent, replayProtectionKeyPair } from '../../../src/testutil'; -import { bip32, networks } from '../../../src'; -import { BIP32Interface } from 'bip32'; +import { bip32, BIP32Interface, networks } from '../../../src'; import { isPsbtInputFinalized } from '../../../src/bitgo/PsbtUtil'; export const network = networks.bitcoin; diff --git a/modules/utxo-lib/test/bitgo/psbt/SignVerifyPsbtAndTx.ts b/modules/utxo-lib/test/bitgo/psbt/SignVerifyPsbtAndTx.ts index dd238836c4..6234202a42 100644 --- a/modules/utxo-lib/test/bitgo/psbt/SignVerifyPsbtAndTx.ts +++ b/modules/utxo-lib/test/bitgo/psbt/SignVerifyPsbtAndTx.ts @@ -10,7 +10,7 @@ import { Triple, UtxoTransaction, } from '../../../src/bitgo'; -import { BIP32Interface } from 'bip32'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { constructPsbt, constructTxnBuilder, diff --git a/modules/utxo-lib/test/bitgo/signature.ts b/modules/utxo-lib/test/bitgo/signature.ts index 5cba5b2e0b..5bb35a8a74 100644 --- a/modules/utxo-lib/test/bitgo/signature.ts +++ b/modules/utxo-lib/test/bitgo/signature.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { BIP32Interface } from 'bip32'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { script as bscript, classify, TxOutput } from '../../src'; import { getKeyName } from '../../src/testutil'; diff --git a/modules/utxo-lib/test/bitgo/signatureModify.ts b/modules/utxo-lib/test/bitgo/signatureModify.ts index 67b16dbac2..56276d8282 100644 --- a/modules/utxo-lib/test/bitgo/signatureModify.ts +++ b/modules/utxo-lib/test/bitgo/signatureModify.ts @@ -1,9 +1,8 @@ /* eslint-disable no-redeclare */ import { script, ScriptSignature, TxOutput } from 'bitcoinjs-lib'; import { isPlaceholderSignature, parseSignatureScript, UtxoTransaction } from '../../src/bitgo'; -import { secp256k1 } from '@noble/curves/secp256k1'; -const n = BigInt(secp256k1.CURVE.n); +const n = BigInt('0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'); const nDiv2 = n / BigInt(2); function bytesToBigInt(bytes: Uint8Array): bigint { diff --git a/modules/utxo-lib/test/integration_local_rpc/generate/outputScripts.util.ts b/modules/utxo-lib/test/integration_local_rpc/generate/outputScripts.util.ts index 56188bfc83..3d88e00afa 100644 --- a/modules/utxo-lib/test/integration_local_rpc/generate/outputScripts.util.ts +++ b/modules/utxo-lib/test/integration_local_rpc/generate/outputScripts.util.ts @@ -1,5 +1,5 @@ -import { BIP32Interface } from 'bip32'; import { Transaction, TxOutput } from 'bitcoinjs-lib'; +import { BIP32Interface } from '@bitgo/secp256k1'; import * as utxolib from '../../../src'; import { createOutputScript2of3, diff --git a/modules/utxo-lib/test/integration_local_rpc/parse.ts b/modules/utxo-lib/test/integration_local_rpc/parse.ts index fe16aa0bdc..0834408ffa 100644 --- a/modules/utxo-lib/test/integration_local_rpc/parse.ts +++ b/modules/utxo-lib/test/integration_local_rpc/parse.ts @@ -1,6 +1,6 @@ import * as assert from 'assert/strict'; import { describe, it } from 'mocha'; -import { BIP32Interface } from 'bip32'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { isTestnet, TxOutput, getNetworkList, getNetworkName, networks } from '../../src'; import { getDefaultCosigner } from '../../src/testutil'; diff --git a/modules/utxo-lib/test/taproot.spec.ts b/modules/utxo-lib/test/taproot.spec.ts index f320e1c6cd..3655742790 100644 --- a/modules/utxo-lib/test/taproot.spec.ts +++ b/modules/utxo-lib/test/taproot.spec.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; -import { ECPairAPI, ECPairFactory } from 'ecpair'; -import { ecc, taproot } from '../src'; +import { ECPairAPI, ECPairFactory, ecc } from '@bitgo/secp256k1'; +import { taproot } from '../src'; import { createTaprootOutputScript, getTaprootOutputKey } from '../src/taproot'; const ECPair: ECPairAPI = ECPairFactory(ecc); diff --git a/modules/utxo-lib/test/transaction_util.ts b/modules/utxo-lib/test/transaction_util.ts index 26e24288a8..9f3e58a405 100644 --- a/modules/utxo-lib/test/transaction_util.ts +++ b/modules/utxo-lib/test/transaction_util.ts @@ -1,6 +1,6 @@ -import { BIP32Interface } from 'bip32'; import * as assert from 'assert'; import { TxOutput } from 'bitcoinjs-lib'; +import { BIP32Interface } from '@bitgo/secp256k1'; import { networks, Network } from '../src'; From 8cbdf3ec4be6cc52abd405c369befb8814957063 Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Tue, 7 Oct 2025 12:29:49 +0530 Subject: [PATCH 05/34] feat(sdk-coin-canton): added pre-approval builder Ticket: COIN-5918 --- .../sdk-coin-canton/resources/hash/hash.d.ts | 5 + .../sdk-coin-canton/resources/hash/hash.js | 297 ++++++++++++++++++ modules/sdk-coin-canton/src/lib/iface.ts | 26 +- .../src/lib/oneStepPreApprovalBuilder.ts | 177 +++++++++++ .../src/lib/transaction/transaction.ts | 50 ++- .../src/lib/transactionBuilder.ts | 59 ++-- .../src/lib/transferBuilder.ts | 5 + modules/sdk-coin-canton/src/lib/utils.ts | 7 + .../walletInitTransaction.ts | 1 - modules/sdk-coin-canton/test/resources.ts | 36 +++ .../oneStepEnablementBuilder.ts | 88 ++++++ modules/sdk-coin-canton/test/unit/utils.ts | 12 +- .../sdk-core/src/account-lib/baseCoin/enum.ts | 2 + 13 files changed, 727 insertions(+), 38 deletions(-) create mode 100644 modules/sdk-coin-canton/resources/hash/hash.d.ts create mode 100644 modules/sdk-coin-canton/resources/hash/hash.js create mode 100644 modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts create mode 100644 modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts diff --git a/modules/sdk-coin-canton/resources/hash/hash.d.ts b/modules/sdk-coin-canton/resources/hash/hash.d.ts new file mode 100644 index 0000000000..e03d4a9e6e --- /dev/null +++ b/modules/sdk-coin-canton/resources/hash/hash.d.ts @@ -0,0 +1,5 @@ +import type { IPreparedTransaction } from '../../src/lib/iface'; + +declare module '../../resources/hash/hash.js' { + export function computePreparedTransaction(preparedTransaction: IPreparedTransaction): Promise; +} diff --git a/modules/sdk-coin-canton/resources/hash/hash.js b/modules/sdk-coin-canton/resources/hash/hash.js new file mode 100644 index 0000000000..f50b260c84 --- /dev/null +++ b/modules/sdk-coin-canton/resources/hash/hash.js @@ -0,0 +1,297 @@ +// This is the static helper file from canton SDK, replicating it here since we won't be using the canton wallet SDK +// TODO: https://bitgoinc.atlassian.net/browse/COIN-6016 +const PREPARED_TRANSACTION_HASH_PURPOSE = Uint8Array.from([0x00, 0x00, 0x00, 0x30]); +const NODE_ENCODING_VERSION = Uint8Array.from([0x01]); +const HASHING_SCHEME_VERSION = Uint8Array.from([2]); +async function sha256(message) { + const msg = typeof message === 'string' ? new TextEncoder().encode(message) : message; + return crypto.subtle.digest('SHA-256', new Uint8Array(msg)).then((hash) => new Uint8Array(hash)); +} +async function mkByteArray(...args) { + const normalizedArgs = args.map((arg) => { + if (typeof arg === 'number') { + return new Uint8Array([arg]); + } else { + return arg; + } + }); + let totalLength = 0; + normalizedArgs.forEach((arg) => { + totalLength += arg.length; + }); + const mergedArray = new Uint8Array(totalLength); + let offset = 0; + normalizedArgs.forEach((arg) => { + mergedArray.set(arg, offset); + offset += arg.length; + }); + return mergedArray; +} +async function encodeBool(value) { + return new Uint8Array([value ? 1 : 0]); +} +async function encodeInt32(value) { + const buffer = new ArrayBuffer(4); + const view = new DataView(buffer); + view.setInt32(0, value, false); // true for little-endian + return new Uint8Array(buffer); +} +async function encodeInt64(value) { + // eslint-disable-next-line no-undef + const num = typeof value === 'bigint' ? value : BigInt(value || 0); + const buffer = new ArrayBuffer(8); + const view = new DataView(buffer); + view.setBigInt64(0, num, false); // true for little-endian + return new Uint8Array(buffer); +} +export async function encodeString(value = '') { + const utf8Bytes = new TextEncoder().encode(value); + return encodeBytes(utf8Bytes); +} +async function encodeBytes(value) { + const length = await encodeInt32(value.length); + return mkByteArray(length, value); +} +async function encodeHash(value) { + return value; +} +function encodeHexString(value = '') { + // Convert hex string to Uint8Array + const bytes = new Uint8Array(value.length / 2); + for (let i = 0; i < value.length; i += 2) { + bytes[i / 2] = parseInt(value.slice(i, i + 2), 16); + } + return encodeBytes(bytes); +} +// Maybe suspicious? +async function encodeOptional(value, encodeFn) { + if (value === undefined || value === null) { + return new Uint8Array([0]); // Return empty array for undefined fields + } else { + return mkByteArray(1, await encodeFn(value)); + } +} +// Maybe suspicious? +async function encodeProtoOptional(parentValue, fieldName, value, encodeFn) { + if (parentValue && parentValue[fieldName] !== undefined) { + return mkByteArray(1, await encodeFn(value)); + } else { + return new Uint8Array([0]); // Return empty array for undefined fields + } +} +async function encodeRepeated(values = [], encodeFn) { + const length = await encodeInt32(values.length); + const encodedValues = await Promise.all(values.map(encodeFn)); + return mkByteArray(length, ...encodedValues); +} +function findSeed(nodeId, nodeSeeds) { + const seed = nodeSeeds.find((seed) => seed.nodeId.toString() === nodeId)?.seed; + return seed; +} +async function encodeIdentifier(identifier) { + return mkByteArray( + await encodeString(identifier.packageId), + await encodeRepeated(identifier.moduleName.split('.'), encodeString), + await encodeRepeated(identifier.entityName.split('.'), encodeString) + ); +} +async function encodeMetadata(metadata) { + return mkByteArray( + Uint8Array.from([0x01]), + await encodeRepeated(metadata.submitterInfo?.actAs, encodeString), + await encodeString(metadata.submitterInfo?.commandId), + await encodeString(metadata.transactionUuid), + await encodeInt32(metadata.mediatorGroup), + await encodeString(metadata.synchronizerId), + await encodeProtoOptional(metadata, 'minLedgerEffectiveTime', metadata.minLedgerEffectiveTime, encodeInt64), + await encodeProtoOptional(metadata, 'maxLedgerEffectiveTime', metadata.maxLedgerEffectiveTime, encodeInt64), + await encodeInt64(metadata.preparationTime), + await encodeRepeated(metadata.inputContracts, encodeInputContract) + ); +} +async function encodeCreateNode(create, nodeId, nodeSeeds) { + return create + ? mkByteArray( + NODE_ENCODING_VERSION, + await encodeString(create.lfVersion), + 0 /** Create node tag */, + await encodeOptional(findSeed(nodeId, nodeSeeds), encodeHash), + await encodeHexString(create.contractId), + await encodeString(create.packageName), + await encodeIdentifier(create.templateId), + await encodeValue(create.argument), + await encodeRepeated(create.signatories, encodeString), + await encodeRepeated(create.stakeholders, encodeString) + ) + : mkByteArray(); +} +async function encodeExerciseNode(exercise, nodeId, nodesDict, nodeSeeds) { + return mkByteArray( + NODE_ENCODING_VERSION, + await encodeString(exercise.lfVersion), + 1 /** Exercise node tag */, + await encodeHash(findSeed(nodeId, nodeSeeds)), + await encodeHexString(exercise.contractId), + await encodeString(exercise.packageName), + await encodeIdentifier(exercise.templateId), + await encodeRepeated(exercise.signatories, encodeString), + await encodeRepeated(exercise.stakeholders, encodeString), + await encodeRepeated(exercise.actingParties, encodeString), + await encodeProtoOptional(exercise, 'interfaceId', exercise.interfaceId, encodeIdentifier), + await encodeString(exercise.choiceId), + await encodeValue(exercise.chosenValue), + await encodeBool(exercise.consuming), + await encodeProtoOptional(exercise, 'exerciseResult', exercise.exerciseResult, encodeValue), + await encodeRepeated(exercise.choiceObservers, encodeString), + await encodeRepeated(exercise.children, encodeNodeId(nodesDict, nodeSeeds)) + ); +} +async function encodeFetchNode(fetch) { + return mkByteArray( + NODE_ENCODING_VERSION, + await encodeString(fetch.lfVersion), + 2 /** Fetch node tag */, + await encodeHexString(fetch.contractId), + await encodeString(fetch.packageName), + await encodeIdentifier(fetch.templateId), + await encodeRepeated(fetch.signatories, encodeString), + await encodeRepeated(fetch.stakeholders, encodeString), + await encodeProtoOptional(fetch, 'interfaceId', fetch.interfaceId, encodeIdentifier), + await encodeRepeated(fetch.actingParties, encodeString) + ); +} +async function encodeRollbackNode(rollback, nodesDict, nodeSeeds) { + return mkByteArray( + NODE_ENCODING_VERSION, + 3 /** Rollback node tag */, + await encodeRepeated(rollback.children, encodeNodeId(nodesDict, nodeSeeds)) + ); +} +async function encodeInputContract(contract) { + if (contract.contract.oneofKind === 'v1') + return mkByteArray( + await encodeInt64(contract.createdAt), + await sha256(await encodeCreateNode(contract.contract.v1, 'unused_node_id', [])) + ); + else throw new Error('Unsupported contract version'); +} +async function encodeValue(value) { + if (value.sum.oneofKind === 'unit') { + return Uint8Array.from([0]); // Unit value + } else if (value.sum.oneofKind === 'bool') { + return mkByteArray(Uint8Array.from([0x01]), await encodeBool(value.sum.bool)); + } else if (value.sum.oneofKind === 'int64') { + return mkByteArray(Uint8Array.from([0x02]), await encodeInt64(parseInt(value.sum.int64, 10))); + } else if (value.sum.oneofKind === 'numeric') { + return mkByteArray(Uint8Array.from([0x03]), await encodeString(value.sum.numeric)); + } else if (value.sum.oneofKind === 'timestamp') { + // eslint-disable-next-line no-undef + return mkByteArray(Uint8Array.from([0x04]), await encodeInt64(BigInt(value.sum.timestamp))); + } else if (value.sum.oneofKind === 'date') { + return mkByteArray(Uint8Array.from([0x05]), await encodeInt32(value.sum.date)); + } else if (value.sum.oneofKind === 'party') { + return mkByteArray(Uint8Array.from([0x06]), await encodeString(value.sum.party)); + } else if (value.sum.oneofKind === 'text') { + return mkByteArray(Uint8Array.from([0x07]), await encodeString(value.sum.text)); + } else if (value.sum.oneofKind === 'contractId') { + return mkByteArray(Uint8Array.from([0x08]), await encodeHexString(value.sum.contractId)); + } else if (value.sum.oneofKind === 'optional') { + return mkByteArray( + Uint8Array.from([0x09]), + await encodeProtoOptional(value.sum.optional, 'value', value.sum.optional.value, encodeValue) + ); + } else if (value.sum.oneofKind === 'list') { + return mkByteArray(Uint8Array.from([0x0a]), await encodeRepeated(value.sum.list.elements, encodeValue)); + } else if (value.sum.oneofKind === 'textMap') { + return mkByteArray(Uint8Array.from([0x0b]), await encodeRepeated(value.sum.textMap?.entries, encodeTextMapEntry)); + } else if (value.sum.oneofKind === 'record') { + return mkByteArray( + Uint8Array.from([0x0c]), + await encodeProtoOptional(value.sum.record, 'recordId', value.sum.record.recordId, encodeIdentifier), + await encodeRepeated(value.sum.record.fields, encodeRecordField) + ); + } else if (value.sum.oneofKind === 'variant') { + return mkByteArray( + Uint8Array.from([0x0d]), + await encodeProtoOptional(value.sum.variant, 'variantId', value.sum.variant.variantId, encodeIdentifier), + await encodeString(value.sum.variant.constructor), + await encodeValue(value.sum.variant.value) + ); + } else if (value.sum.oneofKind === 'enum') { + return mkByteArray( + Uint8Array.from([0x0e]), + await encodeProtoOptional(value.sum.enum, 'enumId', value.sum.enum.enumId, encodeIdentifier), + await encodeString(value.sum.enum.constructor) + ); + } else if (value.sum.oneofKind === 'genMap') { + return mkByteArray(Uint8Array.from([0x0f]), await encodeRepeated(value.sum.genMap?.entries, encodeGenMapEntry)); + } + throw new Error('Unsupported value type: ' + JSON.stringify(value)); +} +async function encodeTextMapEntry(entry) { + return mkByteArray(await encodeString(entry.key), await encodeValue(entry.value)); +} +async function encodeRecordField(field) { + return mkByteArray(await encodeOptional(field.label, encodeString), await encodeValue(field.value)); +} +async function encodeGenMapEntry(entry) { + return mkByteArray(await encodeValue(entry.key), await encodeValue(entry.value)); +} +function encodeNodeId(nodesDict, nodeSeeds) { + return async (nodeId) => { + const node = nodesDict[nodeId]; + if (!node) { + throw new Error(`Node with ID ${nodeId} not found in transaction`); + } + const encodedNode = await encodeNode(node, nodesDict, nodeSeeds); + return sha256(encodedNode); + }; +} +async function encodeNode(node, nodesDict, nodeSeeds) { + if (node.versionedNode.oneofKind === 'v1') { + if (node.versionedNode.v1.nodeType.oneofKind === 'create') { + return encodeCreateNode(node.versionedNode.v1.nodeType.create, node.nodeId, nodeSeeds); + } else if (node.versionedNode.v1.nodeType.oneofKind === 'exercise') { + return encodeExerciseNode(node.versionedNode.v1.nodeType.exercise, node.nodeId, nodesDict, nodeSeeds); + } else if (node.versionedNode.v1.nodeType.oneofKind === 'fetch') { + return encodeFetchNode(node.versionedNode.v1.nodeType.fetch); + } else if (node.versionedNode.v1.nodeType.oneofKind === 'rollback') { + return encodeRollbackNode(node.versionedNode.v1.nodeType.rollback, nodesDict, nodeSeeds); + } + throw new Error('Unsupported node type'); + } else { + throw new Error(`Unsupported node version`); + } +} +function createNodesDict(preparedTransaction) { + const nodesDict = {}; + const nodes = preparedTransaction.transaction?.nodes || []; + for (const node of nodes) { + nodesDict[node.nodeId] = node; + } + return nodesDict; +} +async function encodeTransaction(transaction, nodesDict, nodeSeeds) { + return mkByteArray( + await encodeString(transaction.version), + await encodeRepeated(transaction.roots, encodeNodeId(nodesDict, nodeSeeds)) + ); +} +async function hashTransaction(transaction, nodesDict) { + const encodedTransaction = await encodeTransaction(transaction, nodesDict, transaction.nodeSeeds); + const hash = await sha256(await mkByteArray(PREPARED_TRANSACTION_HASH_PURPOSE, encodedTransaction)); + return hash; +} +async function hashMetadata(metadata) { + const hash = await sha256(await mkByteArray(PREPARED_TRANSACTION_HASH_PURPOSE, await encodeMetadata(metadata))); + return hash; +} +async function encodePreparedTransaction(preparedTransaction) { + const nodesDict = createNodesDict(preparedTransaction); + const transactionHash = await hashTransaction(preparedTransaction.transaction, nodesDict); + const metadataHash = await hashMetadata(preparedTransaction.metadata); + return mkByteArray(PREPARED_TRANSACTION_HASH_PURPOSE, HASHING_SCHEME_VERSION, transactionHash, metadataHash); +} +export async function computePreparedTransaction(preparedTransaction) { + return sha256(await encodePreparedTransaction(preparedTransaction)); +} diff --git a/modules/sdk-coin-canton/src/lib/iface.ts b/modules/sdk-coin-canton/src/lib/iface.ts index 66bff2f94f..4df4130d14 100644 --- a/modules/sdk-coin-canton/src/lib/iface.ts +++ b/modules/sdk-coin-canton/src/lib/iface.ts @@ -27,7 +27,7 @@ export interface CantonPrepareCommandResponse { preparedTransaction?: string; preparedTransactionHash: string; hashingSchemeVersion: string; - hashingDetails?: string; + hashingDetails?: string | null; } export interface PreparedParty { @@ -57,3 +57,27 @@ export interface WalletInitRequest { confirmationThreshold: number; observingParticipantUids: string[]; } + +interface PreApprovalCreateCommand { + templateId: string; + createArguments: { + receiver: string; + provider: string; + expectedDso: string; + }; +} + +export interface OneStepEnablementRequest { + commandId: string; + commands: [ + { + CreateCommand: PreApprovalCreateCommand; + } + ]; + disclosedContracts: []; + synchronizerId: string; + verboseHashing: boolean; + actAs: string[]; + readAs: string[]; + packageIdSelectionPreference: string[]; +} diff --git a/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts b/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts new file mode 100644 index 0000000000..676c119265 --- /dev/null +++ b/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts @@ -0,0 +1,177 @@ +import { TransactionType } from '@bitgo/sdk-core'; +import { BaseCoin as CoinConfig } from '@bitgo/statics'; +import { CantonPrepareCommandResponse, OneStepEnablementRequest } from './iface'; +import { TransactionBuilder } from './transactionBuilder'; +import { Transaction } from './transaction/transaction'; + +export class OneStepPreApprovalBuilder extends TransactionBuilder { + private _synchronizerId: string; + private _commandId: string; + private _templateId: string; + private _receiverPartyId: string; + private _providerPartyId: string; + private _expectedDso: string; + constructor(_coinConfig: Readonly) { + super(_coinConfig); + } + + initBuilder(tx: Transaction): void { + super.initBuilder(tx); + this.setTransactionType(); + } + + get transactionType(): TransactionType { + return TransactionType.OneStepPreApproval; + } + + setTransactionType(): void { + this.transaction.transactionType = TransactionType.OneStepPreApproval; + } + + setTransaction(transaction: CantonPrepareCommandResponse): void { + this.transaction.prepareCommand = transaction; + } + + /** + * Sets the synchronizer ID for the pre-approval builder. + * + * @param id - The synchronizer identifier (must be a non-empty string). + * @returns The current builder instance for chaining. + * @throws Error if the synchronizer ID is empty. + */ + synchronizerId(id: string): this { + if (!id.trim()) { + throw new Error('synchronizer must be a non-empty string'); + } + this._synchronizerId = id.trim(); + return this; + } + + /** + * Sets the unique id for the 1-step enablement + * Also sets the _id of the transaction + * + * @param id - A uuid + * @returns The current builder instance for chaining. + * @throws Error if id is empty. + */ + commandId(id: string): this { + if (!id.trim()) { + throw new Error('commandId must be a non-empty string'); + } + this._commandId = id.trim(); + // also set the transaction _id + this.transaction.id = id.trim(); + return this; + } + + /** + * Sets the template id for the 1-step enablement + * + * @param id - the template if of the form `#splice-wallet:Splice.Wallet.TransferPreapproval:TransferPreapprovalProposal` + * @returns The current builder instance for chaining. + * @throws Error if id is empty. + */ + templateId(id: string): this { + if (!id.trim()) { + throw new Error('templateId must be a non-empty string'); + } + this._templateId = id.trim(); + return this; + } + + /** + * Sets the receiver for the 1-step enablement + * + * @param id - the receiver party id (address) + * @returns The current builder instance for chaining. + * @throws Error if id is empty. + */ + receiverPartyId(id: string): this { + if (!id.trim()) { + throw new Error('receiverPartyId must be a non-empty string'); + } + this._receiverPartyId = id.trim(); + return this; + } + + /** + * Sets the provider for the 1-step enablement + * + * @param id - the validator party id (address) + * @returns The current builder instance for chaining. + * @throws Error if id is empty. + */ + providerPartyId(id: string): this { + if (!id.trim()) { + throw new Error('providerPartyId must be a non-empty string'); + } + this._providerPartyId = id.trim(); + return this; + } + + /** + * Sets the dso id for the 1-step enablement + * + * @param id - the dso id of the validator + * @returns The current builder instance for chaining. + * @throws Error if id is empty. + */ + expectedDso(id: string): this { + if (!id.trim()) { + throw new Error('expectedDso must be a non-empty string'); + } + this._expectedDso = id.trim(); + return this; + } + + /** + * Builds and returns the OneStepEnablementRequest object from the builder's internal state. + * + * This method performs validation before constructing the object. If required fields are + * missing or invalid, it throws an error. + * + * @returns {OneStepEnablementRequest} - A fully constructed and validated request object for 1-step enablement. + * @throws {Error} If any required field is missing or fails validation. + */ + toRequestObject(): OneStepEnablementRequest { + this.validate(); + + return { + commandId: this._commandId, + commands: [ + { + CreateCommand: { + templateId: this._templateId, + createArguments: { + receiver: this._receiverPartyId, + provider: this._providerPartyId, + expectedDso: this._expectedDso, + }, + }, + }, + ], + disclosedContracts: [], + synchronizerId: this._synchronizerId, + verboseHashing: false, + actAs: [this._receiverPartyId], + readAs: [], + packageIdSelectionPreference: [], + }; + } + + /** + * Validates the internal state of the builder before building the request object. + * + * @private + * @throws {Error} If any required field is missing or invalid. + */ + private validate(): void { + if (!this._receiverPartyId) throw new Error('receiver partyId is missing'); + if (!this._providerPartyId) throw new Error('provider partyId is missing'); + if (!this._expectedDso) throw new Error('expectedDso is missing'); + if (!this._commandId) throw new Error('commandId is missing'); + if (!this._templateId) throw new Error('templateId is missing'); + if (!this._synchronizerId) throw new Error('synchronizerId is missing'); + } +} diff --git a/modules/sdk-coin-canton/src/lib/transaction/transaction.ts b/modules/sdk-coin-canton/src/lib/transaction/transaction.ts index b92816d724..705b397265 100644 --- a/modules/sdk-coin-canton/src/lib/transaction/transaction.ts +++ b/modules/sdk-coin-canton/src/lib/transaction/transaction.ts @@ -4,19 +4,33 @@ import { CantonPrepareCommandResponse, PreparedTxnParsedInfo, TxData } from '../ import utils from '../utils'; export class Transaction extends BaseTransaction { - private _transaction: CantonPrepareCommandResponse; + private _prepareCommand: CantonPrepareCommandResponse; constructor(coinConfig: Readonly) { super(coinConfig); } - get transaction(): CantonPrepareCommandResponse { - return this._transaction; + get prepareCommand(): CantonPrepareCommandResponse { + return this._prepareCommand; } - set transaction(transaction: CantonPrepareCommandResponse) { - this._transaction = transaction; - this._id = transaction.preparedTransactionHash; + set prepareCommand(transaction: CantonPrepareCommandResponse) { + this._prepareCommand = transaction; + } + + set transactionType(transactionType: TransactionType) { + this._type = transactionType; + } + + get id(): string { + if (!this._id) { + throw new InvalidTransactionError('transaction is is not set'); + } + return this._id; + } + + set id(id: string) { + this._id = id; } canSign(key: BaseKey): boolean { @@ -24,14 +38,14 @@ export class Transaction extends BaseTransaction { } toBroadcastFormat(): string { - if (!this._transaction) { + if (!this._prepareCommand) { throw new InvalidTransactionError('Empty transaction data'); } - return this._transaction.preparedTransactionHash; + return Buffer.from(JSON.stringify(this._prepareCommand)).toString('base64'); } toJson(): TxData { - if (!this._transaction || !this._transaction.preparedTransaction) { + if (!this._prepareCommand || !this._prepareCommand.preparedTransaction) { throw new InvalidTransactionError('Empty transaction data'); } const result: TxData = { @@ -43,7 +57,7 @@ export class Transaction extends BaseTransaction { // TODO: extract other required data (utxo used, request time, execute before etc) let parsedInfo: PreparedTxnParsedInfo; try { - parsedInfo = utils.parseRawCantonTransactionData(this._transaction.preparedTransaction); + parsedInfo = utils.parseRawCantonTransactionData(this._prepareCommand.preparedTransaction); } catch (e) { throw new InvalidTransactionError(`Failed to parse transaction hash: ${e instanceof Error ? e.message : e}`); } @@ -51,4 +65,20 @@ export class Transaction extends BaseTransaction { result.receiver = parsedInfo.receiver; return result; } + + getSignablePayload(): Buffer { + if (!this._prepareCommand) { + throw new InvalidTransactionError('Empty transaction data'); + } + return Buffer.from(this._prepareCommand.preparedTransactionHash); + } + + fromRawTransaction(rawTx: string): void { + try { + const decoded: CantonPrepareCommandResponse = JSON.parse(Buffer.from(rawTx, 'base64').toString('utf8')); + this.prepareCommand = decoded; + } catch (e) { + throw new InvalidTransactionError('Unable to parse raw transaction data'); + } + } } diff --git a/modules/sdk-coin-canton/src/lib/transactionBuilder.ts b/modules/sdk-coin-canton/src/lib/transactionBuilder.ts index 3e078c7bd3..6f6a965334 100644 --- a/modules/sdk-coin-canton/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-canton/src/lib/transactionBuilder.ts @@ -3,12 +3,13 @@ import { BaseKey, BaseTransactionBuilder, BuildTransactionError, - FeeOptions, PublicKey as BasePublicKey, Signature, TransactionType, } from '@bitgo/sdk-core'; import BigNumber from 'bignumber.js'; +import { CantonPrepareCommandResponse } from './iface'; +import { KeyPair } from './keyPair'; import { Transaction } from './transaction/transaction'; import utils from './utils'; @@ -16,7 +17,10 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { protected _transaction: Transaction; private _signatures: Signature[] = []; - // get and set region + initBuilder(tx: Transaction): void { + this._transaction = tx; + } + /** * The transaction type. */ @@ -28,9 +32,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { } /** @inheritdoc */ - protected set transaction(transaction: Transaction) { - this._transaction = transaction; - } + abstract setTransaction(transaction: CantonPrepareCommandResponse): void; /** @inheritdoc */ protected signImplementation(key: BaseKey): Transaction { @@ -42,21 +44,6 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { this._signatures.push({ publicKey, signature }); } - /** - * Sets the sender of this transaction. - * This account will be responsible for paying transaction fees. - * - * @param {string} senderAddress the account that is sending this transaction - * @returns {TransactionBuilder} This transaction builder - */ - sender(senderAddress: string): this { - throw new Error('Method not implemented.'); - } - - fee(feeOptions: FeeOptions): this { - throw new Error('Method not implemented.'); - } - /** @inheritdoc */ protected fromImplementation(rawTransaction: string): Transaction { throw new Error('Method not implemented.'); @@ -77,17 +64,39 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { /** @inheritdoc */ validateKey(key: BaseKey): void { - throw new Error('Method not implemented.'); + let keyPair: KeyPair; + try { + keyPair = new KeyPair({ prv: key.key }); + } catch { + throw new BuildTransactionError('Invalid key'); + } + if (!keyPair.getKeys().prv) { + throw new BuildTransactionError('Invalid key'); + } } /** @inheritdoc */ - validateRawTransaction(rawTransaction: string): void { - throw new Error('Method not implemented.'); + async validateRawTransaction(rawTransaction: string): Promise { + if (!rawTransaction || !this._transaction.prepareCommand) { + throw new BuildTransactionError('invalid raw transaction'); + } + const localHash = await utils.computeHashFromPrepareSubmissionResponse(rawTransaction); + if (localHash !== this._transaction.prepareCommand.preparedTransactionHash) { + throw new BuildTransactionError('invalid raw transaction, hash not matching'); + } } /** @inheritdoc */ - validateTransaction(transaction?: Transaction): void { - throw new Error('Method not implemented.'); + async validateTransaction(transaction?: Transaction): Promise { + if (!transaction?.prepareCommand?.preparedTransaction) { + return; + } + const localHash = await utils.computeHashFromPrepareSubmissionResponse( + transaction.prepareCommand.preparedTransaction + ); + if (localHash !== transaction.prepareCommand.preparedTransactionHash) { + throw new BuildTransactionError('invalid transaction'); + } } /** @inheritdoc */ diff --git a/modules/sdk-coin-canton/src/lib/transferBuilder.ts b/modules/sdk-coin-canton/src/lib/transferBuilder.ts index e57cedf7c9..1dd42469c4 100644 --- a/modules/sdk-coin-canton/src/lib/transferBuilder.ts +++ b/modules/sdk-coin-canton/src/lib/transferBuilder.ts @@ -1,6 +1,7 @@ import { TransactionType } from '@bitgo/sdk-core'; import { BaseCoin as CoinConfig } from '@bitgo/statics'; import { TransactionBuilder } from './transactionBuilder'; +import { CantonPrepareCommandResponse } from './iface'; export class TransferBuilder extends TransactionBuilder { constructor(_coinConfig: Readonly) { @@ -10,4 +11,8 @@ export class TransferBuilder extends TransactionBuilder { protected get transactionType(): TransactionType { return TransactionType.Send; } + + setTransaction(transaction: CantonPrepareCommandResponse): void { + this.transaction.prepareCommand = transaction; + } } diff --git a/modules/sdk-coin-canton/src/lib/utils.ts b/modules/sdk-coin-canton/src/lib/utils.ts index 8732d69b42..3ab062d8e0 100644 --- a/modules/sdk-coin-canton/src/lib/utils.ts +++ b/modules/sdk-coin-canton/src/lib/utils.ts @@ -2,6 +2,7 @@ import crypto from 'crypto'; import { BaseUtils, isValidEd25519PublicKey } from '@bitgo/sdk-core'; +import { computePreparedTransaction } from '../../resources/hash/hash.js'; import { PreparedTransaction } from '../../resources/proto/preparedTransaction.js'; import { CryptoKeyFormat, SigningAlgorithmSpec, SigningKeySpec } from './constant'; @@ -123,6 +124,12 @@ export class Utils implements BaseUtils { return this.computeHashFromTopologyTransaction(txBuffers); } + async computeHashFromPrepareSubmissionResponse(preparedTransactionBase64: string): Promise { + const preparedTransaction = this.decodePreparedTransaction(preparedTransactionBase64); + const hash = await computePreparedTransaction(preparedTransaction); + return Buffer.from(hash).toString('base64'); + } + /** * Computes the final topology transaction hash for a list of prepared Canton transactions. * diff --git a/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts b/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts index db980e04a7..fe108d7259 100644 --- a/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts +++ b/modules/sdk-coin-canton/src/lib/walletInitialization/walletInitTransaction.ts @@ -1,7 +1,6 @@ import { BaseKey, BaseTransaction, InvalidTransactionError, TransactionType } from '@bitgo/sdk-core'; import { BaseCoin as CoinConfig } from '@bitgo/statics'; import { PreparedParty, WalletInitTxData } from '../iface'; -import { Buffer } from 'buffer'; export class WalletInitTransaction extends BaseTransaction { private _preparedParty: PreparedParty; diff --git a/modules/sdk-coin-canton/test/resources.ts b/modules/sdk-coin-canton/test/resources.ts index 31d81e6580..01cff323de 100644 --- a/modules/sdk-coin-canton/test/resources.ts +++ b/modules/sdk-coin-canton/test/resources.ts @@ -24,8 +24,44 @@ export const InvalidGenerateTopologyResponse = { multiHash: 'EiDQky+Uxo2zEwFp+JabeazILMMd7QR639/A/u+OGR+npg==', }; +export const PrepareSubmissionResponse = { + preparedTransaction: + 'CqGRAQoDMi4xEgEwGu8DCgEzwj7oAxLlAwoDMi4xEooBMDAzYWJmZTUzOGQwYjUxNzg0N2M2M2RkODdlYjQ4OGUzYzRmZjY5MDEyOGNlNjhhODI4ZjRiZWJiNzg5YTZkNjE0Y2ExMTEyMjAyYTI4NDJhNmUwNDgxNGI0YWRkNWJlNTdmOGZkNWQ3ZGE2NWRiZDVkYjZhZTkyODVkNzZlYmMwZDliMzE4ODdhGg1zcGxpY2UtYW11bGV0ImEKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDFNwbGljZS5Sb3VuZBoPT3Blbk1pbmluZ1JvdW5kKklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhMklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhGvINCgIxMcI+6g0K5w0KAzIuMRJCMDBjNWJkZWU1YjkxNDY3YjZkMDZjYmYzNGI0NjQzYmUxMDk4MzhhY2MwOWNmOWFjOWVkNDI5ZmFmYWM5NmJiOTFmGg1zcGxpY2UtYW11bGV0In8KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESIFNwbGljZS5BbXVsZXRUcmFuc2Zlckluc3RydWN0aW9uGhlBbXVsZXRUcmFuc2Zlckluc3RydWN0aW9uKtwIctkICn8KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESIFNwbGljZS5BbXVsZXRUcmFuc2Zlckluc3RydWN0aW9uGhlBbXVsZXRUcmFuc2Zlckluc3RydWN0aW9uElQKDGxvY2tlZEFtdWxldBJESkIwMGQ3ZTI3OTM0Mzc5YWMzZDI4NTljNzM1OGU2YTYxYzA2YWI3ZmY2ZDI4ZGQwYTMyNTFjNDY1Mzg4ZjY5ZGI2MWYS/wYKCHRyYW5zZmVyEvIGcu8GCnQKQDU1YmE0ZGViMGFkNDY2MmM0MTY4YjM5ODU5NzM4YTBlOTEzODhkMjUyMjg2NDgwYzczMzFiM2Y3MWE1MTcyODESJlNwbGljZS5BcGkuVG9rZW4uVHJhbnNmZXJJbnN0cnVjdGlvblYxGghUcmFuc2ZlchJkCgZzZW5kZXISWjpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OBJxCghyZWNlaXZlchJlOmNyYXZpLWRlbW8tcGFydHktdHhuLTAxLXRhcHBlcjo6MTIyMGVhN2FiNWE3MjNmOGE2YjIwNzhlNjE3ZTZjNThjYjdlNzhlNDk5NDdkZGMyMzllMWE5NDFhYTU2ZTZiYTA4YjQSGQoGYW1vdW50Eg8yDTUwLjAwMDAwMDAwMDAS6AEKDGluc3RydW1lbnRJZBLXAXLUAQpsCkA3MThhMGY3N2U1MDVhOGRlMjJmMTg4YmQ0Yzg3ZmU3NDEwMTI3NGU5ZDRjYjFiZmFjN2QwOWFlYzcxNThkMzViEhpTcGxpY2UuQXBpLlRva2VuLkhvbGRpbmdWMRoMSW5zdHJ1bWVudElkElQKBWFkbWluEks6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWESDgoCaWQSCEIGQW11bGV0EhgKC3JlcXVlc3RlZEF0Egkp6ad1trhABgASGgoNZXhlY3V0ZUJlZm9yZRIJKenzqjnhQAYAElwKEGlucHV0SG9sZGluZ0NpZHMSSFpGCkRKQjAwZDdlMjc5MzQzNzlhYzNkMjg1OWM3MzU4ZTZhNjFjMDZhYjdmZjZkMjhkZDBhMzI1MWM0NjUzODhmNjlkYjYxZhKDAQoEbWV0YRJ7cnkKaQpANGRlZDZiNjY4Y2IzYjY0ZjdhODhhMzA4NzRjZDQxYzc1ODI5ZjVlMDY0YjNmYmJhZGY0MWVjN2U4MzYzMzU0ZhIbU3BsaWNlLkFwaS5Ub2tlbi5NZXRhZGF0YVYxGghNZXRhZGF0YRIMCgZ2YWx1ZXMSAmIAMklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhMlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4OklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhOmNyYXZpLWRlbW8tcGFydHktdHhuLTAxLXRhcHBlcjo6MTIyMGVhN2FiNWE3MjNmOGE2YjIwNzhlNjE3ZTZjNThjYjdlNzhlNDk5NDdkZGMyMzllMWE5NDFhYTU2ZTZiYTA4YjQ6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTga8QMKATHCPuoDEucDCgMyLjESigEwMDNiOTAzMDQ3OWExZWE1MGI0MjA3MjVjNDEwYjY0YzQ2MDliNjRhYjQ5OTZkZTcwN2VmOTlhNjJjZmEwOWY5MDdjYTExMTIyMGEwYmNmNjRlNzNiYjNhZTM3ZDBmZjhjZmUyZWQyMzU0NjZjYmVkY2NhNjViZjRiYjgzZDFiZDg5ZjM0MzM5ZjQaDXNwbGljZS1hbXVsZXQiYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGgtBbXVsZXRSdWxlcypJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTJJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYRreBgoBNMI+1wYS1AYKAzIuMRKKATAwYmMwMmQyZjUwMjhkMDAxMGRiZDczZDM0NThkZDliODI3MGVkMGU4YmZkZmJlNTk0NzcxYjhjNWM5YTdjYzA2YmNhMTExMjIwM2QzYWI5YWFhMmY1NjZmMWFjNGI3OTMwZWNjYzMxZjc4ZWU5MjhlMzM1YjU5NDAyNjE4YzAwZDg1MTUwZWU0NxoNc3BsaWNlLWFtdWxldCJZCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEg1TcGxpY2UuQW11bGV0GgZBbXVsZXQqSURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEqWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgySURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEyWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTg6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNThCZwpANzE4YTBmNzdlNTA1YThkZTIyZjE4OGJkNGM4N2ZlNzQxMDEyNzRlOWQ0Y2IxYmZhYzdkMDlhZWM3MTU4ZDM1YhIaU3BsaWNlLkFwaS5Ub2tlbi5Ib2xkaW5nVjEaB0hvbGRpbmca6wYKATjCPuQGGuEGCgMyLjESigEwMGJjMDJkMmY1MDI4ZDAwMTBkYmQ3M2QzNDU4ZGQ5YjgyNzBlZDBlOGJmZGZiZTU5NDc3MWI4YzVjOWE3Y2MwNmJjYTExMTIyMDNkM2FiOWFhYTJmNTY2ZjFhYzRiNzkzMGVjY2MzMWY3OGVlOTI4ZTMzNWI1OTQwMjYxOGMwMGQ4NTE1MGVlNDcaDXNwbGljZS1hbXVsZXQiWQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRINU3BsaWNlLkFtdWxldBoGQW11bGV0KklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhKlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4MklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhMlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4OklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhOlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4SgdBcmNoaXZlUmVyYwphCkA5ZTcwYThiMzUxMGQ2MTdmOGExMzYyMTNmMzNkNmE5MDNhMTBjYTBlZWVjNzZiYjA2YmE1NWQxZWQ5NjgwZjY5EhREQS5JbnRlcm5hbC5UZW1wbGF0ZRoHQXJjaGl2ZVgBagIKABq9CQoCMTDCPrUJCrIJCgMyLjESQjAwNzNkZDA0OTI2NTQzMDVjYTYxODM5ZTNjNWIxMzQzMDc3YTE4OTE5MjliNmVhODQxMDI0N2Q2YTM2MDcwNGM4NhoNc3BsaWNlLWFtdWxldCJZCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEg1TcGxpY2UuQW11bGV0GgZBbXVsZXQqsgVyrwUKWQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRINU3BsaWNlLkFtdWxldBoGQW11bGV0ElIKA2RzbxJLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhEmMKBW93bmVyElo6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgSmAMKBmFtb3VudBKNA3KKAwpfCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgtTcGxpY2UuRmVlcxoORXhwaXJpbmdBbW91bnQSIQoNaW5pdGlhbEFtb3VudBIQMg45NTAuMDAwMDAwMDAwMBJ4CgljcmVhdGVkQXQSa3JpClcKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDFNwbGljZS5UeXBlcxoFUm91bmQSDgoGbnVtYmVyEgQY5tgBEokBCgxyYXRlUGVyUm91bmQSeXJ3Cl0KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGgxSYXRlUGVyUm91bmQSFgoEcmF0ZRIOMgwwLjAwMDIwMDI3MjYySURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEyWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTg6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTga7wMKATbCPugDEuUDCgMyLjESigEwMDNhYmZlNTM4ZDBiNTE3ODQ3YzYzZGQ4N2ViNDg4ZTNjNGZmNjkwMTI4Y2U2OGE4MjhmNGJlYmI3ODlhNmQ2MTRjYTExMTIyMDJhMjg0MmE2ZTA0ODE0YjRhZGQ1YmU1N2Y4ZmQ1ZDdkYTY1ZGJkNWRiNmFlOTI4NWQ3NmViYzBkOWIzMTg4N2EaDXNwbGljZS1hbXVsZXQiYQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIMU3BsaWNlLlJvdW5kGg9PcGVuTWluaW5nUm91bmQqSURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEySURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEa9QwKATLCPu4MGusMCgMyLjESigEwMDNiOTAzMDQ3OWExZWE1MGI0MjA3MjVjNDEwYjY0YzQ2MDliNjRhYjQ5OTZkZTcwN2VmOTlhNjJjZmEwOWY5MDdjYTExMTIyMGEwYmNmNjRlNzNiYjNhZTM3ZDBmZjhjZmUyZWQyMzU0NjZjYmVkY2NhNjViZjRiYjgzZDFiZDg5ZjM0MzM5ZjQaDXNwbGljZS1hbXVsZXQiYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGgtBbXVsZXRSdWxlcypJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTJJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OEoXQW11bGV0UnVsZXNfQ29tcHV0ZUZlZXNSvQdyugcKbwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGhdBbXVsZXRSdWxlc19Db21wdXRlRmVlcxLOAgoHY29udGV4dBLCAnK/AgpnCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhJTcGxpY2UuQW11bGV0UnVsZXMaD1RyYW5zZmVyQ29udGV4dBKhAQoPb3Blbk1pbmluZ1JvdW5kEo0BSooBMDAzYWJmZTUzOGQwYjUxNzg0N2M2M2RkODdlYjQ4OGUzYzRmZjY5MDEyOGNlNjhhODI4ZjRiZWJiNzg5YTZkNjE0Y2ExMTEyMjAyYTI4NDJhNmUwNDgxNGI0YWRkNWJlNTdmOGZkNWQ3ZGE2NWRiZDVkYjZhZTkyODVkNzZlYmMwZDliMzE4ODdhEhkKE2lzc3VpbmdNaW5pbmdSb3VuZHMSAmoAEhUKD3ZhbGlkYXRvclJpZ2h0cxICagASZAoGc2VuZGVyElo6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgSrwIKB291dHB1dHMSowJaoAIKnQJymgIKZgpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGg5UcmFuc2Zlck91dHB1dBJxCghyZWNlaXZlchJlOmNyYXZpLWRlbW8tcGFydHktdHhuLTAxLXRhcHBlcjo6MTIyMGVhN2FiNWE3MjNmOGE2YjIwNzhlNjE3ZTZjNThjYjdlNzhlNDk5NDdkZGMyMzllMWE5NDFhYTU2ZTZiYTA4YjQSIgoQcmVjZWl2ZXJGZWVSYXRpbxIOMgwwLjAwMDAwMDAwMDASGQoGYW1vdW50Eg8yDTUwLjAwMDAwMDAwMDASXgoLZXhwZWN0ZWREc28ST1JNCks6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWFiATNqlgFykwEKdQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGh1BbXVsZXRSdWxlc19Db21wdXRlRmVlc1Jlc3VsdBIaCgRmZWVzEhJaEAoOMgwwLjAwMDAwMDAwMDAa9QUKATfCPu4FEusFCgMyLjESigEwMGJjMDJkMmY1MDI4ZDAwMTBkYmQ3M2QzNDU4ZGQ5YjgyNzBlZDBlOGJmZGZiZTU5NDc3MWI4YzVjOWE3Y2MwNmJjYTExMTIyMDNkM2FiOWFhYTJmNTY2ZjFhYzRiNzkzMGVjY2MzMWY3OGVlOTI4ZTMzNWI1OTQwMjYxOGMwMGQ4NTE1MGVlNDcaDXNwbGljZS1hbXVsZXQiWQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRINU3BsaWNlLkFtdWxldBoGQW11bGV0KklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhKlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4MklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhMlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4OklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhOlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4GqAdCgEwwj6ZHRqWHQoDMi4xEooBMDA5ZjAwZTViZjAwNjQwMTE4ZDg0OTA4MGFhZjIyYmM5NjNhODQ1OGQzMjI1ODVjZWJmMTExOWNiN2JmMzdhOTU1Y2ExMTEyMjA2NWI3NzVmYjhhNDE5OTkwNGVkMzJmYTkyNzdmZDljMGU4MmJiODIzMTlhNzE1MTI0OWRmMTI0MTgyMDcyMzgxGg1zcGxpY2UtYW11bGV0In0KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESH1NwbGljZS5FeHRlcm5hbFBhcnR5QW11bGV0UnVsZXMaGEV4dGVybmFsUGFydHlBbXVsZXRSdWxlcypJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTJJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OEJ7CkA1NWJhNGRlYjBhZDQ2NjJjNDE2OGIzOTg1OTczOGEwZTkxMzg4ZDI1MjI4NjQ4MGM3MzMxYjNmNzFhNTE3MjgxEiZTcGxpY2UuQXBpLlRva2VuLlRyYW5zZmVySW5zdHJ1Y3Rpb25WMRoPVHJhbnNmZXJGYWN0b3J5ShhUcmFuc2ZlckZhY3RvcnlfVHJhbnNmZXJSkBFyjREKhAEKQDU1YmE0ZGViMGFkNDY2MmM0MTY4YjM5ODU5NzM4YTBlOTEzODhkMjUyMjg2NDgwYzczMzFiM2Y3MWE1MTcyODESJlNwbGljZS5BcGkuVG9rZW4uVHJhbnNmZXJJbnN0cnVjdGlvblYxGhhUcmFuc2ZlckZhY3RvcnlfVHJhbnNmZXISXAoNZXhwZWN0ZWRBZG1pbhJLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhEswHCgh0cmFuc2ZlchK/B3K8Bwp0CkA1NWJhNGRlYjBhZDQ2NjJjNDE2OGIzOTg1OTczOGEwZTkxMzg4ZDI1MjI4NjQ4MGM3MzMxYjNmNzFhNTE3MjgxEiZTcGxpY2UuQXBpLlRva2VuLlRyYW5zZmVySW5zdHJ1Y3Rpb25WMRoIVHJhbnNmZXISZAoGc2VuZGVyElo6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgScQoIcmVjZWl2ZXISZTpjcmF2aS1kZW1vLXBhcnR5LXR4bi0wMS10YXBwZXI6OjEyMjBlYTdhYjVhNzIzZjhhNmIyMDc4ZTYxN2U2YzU4Y2I3ZTc4ZTQ5OTQ3ZGRjMjM5ZTFhOTQxYWE1NmU2YmEwOGI0EhkKBmFtb3VudBIPMg01MC4wMDAwMDAwMDAwEugBCgxpbnN0cnVtZW50SWQS1wFy1AEKbApANzE4YTBmNzdlNTA1YThkZTIyZjE4OGJkNGM4N2ZlNzQxMDEyNzRlOWQ0Y2IxYmZhYzdkMDlhZWM3MTU4ZDM1YhIaU3BsaWNlLkFwaS5Ub2tlbi5Ib2xkaW5nVjEaDEluc3RydW1lbnRJZBJUCgVhZG1pbhJLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhEg4KAmlkEghCBkFtdWxldBIYCgtyZXF1ZXN0ZWRBdBIJKemndba4QAYAEhoKDWV4ZWN1dGVCZWZvcmUSCSnp86o54UAGABKoAQoQaW5wdXRIb2xkaW5nQ2lkcxKTAVqQAQqNAUqKATAwYmMwMmQyZjUwMjhkMDAxMGRiZDczZDM0NThkZDliODI3MGVkMGU4YmZkZmJlNTk0NzcxYjhjNWM5YTdjYzA2YmNhMTExMjIwM2QzYWI5YWFhMmY1NjZmMWFjNGI3OTMwZWNjYzMxZjc4ZWU5MjhlMzM1YjU5NDAyNjE4YzAwZDg1MTUwZWU0NxKDAQoEbWV0YRJ7cnkKaQpANGRlZDZiNjY4Y2IzYjY0ZjdhODhhMzA4NzRjZDQxYzc1ODI5ZjVlMDY0YjNmYmJhZGY0MWVjN2U4MzYzMzU0ZhIbU3BsaWNlLkFwaS5Ub2tlbi5NZXRhZGF0YVYxGghNZXRhZGF0YRIMCgZ2YWx1ZXMSAmIAEtYHCglleHRyYUFyZ3MSyAdyxQcKagpANGRlZDZiNjY4Y2IzYjY0ZjdhODhhMzA4NzRjZDQxYzc1ODI5ZjVlMDY0YjNmYmJhZGY0MWVjN2U4MzYzMzU0ZhIbU3BsaWNlLkFwaS5Ub2tlbi5NZXRhZGF0YVYxGglFeHRyYUFyZ3MS0AUKB2NvbnRleHQSxAVywQUKbgpANGRlZDZiNjY4Y2IzYjY0ZjdhODhhMzA4NzRjZDQxYzc1ODI5ZjVlMDY0YjNmYmJhZGY0MWVjN2U4MzYzMzU0ZhIbU3BsaWNlLkFwaS5Ub2tlbi5NZXRhZGF0YVYxGg1DaG9pY2VDb250ZXh0Es4ECgZ2YWx1ZXMSwwRiwAQKngIKDGFtdWxldC1ydWxlcxKNAnqKAgppCkA0ZGVkNmI2NjhjYjNiNjRmN2E4OGEzMDg3NGNkNDFjNzU4MjlmNWUwNjRiM2ZiYmFkZjQxZWM3ZTgzNjMzNTRmEhtTcGxpY2UuQXBpLlRva2VuLk1ldGFkYXRhVjEaCEFueVZhbHVlEg1BVl9Db250cmFjdElkGo0BSooBMDAzYjkwMzA0NzlhMWVhNTBiNDIwNzI1YzQxMGI2NGM0NjA5YjY0YWI0OTk2ZGU3MDdlZjk5YTYyY2ZhMDlmOTA3Y2ExMTEyMjBhMGJjZjY0ZTczYmIzYWUzN2QwZmY4Y2ZlMmVkMjM1NDY2Y2JlZGNjYTY1YmY0YmI4M2QxYmQ4OWYzNDMzOWY0CpwCCgpvcGVuLXJvdW5kEo0CeooCCmkKQDRkZWQ2YjY2OGNiM2I2NGY3YTg4YTMwODc0Y2Q0MWM3NTgyOWY1ZTA2NGIzZmJiYWRmNDFlYzdlODM2MzM1NGYSG1NwbGljZS5BcGkuVG9rZW4uTWV0YWRhdGFWMRoIQW55VmFsdWUSDUFWX0NvbnRyYWN0SWQajQFKigEwMDNhYmZlNTM4ZDBiNTE3ODQ3YzYzZGQ4N2ViNDg4ZTNjNGZmNjkwMTI4Y2U2OGE4MjhmNGJlYmI3ODlhNmQ2MTRjYTExMTIyMDJhMjg0MmE2ZTA0ODE0YjRhZGQ1YmU1N2Y4ZmQ1ZDdkYTY1ZGJkNWRiNmFlOTI4NWQ3NmViYzBkOWIzMTg4N2ESgwEKBG1ldGESe3J5CmkKQDRkZWQ2YjY2OGNiM2I2NGY3YTg4YTMwODc0Y2Q0MWM3NTgyOWY1ZTA2NGIzZmJiYWRmNDFlYzdlODM2MzM1NGYSG1NwbGljZS5BcGkuVG9rZW4uTWV0YWRhdGFWMRoITWV0YWRhdGESDAoGdmFsdWVzEgJiAGIBMWIBMmIBNGIBNWICMTFqyQZyxgYKhQEKQDU1YmE0ZGViMGFkNDY2MmM0MTY4YjM5ODU5NzM4YTBlOTEzODhkMjUyMjg2NDgwYzczMzFiM2Y3MWE1MTcyODESJlNwbGljZS5BcGkuVG9rZW4uVHJhbnNmZXJJbnN0cnVjdGlvblYxGhlUcmFuc2Zlckluc3RydWN0aW9uUmVzdWx0EtcDCgZvdXRwdXQSzAN6yQMKjAEKQDU1YmE0ZGViMGFkNDY2MmM0MTY4YjM5ODU5NzM4YTBlOTEzODhkMjUyMjg2NDgwYzczMzFiM2Y3MWE1MTcyODESJlNwbGljZS5BcGkuVG9rZW4uVHJhbnNmZXJJbnN0cnVjdGlvblYxGiBUcmFuc2Zlckluc3RydWN0aW9uUmVzdWx0X091dHB1dBIhVHJhbnNmZXJJbnN0cnVjdGlvblJlc3VsdF9QZW5kaW5nGpQCcpECCq4BCkA1NWJhNGRlYjBhZDQ2NjJjNDE2OGIzOTg1OTczOGEwZTkxMzg4ZDI1MjI4NjQ4MGM3MzMxYjNmNzFhNTE3MjgxEiZTcGxpY2UuQXBpLlRva2VuLlRyYW5zZmVySW5zdHJ1Y3Rpb25WMRpCVHJhbnNmZXJJbnN0cnVjdGlvblJlc3VsdF9PdXRwdXQuVHJhbnNmZXJJbnN0cnVjdGlvblJlc3VsdF9QZW5kaW5nEl4KFnRyYW5zZmVySW5zdHJ1Y3Rpb25DaWQSREpCMDBjNWJkZWU1YjkxNDY3YjZkMDZjYmYzNGI0NjQzYmUxMDk4MzhhY2MwOWNmOWFjOWVkNDI5ZmFmYWM5NmJiOTFmElwKEHNlbmRlckNoYW5nZUNpZHMSSFpGCkRKQjAwNzNkZDA0OTI2NTQzMDVjYTYxODM5ZTNjNWIxMzQzMDc3YTE4OTE5MjliNmVhODQxMDI0N2Q2YTM2MDcwNGM4NhKDAQoEbWV0YRJ7cnkKaQpANGRlZDZiNjY4Y2IzYjY0ZjdhODhhMzA4NzRjZDQxYzc1ODI5ZjVlMDY0YjNmYmJhZGY0MWVjN2U4MzYzMzU0ZhIbU3BsaWNlLkFwaS5Ub2tlbi5NZXRhZGF0YVYxGghNZXRhZGF0YRIMCgZ2YWx1ZXMSAmIAGpsNCgE5wj6UDQqRDQoDMi4xEkIwMGQ3ZTI3OTM0Mzc5YWMzZDI4NTljNzM1OGU2YTYxYzA2YWI3ZmY2ZDI4ZGQwYTMyNTFjNDY1Mzg4ZjY5ZGI2MWYaDXNwbGljZS1hbXVsZXQiXwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRINU3BsaWNlLkFtdWxldBoMTG9ja2VkQW11bGV0KosJcogJCl8KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDVNwbGljZS5BbXVsZXQaDExvY2tlZEFtdWxldBK8BQoGYW11bGV0ErEFcq4FClkKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDVNwbGljZS5BbXVsZXQaBkFtdWxldBJSCgNkc28SSzpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYRJjCgVvd25lchJaOlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4EpcDCgZhbW91bnQSjANyiQMKXwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRILU3BsaWNlLkZlZXMaDkV4cGlyaW5nQW1vdW50EiAKDWluaXRpYWxBbW91bnQSDzINNTAuMDAwMDAwMDAwMBJ4CgljcmVhdGVkQXQSa3JpClcKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDFNwbGljZS5UeXBlcxoFUm91bmQSDgoGbnVtYmVyEgQY5tgBEokBCgxyYXRlUGVyUm91bmQSeXJ3Cl0KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGgxSYXRlUGVyUm91bmQSFgoEcmF0ZRIOMgwwLjAwMDIwMDI3MjYS5QIKBGxvY2sS3AJy2QIKWwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRINU3BsaWNlLkV4cGlyeRoIVGltZUxvY2sSWgoHaG9sZGVycxJPWk0KSzpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYRIWCglleHBpcmVzQXQSCSnp86o54UAGABKFAQoKb3B0Q29udGV4dBJ3UnUKc0JxdHJhbnNmZXIgdG8gJ3JhdmktZGVtby1wYXJ0eS10eG4tMDEtdGFwcGVyOjoxMjIwZWE3YWI1YTcyM2Y4YTZiMjA3OGU2MTdlNmM1OGNiN2U3OGU0OTk0N2RkYzIzOWUxYTk0MWFhNTZlNmJhMDhiNCcySURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEyWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTg6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgagSEKATXCPvogGvcgCgMyLjESigEwMDNiOTAzMDQ3OWExZWE1MGI0MjA3MjVjNDEwYjY0YzQ2MDliNjRhYjQ5OTZkZTcwN2VmOTlhNjJjZmEwOWY5MDdjYTExMTIyMGEwYmNmNjRlNzNiYjNhZTM3ZDBmZjhjZmUyZWQyMzU0NjZjYmVkY2NhNjViZjRiYjgzZDFiZDg5ZjM0MzM5ZjQaDXNwbGljZS1hbXVsZXQiYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGgtBbXVsZXRSdWxlcypJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTJJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OEoUQW11bGV0UnVsZXNfVHJhbnNmZXJSlQ5ykg4KbApAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGhRBbXVsZXRSdWxlc19UcmFuc2ZlchLwCQoIdHJhbnNmZXIS4wly4AkKYApAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGghUcmFuc2ZlchJkCgZzZW5kZXISWjpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OBJmCghwcm92aWRlchJaOlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4EpgCCgZpbnB1dHMSjQJaigIKhwJ6hAIKZQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGg1UcmFuc2ZlcklucHV0EgtJbnB1dEFtdWxldBqNAUqKATAwYmMwMmQyZjUwMjhkMDAxMGRiZDczZDM0NThkZDliODI3MGVkMGU4YmZkZmJlNTk0NzcxYjhjNWM5YTdjYzA2YmNhMTExMjIwM2QzYWI5YWFhMmY1NjZmMWFjNGI3OTMwZWNjYzMxZjc4ZWU5MjhlMzM1YjU5NDAyNjE4YzAwZDg1MTUwZWU0NxKSBQoHb3V0cHV0cxKGBVqDBQqABXL9BApmCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhJTcGxpY2UuQW11bGV0UnVsZXMaDlRyYW5zZmVyT3V0cHV0EmYKCHJlY2VpdmVyElo6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgSIgoQcmVjZWl2ZXJGZWVSYXRpbxIOMgwwLjAwMDAwMDAwMDASGQoGYW1vdW50Eg8yDTUwLjAwMDAwMDAwMDAS6wIKBGxvY2sS4gJS3wIK3AJy2QIKWwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRINU3BsaWNlLkV4cGlyeRoIVGltZUxvY2sSWgoHaG9sZGVycxJPWk0KSzpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYRIWCglleHBpcmVzQXQSCSnp86o54UAGABKFAQoKb3B0Q29udGV4dBJ3UnUKc0JxdHJhbnNmZXIgdG8gJ3JhdmktZGVtby1wYXJ0eS10eG4tMDEtdGFwcGVyOjoxMjIwZWE3YWI1YTcyM2Y4YTZiMjA3OGU2MTdlNmM1OGNiN2U3OGU0OTk0N2RkYzIzOWUxYTk0MWFhNTZlNmJhMDhiNCcSzgIKB2NvbnRleHQSwgJyvwIKZwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGg9UcmFuc2ZlckNvbnRleHQSoQEKD29wZW5NaW5pbmdSb3VuZBKNAUqKATAwM2FiZmU1MzhkMGI1MTc4NDdjNjNkZDg3ZWI0ODhlM2M0ZmY2OTAxMjhjZTY4YTgyOGY0YmViYjc4OWE2ZDYxNGNhMTExMjIwMmEyODQyYTZlMDQ4MTRiNGFkZDViZTU3ZjhmZDVkN2RhNjVkYmQ1ZGI2YWU5Mjg1ZDc2ZWJjMGQ5YjMxODg3YRIZChNpc3N1aW5nTWluaW5nUm91bmRzEgJqABIVCg92YWxpZGF0b3JSaWdodHMSAmoAEl4KC2V4cGVjdGVkRHNvEk9STQpLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhYgE2YgE3YgE4YgE5YgIxMGr1DXLyDQpmCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhJTcGxpY2UuQW11bGV0UnVsZXMaDlRyYW5zZmVyUmVzdWx0EnQKBXJvdW5kEmtyaQpXCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgxTcGxpY2UuVHlwZXMaBVJvdW5kEg4KBm51bWJlchIEGObYARL6BgoHc3VtbWFyeRLuBnLrBgpnCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhJTcGxpY2UuQW11bGV0UnVsZXMaD1RyYW5zZmVyU3VtbWFyeRImChRpbnB1dEFwcFJld2FyZEFtb3VudBIOMgwwLjAwMDAwMDAwMDASLAoaaW5wdXRWYWxpZGF0b3JSZXdhcmRBbW91bnQSDjIMMC4wMDAwMDAwMDAwEiUKE2lucHV0U3ZSZXdhcmRBbW91bnQSDjIMMC4wMDAwMDAwMDAwEiYKEWlucHV0QW11bGV0QW1vdW50EhEyDzEwMDAuMDAwMDAwMDAwMBLDAgoOYmFsYW5jZUNoYW5nZXMSsAJqrQIKqgIKWjpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OBLLAXLIAQplCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhJTcGxpY2UuQW11bGV0UnVsZXMaDUJhbGFuY2VDaGFuZ2USNAoiY2hhbmdlVG9Jbml0aWFsQW1vdW50QXNPZlJvdW5kWmVybxIOMgwyLjc3OTk4Mzk2MDYSKQoXY2hhbmdlVG9Ib2xkaW5nRmVlc1JhdGUSDjIMMC4wMDAyMDAyNzI2Eh0KC2hvbGRpbmdGZWVzEg4yDDAuMDAwMDAwMDAwMBIgCgpvdXRwdXRGZWVzEhJaEAoOMgwwLjAwMDAwMDAwMDASIQoPc2VuZGVyQ2hhbmdlRmVlEg4yDDAuMDAwMDAwMDAwMBImChJzZW5kZXJDaGFuZ2VBbW91bnQSEDIOOTUwLjAwMDAwMDAwMDASHQoLYW11bGV0UHJpY2USDjIMMC4wOTUwMDAwMDAwEjAKGmlucHV0VmFsaWRhdG9yRmF1Y2V0QW1vdW50EhJSEAoOMgwwLjAwMDAwMDAwMDASOAoiaW5wdXRVbmNsYWltZWRBY3Rpdml0eVJlY29yZEFtb3VudBISUhAKDjIMMC4wMDAwMDAwMDAwEuUBCg5jcmVhdGVkQW11bGV0cxLSAVrPAQrMAXrJAQplCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhJTcGxpY2UuQW11bGV0UnVsZXMaDUNyZWF0ZWRBbXVsZXQSGlRyYW5zZmVyUmVzdWx0TG9ja2VkQW11bGV0GkRKQjAwZDdlMjc5MzQzNzlhYzNkMjg1OWM3MzU4ZTZhNjFjMDZhYjdmZjZkMjhkZDBhMzI1MWM0NjUzODhmNjlkYjYxZhJeChJzZW5kZXJDaGFuZ2VBbXVsZXQSSFJGCkRKQjAwNzNkZDA0OTI2NTQzMDVjYTYxODM5ZTNjNWIxMzQzMDc3YTE4OTE5MjliNmVhODQxMDI0N2Q2YTM2MDcwNGM4NhLMAgoEbWV0YRLDAlLAAgq9AnK6AgppCkA0ZGVkNmI2NjhjYjNiNjRmN2E4OGEzMDg3NGNkNDFjNzU4MjlmNWUwNjRiM2ZiYmFkZjQxZWM3ZTgzNjMzNTRmEhtTcGxpY2UuQXBpLlRva2VuLk1ldGFkYXRhVjEaCE1ldGFkYXRhEswBCgZ2YWx1ZXMSwQFivgEKhAEKJnNwbGljZS5sZmRlY2VudHJhbGl6ZWR0cnVzdC5vcmcvc2VuZGVyElpCWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTgKNQonc3BsaWNlLmxmZGVjZW50cmFsaXplZHRydXN0Lm9yZy90eC1raW5kEgpCCHRyYW5zZmVyIiISIF3UMbLHNDZFwYbbTSkF0Mqj0jaj/7clw4U1rQzFfvRGIiQIAhIgySalmynaOg5HTwNUEjM5bGa1u9XlUGABNmCtRNeWzskiJAgFEiANaOJaZBzr1jLdnsigIlppJR+opSDaKrWrj3eMRnGpHiIkCAgSIIrEze1HbnjoTJPNyKAuDkPQ6txcBKTB7FKi2ptOKsmdIiQICRIg2X1YghNLdq8C425o8+asBwFGGB+gt9WvbGgsR0QvRJQiJAgKEiBTO7ltnV2coPon5skGGPQKU888lUF384hT/gURUn+ACiIkCAsSIDUT5/KxjPqvwj+ozTTiH7FrzkQhXyeRK02th/6SfbibEv97EoABClh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4EiQ3YWRkNDZjMi1jZGI2LTRlZjktYTk4ZS0xZjIxN2YyYzYwMzkaU2dsb2JhbC1kb21haW46OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhKiRkMDRkOTcyOS0xZTYxLTRjOWYtODZjOS05MTI3ZjM2ZWIwNmMw/KWeiJCXkAM68hwKtRUKAzIuMRKKATAwM2FiZmU1MzhkMGI1MTc4NDdjNjNkZDg3ZWI0ODhlM2M0ZmY2OTAxMjhjZTY4YTgyOGY0YmViYjc4OWE2ZDYxNGNhMTExMjIwMmEyODQyYTZlMDQ4MTRiNGFkZDViZTU3ZjhmZDVkN2RhNjVkYmQ1ZGI2YWU5Mjg1ZDc2ZWJjMGQ5YjMxODg3YRoNc3BsaWNlLWFtdWxldCJhCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgxTcGxpY2UuUm91bmQaD09wZW5NaW5pbmdSb3VuZCqYEnKVEgphCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgxTcGxpY2UuUm91bmQaD09wZW5NaW5pbmdSb3VuZBJSCgNkc28SSzpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYRJ0CgVyb3VuZBJrcmkKVwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIMU3BsaWNlLlR5cGVzGgVSb3VuZBIOCgZudW1iZXISBBjm2AESHQoLYW11bGV0UHJpY2USDjIMMC4wOTUwMDAwMDAwEhQKB29wZW5zQXQSCSnpp3W2uEAGABIbCg50YXJnZXRDbG9zZXNBdBIJKekz/P24QAYAEoYBCgppc3N1aW5nRm9yEnhydgpaCkBiNzBkYjgzNjllMWM0NjFkNWM3MGYxYzg2ZjUyNmEyOWU5Nzc2YzY1NWU2ZmZjMjU2MGY5NWIwNWNjYjhiOTQ2Eg1EQS5UaW1lLlR5cGVzGgdSZWxUaW1lEhgKDG1pY3Jvc2Vjb25kcxIIGIDI14rK5AMS0gkKEXRyYW5zZmVyQ29uZmlnVXNkErwJcrkJCmcKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESE1NwbGljZS5BbXVsZXRDb25maWcaDlRyYW5zZmVyQ29uZmlnEoEBCgljcmVhdGVGZWUSdHJyClkKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGghGaXhlZEZlZRIVCgNmZWUSDjIMMC4wMDAwMDAwMDAwEocBCgpob2xkaW5nRmVlEnlydwpdCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgtTcGxpY2UuRmVlcxoMUmF0ZVBlclJvdW5kEhYKBHJhdGUSDjIMMC4wMDAwMTkwMjU5EsMECgt0cmFuc2ZlckZlZRKzBHKwBApcCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgtTcGxpY2UuRmVlcxoLU3RlcHBlZFJhdGUSHQoLaW5pdGlhbFJhdGUSDjIMMC4wMDAwMDAwMDAwErADCgVzdGVwcxKmA1qjAwqHAXKEAQpUCkA1YWVlOWIyMWI4ZTlhNGM0OTc1YjVmNGM0MTk4ZTZlNmU4NDY5ZGY0OWUyMDEwODIwZTc5MmYzOTNkYjg3MGY0EghEQS5UeXBlcxoGVHVwbGUyEhYKAl8xEhAyDjEwMC4wMDAwMDAwMDAwEhQKAl8yEg4yDDAuMDAwMDAwMDAwMAqIAXKFAQpUCkA1YWVlOWIyMWI4ZTlhNGM0OTc1YjVmNGM0MTk4ZTZlNmU4NDY5ZGY0OWUyMDEwODIwZTc5MmYzOTNkYjg3MGY0EghEQS5UeXBlcxoGVHVwbGUyEhcKAl8xEhEyDzEwMDAuMDAwMDAwMDAwMBIUCgJfMhIOMgwwLjAwMDAwMDAwMDAKiwFyiAEKVApANWFlZTliMjFiOGU5YTRjNDk3NWI1ZjRjNDE5OGU2ZTZlODQ2OWRmNDllMjAxMDgyMGU3OTJmMzkzZGI4NzBmNBIIREEuVHlwZXMaBlR1cGxlMhIaCgJfMRIUMhIxMDAwMDAwLjAwMDAwMDAwMDASFAoCXzISDjIMMC4wMDAwMDAwMDAwEoUBCg1sb2NrSG9sZGVyRmVlEnRycgpZCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgtTcGxpY2UuRmVlcxoIRml4ZWRGZWUSFQoDZmVlEg4yDDAuMDAwMDAwMDAwMBIuChxleHRyYUZlYXR1cmVkQXBwUmV3YXJkQW1vdW50Eg4yDDEuMDAwMDAwMDAwMBITCgxtYXhOdW1JbnB1dHMSAxjIARIUCg1tYXhOdW1PdXRwdXRzEgMYyAESFwoRbWF4TnVtTG9ja0hvbGRlcnMSAhhkEqwDCg5pc3N1YW5jZUNvbmZpZxKZA3KWAwpjCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEg9TcGxpY2UuSXNzdWFuY2UaDklzc3VhbmNlQ29uZmlnEjAKFGFtdWxldFRvSXNzdWVQZXJZZWFyEhgyFjQwMDAwMDAwMDAwLjAwMDAwMDAwMDASKwoZdmFsaWRhdG9yUmV3YXJkUGVyY2VudGFnZRIOMgwwLjA1MDAwMDAwMDASJQoTYXBwUmV3YXJkUGVyY2VudGFnZRIOMgwwLjE1MDAwMDAwMDASJAoSdmFsaWRhdG9yUmV3YXJkQ2FwEg4yDDAuMjAwMDAwMDAwMBIqChRmZWF0dXJlZEFwcFJld2FyZENhcBISMhAyMDAwMC4wMDAwMDAwMDAwEigKFnVuZmVhdHVyZWRBcHBSZXdhcmRDYXASDjIMMC42MDAwMDAwMDAwEi0KFW9wdFZhbGlkYXRvckZhdWNldENhcBIUUhIKEDIONTcwLjAwMDAwMDAwMDAShgEKDHRpY2tEdXJhdGlvbhJ2cnQKWgpAYjcwZGI4MzY5ZTFjNDYxZDVjNzBmMWM4NmY1MjZhMjllOTc3NmM2NTVlNmZmYzI1NjBmOTViMDVjY2I4Yjk0NhINREEuVGltZS5UeXBlcxoHUmVsVGltZRIWCgxtaWNyb3NlY29uZHMSBhiAmJq8BDJJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYcA+6cPJlYmXkAPSPqwHCgMyLjESpAcKRQA6v+U40LUXhHxj3YfrSI48T/aQEozmioKPS+u3iabWFMoREiAqKEKm4EgUtK3Vvlf4/V19pl29XbaukoXXbrwNmzGIehINc3BsaWNlLWFtdWxldBpiCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEgZTcGxpY2USBVJvdW5kGg9PcGVuTWluaW5nUm91bmQi5wRq5AQKTQpLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhCgwKCmoICgYKBBjm2AEKEAoOMgwwLjA5NTAwMDAwMDAKCwoJKemndba4QAYACgsKCSnpM/z9uEAGAAoQCg5qDAoKCggYgMjXisrkAwqbAgqYAmqVAgoWChRqEgoQCg4yDDAuMDAwMDAwMDAwMAoWChRqEgoQCg4yDDAuMDAwMDE5MDI1OQqkAQqhAWqeAQoQCg4yDDAuMDAwMDAwMDAwMAqJAQqGAVqDAQooaiYKEgoQMg4xMDAuMDAwMDAwMDAwMAoQCg4yDDAuMDAwMDAwMDAwMAopaicKEwoRMg8xMDAwLjAwMDAwMDAwMDAKEAoOMgwwLjAwMDAwMDAwMDAKLGoqChYKFDISMTAwMDAwMC4wMDAwMDAwMDAwChAKDjIMMC4wMDAwMDAwMDAwChYKFGoSChAKDjIMMC4wMDAwMDAwMDAwChAKDjIMMS4wMDAwMDAwMDAwCgUKAxjIAQoFCgMYyAEKBAoCGGQKmAEKlQFqkgEKGgoYMhY0MDAwMDAwMDAwMC4wMDAwMDAwMDAwChAKDjIMMC4wNTAwMDAwMDAwChAKDjIMMC4xNTAwMDAwMDAwChAKDjIMMC4yMDAwMDAwMDAwChQKEjIQMjAwMDAuMDAwMDAwMDAwMAoQCg4yDDAuNjAwMDAwMDAwMAoWChRSEgoQMg41NzAuMDAwMDAwMDAwMAoOCgxqCgoICgYYgJiavAQqSURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE56WGykrhABgBCKgomCiQIARIgtT9saRZa34xXgKpJVjpDkY8gRT/OuBVESf5hjY7c70sQHjqCRQqbNQoDMi4xEooBMDAzYjkwMzA0NzlhMWVhNTBiNDIwNzI1YzQxMGI2NGM0NjA5YjY0YWI0OTk2ZGU3MDdlZjk5YTYyY2ZhMDlmOTA3Y2ExMTEyMjBhMGJjZjY0ZTczYmIzYWUzN2QwZmY4Y2ZlMmVkMjM1NDY2Y2JlZGNjYTY1YmY0YmI4M2QxYmQ4OWYzNDMzOWY0Gg1zcGxpY2UtYW11bGV0ImMKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESElNwbGljZS5BbXVsZXRSdWxlcxoLQW11bGV0UnVsZXMq/DFy+TEKYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRISU3BsaWNlLkFtdWxldFJ1bGVzGgtBbXVsZXRSdWxlcxJSCgNkc28SSzpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYRKtMAoOY29uZmlnU2NoZWR1bGUSmjBylzAKXQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIPU3BsaWNlLlNjaGVkdWxlGghTY2hlZHVsZRKhLwoMaW5pdGlhbFZhbHVlEpAvco0vCmUKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESE1NwbGljZS5BbXVsZXRDb25maWcaDEFtdWxldENvbmZpZxLPCQoOdHJhbnNmZXJDb25maWcSvAlyuQkKZwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRITU3BsaWNlLkFtdWxldENvbmZpZxoOVHJhbnNmZXJDb25maWcSgQEKCWNyZWF0ZUZlZRJ0cnIKWQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRILU3BsaWNlLkZlZXMaCEZpeGVkRmVlEhUKA2ZlZRIOMgwwLjAwMDAwMDAwMDAShwEKCmhvbGRpbmdGZWUSeXJ3Cl0KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGgxSYXRlUGVyUm91bmQSFgoEcmF0ZRIOMgwwLjAwMDAxOTAyNTkSwwQKC3RyYW5zZmVyRmVlErMEcrAEClwKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGgtTdGVwcGVkUmF0ZRIdCgtpbml0aWFsUmF0ZRIOMgwwLjAwMDAwMDAwMDASsAMKBXN0ZXBzEqYDWqMDCocBcoQBClQKQDVhZWU5YjIxYjhlOWE0YzQ5NzViNWY0YzQxOThlNmU2ZTg0NjlkZjQ5ZTIwMTA4MjBlNzkyZjM5M2RiODcwZjQSCERBLlR5cGVzGgZUdXBsZTISFgoCXzESEDIOMTAwLjAwMDAwMDAwMDASFAoCXzISDjIMMC4wMDAwMDAwMDAwCogBcoUBClQKQDVhZWU5YjIxYjhlOWE0YzQ5NzViNWY0YzQxOThlNmU2ZTg0NjlkZjQ5ZTIwMTA4MjBlNzkyZjM5M2RiODcwZjQSCERBLlR5cGVzGgZUdXBsZTISFwoCXzESETIPMTAwMC4wMDAwMDAwMDAwEhQKAl8yEg4yDDAuMDAwMDAwMDAwMAqLAXKIAQpUCkA1YWVlOWIyMWI4ZTlhNGM0OTc1YjVmNGM0MTk4ZTZlNmU4NDY5ZGY0OWUyMDEwODIwZTc5MmYzOTNkYjg3MGY0EghEQS5UeXBlcxoGVHVwbGUyEhoKAl8xEhQyEjEwMDAwMDAuMDAwMDAwMDAwMBIUCgJfMhIOMgwwLjAwMDAwMDAwMDAShQEKDWxvY2tIb2xkZXJGZWUSdHJyClkKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGghGaXhlZEZlZRIVCgNmZWUSDjIMMC4wMDAwMDAwMDAwEi4KHGV4dHJhRmVhdHVyZWRBcHBSZXdhcmRBbW91bnQSDjIMMS4wMDAwMDAwMDAwEhMKDG1heE51bUlucHV0cxIDGMgBEhQKDW1heE51bU91dHB1dHMSAxjIARIXChFtYXhOdW1Mb2NrSG9sZGVycxICGGQSsxgKDWlzc3VhbmNlQ3VydmUSoRhynhgKXQpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIPU3BsaWNlLlNjaGVkdWxlGghTY2hlZHVsZRKqAwoMaW5pdGlhbFZhbHVlEpkDcpYDCmMKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESD1NwbGljZS5Jc3N1YW5jZRoOSXNzdWFuY2VDb25maWcSMAoUYW11bGV0VG9Jc3N1ZVBlclllYXISGDIWNDAwMDAwMDAwMDAuMDAwMDAwMDAwMBIrChl2YWxpZGF0b3JSZXdhcmRQZXJjZW50YWdlEg4yDDAuMDUwMDAwMDAwMBIlChNhcHBSZXdhcmRQZXJjZW50YWdlEg4yDDAuMTUwMDAwMDAwMBIkChJ2YWxpZGF0b3JSZXdhcmRDYXASDjIMMC4yMDAwMDAwMDAwEioKFGZlYXR1cmVkQXBwUmV3YXJkQ2FwEhIyEDIwMDAwLjAwMDAwMDAwMDASKAoWdW5mZWF0dXJlZEFwcFJld2FyZENhcBIOMgwwLjYwMDAwMDAwMDASLQoVb3B0VmFsaWRhdG9yRmF1Y2V0Q2FwEhRSEgoQMg41NzAuMDAwMDAwMDAwMBKPFAoMZnV0dXJlVmFsdWVzEv4TWvsTCvwEcvkEClQKQDVhZWU5YjIxYjhlOWE0YzQ5NzViNWY0YzQxOThlNmU2ZTg0NjlkZjQ5ZTIwMTA4MjBlNzkyZjM5M2RiODcwZjQSCERBLlR5cGVzGgZUdXBsZTISfgoCXzESeHJ2CloKQGI3MGRiODM2OWUxYzQ2MWQ1YzcwZjFjODZmNTI2YTI5ZTk3NzZjNjU1ZTZmZmMyNTYwZjk1YjA1Y2NiOGI5NDYSDURBLlRpbWUuVHlwZXMaB1JlbFRpbWUSGAoMbWljcm9zZWNvbmRzEggYgMDP4OiVBxKgAwoCXzISmQNylgMKYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIPU3BsaWNlLklzc3VhbmNlGg5Jc3N1YW5jZUNvbmZpZxIwChRhbXVsZXRUb0lzc3VlUGVyWWVhchIYMhYyMDAwMDAwMDAwMC4wMDAwMDAwMDAwEisKGXZhbGlkYXRvclJld2FyZFBlcmNlbnRhZ2USDjIMMC4xMjAwMDAwMDAwEiUKE2FwcFJld2FyZFBlcmNlbnRhZ2USDjIMMC40MDAwMDAwMDAwEiQKEnZhbGlkYXRvclJld2FyZENhcBIOMgwwLjIwMDAwMDAwMDASKgoUZmVhdHVyZWRBcHBSZXdhcmRDYXASEjIQMjAwMDAuMDAwMDAwMDAwMBIoChZ1bmZlYXR1cmVkQXBwUmV3YXJkQ2FwEg4yDDAuNjAwMDAwMDAwMBItChVvcHRWYWxpZGF0b3JGYXVjZXRDYXASFFISChAyDjU3MC4wMDAwMDAwMDAwCvwEcvkEClQKQDVhZWU5YjIxYjhlOWE0YzQ5NzViNWY0YzQxOThlNmU2ZTg0NjlkZjQ5ZTIwMTA4MjBlNzkyZjM5M2RiODcwZjQSCERBLlR5cGVzGgZUdXBsZTISfgoCXzESeHJ2CloKQGI3MGRiODM2OWUxYzQ2MWQ1YzcwZjFjODZmNTI2YTI5ZTk3NzZjNjU1ZTZmZmMyNTYwZjk1YjA1Y2NiOGI5NDYSDURBLlRpbWUuVHlwZXMaB1JlbFRpbWUSGAoMbWljcm9zZWNvbmRzEggYgMDuobrBFRKgAwoCXzISmQNylgMKYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIPU3BsaWNlLklzc3VhbmNlGg5Jc3N1YW5jZUNvbmZpZxIwChRhbXVsZXRUb0lzc3VlUGVyWWVhchIYMhYxMDAwMDAwMDAwMC4wMDAwMDAwMDAwEisKGXZhbGlkYXRvclJld2FyZFBlcmNlbnRhZ2USDjIMMC4xODAwMDAwMDAwEiUKE2FwcFJld2FyZFBlcmNlbnRhZ2USDjIMMC42MjAwMDAwMDAwEiQKEnZhbGlkYXRvclJld2FyZENhcBIOMgwwLjIwMDAwMDAwMDASKgoUZmVhdHVyZWRBcHBSZXdhcmRDYXASEjIQMjAwMDAuMDAwMDAwMDAwMBIoChZ1bmZlYXR1cmVkQXBwUmV3YXJkQ2FwEg4yDDAuNjAwMDAwMDAwMBItChVvcHRWYWxpZGF0b3JGYXVjZXRDYXASFFISChAyDjU3MC4wMDAwMDAwMDAwCvsEcvgEClQKQDVhZWU5YjIxYjhlOWE0YzQ5NzViNWY0YzQxOThlNmU2ZTg0NjlkZjQ5ZTIwMTA4MjBlNzkyZjM5M2RiODcwZjQSCERBLlR5cGVzGgZUdXBsZTISfgoCXzESeHJ2CloKQGI3MGRiODM2OWUxYzQ2MWQ1YzcwZjFjODZmNTI2YTI5ZTk3NzZjNjU1ZTZmZmMyNTYwZjk1YjA1Y2NiOGI5NDYSDURBLlRpbWUuVHlwZXMaB1JlbFRpbWUSGAoMbWljcm9zZWNvbmRzEggYgICbxpfaRxKfAwoCXzISmANylQMKYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIPU3BsaWNlLklzc3VhbmNlGg5Jc3N1YW5jZUNvbmZpZxIvChRhbXVsZXRUb0lzc3VlUGVyWWVhchIXMhU1MDAwMDAwMDAwLjAwMDAwMDAwMDASKwoZdmFsaWRhdG9yUmV3YXJkUGVyY2VudGFnZRIOMgwwLjIxMDAwMDAwMDASJQoTYXBwUmV3YXJkUGVyY2VudGFnZRIOMgwwLjY5MDAwMDAwMDASJAoSdmFsaWRhdG9yUmV3YXJkQ2FwEg4yDDAuMjAwMDAwMDAwMBIqChRmZWF0dXJlZEFwcFJld2FyZENhcBISMhAyMDAwMC4wMDAwMDAwMDAwEigKFnVuZmVhdHVyZWRBcHBSZXdhcmRDYXASDjIMMC42MDAwMDAwMDAwEi0KFW9wdFZhbGlkYXRvckZhdWNldENhcBIUUhIKEDIONTcwLjAwMDAwMDAwMDAK/ARy+QQKVApANWFlZTliMjFiOGU5YTRjNDk3NWI1ZjRjNDE5OGU2ZTZlODQ2OWRmNDllMjAxMDgyMGU3OTJmMzkzZGI4NzBmNBIIREEuVHlwZXMaBlR1cGxlMhJ/CgJfMRJ5cncKWgpAYjcwZGI4MzY5ZTFjNDYxZDVjNzBmMWM4NmY1MjZhMjllOTc3NmM2NTVlNmZmYzI1NjBmOTViMDVjY2I4Yjk0NhINREEuVGltZS5UeXBlcxoHUmVsVGltZRIZCgxtaWNyb3NlY29uZHMSCRiAgLaMr7SPARKfAwoCXzISmANylQMKYwpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIPU3BsaWNlLklzc3VhbmNlGg5Jc3N1YW5jZUNvbmZpZxIvChRhbXVsZXRUb0lzc3VlUGVyWWVhchIXMhUyNTAwMDAwMDAwLjAwMDAwMDAwMDASKwoZdmFsaWRhdG9yUmV3YXJkUGVyY2VudGFnZRIOMgwwLjIwMDAwMDAwMDASJQoTYXBwUmV3YXJkUGVyY2VudGFnZRIOMgwwLjc1MDAwMDAwMDASJAoSdmFsaWRhdG9yUmV3YXJkQ2FwEg4yDDAuMjAwMDAwMDAwMBIqChRmZWF0dXJlZEFwcFJld2FyZENhcBISMhAyMDAwMC4wMDAwMDAwMDAwEigKFnVuZmVhdHVyZWRBcHBSZXdhcmRDYXASDjIMMC42MDAwMDAwMDAwEi0KFW9wdFZhbGlkYXRvckZhdWNldENhcBIUUhIKEDIONTcwLjAwMDAwMDAwMDASoAgKGWRlY2VudHJhbGl6ZWRTeW5jaHJvbml6ZXISgghy/wcKiwEKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESIFNwbGljZS5EZWNlbnRyYWxpemVkU3luY2hyb25pemVyGiVBbXVsZXREZWNlbnRyYWxpemVkU3luY2hyb25pemVyQ29uZmlnEtwBChVyZXF1aXJlZFN5bmNocm9uaXplcnMSwgFyvwEKVQpAYzNiYjBjNWQwNDc5OWIzZjExYmFkN2MzYzEwMjk2M2UxMTVjZjUzZGEzZTRhZmNiY2ZkOWYwNmViZDgyYjRmZhIMREEuU2V0LlR5cGVzGgNTZXQSZgoDbWFwEl9qXQpbClVCU2dsb2JhbC1kb21haW46OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhEgIKABJrChJhY3RpdmVTeW5jaHJvbml6ZXISVUJTZ2xvYmFsLWRvbWFpbjo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWESogQKBGZlZXMSmQRylgQKfApAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIgU3BsaWNlLkRlY2VudHJhbGl6ZWRTeW5jaHJvbml6ZXIaFlN5bmNocm9uaXplckZlZXNDb25maWcStwIKFWJhc2VSYXRlVHJhZmZpY0xpbWl0cxKdAnKaAgp7CkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEiBTcGxpY2UuRGVjZW50cmFsaXplZFN5bmNocm9uaXplchoVQmFzZVJhdGVUcmFmZmljTGltaXRzEhMKC2J1cnN0QW1vdW50EgQYgOowEoUBCgtidXJzdFdpbmRvdxJ2cnQKWgpAYjcwZGI4MzY5ZTFjNDYxZDVjNzBmMWM4NmY1MjZhMjllOTc3NmM2NTVlNmZmYzI1NjBmOTViMDVjY2I4Yjk0NhINREEuVGltZS5UeXBlcxoHUmVsVGltZRIWCgxtaWNyb3NlY29uZHMSBhiAsLT4CBIkChFleHRyYVRyYWZmaWNQcmljZRIPMg02MC4wMDAwMDAwMDAwEh4KGHJlYWRWc1dyaXRlU2NhbGluZ0ZhY3RvchICGAgSFgoObWluVG9wdXBBbW91bnQSBBiAtRgShgEKDHRpY2tEdXJhdGlvbhJ2cnQKWgpAYjcwZGI4MzY5ZTFjNDYxZDVjNzBmMWM4NmY1MjZhMjllOTc3NmM2NTVlNmZmYzI1NjBmOTViMDVjY2I4Yjk0NhINREEuVGltZS5UeXBlcxoHUmVsVGltZRIWCgxtaWNyb3NlY29uZHMSBhiAmJq8BBKaAgoNcGFja2FnZUNvbmZpZxKIAnKFAgpmCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEhNTcGxpY2UuQW11bGV0Q29uZmlnGg1QYWNrYWdlQ29uZmlnEhIKBmFtdWxldBIIQgYwLjEuMTQSHQoRYW11bGV0TmFtZVNlcnZpY2USCEIGMC4xLjE0EhkKDWRzb0dvdmVybmFuY2USCEIGMC4xLjE5Eh0KEnZhbGlkYXRvckxpZmVjeWNsZRIHQgUwLjEuNRISCgZ3YWxsZXQSCEIGMC4xLjE0EhoKDndhbGxldFBheW1lbnRzEghCBjAuMS4xNBIcChZ0cmFuc2ZlclByZWFwcHJvdmFsRmVlEgJSABI1Ch9mZWF0dXJlZEFwcEFjdGl2aXR5TWFya2VyQW1vdW50EhJSEAoOMgwxLjAwMDAwMDAwMDASEgoMZnV0dXJlVmFsdWVzEgJaABIOCghpc0Rldk5ldBICEAEySURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWHAPt3IidTglpAD0j7WDwoDMi4xEs4PCkUAO5AwR5oepQtCByXEELZMRgm2SrSZbecH75mmLPoJ+QfKERIgoLz2TnO7OuN9D/jP4u0jVGbL7cymW/S7g9G9ifNDOfQSDXNwbGljZS1hbXVsZXQaZApAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIGU3BsaWNlEgtBbXVsZXRSdWxlcxoLQW11bGV0UnVsZXMijw1qjA0KTQpLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhCrQMCrEMaq4MCqUMCqIMap8MCpsCCpgCapUCChYKFGoSChAKDjIMMC4wMDAwMDAwMDAwChYKFGoSChAKDjIMMC4wMDAwMTkwMjU5CqQBCqEBap4BChAKDjIMMC4wMDAwMDAwMDAwCokBCoYBWoMBCihqJgoSChAyDjEwMC4wMDAwMDAwMDAwChAKDjIMMC4wMDAwMDAwMDAwCilqJwoTChEyDzEwMDAuMDAwMDAwMDAwMAoQCg4yDDAuMDAwMDAwMDAwMAosaioKFgoUMhIxMDAwMDAwLjAwMDAwMDAwMDAKEAoOMgwwLjAwMDAwMDAwMDAKFgoUahIKEAoOMgwwLjAwMDAwMDAwMDAKEAoOMgwxLjAwMDAwMDAwMDAKBQoDGMgBCgUKAxjIAQoECgIYZAr1BgryBmrvBgqYAQqVAWqSAQoaChgyFjQwMDAwMDAwMDAwLjAwMDAwMDAwMDAKEAoOMgwwLjA1MDAwMDAwMDAKEAoOMgwwLjE1MDAwMDAwMDAKEAoOMgwwLjIwMDAwMDAwMDAKFAoSMhAyMDAwMC4wMDAwMDAwMDAwChAKDjIMMC42MDAwMDAwMDAwChYKFFISChAyDjU3MC4wMDAwMDAwMDAwCtEFCs4FWssFCrABaq0BChAKDmoMCgoKCBiAwM/g6JUHCpgBCpUBapIBChoKGDIWMjAwMDAwMDAwMDAuMDAwMDAwMDAwMAoQCg4yDDAuMTIwMDAwMDAwMAoQCg4yDDAuNDAwMDAwMDAwMAoQCg4yDDAuMjAwMDAwMDAwMAoUChIyEDIwMDAwLjAwMDAwMDAwMDAKEAoOMgwwLjYwMDAwMDAwMDAKFgoUUhIKEDIONTcwLjAwMDAwMDAwMDAKsAFqrQEKEAoOagwKCgoIGIDA7qG6wRUKmAEKlQFqkgEKGgoYMhYxMDAwMDAwMDAwMC4wMDAwMDAwMDAwChAKDjIMMC4xODAwMDAwMDAwChAKDjIMMC42MjAwMDAwMDAwChAKDjIMMC4yMDAwMDAwMDAwChQKEjIQMjAwMDAuMDAwMDAwMDAwMAoQCg4yDDAuNjAwMDAwMDAwMAoWChRSEgoQMg41NzAuMDAwMDAwMDAwMAqvAWqsAQoQCg5qDAoKCggYgICbxpfaRwqXAQqUAWqRAQoZChcyFTUwMDAwMDAwMDAuMDAwMDAwMDAwMAoQCg4yDDAuMjEwMDAwMDAwMAoQCg4yDDAuNjkwMDAwMDAwMAoQCg4yDDAuMjAwMDAwMDAwMAoUChIyEDIwMDAwLjAwMDAwMDAwMDAKEAoOMgwwLjYwMDAwMDAwMDAKFgoUUhIKEDIONTcwLjAwMDAwMDAwMDAKsAFqrQEKEQoPag0KCwoJGICAtoyvtI8BCpcBCpQBapEBChkKFzIVMjUwMDAwMDAwMC4wMDAwMDAwMDAwChAKDjIMMC4yMDAwMDAwMDAwChAKDjIMMC43NTAwMDAwMDAwChAKDjIMMC4yMDAwMDAwMDAwChQKEjIQMjAwMDAuMDAwMDAwMDAwMAoQCg4yDDAuNjAwMDAwMDAwMAoWChRSEgoQMg41NzAuMDAwMDAwMDAwMAqNAgqKAmqHAgpnCmVqYwphCl9iXQpbClVCU2dsb2JhbC1kb21haW46OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhEgIKAApXClVCU2dsb2JhbC1kb21haW46OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhCkMKQWo/ChwKGmoYCgYKBBiA6jAKDgoMagoKCAoGGICwtPgIChEKDzINNjAuMDAwMDAwMDAwMAoECgIYCAoGCgQYgLUYCg4KDGoKCggKBhiAmJq8BApLCklqRwoKCghCBjAuMS4xNAoKCghCBjAuMS4xNAoKCghCBjAuMS4xOQoJCgdCBTAuMS41CgoKCEIGMC4xLjE0CgoKCEIGMC4xLjE0CgQKAlIAChQKElIQCg4yDDEuMDAwMDAwMDAwMAoECgJaAAoECgIQASpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTldZIIKtkAGAEIqCiYKJAgBEiAq8EtMq9+TalRq5epvA9S5EXsGT7RLa6WY5hrOoiCbyBAeOtEICo8FCgMyLjESigEwMDlmMDBlNWJmMDA2NDAxMThkODQ5MDgwYWFmMjJiYzk2M2E4NDU4ZDMyMjU4NWNlYmYxMTE5Y2I3YmYzN2E5NTVjYTExMTIyMDY1Yjc3NWZiOGE0MTk5OTA0ZWQzMmZhOTI3N2ZkOWMwZTgyYmI4MjMxOWE3MTUxMjQ5ZGYxMjQxODIwNzIzODEaDXNwbGljZS1hbXVsZXQifQpAYTViMDU1NDkyZmI4ZjA4YjJlN2JjMGZjOTRkYTZkYTUwYzM5YzJlMWQ3ZjI0Y2Q1ZWE4ZGIxMmZjODdjMTMzMhIfU3BsaWNlLkV4dGVybmFsUGFydHlBbXVsZXRSdWxlcxoYRXh0ZXJuYWxQYXJ0eUFtdWxldFJ1bGVzKtYBctMBCn0KQGE1YjA1NTQ5MmZiOGYwOGIyZTdiYzBmYzk0ZGE2ZGE1MGMzOWMyZTFkN2YyNGNkNWVhOGRiMTJmYzg3YzEzMzISH1NwbGljZS5FeHRlcm5hbFBhcnR5QW11bGV0UnVsZXMaGEV4dGVybmFsUGFydHlBbXVsZXRSdWxlcxJSCgNkc28SSzpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTJJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYTpJRFNPOjoxMjIwYmU1OGMyOWU2NWRlNDBiZjI3M2JlMWRjMmIyNjZkNDNhOWEwMDJlYTViMTg5NTVhZWVmN2FhYzg4MWJiNDcxYcA+uKzv4J+ejgPSPrEDCgMyLjESqQMKRQCfAOW/AGQBGNhJCAqvIryWOoRY0yJYXOvxEZy3vzepVcoREiBlt3X7ikGZkE7TL6knf9nA6Cu4IxmnFRJJ3xJBggcjgRINc3BsaWNlLWFtdWxldBp+CkBhNWIwNTU0OTJmYjhmMDhiMmU3YmMwZmM5NGRhNmRhNTBjMzljMmUxZDdmMjRjZDVlYThkYjEyZmM4N2MxMzMyEgZTcGxpY2USGEV4dGVybmFsUGFydHlBbXVsZXRSdWxlcxoYRXh0ZXJuYWxQYXJ0eUFtdWxldFJ1bGVzIlFqTwpNCks6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEqSURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE5ONYb/PE4BgBCKgomCiQIARIgg6XaQb6Ove2ZeEETfGZZCQBZC/+uO0vA1Vrm1nkOd7oQHjqVDwr8CQoDMi4xEooBMDBiYzAyZDJmNTAyOGQwMDEwZGJkNzNkMzQ1OGRkOWI4MjcwZWQwZThiZmRmYmU1OTQ3NzFiOGM1YzlhN2NjMDZiY2ExMTEyMjAzZDNhYjlhYWEyZjU2NmYxYWM0Yjc5MzBlY2NjMzFmNzhlZTkyOGUzMzViNTk0MDI2MThjMDBkODUxNTBlZTQ3Gg1zcGxpY2UtYW11bGV0IlkKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDVNwbGljZS5BbXVsZXQaBkFtdWxldCqzBXKwBQpZCkAzY2ExMzQzYWIyNmI0NTNkMzhjOGFkYjcwZGNhNWYxZWFkODQ0MGM0MmI1OWI2OGYwNzA3ODY5NTVjYmY5ZWMxEg1TcGxpY2UuQW11bGV0GgZBbXVsZXQSUgoDZHNvEks6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWESYwoFb3duZXISWjpYdGVzdC1iYWxhLXBhcnR5LTAxOjoxMjIwMzg5ZTY0ODA3NGM3MDhlYWQ1MjdmZDlmNDM2OTFlMDQ2M2U3NTljMDllZTRkOTk0ZDY4M2IxYWEyY2M3NGQ1OBKZAwoGYW1vdW50Eo4DcosDCl8KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGg5FeHBpcmluZ0Ftb3VudBIiCg1pbml0aWFsQW1vdW50EhEyDzEwMDAuMDAwMDAwMDAwMBJ4CgljcmVhdGVkQXQSa3JpClcKQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESDFNwbGljZS5UeXBlcxoFUm91bmQSDgoGbnVtYmVyEgQY2tgBEokBCgxyYXRlUGVyUm91bmQSeXJ3Cl0KQDNjYTEzNDNhYjI2YjQ1M2QzOGM4YWRiNzBkY2E1ZjFlYWQ4NDQwYzQyYjU5YjY4ZjA3MDc4Njk1NWNiZjllYzESC1NwbGljZS5GZWVzGgxSYXRlUGVyUm91bmQSFgoEcmF0ZRIOMgwwLjAwMDIwMDI3MjYySURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEyWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTg6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWE6WHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTjAPs3F7dr/lpAD0j6IBQoDMi4xEoAFCkUAvALS9QKNABDb1z00WN2bgnDtDov9++WUdxuMXJp8wGvKERIgPTq5qqL1ZvGsS3kw7Mwx947pKOM1tZQCYYwA2FFQ7kcSDXNwbGljZS1hbXVsZXQaWgpAM2NhMTM0M2FiMjZiNDUzZDM4YzhhZGI3MGRjYTVmMWVhZDg0NDBjNDJiNTliNjhmMDcwNzg2OTU1Y2JmOWVjMRIGU3BsaWNlEgZBbXVsZXQaBkFtdWxldCLxAWruAQpNCks6SURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEKXApaOlh0ZXN0LWJhbGEtcGFydHktMDE6OjEyMjAzODllNjQ4MDc0YzcwOGVhZDUyN2ZkOWY0MzY5MWUwNDYzZTc1OWMwOWVlNGQ5OTRkNjgzYjFhYTJjYzc0ZDU4Cj8KPWo7ChMKETIPMTAwMC4wMDAwMDAwMDAwCgwKCmoICgYKBBja2AEKFgoUahIKEAoOMgwwLjAwMDIwMDI3MjYqSURTTzo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEqWHRlc3QtYmFsYS1wYXJ0eS0wMTo6MTIyMDM4OWU2NDgwNzRjNzA4ZWFkNTI3ZmQ5ZjQzNjkxZTA0NjNlNzU5YzA5ZWU0ZDk5NGQ2ODNiMWFhMmNjNzRkNTg5zWJb+7dABgBCKgomCiQIARIgja6ZmldCirmJDw8TItHU4LrCK22NkAeuFjTkrfCq2goQHkjpz9azi5eQA1Do56vNk5yQAw==', + preparedTransactionHash: '7Ey4Q2TqWQcK1eAl6p15UT02M4mx92Tvo9ifvtzlm5o=', + hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2', + hashingDetails: + "'00000030' # Hash Purpose\n'02' # 02 (Hashing Scheme Version)\n '00000030' # Hash Purpose\n # Transaction Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n # Root Nodes\n '00000001' # 1 (int)\n '01' # 01 (Node Encoding Version)\n # Exercise Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '01' # Exercise Node Tag\n # Node Seed\n '5dd431b2c7343645c186db4d2905d0caa3d236a3ffb725c38535ad0cc57ef446' # seed\n # Contract Id\n '00000045' # 69 (int)\n '009f00e5bf00640118d849080aaf22bc963a8458d322585cebf1119cb7bf37a955ca11122065b775fb8a4199904ed32fa9277fd9c0e82bb82319a7151249df124182072381' # 009f00e5bf00640118d849080aaf22bc963a8458d322585cebf1119cb7bf37a955ca11122065b775fb8a4199904ed32fa9277fd9c0e82bb82319a7151249df124182072381 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000018' # 24 (int)\n '45787465726e616c5061727479416d756c657452756c6573' # ExternalPartyAmuletRules (string)\n '00000001' # 1 (int)\n '00000018' # 24 (int)\n '45787465726e616c5061727479416d756c657452756c6573' # ExternalPartyAmuletRules (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Acting Parties\n '00000001' # 1 (int)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Interface Id\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '5472616e73666572466163746f7279' # TransferFactory (string)\n # Choice Id\n '00000018' # 24 (int)\n '5472616e73666572466163746f72795f5472616e73666572' # TransferFactory_Transfer (string)\n # Chosen Value\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000001' # 1 (int)\n '00000018' # 24 (int)\n '5472616e73666572466163746f72795f5472616e73666572' # TransferFactory_Transfer (string)\n '00000003' # 3 (int)\n '01' # Some\n '0000000d' # 13 (int)\n '657870656374656441646d696e' # expectedAdmin (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000008' # 8 (int)\n '7472616e73666572' # transfer (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '5472616e73666572' # Transfer (string)\n '00000008' # 8 (int)\n '01' # Some\n '00000006' # 6 (int)\n '73656e646572' # sender (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000008' # 8 (int)\n '7265636569766572' # receiver (string)\n '06' # Party Type Tag\n '00000063' # 99 (int)\n '726176692d64656d6f2d70617274792d74786e2d30312d7461707065723a3a3132323065613761623561373233663861366232303738653631376536633538636237653738653439393437646463323339653161393431616135366536626130386234' # ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4 (string)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '03' # Numeric Type Tag\n '0000000d' # 13 (int)\n '35302e30303030303030303030' # 50.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '696e737472756d656e744964' # instrumentId (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '37313861306637376535303561386465323266313838626434633837666537343130313237346539643463623162666163376430396165633731353864333562' # 718a0f77e505a8de22f188bd4c87fe74101274e9d4cb1bfac7d09aec7158d35b (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000009' # 9 (int)\n '486f6c64696e675631' # HoldingV1 (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '496e737472756d656e744964' # InstrumentId (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000005' # 5 (int)\n '61646d696e' # admin (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000002' # 2 (int)\n '6964' # id (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '01' # Some\n '0000000b' # 11 (int)\n '7265717565737465644174' # requestedAt (string)\n '04' # Timestamp Type Tag\n '000640b8b675a7e9' # 1760011939588073 (long)\n '01' # Some\n '0000000d' # 13 (int)\n '657865637574654265666f7265' # executeBefore (string)\n '04' # Timestamp Type Tag\n '000640e139aaf3e9' # 1760185939588073 (long)\n '01' # Some\n '00000010' # 16 (int)\n '696e707574486f6c64696e6743696473' # inputHoldingCids (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '08' # ContractId Type Tag\n '00000045' # 69 (int)\n '00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47' # 00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47 (contractId)\n '01' # Some\n '00000004' # 4 (int)\n '6d657461' # meta (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4d65746164617461' # Metadata (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '76616c756573' # values (string)\n '0b' # TextMap Type Tag\n '00000000' # 0 (int)\n '01' # Some\n '00000009' # 9 (int)\n '657874726141726773' # extraArgs (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000009' # 9 (int)\n '457874726141726773' # ExtraArgs (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000007' # 7 (int)\n '636f6e74657874' # context (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '0000000d' # 13 (int)\n '43686f696365436f6e74657874' # ChoiceContext (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '76616c756573' # values (string)\n '0b' # TextMap Type Tag\n '00000002' # 2 (int)\n '0000000c' # 12 (int)\n '616d756c65742d72756c6573' # amulet-rules (string)\n '0d' # Variant Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '416e7956616c7565' # AnyValue (string)\n '0000000d' # 13 (int)\n '41565f436f6e74726163744964' # AV_ContractId (string)\n '08' # ContractId Type Tag\n '00000045' # 69 (int)\n '003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4' # 003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4 (contractId)\n '0000000a' # 10 (int)\n '6f70656e2d726f756e64' # open-round (string)\n '0d' # Variant Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '416e7956616c7565' # AnyValue (string)\n '0000000d' # 13 (int)\n '41565f436f6e74726163744964' # AV_ContractId (string)\n '08' # ContractId Type Tag\n '00000045' # 69 (int)\n '003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a' # 003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a (contractId)\n '01' # Some\n '00000004' # 4 (int)\n '6d657461' # meta (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4d65746164617461' # Metadata (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '76616c756573' # values (string)\n '0b' # TextMap Type Tag\n '00000000' # 0 (int)\n # Consuming\n '00' # false (bool)\n # Exercise Result\n '01' # Some\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000001' # 1 (int)\n '00000019' # 25 (int)\n '5472616e73666572496e737472756374696f6e526573756c74' # TransferInstructionResult (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000006' # 6 (int)\n '6f7574707574' # output (string)\n '0d' # Variant Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000001' # 1 (int)\n '00000020' # 32 (int)\n '5472616e73666572496e737472756374696f6e526573756c745f4f7574707574' # TransferInstructionResult_Output (string)\n '00000021' # 33 (int)\n '5472616e73666572496e737472756374696f6e526573756c745f50656e64696e67' # TransferInstructionResult_Pending (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000002' # 2 (int)\n '00000020' # 32 (int)\n '5472616e73666572496e737472756374696f6e526573756c745f4f7574707574' # TransferInstructionResult_Output (string)\n '00000021' # 33 (int)\n '5472616e73666572496e737472756374696f6e526573756c745f50656e64696e67' # TransferInstructionResult_Pending (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000016' # 22 (int)\n '7472616e73666572496e737472756374696f6e436964' # transferInstructionCid (string)\n '08' # ContractId Type Tag\n '00000021' # 33 (int)\n '00c5bdee5b91467b6d06cbf34b4643be109838acc09cf9ac9ed429fafac96bb91f' # 00c5bdee5b91467b6d06cbf34b4643be109838acc09cf9ac9ed429fafac96bb91f (contractId)\n '01' # Some\n '00000010' # 16 (int)\n '73656e6465724368616e676543696473' # senderChangeCids (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '08' # ContractId Type Tag\n '00000021' # 33 (int)\n '0073dd0492654305ca61839e3c5b1343077a1891929b6ea8410247d6a360704c86' # 0073dd0492654305ca61839e3c5b1343077a1891929b6ea8410247d6a360704c86 (contractId)\n '01' # Some\n '00000004' # 4 (int)\n '6d657461' # meta (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4d65746164617461' # Metadata (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '76616c756573' # values (string)\n '0b' # TextMap Type Tag\n '00000000' # 0 (int)\n # Choice Observers\n '00000000' # 0 (int)\n # Children\n '00000005' # 5 (int)\n '01' # 01 (Node Encoding Version)\n # Fetch Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '02' # Fetch Node Tag\n # Contract Id\n '00000045' # 69 (int)\n '003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4' # 003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Interface Id\n '00' # None\n # Acting Parties\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '3b8efcebf75a59ff956476e591cff03abe4dd5812c5d49cb8e87d0d6c8155f6e' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Exercise Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '01' # Exercise Node Tag\n # Node Seed\n 'c926a59b29da3a0e474f03541233396c66b5bbd5e55060013660ad44d796cec9' # seed\n # Contract Id\n '00000045' # 69 (int)\n '003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4' # 003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Acting Parties\n '00000001' # 1 (int)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Interface Id\n '00' # None\n # Choice Id\n '00000017' # 23 (int)\n '416d756c657452756c65735f436f6d7075746546656573' # AmuletRules_ComputeFees (string)\n # Chosen Value\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '00000017' # 23 (int)\n '416d756c657452756c65735f436f6d7075746546656573' # AmuletRules_ComputeFees (string)\n '00000004' # 4 (int)\n '01' # Some\n '00000007' # 7 (int)\n '636f6e74657874' # context (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '5472616e73666572436f6e74657874' # TransferContext (string)\n '00000003' # 3 (int)\n '01' # Some\n '0000000f' # 15 (int)\n '6f70656e4d696e696e67526f756e64' # openMiningRound (string)\n '08' # ContractId Type Tag\n '00000045' # 69 (int)\n '003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a' # 003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a (contractId)\n '01' # Some\n '00000013' # 19 (int)\n '69737375696e674d696e696e67526f756e6473' # issuingMiningRounds (string)\n '0f' # GenMap Type Tag\n '00000000' # 0 (int)\n '01' # Some\n '0000000f' # 15 (int)\n '76616c696461746f72526967687473' # validatorRights (string)\n '0f' # GenMap Type Tag\n '00000000' # 0 (int)\n '01' # Some\n '00000006' # 6 (int)\n '73656e646572' # sender (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000007' # 7 (int)\n '6f757470757473' # outputs (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '5472616e736665724f7574707574' # TransferOutput (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000008' # 8 (int)\n '7265636569766572' # receiver (string)\n '06' # Party Type Tag\n '00000063' # 99 (int)\n '726176692d64656d6f2d70617274792d74786e2d30312d7461707065723a3a3132323065613761623561373233663861366232303738653631376536633538636237653738653439393437646463323339653161393431616135366536626130386234' # ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4 (string)\n '01' # Some\n '00000010' # 16 (int)\n '7265636569766572466565526174696f' # receiverFeeRatio (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '03' # Numeric Type Tag\n '0000000d' # 13 (int)\n '35302e30303030303030303030' # 50.0000000000 (numeric)\n '01' # Some\n '0000000b' # 11 (int)\n '657870656374656444736f' # expectedDso (string)\n '09' # Optional Type Tag\n '01' # Some\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Consuming\n '00' # false (bool)\n # Exercise Result\n '01' # Some\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000001d' # 29 (int)\n '416d756c657452756c65735f436f6d7075746546656573526573756c74' # AmuletRules_ComputeFeesResult (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000004' # 4 (int)\n '66656573' # fees (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n # Choice Observers\n '00000000' # 0 (int)\n # Children\n '00000001' # 1 (int)\n '01' # 01 (Node Encoding Version)\n # Fetch Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '02' # Fetch Node Tag\n # Contract Id\n '00000045' # 69 (int)\n '003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a' # 003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '4f70656e4d696e696e67526f756e64' # OpenMiningRound (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Interface Id\n '00' # None\n # Acting Parties\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '936a24c570ffed7f1606b3653788fc05d0a77f71e430ffe761c295ab5a0e3ede' # (Hashed Inner Node)\n '0ab579f128227a2b1b313de7f32a10483f514d4ea5ff4dbac41079a0204a065d' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Fetch Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '02' # Fetch Node Tag\n # Contract Id\n '00000045' # 69 (int)\n '00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47' # 00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Interface Id\n '01' # Some\n '00000040' # 64 (int)\n '37313861306637376535303561386465323266313838626434633837666537343130313237346539643463623162666163376430396165633731353864333562' # 718a0f77e505a8de22f188bd4c87fe74101274e9d4cb1bfac7d09aec7158d35b (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000009' # 9 (int)\n '486f6c64696e675631' # HoldingV1 (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '486f6c64696e67' # Holding (string)\n # Acting Parties\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '7d6ba8d94725509e9b6e035155ec45ae54c5f09353479cdd01b4453837ecfa70' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Exercise Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '01' # Exercise Node Tag\n # Node Seed\n '0d68e25a641cebd632dd9ec8a0225a69251fa8a520da2ab5ab8f778c4671a91e' # seed\n # Contract Id\n '00000045' # 69 (int)\n '003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4' # 003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Acting Parties\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Interface Id\n '00' # None\n # Choice Id\n '00000014' # 20 (int)\n '416d756c657452756c65735f5472616e73666572' # AmuletRules_Transfer (string)\n # Chosen Value\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '00000014' # 20 (int)\n '416d756c657452756c65735f5472616e73666572' # AmuletRules_Transfer (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000008' # 8 (int)\n '7472616e73666572' # transfer (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '5472616e73666572' # Transfer (string)\n '00000004' # 4 (int)\n '01' # Some\n '00000006' # 6 (int)\n '73656e646572' # sender (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000008' # 8 (int)\n '70726f7669646572' # provider (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000006' # 6 (int)\n '696e70757473' # inputs (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '0d' # Variant Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000d' # 13 (int)\n '5472616e73666572496e707574' # TransferInput (string)\n '0000000b' # 11 (int)\n '496e707574416d756c6574' # InputAmulet (string)\n '08' # ContractId Type Tag\n '00000045' # 69 (int)\n '00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47' # 00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47 (contractId)\n '01' # Some\n '00000007' # 7 (int)\n '6f757470757473' # outputs (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '5472616e736665724f7574707574' # TransferOutput (string)\n '00000004' # 4 (int)\n '01' # Some\n '00000008' # 8 (int)\n '7265636569766572' # receiver (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000010' # 16 (int)\n '7265636569766572466565526174696f' # receiverFeeRatio (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '03' # Numeric Type Tag\n '0000000d' # 13 (int)\n '35302e30303030303030303030' # 50.0000000000 (numeric)\n '01' # Some\n '00000004' # 4 (int)\n '6c6f636b' # lock (string)\n '09' # Optional Type Tag\n '01' # Some\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '457870697279' # Expiry (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '54696d654c6f636b' # TimeLock (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000007' # 7 (int)\n '686f6c64657273' # holders (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000009' # 9 (int)\n '657870697265734174' # expiresAt (string)\n '04' # Timestamp Type Tag\n '000640e139aaf3e9' # 1760185939588073 (long)\n '01' # Some\n '0000000a' # 10 (int)\n '6f7074436f6e74657874' # optContext (string)\n '09' # Optional Type Tag\n '01' # Some\n '07' # Text Type Tag\n '00000071' # 113 (int)\n '7472616e7366657220746f2027726176692d64656d6f2d70617274792d74786e2d30312d7461707065723a3a313232306561376162356137323366386136623230373865363137653663353863623765373865343939343764646332333965316139343161613536653662613038623427' # transfer to 'ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4' (string)\n '01' # Some\n '00000007' # 7 (int)\n '636f6e74657874' # context (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '5472616e73666572436f6e74657874' # TransferContext (string)\n '00000003' # 3 (int)\n '01' # Some\n '0000000f' # 15 (int)\n '6f70656e4d696e696e67526f756e64' # openMiningRound (string)\n '08' # ContractId Type Tag\n '00000045' # 69 (int)\n '003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a' # 003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a (contractId)\n '01' # Some\n '00000013' # 19 (int)\n '69737375696e674d696e696e67526f756e6473' # issuingMiningRounds (string)\n '0f' # GenMap Type Tag\n '00000000' # 0 (int)\n '01' # Some\n '0000000f' # 15 (int)\n '76616c696461746f72526967687473' # validatorRights (string)\n '0f' # GenMap Type Tag\n '00000000' # 0 (int)\n '01' # Some\n '0000000b' # 11 (int)\n '657870656374656444736f' # expectedDso (string)\n '09' # Optional Type Tag\n '01' # Some\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Consuming\n '00' # false (bool)\n # Exercise Result\n '01' # Some\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '5472616e73666572526573756c74' # TransferResult (string)\n '00000005' # 5 (int)\n '01' # Some\n '00000005' # 5 (int)\n '726f756e64' # round (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '6e756d626572' # number (string)\n '02' # Int64 Type Tag\n '0000000000003633' # 13875 (long)\n '01' # Some\n '00000007' # 7 (int)\n '73756d6d617279' # summary (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '5472616e7366657253756d6d617279' # TransferSummary (string)\n '0000000c' # 12 (int)\n '01' # Some\n '00000014' # 20 (int)\n '696e707574417070526577617264416d6f756e74' # inputAppRewardAmount (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000001a' # 26 (int)\n '696e70757456616c696461746f72526577617264416d6f756e74' # inputValidatorRewardAmount (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '696e7075745376526577617264416d6f756e74' # inputSvRewardAmount (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000011' # 17 (int)\n '696e707574416d756c6574416d6f756e74' # inputAmuletAmount (string)\n '03' # Numeric Type Tag\n '0000000f' # 15 (int)\n '313030302e30303030303030303030' # 1000.0000000000 (numeric)\n '01' # Some\n '0000000e' # 14 (int)\n '62616c616e63654368616e676573' # balanceChanges (string)\n '0f' # GenMap Type Tag\n '00000001' # 1 (int)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000d' # 13 (int)\n '42616c616e63654368616e6765' # BalanceChange (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000022' # 34 (int)\n '6368616e6765546f496e697469616c416d6f756e7441734f66526f756e645a65726f' # changeToInitialAmountAsOfRoundZero (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '322e37373939383339363036' # 2.7799839606 (numeric)\n '01' # Some\n '00000017' # 23 (int)\n '6368616e6765546f486f6c64696e674665657352617465' # changeToHoldingFeesRate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303032303032373236' # 0.0002002726 (numeric)\n '01' # Some\n '0000000b' # 11 (int)\n '686f6c64696e6746656573' # holdingFees (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000a' # 10 (int)\n '6f757470757446656573' # outputFees (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000f' # 15 (int)\n '73656e6465724368616e6765466565' # senderChangeFee (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '73656e6465724368616e6765416d6f756e74' # senderChangeAmount (string)\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3935302e30303030303030303030' # 950.0000000000 (numeric)\n '01' # Some\n '0000000b' # 11 (int)\n '616d756c65745072696365' # amuletPrice (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30393530303030303030' # 0.0950000000 (numeric)\n '01' # Some\n '0000001a' # 26 (int)\n '696e70757456616c696461746f72466175636574416d6f756e74' # inputValidatorFaucetAmount (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000022' # 34 (int)\n '696e707574556e636c61696d656441637469766974795265636f7264416d6f756e74' # inputUnclaimedActivityRecordAmount (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000e' # 14 (int)\n '63726561746564416d756c657473' # createdAmulets (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '0d' # Variant Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000d' # 13 (int)\n '43726561746564416d756c6574' # CreatedAmulet (string)\n '0000001a' # 26 (int)\n '5472616e73666572526573756c744c6f636b6564416d756c6574' # TransferResultLockedAmulet (string)\n '08' # ContractId Type Tag\n '00000021' # 33 (int)\n '00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f' # 00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f (contractId)\n '01' # Some\n '00000012' # 18 (int)\n '73656e6465724368616e6765416d756c6574' # senderChangeAmulet (string)\n '09' # Optional Type Tag\n '01' # Some\n '08' # ContractId Type Tag\n '00000021' # 33 (int)\n '0073dd0492654305ca61839e3c5b1343077a1891929b6ea8410247d6a360704c86' # 0073dd0492654305ca61839e3c5b1343077a1891929b6ea8410247d6a360704c86 (contractId)\n '01' # Some\n '00000004' # 4 (int)\n '6d657461' # meta (string)\n '09' # Optional Type Tag\n '01' # Some\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4d65746164617461' # Metadata (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '76616c756573' # values (string)\n '0b' # TextMap Type Tag\n '00000002' # 2 (int)\n '00000026' # 38 (int)\n '73706c6963652e6c66646563656e7472616c697a656474727573742e6f72672f73656e646572' # splice.lfdecentralizedtrust.org/sender (string)\n '07' # Text Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '00000027' # 39 (int)\n '73706c6963652e6c66646563656e7472616c697a656474727573742e6f72672f74782d6b696e64' # splice.lfdecentralizedtrust.org/tx-kind (string)\n '07' # Text Type Tag\n '00000008' # 8 (int)\n '7472616e73666572' # transfer (string)\n # Choice Observers\n '00000000' # 0 (int)\n # Children\n '00000005' # 5 (int)\n '01' # 01 (Node Encoding Version)\n # Fetch Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '02' # Fetch Node Tag\n # Contract Id\n '00000045' # 69 (int)\n '003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a' # 003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '4f70656e4d696e696e67526f756e64' # OpenMiningRound (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Interface Id\n '00' # None\n # Acting Parties\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '936a24c570ffed7f1606b3653788fc05d0a77f71e430ffe761c295ab5a0e3ede' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Fetch Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '02' # Fetch Node Tag\n # Contract Id\n '00000045' # 69 (int)\n '00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47' # 00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Interface Id\n '00' # None\n # Acting Parties\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '808cb338370d8773e8443e607c65de96779cafda41eee83cdd31e1ee903efc55' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Exercise Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '01' # Exercise Node Tag\n # Node Seed\n '8ac4cded476e78e84c93cdc8a02e0e43d0eadc5c04a4c1ec52a2da9b4e2ac99d' # seed\n # Contract Id\n '00000045' # 69 (int)\n '00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47' # 00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Acting Parties\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Interface Id\n '00' # None\n # Choice Id\n '00000007' # 7 (int)\n '41726368697665' # Archive (string)\n # Chosen Value\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '39653730613862333531306436313766386131333632313366333364366139303361313063613065656563373662623036626135356431656439363830663639' # 9e70a8b3510d617f8a136213f33d6a903a10ca0eeec76bb06ba55d1ed9680f69 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000008' # 8 (int)\n '496e7465726e616c' # Internal (string)\n '00000008' # 8 (int)\n '54656d706c617465' # Template (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '41726368697665' # Archive (string)\n '00000000' # 0 (int)\n # Consuming\n '01' # true (bool)\n # Exercise Result\n '01' # Some\n '00' # Unit Type Tag\n # Choice Observers\n '00000000' # 0 (int)\n # Children\n '00000000' # 0 (int)\n 'a5d6fa2d0a77458bc8fa4752751846e69496594dd729624c1c52439e77e4486f' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '01' # Some\n 'd97d5882134b76af02e36e68f3e6ac070146181fa0b7d5af6c682c47442f4494' # node seed\n # Contract Id\n '00000021' # 33 (int)\n '00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f' # 00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '4c6f636b6564416d756c6574' # LockedAmulet (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '4c6f636b6564416d756c6574' # LockedAmulet (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000006' # 6 (int)\n '616d756c6574' # amulet (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000003' # 3 (int)\n '64736f' # dso (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000005' # 5 (int)\n '6f776e6572' # owner (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '4578706972696e67416d6f756e74' # ExpiringAmount (string)\n '00000003' # 3 (int)\n '01' # Some\n '0000000d' # 13 (int)\n '696e697469616c416d6f756e74' # initialAmount (string)\n '03' # Numeric Type Tag\n '0000000d' # 13 (int)\n '35302e30303030303030303030' # 50.0000000000 (numeric)\n '01' # Some\n '00000009' # 9 (int)\n '637265617465644174' # createdAt (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '6e756d626572' # number (string)\n '02' # Int64 Type Tag\n '0000000000003633' # 13875 (long)\n '01' # Some\n '0000000c' # 12 (int)\n '72617465506572526f756e64' # ratePerRound (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '52617465506572526f756e64' # RatePerRound (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000004' # 4 (int)\n '72617465' # rate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303032303032373236' # 0.0002002726 (numeric)\n '01' # Some\n '00000004' # 4 (int)\n '6c6f636b' # lock (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '457870697279' # Expiry (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '54696d654c6f636b' # TimeLock (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000007' # 7 (int)\n '686f6c64657273' # holders (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000009' # 9 (int)\n '657870697265734174' # expiresAt (string)\n '04' # Timestamp Type Tag\n '000640e139aaf3e9' # 1760185939588073 (long)\n '01' # Some\n '0000000a' # 10 (int)\n '6f7074436f6e74657874' # optContext (string)\n '09' # Optional Type Tag\n '01' # Some\n '07' # Text Type Tag\n '00000071' # 113 (int)\n '7472616e7366657220746f2027726176692d64656d6f2d70617274792d74786e2d30312d7461707065723a3a313232306561376162356137323366386136623230373865363137653663353863623765373865343939343764646332333965316139343161613536653662613038623427' # transfer to 'ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4' (string)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '4257bdf00f8ab5e61186d991cc16e2a395deb05fae585eb458eb3a4ad64a7eb9' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '01' # Some\n '533bb96d9d5d9ca0fa27e6c90618f40a53cf3c954177f38853fe0511527f800a' # node seed\n # Contract Id\n '00000021' # 33 (int)\n '0073dd0492654305ca61839e3c5b1343077a1891929b6ea8410247d6a360704c86' # 0073dd0492654305ca61839e3c5b1343077a1891929b6ea8410247d6a360704c86 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000003' # 3 (int)\n '64736f' # dso (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000005' # 5 (int)\n '6f776e6572' # owner (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '4578706972696e67416d6f756e74' # ExpiringAmount (string)\n '00000003' # 3 (int)\n '01' # Some\n '0000000d' # 13 (int)\n '696e697469616c416d6f756e74' # initialAmount (string)\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3935302e30303030303030303030' # 950.0000000000 (numeric)\n '01' # Some\n '00000009' # 9 (int)\n '637265617465644174' # createdAt (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '6e756d626572' # number (string)\n '02' # Int64 Type Tag\n '0000000000003633' # 13875 (long)\n '01' # Some\n '0000000c' # 12 (int)\n '72617465506572526f756e64' # ratePerRound (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '52617465506572526f756e64' # RatePerRound (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000004' # 4 (int)\n '72617465' # rate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303032303032373236' # 0.0002002726 (numeric)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '70a048cee04a91a8527a3cabbd81d12fd564ca463ffdd16b88d2b00f07554ec6' # (Hashed Inner Node)\n '6f8af2ae8e91f161bb32af9fe42540bc365c21a04277b65d3fa133c519f7b250' # (Hashed Inner Node)\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '01' # Some\n '3513e7f2b18cfaafc23fa8cd34e21fb16bce44215f27912b4dad87fe927db89b' # node seed\n # Contract Id\n '00000021' # 33 (int)\n '00c5bdee5b91467b6d06cbf34b4643be109838acc09cf9ac9ed429fafac96bb91f' # 00c5bdee5b91467b6d06cbf34b4643be109838acc09cf9ac9ed429fafac96bb91f (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000019' # 25 (int)\n '416d756c65745472616e73666572496e737472756374696f6e' # AmuletTransferInstruction (string)\n '00000001' # 1 (int)\n '00000019' # 25 (int)\n '416d756c65745472616e73666572496e737472756374696f6e' # AmuletTransferInstruction (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000019' # 25 (int)\n '416d756c65745472616e73666572496e737472756374696f6e' # AmuletTransferInstruction (string)\n '00000001' # 1 (int)\n '00000019' # 25 (int)\n '416d756c65745472616e73666572496e737472756374696f6e' # AmuletTransferInstruction (string)\n '00000002' # 2 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6c6f636b6564416d756c6574' # lockedAmulet (string)\n '08' # ContractId Type Tag\n '00000021' # 33 (int)\n '00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f' # 00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f (contractId)\n '01' # Some\n '00000008' # 8 (int)\n '7472616e73666572' # transfer (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35356261346465623061643436363263343136386233393835393733386130653931333838643235323238363438306337333331623366373161353137323831' # 55ba4deb0ad4662c4168b39859738a0e91388d252286480c7331b3f71a517281 (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000015' # 21 (int)\n '5472616e73666572496e737472756374696f6e5631' # TransferInstructionV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '5472616e73666572' # Transfer (string)\n '00000008' # 8 (int)\n '01' # Some\n '00000006' # 6 (int)\n '73656e646572' # sender (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000008' # 8 (int)\n '7265636569766572' # receiver (string)\n '06' # Party Type Tag\n '00000063' # 99 (int)\n '726176692d64656d6f2d70617274792d74786e2d30312d7461707065723a3a3132323065613761623561373233663861366232303738653631376536633538636237653738653439393437646463323339653161393431616135366536626130386234' # ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4 (string)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '03' # Numeric Type Tag\n '0000000d' # 13 (int)\n '35302e30303030303030303030' # 50.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '696e737472756d656e744964' # instrumentId (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '37313861306637376535303561386465323266313838626434633837666537343130313237346539643463623162666163376430396165633731353864333562' # 718a0f77e505a8de22f188bd4c87fe74101274e9d4cb1bfac7d09aec7158d35b (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '00000009' # 9 (int)\n '486f6c64696e675631' # HoldingV1 (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '496e737472756d656e744964' # InstrumentId (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000005' # 5 (int)\n '61646d696e' # admin (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000002' # 2 (int)\n '6964' # id (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '01' # Some\n '0000000b' # 11 (int)\n '7265717565737465644174' # requestedAt (string)\n '04' # Timestamp Type Tag\n '000640b8b675a7e9' # 1760011939588073 (long)\n '01' # Some\n '0000000d' # 13 (int)\n '657865637574654265666f7265' # executeBefore (string)\n '04' # Timestamp Type Tag\n '000640e139aaf3e9' # 1760185939588073 (long)\n '01' # Some\n '00000010' # 16 (int)\n '696e707574486f6c64696e6743696473' # inputHoldingCids (string)\n '0a' # List Type Tag\n '00000001' # 1 (int)\n '08' # ContractId Type Tag\n '00000021' # 33 (int)\n '00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f' # 00d7e27934379ac3d2859c7358e6a61c06ab7ff6d28dd0a3251c465388f69db61f (contractId)\n '01' # Some\n '00000004' # 4 (int)\n '6d657461' # meta (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '34646564366236363863623362363466376138386133303837346364343163373538323966356530363462336662626164663431656337653833363333353466' # 4ded6b668cb3b64f7a88a30874cd41c75829f5e064b3fbbadf41ec7e8363354f (string)\n '00000004' # 4 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000003' # 3 (int)\n '417069' # Api (string)\n '00000005' # 5 (int)\n '546f6b656e' # Token (string)\n '0000000a' # 10 (int)\n '4d657461646174615631' # MetadataV1 (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4d65746164617461' # Metadata (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '76616c756573' # values (string)\n '0b' # TextMap Type Tag\n '00000000' # 0 (int)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000003' # 3 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000063' # 99 (int)\n '726176692d64656d6f2d70617274792d74786e2d30312d7461707065723a3a3132323065613761623561373233663861366232303738653631376536633538636237653738653439393437646463323339653161393431616135366536626130386234' # ravi-demo-party-txn-01-tapper::1220ea7ab5a723f8a6b2078e617e6c58cb7e78e49947ddc239e1a941aa56e6ba08b4 (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n 'f8527f2a3e34d1a297e9aaae9b26b1d12f95d14ac3dbe4417a0b52dcd180e260' # (Hashed Inner Node)\n '86dd9ee402afe314837f4223426559f94fbfa1daef52aac4d956bbfe14d623e0' # (Hashed Inner Node)\n'1a39ca65487be7f30f1a7d52f3962ac26be28c82d5fa41973907adab7958967e' # Transaction\n '00000030' # Hash Purpose\n '01' # 01 (Metadata Encoding Version)\n # Act As Parties\n '00000001' # 1 (int)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Command Id\n '00000024' # 36 (int)\n '37616464343663322d636462362d346566392d613938652d316632313766326336303339' # 7add46c2-cdb6-4ef9-a98e-1f217f2c6039 (string)\n # Transaction UUID\n '00000024' # 36 (int)\n '64303464393732392d316536312d346339662d383663392d393132376633366562303663' # d04d9729-1e61-4c9f-86c9-9127f36eb06c (string)\n # Mediator Group\n '00000000' # 0 (int)\n # Synchronizer Id\n '00000053' # 83 (int)\n '676c6f62616c2d646f6d61696e3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Min Time Boundary\n '01' # Some\n '000640b8b675a7e9' # 1760011939588073 (long)\n # Max Time Boundary\n '01' # Some\n '000640e139aaf3e8' # 1760185939588072 (long)\n # Preparation Time\n '000640b9010792fc' # 1760013190664956 (long)\n # Disclosed Contracts\n '00000004' # 4 (int)\n # Created At\n '000640b892b261e9' # 1760011339588073 (long)\n # Create Contract\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '00' # None\n # Contract Id\n '00000045' # 69 (int)\n '003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a' # 003abfe538d0b517847c63dd87eb488e3c4ff690128ce68a828f4bebb789a6d614ca1112202a2842a6e04814b4add5be57f8fd5d7da65dbd5db6ae9285d76ebc0d9b31887a (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '4f70656e4d696e696e67526f756e64' # OpenMiningRound (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '0000000f' # 15 (int)\n '4f70656e4d696e696e67526f756e64' # OpenMiningRound (string)\n '00000009' # 9 (int)\n '01' # Some\n '00000003' # 3 (int)\n '64736f' # dso (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000005' # 5 (int)\n '726f756e64' # round (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '6e756d626572' # number (string)\n '02' # Int64 Type Tag\n '0000000000003633' # 13875 (long)\n '01' # Some\n '0000000b' # 11 (int)\n '616d756c65745072696365' # amuletPrice (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30393530303030303030' # 0.0950000000 (numeric)\n '01' # Some\n '00000007' # 7 (int)\n '6f70656e734174' # opensAt (string)\n '04' # Timestamp Type Tag\n '000640b8b675a7e9' # 1760011939588073 (long)\n '01' # Some\n '0000000e' # 14 (int)\n '746172676574436c6f7365734174' # targetClosesAt (string)\n '04' # Timestamp Type Tag\n '000640b8fdfc33e9' # 1760013139588073 (long)\n '01' # Some\n '0000000a' # 10 (int)\n '69737375696e67466f72' # issuingFor (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '0000079250aaf200' # 8325000000000 (long)\n '01' # Some\n '00000011' # 17 (int)\n '7472616e73666572436f6e666967557364' # transferConfigUsd (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000c' # 12 (int)\n '416d756c6574436f6e666967' # AmuletConfig (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '5472616e73666572436f6e666967' # TransferConfig (string)\n '00000008' # 8 (int)\n '01' # Some\n '00000009' # 9 (int)\n '637265617465466565' # createFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4669786564466565' # FixedFee (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000003' # 3 (int)\n '666565' # fee (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000a' # 10 (int)\n '686f6c64696e67466565' # holdingFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '52617465506572526f756e64' # RatePerRound (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000004' # 4 (int)\n '72617465' # rate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030313930323539' # 0.0000190259 (numeric)\n '01' # Some\n '0000000b' # 11 (int)\n '7472616e73666572466565' # transferFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '5374657070656452617465' # SteppedRate (string)\n '00000002' # 2 (int)\n '01' # Some\n '0000000b' # 11 (int)\n '696e697469616c52617465' # initialRate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000005' # 5 (int)\n '7374657073' # steps (string)\n '0a' # List Type Tag\n '00000003' # 3 (int)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3130302e30303030303030303030' # 100.0000000000 (numeric)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '03' # Numeric Type Tag\n '0000000f' # 15 (int)\n '313030302e30303030303030303030' # 1000.0000000000 (numeric)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '03' # Numeric Type Tag\n '00000012' # 18 (int)\n '313030303030302e30303030303030303030' # 1000000.0000000000 (numeric)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000d' # 13 (int)\n '6c6f636b486f6c646572466565' # lockHolderFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4669786564466565' # FixedFee (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000003' # 3 (int)\n '666565' # fee (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000001c' # 28 (int)\n '65787472614665617475726564417070526577617264416d6f756e74' # extraFeaturedAppRewardAmount (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '312e30303030303030303030' # 1.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '6d61784e756d496e70757473' # maxNumInputs (string)\n '02' # Int64 Type Tag\n '0000000000000064' # 100 (long)\n '01' # Some\n '0000000d' # 13 (int)\n '6d61784e756d4f757470757473' # maxNumOutputs (string)\n '02' # Int64 Type Tag\n '0000000000000064' # 100 (long)\n '01' # Some\n '00000011' # 17 (int)\n '6d61784e756d4c6f636b486f6c64657273' # maxNumLockHolders (string)\n '02' # Int64 Type Tag\n '0000000000000032' # 50 (long)\n '01' # Some\n '0000000e' # 14 (int)\n '69737375616e6365436f6e666967' # issuanceConfig (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '49737375616e6365' # Issuance (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '49737375616e6365436f6e666967' # IssuanceConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '00000014' # 20 (int)\n '616d756c6574546f497373756550657259656172' # amuletToIssuePerYear (string)\n '03' # Numeric Type Tag\n '00000016' # 22 (int)\n '34303030303030303030302e30303030303030303030' # 40000000000.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '76616c696461746f7252657761726450657263656e74616765' # validatorRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30353030303030303030' # 0.0500000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '61707052657761726450657263656e74616765' # appRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e31353030303030303030' # 0.1500000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f72526577617264436170' # validatorRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000014' # 20 (int)\n '6665617475726564417070526577617264436170' # featuredAppRewardCap (string)\n '03' # Numeric Type Tag\n '00000010' # 16 (int)\n '32303030302e30303030303030303030' # 20000.0000000000 (numeric)\n '01' # Some\n '00000016' # 22 (int)\n '756e6665617475726564417070526577617264436170' # unfeaturedAppRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36303030303030303030' # 0.6000000000 (numeric)\n '01' # Some\n '00000015' # 21 (int)\n '6f707456616c696461746f72466175636574436170' # optValidatorFaucetCap (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3537302e30303030303030303030' # 570.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '7469636b4475726174696f6e' # tickDuration (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '0000000023c34600' # 600000000 (long)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n 'f030b5f8f0be9b332faa0d6580d347f356668f096d91fbf1734580c490cd8aa6' # Disclosed Contract\n # Created At\n '000640b60a82645d' # 1760000464807005 (long)\n # Create Contract\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '00' # None\n # Contract Id\n '00000045' # 69 (int)\n '003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4' # 003b9030479a1ea50b420725c410b64c4609b64ab4996de707ef99a62cfa09f907ca111220a0bcf64e73bb3ae37d0ff8cfe2ed235466cbedcca65bf4bb83d1bd89f34339f4 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '416d756c657452756c6573' # AmuletRules (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000003' # 3 (int)\n '64736f' # dso (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '0000000e' # 14 (int)\n '636f6e6669675363686564756c65' # configSchedule (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '5363686564756c65' # Schedule (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '5363686564756c65' # Schedule (string)\n '00000002' # 2 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '696e697469616c56616c7565' # initialValue (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000c' # 12 (int)\n '416d756c6574436f6e666967' # AmuletConfig (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '416d756c6574436f6e666967' # AmuletConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '0000000e' # 14 (int)\n '7472616e73666572436f6e666967' # transferConfig (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000c' # 12 (int)\n '416d756c6574436f6e666967' # AmuletConfig (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '5472616e73666572436f6e666967' # TransferConfig (string)\n '00000008' # 8 (int)\n '01' # Some\n '00000009' # 9 (int)\n '637265617465466565' # createFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4669786564466565' # FixedFee (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000003' # 3 (int)\n '666565' # fee (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000a' # 10 (int)\n '686f6c64696e67466565' # holdingFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '52617465506572526f756e64' # RatePerRound (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000004' # 4 (int)\n '72617465' # rate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030313930323539' # 0.0000190259 (numeric)\n '01' # Some\n '0000000b' # 11 (int)\n '7472616e73666572466565' # transferFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000b' # 11 (int)\n '5374657070656452617465' # SteppedRate (string)\n '00000002' # 2 (int)\n '01' # Some\n '0000000b' # 11 (int)\n '696e697469616c52617465' # initialRate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '00000005' # 5 (int)\n '7374657073' # steps (string)\n '0a' # List Type Tag\n '00000003' # 3 (int)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3130302e30303030303030303030' # 100.0000000000 (numeric)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '03' # Numeric Type Tag\n '0000000f' # 15 (int)\n '313030302e30303030303030303030' # 1000.0000000000 (numeric)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '03' # Numeric Type Tag\n '00000012' # 18 (int)\n '313030303030302e30303030303030303030' # 1000000.0000000000 (numeric)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000000d' # 13 (int)\n '6c6f636b486f6c646572466565' # lockHolderFee (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '4669786564466565' # FixedFee (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000003' # 3 (int)\n '666565' # fee (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303030303030303030' # 0.0000000000 (numeric)\n '01' # Some\n '0000001c' # 28 (int)\n '65787472614665617475726564417070526577617264416d6f756e74' # extraFeaturedAppRewardAmount (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '312e30303030303030303030' # 1.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '6d61784e756d496e70757473' # maxNumInputs (string)\n '02' # Int64 Type Tag\n '0000000000000064' # 100 (long)\n '01' # Some\n '0000000d' # 13 (int)\n '6d61784e756d4f757470757473' # maxNumOutputs (string)\n '02' # Int64 Type Tag\n '0000000000000064' # 100 (long)\n '01' # Some\n '00000011' # 17 (int)\n '6d61784e756d4c6f636b486f6c64657273' # maxNumLockHolders (string)\n '02' # Int64 Type Tag\n '0000000000000032' # 50 (long)\n '01' # Some\n '0000000d' # 13 (int)\n '69737375616e63654375727665' # issuanceCurve (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '5363686564756c65' # Schedule (string)\n '00000001' # 1 (int)\n '00000008' # 8 (int)\n '5363686564756c65' # Schedule (string)\n '00000002' # 2 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '696e697469616c56616c7565' # initialValue (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '49737375616e6365' # Issuance (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '49737375616e6365436f6e666967' # IssuanceConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '00000014' # 20 (int)\n '616d756c6574546f497373756550657259656172' # amuletToIssuePerYear (string)\n '03' # Numeric Type Tag\n '00000016' # 22 (int)\n '34303030303030303030302e30303030303030303030' # 40000000000.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '76616c696461746f7252657761726450657263656e74616765' # validatorRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30353030303030303030' # 0.0500000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '61707052657761726450657263656e74616765' # appRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e31353030303030303030' # 0.1500000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f72526577617264436170' # validatorRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000014' # 20 (int)\n '6665617475726564417070526577617264436170' # featuredAppRewardCap (string)\n '03' # Numeric Type Tag\n '00000010' # 16 (int)\n '32303030302e30303030303030303030' # 20000.0000000000 (numeric)\n '01' # Some\n '00000016' # 22 (int)\n '756e6665617475726564417070526577617264436170' # unfeaturedAppRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36303030303030303030' # 0.6000000000 (numeric)\n '01' # Some\n '00000015' # 21 (int)\n '6f707456616c696461746f72466175636574436170' # optValidatorFaucetCap (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3537302e30303030303030303030' # 570.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '66757475726556616c756573' # futureValues (string)\n '0a' # List Type Tag\n '00000004' # 4 (int)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '00000e574609f000' # 15768000000000 (long)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '49737375616e6365' # Issuance (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '49737375616e6365436f6e666967' # IssuanceConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '00000014' # 20 (int)\n '616d756c6574546f497373756550657259656172' # amuletToIssuePerYear (string)\n '03' # Numeric Type Tag\n '00000016' # 22 (int)\n '32303030303030303030302e30303030303030303030' # 20000000000.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '76616c696461746f7252657761726450657263656e74616765' # validatorRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e31323030303030303030' # 0.1200000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '61707052657761726450657263656e74616765' # appRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e34303030303030303030' # 0.4000000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f72526577617264436170' # validatorRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000014' # 20 (int)\n '6665617475726564417070526577617264436170' # featuredAppRewardCap (string)\n '03' # Numeric Type Tag\n '00000010' # 16 (int)\n '32303030302e30303030303030303030' # 20000.0000000000 (numeric)\n '01' # Some\n '00000016' # 22 (int)\n '756e6665617475726564417070526577617264436170' # unfeaturedAppRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36303030303030303030' # 0.6000000000 (numeric)\n '01' # Some\n '00000015' # 21 (int)\n '6f707456616c696461746f72466175636574436170' # optValidatorFaucetCap (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3537302e30303030303030303030' # 570.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '00002b05d21dd000' # 47304000000000 (long)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '49737375616e6365' # Issuance (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '49737375616e6365436f6e666967' # IssuanceConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '00000014' # 20 (int)\n '616d756c6574546f497373756550657259656172' # amuletToIssuePerYear (string)\n '03' # Numeric Type Tag\n '00000016' # 22 (int)\n '31303030303030303030302e30303030303030303030' # 10000000000.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '76616c696461746f7252657761726450657263656e74616765' # validatorRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e31383030303030303030' # 0.1800000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '61707052657761726450657263656e74616765' # appRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36323030303030303030' # 0.6200000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f72526577617264436170' # validatorRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000014' # 20 (int)\n '6665617475726564417070526577617264436170' # featuredAppRewardCap (string)\n '03' # Numeric Type Tag\n '00000010' # 16 (int)\n '32303030302e30303030303030303030' # 20000.0000000000 (numeric)\n '01' # Some\n '00000016' # 22 (int)\n '756e6665617475726564417070526577617264436170' # unfeaturedAppRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36303030303030303030' # 0.6000000000 (numeric)\n '01' # Some\n '00000015' # 21 (int)\n '6f707456616c696461746f72466175636574436170' # optValidatorFaucetCap (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3537302e30303030303030303030' # 570.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '00008f68bc636000' # 157680000000000 (long)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '49737375616e6365' # Issuance (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '49737375616e6365436f6e666967' # IssuanceConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '00000014' # 20 (int)\n '616d756c6574546f497373756550657259656172' # amuletToIssuePerYear (string)\n '03' # Numeric Type Tag\n '00000015' # 21 (int)\n '353030303030303030302e30303030303030303030' # 5000000000.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '76616c696461746f7252657761726450657263656e74616765' # validatorRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32313030303030303030' # 0.2100000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '61707052657761726450657263656e74616765' # appRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36393030303030303030' # 0.6900000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f72526577617264436170' # validatorRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000014' # 20 (int)\n '6665617475726564417070526577617264436170' # featuredAppRewardCap (string)\n '03' # Numeric Type Tag\n '00000010' # 16 (int)\n '32303030302e30303030303030303030' # 20000.0000000000 (numeric)\n '01' # Some\n '00000016' # 22 (int)\n '756e6665617475726564417070526577617264436170' # unfeaturedAppRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36303030303030303030' # 0.6000000000 (numeric)\n '01' # Some\n '00000015' # 21 (int)\n '6f707456616c696461746f72466175636574436170' # optValidatorFaucetCap (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3537302e30303030303030303030' # 570.0000000000 (numeric)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '35616565396232316238653961346334393735623566346334313938653665366538343639646634396532303130383230653739326633393364623837306634' # 5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4 (string)\n '00000002' # 2 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '5475706c6532' # Tuple2 (string)\n '00000002' # 2 (int)\n '01' # Some\n '00000002' # 2 (int)\n '5f31' # _1 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '00011ed178c6c000' # 315360000000000 (long)\n '01' # Some\n '00000002' # 2 (int)\n '5f32' # _2 (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000008' # 8 (int)\n '49737375616e6365' # Issuance (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '49737375616e6365436f6e666967' # IssuanceConfig (string)\n '00000007' # 7 (int)\n '01' # Some\n '00000014' # 20 (int)\n '616d756c6574546f497373756550657259656172' # amuletToIssuePerYear (string)\n '03' # Numeric Type Tag\n '00000015' # 21 (int)\n '323530303030303030302e30303030303030303030' # 2500000000.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '76616c696461746f7252657761726450657263656e74616765' # validatorRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000013' # 19 (int)\n '61707052657761726450657263656e74616765' # appRewardPercentage (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e37353030303030303030' # 0.7500000000 (numeric)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f72526577617264436170' # validatorRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e32303030303030303030' # 0.2000000000 (numeric)\n '01' # Some\n '00000014' # 20 (int)\n '6665617475726564417070526577617264436170' # featuredAppRewardCap (string)\n '03' # Numeric Type Tag\n '00000010' # 16 (int)\n '32303030302e30303030303030303030' # 20000.0000000000 (numeric)\n '01' # Some\n '00000016' # 22 (int)\n '756e6665617475726564417070526577617264436170' # unfeaturedAppRewardCap (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e36303030303030303030' # 0.6000000000 (numeric)\n '01' # Some\n '00000015' # 21 (int)\n '6f707456616c696461746f72466175636574436170' # optValidatorFaucetCap (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000e' # 14 (int)\n '3537302e30303030303030303030' # 570.0000000000 (numeric)\n '01' # Some\n '00000019' # 25 (int)\n '646563656e7472616c697a656453796e6368726f6e697a6572' # decentralizedSynchronizer (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000019' # 25 (int)\n '446563656e7472616c697a656453796e6368726f6e697a6572' # DecentralizedSynchronizer (string)\n '00000001' # 1 (int)\n '00000025' # 37 (int)\n '416d756c6574446563656e7472616c697a656453796e6368726f6e697a6572436f6e666967' # AmuletDecentralizedSynchronizerConfig (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000015' # 21 (int)\n '726571756972656453796e6368726f6e697a657273' # requiredSynchronizers (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '63336262306335643034373939623366313162616437633363313032393633653131356366353364613365346166636263666439663036656264383262346666' # c3bb0c5d04799b3f11bad7c3c102963e115cf53da3e4afcbcfd9f06ebd82b4ff (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000003' # 3 (int)\n '536574' # Set (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000003' # 3 (int)\n '536574' # Set (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000003' # 3 (int)\n '6d6170' # map (string)\n '0f' # GenMap Type Tag\n '00000001' # 1 (int)\n '07' # Text Type Tag\n '00000053' # 83 (int)\n '676c6f62616c2d646f6d61696e3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00' # Unit Type Tag\n '01' # Some\n '00000012' # 18 (int)\n '61637469766553796e6368726f6e697a6572' # activeSynchronizer (string)\n '07' # Text Type Tag\n '00000053' # 83 (int)\n '676c6f62616c2d646f6d61696e3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000004' # 4 (int)\n '66656573' # fees (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000019' # 25 (int)\n '446563656e7472616c697a656453796e6368726f6e697a6572' # DecentralizedSynchronizer (string)\n '00000001' # 1 (int)\n '00000016' # 22 (int)\n '53796e6368726f6e697a657246656573436f6e666967' # SynchronizerFeesConfig (string)\n '00000004' # 4 (int)\n '01' # Some\n '00000015' # 21 (int)\n '6261736552617465547261666669634c696d697473' # baseRateTrafficLimits (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000019' # 25 (int)\n '446563656e7472616c697a656453796e6368726f6e697a6572' # DecentralizedSynchronizer (string)\n '00000001' # 1 (int)\n '00000015' # 21 (int)\n '4261736552617465547261666669634c696d697473' # BaseRateTrafficLimits (string)\n '00000002' # 2 (int)\n '01' # Some\n '0000000b' # 11 (int)\n '6275727374416d6f756e74' # burstAmount (string)\n '02' # Int64 Type Tag\n '0000000000061a80' # 400000 (long)\n '01' # Some\n '0000000b' # 11 (int)\n '627572737457696e646f77' # burstWindow (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '0000000047868c00' # 1200000000 (long)\n '01' # Some\n '00000011' # 17 (int)\n '6578747261547261666669635072696365' # extraTrafficPrice (string)\n '03' # Numeric Type Tag\n '0000000d' # 13 (int)\n '36302e30303030303030303030' # 60.0000000000 (numeric)\n '01' # Some\n '00000018' # 24 (int)\n '72656164567357726974655363616c696e67466163746f72' # readVsWriteScalingFactor (string)\n '02' # Int64 Type Tag\n '0000000000000004' # 4 (long)\n '01' # Some\n '0000000e' # 14 (int)\n '6d696e546f707570416d6f756e74' # minTopupAmount (string)\n '02' # Int64 Type Tag\n '0000000000030d40' # 200000 (long)\n '01' # Some\n '0000000c' # 12 (int)\n '7469636b4475726174696f6e' # tickDuration (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '62373064623833363965316334363164356337306631633836663532366132396539373736633635356536666663323536306639356230356363623862393436' # b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946 (string)\n '00000003' # 3 (int)\n '00000002' # 2 (int)\n '4441' # DA (string)\n '00000004' # 4 (int)\n '54696d65' # Time (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000007' # 7 (int)\n '52656c54696d65' # RelTime (string)\n '00000001' # 1 (int)\n '01' # Some\n '0000000c' # 12 (int)\n '6d6963726f7365636f6e6473' # microseconds (string)\n '02' # Int64 Type Tag\n '0000000023c34600' # 600000000 (long)\n '01' # Some\n '0000000d' # 13 (int)\n '7061636b616765436f6e666967' # packageConfig (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '0000000c' # 12 (int)\n '416d756c6574436f6e666967' # AmuletConfig (string)\n '00000001' # 1 (int)\n '0000000d' # 13 (int)\n '5061636b616765436f6e666967' # PackageConfig (string)\n '00000006' # 6 (int)\n '01' # Some\n '00000006' # 6 (int)\n '616d756c6574' # amulet (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '302e312e3134' # 0.1.14 (string)\n '01' # Some\n '00000011' # 17 (int)\n '616d756c65744e616d6553657276696365' # amuletNameService (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '302e312e3134' # 0.1.14 (string)\n '01' # Some\n '0000000d' # 13 (int)\n '64736f476f7665726e616e6365' # dsoGovernance (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '302e312e3139' # 0.1.19 (string)\n '01' # Some\n '00000012' # 18 (int)\n '76616c696461746f724c6966656379636c65' # validatorLifecycle (string)\n '07' # Text Type Tag\n '00000005' # 5 (int)\n '302e312e35' # 0.1.5 (string)\n '01' # Some\n '00000006' # 6 (int)\n '77616c6c6574' # wallet (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '302e312e3134' # 0.1.14 (string)\n '01' # Some\n '0000000e' # 14 (int)\n '77616c6c65745061796d656e7473' # walletPayments (string)\n '07' # Text Type Tag\n '00000006' # 6 (int)\n '302e312e3134' # 0.1.14 (string)\n '01' # Some\n '00000016' # 22 (int)\n '7472616e73666572507265617070726f76616c466565' # transferPreapprovalFee (string)\n '09' # Optional Type Tag\n '00' # None\n '01' # Some\n '0000001f' # 31 (int)\n '666561747572656441707041637469766974794d61726b6572416d6f756e74' # featuredAppActivityMarkerAmount (string)\n '09' # Optional Type Tag\n '01' # Some\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '312e30303030303030303030' # 1.0000000000 (numeric)\n '01' # Some\n '0000000c' # 12 (int)\n '66757475726556616c756573' # futureValues (string)\n '0a' # List Type Tag\n '00000000' # 0 (int)\n '01' # Some\n '00000008' # 8 (int)\n '69734465764e6574' # isDevNet (string)\n '01' # Bool Type Tag\n '01' # true (bool)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '95a49980ed74d6d8c5e20e11ed7e481bd2d33e5f1a10092b3a889eff85788200' # Disclosed Contract\n # Created At\n '000638f1fc1bd638' # 1751461828220472 (long)\n # Create Contract\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '00' # None\n # Contract Id\n '00000045' # 69 (int)\n '009f00e5bf00640118d849080aaf22bc963a8458d322585cebf1119cb7bf37a955ca11122065b775fb8a4199904ed32fa9277fd9c0e82bb82319a7151249df124182072381' # 009f00e5bf00640118d849080aaf22bc963a8458d322585cebf1119cb7bf37a955ca11122065b775fb8a4199904ed32fa9277fd9c0e82bb82319a7151249df124182072381 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '61356230353534393266623866303862326537626330666339346461366461353063333963326531643766323463643565613864623132666338376331333332' # a5b055492fb8f08b2e7bc0fc94da6da50c39c2e1d7f24cd5ea8db12fc87c1332 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000018' # 24 (int)\n '45787465726e616c5061727479416d756c657452756c6573' # ExternalPartyAmuletRules (string)\n '00000001' # 1 (int)\n '00000018' # 24 (int)\n '45787465726e616c5061727479416d756c657452756c6573' # ExternalPartyAmuletRules (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '61356230353534393266623866303862326537626330666339346461366461353063333963326531643766323463643565613864623132666338376331333332' # a5b055492fb8f08b2e7bc0fc94da6da50c39c2e1d7f24cd5ea8db12fc87c1332 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000018' # 24 (int)\n '45787465726e616c5061727479416d756c657452756c6573' # ExternalPartyAmuletRules (string)\n '00000001' # 1 (int)\n '00000018' # 24 (int)\n '45787465726e616c5061727479416d756c657452756c6573' # ExternalPartyAmuletRules (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000003' # 3 (int)\n '64736f' # dso (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Signatories\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n # Stakeholders\n '00000001' # 1 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '2ad8b93014f4d1b59b4467f534d5fce26f20195ab082ed096a25e6df3bbdcbb9' # Disclosed Contract\n # Created At\n '000640b7fb5b62cd' # 1760008800527053 (long)\n # Create Contract\n '01' # 01 (Node Encoding Version)\n # Create Node\n # Node Version\n '00000003' # 3 (int)\n '322e31' # 2.1 (string)\n '00' # Create Node Tag\n # Node Seed\n '00' # None\n # Contract Id\n '00000045' # 69 (int)\n '00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47' # 00bc02d2f5028d0010dbd73d3458dd9b8270ed0e8bfdfbe594771b8c5c9a7cc06bca1112203d3ab9aaa2f566f1ac4b7930eccc31f78ee928e335b59402618c00d85150ee47 (contractId)\n # Package Name\n '0000000d' # 13 (int)\n '73706c6963652d616d756c6574' # splice-amulet (string)\n # Template Id\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n # Arg\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000001' # 1 (int)\n '00000006' # 6 (int)\n '416d756c6574' # Amulet (string)\n '00000003' # 3 (int)\n '01' # Some\n '00000003' # 3 (int)\n '64736f' # dso (string)\n '06' # Party Type Tag\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '01' # Some\n '00000005' # 5 (int)\n '6f776e6572' # owner (string)\n '06' # Party Type Tag\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '01' # Some\n '00000006' # 6 (int)\n '616d6f756e74' # amount (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000e' # 14 (int)\n '4578706972696e67416d6f756e74' # ExpiringAmount (string)\n '00000003' # 3 (int)\n '01' # Some\n '0000000d' # 13 (int)\n '696e697469616c416d6f756e74' # initialAmount (string)\n '03' # Numeric Type Tag\n '0000000f' # 15 (int)\n '313030302e30303030303030303030' # 1000.0000000000 (numeric)\n '01' # Some\n '00000009' # 9 (int)\n '637265617465644174' # createdAt (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000005' # 5 (int)\n '5479706573' # Types (string)\n '00000001' # 1 (int)\n '00000005' # 5 (int)\n '526f756e64' # Round (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000006' # 6 (int)\n '6e756d626572' # number (string)\n '02' # Int64 Type Tag\n '000000000000362d' # 13869 (long)\n '01' # Some\n '0000000c' # 12 (int)\n '72617465506572526f756e64' # ratePerRound (string)\n '0c' # Record Type Tag\n '01' # Some\n '00000040' # 64 (int)\n '33636131333433616232366234353364333863386164623730646361356631656164383434306334326235396236386630373037383639353563626639656331' # 3ca1343ab26b453d38c8adb70dca5f1ead8440c42b59b68f070786955cbf9ec1 (string)\n '00000002' # 2 (int)\n '00000006' # 6 (int)\n '53706c696365' # Splice (string)\n '00000004' # 4 (int)\n '46656573' # Fees (string)\n '00000001' # 1 (int)\n '0000000c' # 12 (int)\n '52617465506572526f756e64' # RatePerRound (string)\n '00000001' # 1 (int)\n '01' # Some\n '00000004' # 4 (int)\n '72617465' # rate (string)\n '03' # Numeric Type Tag\n '0000000c' # 12 (int)\n '302e30303032303032373236' # 0.0002002726 (numeric)\n # Signatories\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n # Stakeholders\n '00000002' # 2 (int)\n '00000049' # 73 (int)\n '44534f3a3a3132323062653538633239653635646534306266323733626531646332623236366434336139613030326561356231383935356165656637616163383831626234373161' # DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a (string)\n '00000058' # 88 (int)\n '746573742d62616c612d70617274792d30313a3a3132323033383965363438303734633730386561643532376664396634333639316530343633653735396330396565346439393464363833623161613263633734643538' # test-bala-party-01::1220389e648074c708ead527fd9f43691e0463e759c09ee4d994d683b1aa2cc74d58 (string)\n '318cf3d700f90f834db9a17ebe39fdf6355a33ccb9ee79bcae0152282344e652' # Disclosed Contract\n'e30879e3cc0ff675f010e7f87332a983a51cef694827b50ee9554a898f7e32e7' # Metadata\n", +}; + export const WalletInitRequestData = { synchronizer: 'global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', partyHint: '1220b', publicKey: 'zs4J2IrVpfYNHN0bR7EHS0Fb3rETUyyu2L2QwxucPjg=', }; + +export const OneStepEnablement = { + synchronizer: 'global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', + partyId: 'ravi-test-party-1::12205b4e3537a95126d90604592344d8ad3c3ddccda4f79901954280ee19c576714d', + validatorPartyId: 'Bitgo-devnet-validator-1::1220a0a0f60b0e62b5d750c484b18c091dba23080c133d944614ba75a5858cba3045', + templateId: '#splice-wallet:Splice.Wallet.TransferPreapproval:TransferPreapprovalProposal', + expectedDsoId: 'DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', + commandId: '3935a06d-3b03-41be-99a5-95b2ecaabf7d', + synchronizerId: 'global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', +}; + +export const OneStepPreApprovalPrepareResponse = { + preparedTransaction: + 'CugHCgMyLjESATAauQcKATDCPrIHCq8HCgMyLjESQjAwNjEzZDQwNjc2YjU1M2M1MDdiZTljODUzY2Q4MWQyOTFlMTg2NDQ5OWRmM2Q1N2QyM2Y3ODIwZmNkNWI1ZjJmMhoNc3BsaWNlLXdhbGxldCKCAQpANjkwYzFkNDdiYWMwNmRiNDE5ZGIzNDRkNTlhN2EzMGM1M2ZhM2Y1ZDk2MTk0M2ZlMTc4MmNmYzZjNzg3OTRkOBIhU3BsaWNlLldhbGxldC5UcmFuc2ZlclByZWFwcHJvdmFsGhtUcmFuc2ZlclByZWFwcHJvdmFsUHJvcG9zYWwqvQNyugMKggEKQDY5MGMxZDQ3YmFjMDZkYjQxOWRiMzQ0ZDU5YTdhMzBjNTNmYTNmNWQ5NjE5NDNmZTE3ODJjZmM2Yzc4Nzk0ZDgSIVNwbGljZS5XYWxsZXQuVHJhbnNmZXJQcmVhcHByb3ZhbBobVHJhbnNmZXJQcmVhcHByb3ZhbFByb3Bvc2FsEmUKCHJlY2VpdmVyElk6V3JhdmktdGVzdC1wYXJ0eS0xOjoxMjIwNWI0ZTM1MzdhOTUxMjZkOTA2MDQ1OTIzNDRkOGFkM2MzZGRjY2RhNGY3OTkwMTk1NDI4MGVlMTljNTc2NzE0ZBJsCghwcm92aWRlchJgOl5CaXRnby1kZXZuZXQtdmFsaWRhdG9yLTE6OjEyMjBhMGEwZjYwYjBlNjJiNWQ3NTBjNDg0YjE4YzA5MWRiYTIzMDgwYzEzM2Q5NDQ2MTRiYTc1YTU4NThjYmEzMDQ1El4KC2V4cGVjdGVkRHNvEk9STQpLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhMldyYXZpLXRlc3QtcGFydHktMTo6MTIyMDViNGUzNTM3YTk1MTI2ZDkwNjA0NTkyMzQ0ZDhhZDNjM2RkY2NkYTRmNzk5MDE5NTQyODBlZTE5YzU3NjcxNGQ6XkJpdGdvLWRldm5ldC12YWxpZGF0b3ItMTo6MTIyMGEwYTBmNjBiMGU2MmI1ZDc1MGM0ODRiMThjMDkxZGJhMjMwODBjMTMzZDk0NDYxNGJhNzVhNTg1OGNiYTMwNDU6V3JhdmktdGVzdC1wYXJ0eS0xOjoxMjIwNWI0ZTM1MzdhOTUxMjZkOTA2MDQ1OTIzNDRkOGFkM2MzZGRjY2RhNGY3OTkwMTk1NDI4MGVlMTljNTc2NzE0ZCIiEiCQek+Zx9Y40PKa6qW8zpVWpF3ujaLLe9a0RB0rC2/gdhKFAhJ/CldyYXZpLXRlc3QtcGFydHktMTo6MTIyMDViNGUzNTM3YTk1MTI2ZDkwNjA0NTkyMzQ0ZDhhZDNjM2RkY2NkYTRmNzk5MDE5NTQyODBlZTE5YzU3NjcxNGQSJDM5MzVhMDZkLTNiMDMtNDFiZS05OWE1LTk1YjJlY2FhYmY3ZBpTZ2xvYmFsLWRvbWFpbjo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEqJGVmMGNmMzVkLTY5YzctNGU1Yi1hOGE5LWZiOGRlMjkyMGYyYTC964WA66CQAw==', + preparedTransactionHash: 'mc9/dvRWRtx4mFrbb3RDtThtGSOLlbyQjyS6d3LHAPg=', + hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2', + hashingDetails: null, +}; + +export const InvalidOneStepPreApprovalPrepareResponse = { + preparedTransaction: + 'CugHCgMyLjESATAauQcKATDCPrIHCq8HCgMyLjESQjAwNjEzZDQwNjc2YjU1M2M1MDdiZTljODUzY2Q4MWQyOTFlMTg2NDQ5OWRmM2Q1N2QyM2Y3ODIwZmNkNWI1ZjJmMhoNc3BsaWNlLXdhbGxldCKCAQpANjkwYzFkNDdiYWMwNmRiNDE5ZGIzNDRkNTlhN2EzMGM1M2ZhM2Y1ZDk2MTk0M2ZlMTc4MmNmYzZjNzg3OTRkOBIhU3BsaWNlLldhbGxldC5UcmFuc2ZlclByZWFwcHJvdmFsGhtUcmFuc2ZlclByZWFwcHJvdmFsUHJvcG9zYWwqvQNyugMKggEKQDY5MGMxZDQ3YmFjMDZkYjQxOWRiMzQ0ZDU5YTdhMzBjNTNmYTNmNWQ5NjE5NDNmZTE3ODJjZmM2Yzc4Nzk0ZDgSIVNwbGljZS5XYWxsZXQuVHJhbnNmZXJQcmVhcHByb3ZhbBobVHJhbnNmZXJQcmVhcHByb3ZhbFByb3Bvc2FsEmUKCHJlY2VpdmVyElk6V3JhdmktdGVzdC1wYXJ0eS0xOjoxMjIwNWI0ZTM1MzdhOTUxMjZkOTA2MDQ1OTIzNDRkOGFkM2MzZGRjY2RhNGY3OTkwMTk1NDI4MGVlMTljNTc2NzE0ZBJsCghwcm92aWRlchJgOl5CaXRnby1kZXZuZXQtdmFsaWRhdG9yLTE6OjEyMjBhMGEwZjYwYjBlNjJiNWQ3NTBjNDg0YjE4YzA5MWRiYTIzMDgwYzEzM2Q5NDQ2MTRiYTc1YTU4NThjYmEzMDQ1El4KC2V4cGVjdGVkRHNvEk9STQpLOklEU086OjEyMjBiZTU4YzI5ZTY1ZGU0MGJmMjczYmUxZGMyYjI2NmQ0M2E5YTAwMmVhNWIxODk1NWFlZWY3YWFjODgxYmI0NzFhMldyYXZpLXRlc3QtcGFydHktMTo6MTIyMDViNGUzNTM3YTk1MTI2ZDkwNjA0NTkyMzQ0ZDhhZDNjM2RkY2NkYTRmNzk5MDE5NTQyODBlZTE5YzU3NjcxNGQ6XkJpdGdvLWRldm5ldC12YWxpZGF0b3ItMTo6MTIyMGEwYTBmNjBiMGU2MmI1ZDc1MGM0ODRiMThjMDkxZGJhMjMwODBjMTMzZDk0NDYxNGJhNzVhNTg1OGNiYTMwNDU6V3JhdmktdGVzdC1wYXJ0eS0xOjoxMjIwNWI0ZTM1MzdhOTUxMjZkOTA2MDQ1OTIzNDRkOGFkM2MzZGRjY2RhNGY3OTkwMTk1NDI4MGVlMTljNTc2NzE0ZCIiEiCQek+Zx9Y40PKa6qW8zpVWpF3ujaLLe9a0RB0rC2/gdhKFAhJ/CldyYXZpLXRlc3QtcGFydHktMTo6MTIyMDViNGUzNTM3YTk1MTI2ZDkwNjA0NTkyMzQ0ZDhhZDNjM2RkY2NkYTRmNzk5MDE5NTQyODBlZTE5YzU3NjcxNGQSJDM5MzVhMDZkLTNiMDMtNDFiZS05OWE1LTk1YjJlY2FhYmY3ZBpTZ2xvYmFsLWRvbWFpbjo6MTIyMGJlNThjMjllNjVkZTQwYmYyNzNiZTFkYzJiMjY2ZDQzYTlhMDAyZWE1YjE4OTU1YWVlZjdhYWM4ODFiYjQ3MWEqJGVmMGNmMzVkLTY5YzctNGU1Yi1hOGE5LWZiOGRlMjkyMGYyYTC964WA66CQAw==', + // the hash is invalid here + preparedTransactionHash: 'mc9/dvRWRtx4mFrbb3RDtThtGSOLlbyQjyS6d3LHAPe=', + hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2', + hashingDetails: null, +}; diff --git a/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts b/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts new file mode 100644 index 0000000000..9a3404804d --- /dev/null +++ b/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts @@ -0,0 +1,88 @@ +import assert from 'assert'; +import should from 'should'; + +import { coins } from '@bitgo/statics'; + +import { Transaction } from '../../../../src'; +import { OneStepEnablementRequest } from '../../../../src/lib/iface'; +import { OneStepPreApprovalBuilder } from '../../../../src/lib/oneStepPreApprovalBuilder'; + +import { + InvalidOneStepPreApprovalPrepareResponse, + OneStepEnablement, + OneStepPreApprovalPrepareResponse, +} from '../../../resources'; + +describe('Wallet Pre-approval Enablement Builder', () => { + it('should get the wallet init request object', function () { + const txBuilder = new OneStepPreApprovalBuilder(coins.get('tcanton')); + const oneStepEnablementTx = new Transaction(coins.get('tcanton')); + txBuilder.initBuilder(oneStepEnablementTx); + const { synchronizer, commandId, partyId, validatorPartyId, expectedDsoId, templateId, synchronizerId } = + OneStepEnablement; + txBuilder + .commandId(commandId) + .templateId(templateId) + .expectedDso(expectedDsoId) + .templateId(templateId) + .providerPartyId(validatorPartyId) + .receiverPartyId(partyId) + .synchronizerId(synchronizerId); + const requestObj: OneStepEnablementRequest = txBuilder.toRequestObject(); + should.exist(requestObj); + assert.equal(requestObj.synchronizerId, synchronizer); + assert.equal(requestObj.commandId, commandId); + assert.equal(requestObj.commands.length, 1); + const command = requestObj.commands[0]; + should.exist(command); + const createCommand = command.CreateCommand; + should.exist(createCommand); + assert.equal(createCommand.templateId, templateId); + const createArguments = createCommand.createArguments; + should.exist(createArguments); + assert.equal(createArguments.expectedDso, expectedDsoId); + assert.equal(createArguments.provider, validatorPartyId); + assert.equal(createArguments.receiver, partyId); + }); + + it('should validate raw transaction', function () { + const txBuilder = new OneStepPreApprovalBuilder(coins.get('tcanton')); + const oneStepEnablementTx = new Transaction(coins.get('tcanton')); + txBuilder.initBuilder(oneStepEnablementTx); + txBuilder.setTransaction(OneStepPreApprovalPrepareResponse); + txBuilder.validateRawTransaction(OneStepPreApprovalPrepareResponse.preparedTransaction); + }); + + it('should validate the transaction', function () { + const txBuilder = new OneStepPreApprovalBuilder(coins.get('tcanton')); + const oneStepEnablementTx = new Transaction(coins.get('tcanton')); + oneStepEnablementTx.prepareCommand = OneStepPreApprovalPrepareResponse; + txBuilder.initBuilder(oneStepEnablementTx); + txBuilder.setTransaction(OneStepPreApprovalPrepareResponse); + txBuilder.validateTransaction(oneStepEnablementTx); + }); + + it('should throw error in validating raw transaction', function () { + const txBuilder = new OneStepPreApprovalBuilder(coins.get('tcanton')); + const oneStepEnablementTx = new Transaction(coins.get('tcanton')); + txBuilder.initBuilder(oneStepEnablementTx); + txBuilder.setTransaction(InvalidOneStepPreApprovalPrepareResponse); + try { + txBuilder.validateRawTransaction(InvalidOneStepPreApprovalPrepareResponse.preparedTransaction); + } catch (e) { + assert.equal(e.message, 'invalid raw transaction, hash not matching'); + } + }); + + it('should throw error in validating raw transaction', function () { + const txBuilder = new OneStepPreApprovalBuilder(coins.get('tcanton')); + const oneStepEnablementTx = new Transaction(coins.get('tcanton')); + txBuilder.initBuilder(oneStepEnablementTx); + oneStepEnablementTx.prepareCommand = InvalidOneStepPreApprovalPrepareResponse; + try { + txBuilder.validateTransaction(oneStepEnablementTx); + } catch (e) { + assert.equal(e.message, 'invalid transaction'); + } + }); +}); diff --git a/modules/sdk-coin-canton/test/unit/utils.ts b/modules/sdk-coin-canton/test/unit/utils.ts index 72f48667c4..57ce0c0a48 100644 --- a/modules/sdk-coin-canton/test/unit/utils.ts +++ b/modules/sdk-coin-canton/test/unit/utils.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import should from 'should'; import utils from '../../src/lib/utils'; -import { GenerateTopologyResponse, PreparedTransactionRawData } from '../resources'; +import { GenerateTopologyResponse, PreparedTransactionRawData, PrepareSubmissionResponse } from '../resources'; describe('Canton Util', function () { describe('Raw transaction parser', function () { @@ -21,4 +21,14 @@ describe('Canton Util', function () { assert.strictEqual(computedHash, GenerateTopologyResponse.multiHash); }); }); + + describe('Prepare submission response validation', function () { + it('should locally generate and validate the hash for prepare submission response', async function () { + const computedHash = await utils.computeHashFromPrepareSubmissionResponse( + PrepareSubmissionResponse.preparedTransaction + ); + should.exist(computedHash); + assert.strictEqual(computedHash, PrepareSubmissionResponse.preparedTransactionHash); + }); + }); }); diff --git a/modules/sdk-core/src/account-lib/baseCoin/enum.ts b/modules/sdk-core/src/account-lib/baseCoin/enum.ts index 80e8cfd104..f5cb498b58 100644 --- a/modules/sdk-core/src/account-lib/baseCoin/enum.ts +++ b/modules/sdk-core/src/account-lib/baseCoin/enum.ts @@ -87,6 +87,8 @@ export enum TransactionType { FlushERC721, // Flush ERC1155 tokens from a forwarder address to base address FlushERC1155, + // Set up 1-step pre-approval for canton + OneStepPreApproval, // trx FREEZE, From d1dac44e2e36451d352bfea386710d3f2c363b9c Mon Sep 17 00:00:00 2001 From: Noel Hawat Date: Thu, 25 Sep 2025 12:24:53 -0400 Subject: [PATCH 06/34] fix(sdk-coin-avaxp): update utxo selection to also check STAKEABLE_LOCK_OUT noticed that some utxo will be of type 22 with locktim 0 those are eligible to be used for transactions TICKET: SC-3257 --- .../src/lib/atomicTransactionBuilder.ts | 7 ++-- .../src/lib/delegatorTxBuilder.ts | 7 ++-- modules/sdk-coin-avaxp/src/lib/iface.ts | 8 ++++- .../lib/permissionlessValidatorTxBuilder.ts | 33 ++++--------------- .../src/lib/transactionBuilder.ts | 9 ----- modules/sdk-coin-avaxp/src/lib/utxoEngine.ts | 9 +++-- .../sdk-coin-avaxp/test/resources/avaxp.ts | 2 +- 7 files changed, 32 insertions(+), 43 deletions(-) diff --git a/modules/sdk-coin-avaxp/src/lib/atomicTransactionBuilder.ts b/modules/sdk-coin-avaxp/src/lib/atomicTransactionBuilder.ts index 5ea6f78b1b..9a88e82f4a 100644 --- a/modules/sdk-coin-avaxp/src/lib/atomicTransactionBuilder.ts +++ b/modules/sdk-coin-avaxp/src/lib/atomicTransactionBuilder.ts @@ -11,7 +11,7 @@ import { } from 'avalanche/dist/apis/platformvm'; import { Credential } from 'avalanche/dist/common'; import { BuildTransactionError } from '@bitgo/sdk-core'; -import { SECP256K1_Transfer_Output } from './iface'; +import { SECP256K1_STAKEABLE_LOCK_OUT, SECP256K1_Transfer_Output } from './iface'; /** * Cross-chain transactions (export and import) are atomic operations. @@ -104,7 +104,10 @@ export abstract class AtomicTransactionBuilder extends DeprecatedTransactionBuil }); this.transaction._utxos.forEach((utxo, i) => { - if (utxo.outputID === SECP256K1_Transfer_Output) { + if ( + utxo.outputID === SECP256K1_Transfer_Output || + (utxo.outputID === SECP256K1_STAKEABLE_LOCK_OUT && utxo.locktime === '0') + ) { const txidBuf = utils.cb58Decode(utxo.txid); const amt: BN = new BN(utxo.amount); const outputidx = utils.outputidxNumberToBuffer(utxo.outputidx); diff --git a/modules/sdk-coin-avaxp/src/lib/delegatorTxBuilder.ts b/modules/sdk-coin-avaxp/src/lib/delegatorTxBuilder.ts index c84531ae11..7c13aea74f 100644 --- a/modules/sdk-coin-avaxp/src/lib/delegatorTxBuilder.ts +++ b/modules/sdk-coin-avaxp/src/lib/delegatorTxBuilder.ts @@ -16,7 +16,7 @@ import { UnsignedTx, } from 'avalanche/dist/apis/platformvm'; import { BinTools, BN } from 'avalanche'; -import { SECP256K1_Transfer_Output, DeprecatedTx, DeprecatedBaseTx } from './iface'; +import { SECP256K1_Transfer_Output, DeprecatedTx, DeprecatedBaseTx, SECP256K1_STAKEABLE_LOCK_OUT } from './iface'; import utils from './utils'; import { Credential } from 'avalanche/dist/common'; import { deprecatedRecoverUtxos } from './utxoEngine'; @@ -309,7 +309,10 @@ export class DelegatorTxBuilder extends DeprecatedTransactionBuilder { const buildOutputs = this.transaction._utxos[0].addresses.length !== 0; this.transaction._utxos.forEach((utxo, i) => { - if (utxo.outputID === SECP256K1_Transfer_Output) { + if ( + utxo.outputID === SECP256K1_Transfer_Output || + (utxo.outputID === SECP256K1_STAKEABLE_LOCK_OUT && utxo.locktime === '0') + ) { const txidBuf = utils.cb58Decode(utxo.txid); const amt: BN = new BN(utxo.amount); const outputidx = utils.outputidxNumberToBuffer(utxo.outputidx); diff --git a/modules/sdk-coin-avaxp/src/lib/iface.ts b/modules/sdk-coin-avaxp/src/lib/iface.ts index 2759559dc9..8bac4adf66 100644 --- a/modules/sdk-coin-avaxp/src/lib/iface.ts +++ b/modules/sdk-coin-avaxp/src/lib/iface.ts @@ -50,6 +50,7 @@ export interface TxData { */ export type DecodedUtxoObj = { outputID: number; + locktime?: string; amount: string; txid: string; outputidx: string; @@ -61,9 +62,14 @@ export type DecodedUtxoObj = { /** * TypeId value for SECP256K1 Transfer Output * - * {@link https://docs.avax.network/specs/platform-transaction-serialization#secp256k1-transfer-output-example } + * {@link https://build.avax.network/docs/api-reference/p-chain/txn-format#secp256k1-transfer-output } */ export const SECP256K1_Transfer_Output = 7; +/** + * TypeId value for Stakeable Lock Output + * {@link https://build.avax.network/docs/api-reference/p-chain/txn-format#stakeablelockout } + */ +export const SECP256K1_STAKEABLE_LOCK_OUT = 22; export const ADDRESS_SEPARATOR = '~'; export const INPUT_SEPARATOR = ':'; diff --git a/modules/sdk-coin-avaxp/src/lib/permissionlessValidatorTxBuilder.ts b/modules/sdk-coin-avaxp/src/lib/permissionlessValidatorTxBuilder.ts index a0c16fb00c..ec2ba76bb0 100644 --- a/modules/sdk-coin-avaxp/src/lib/permissionlessValidatorTxBuilder.ts +++ b/modules/sdk-coin-avaxp/src/lib/permissionlessValidatorTxBuilder.ts @@ -30,7 +30,7 @@ import { import { BaseCoin as CoinConfig } from '@bitgo/statics'; import { Buffer as BufferAvax } from 'avalanche'; import BigNumber from 'bignumber.js'; -import { DecodedUtxoObj, SECP256K1_Transfer_Output, Tx } from './iface'; +import { DecodedUtxoObj, SECP256K1_STAKEABLE_LOCK_OUT, SECP256K1_Transfer_Output, Tx } from './iface'; import { KeyPair } from './keyPair'; import { Transaction } from './transaction'; import { TransactionBuilder } from './transactionBuilder'; @@ -291,9 +291,6 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { this.transaction._stakeAmount = permissionlessValidatorTx.stake[0].output.amount(); this.stakeAmount(this.transaction._stakeAmount); this.transaction._utxos = recoverUtxos(permissionlessValidatorTx.getInputs()); - // TODO(CR-1073): remove log - console.log('utxos: ', this.transaction._utxos); - console.log('fromAddresses: ', this.transaction.fromAddresses); return this; } @@ -338,8 +335,6 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { const bitgoAddresses = this.transaction._fromAddresses.map((b) => avaxUtils.format(this.transaction._network.alias, this.transaction._network.hrp, b) ); - // TODO(CR-1073): remove log - console.log(`bitgoAddress: ${bitgoAddresses}`); // if we are in OVC, none of the utxos will have addresses since they come from // deserialized inputs (which don't have addresses), not the IMS @@ -371,12 +366,12 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { utxo.addresses.forEach((a) => { bitgoIndexToOnChainIndex.set(bitgoAddresses.indexOf(a), utxo.addresses.indexOf(a)); }); - // TODO(CR-1073): remove log - console.log(`utxo.addresses: ${utxo.addresses}`); - console.log(`bitgoIndexToOnChainIndex: ${Array.from(bitgoIndexToOnChainIndex)}`); // in OVC, output.addressesIndex is defined correctly from the previous iteration - if (utxo.outputID === SECP256K1_Transfer_Output) { + if ( + utxo.outputID === SECP256K1_Transfer_Output || + (utxo.outputID === SECP256K1_STAKEABLE_LOCK_OUT && utxo.locktime === '0') + ) { const utxoAmount = BigInt(utxo.amount); // either user (0) or recovery (2) // On regular mode: [user, bitgo] (i.e. [0, 1]) @@ -400,8 +395,6 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { new BigIntPr(utxoAmount), new Input([...addressesIndex].sort().map((num) => new Int(num))) ); - // TODO(CR-1073): remove log - console.log(`using addressesIndex sorted: ${[...addressesIndex].sort()}`); const input = new avaxSerial.TransferableInput(utxoId, assetId, transferInputs); utxos.push(new Utxo(utxoId, assetId, transferInputs)); @@ -413,12 +406,7 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { // For the user/backup signature we store the address that matches the key // if bitgo address comes before < user/backup address - // TODO(CR-1073): remove log - console.log(`bitgo index on chain: ${utxo.addressesIndex[bitgoIndex]}`); - console.log(`user Or Backup Index: ${utxo.addressesIndex[userOrBackupIndex]}`); if (utxo.addressesIndex[bitgoIndex] < utxo.addressesIndex[userOrBackupIndex]) { - // TODO(CR-1073): remove log - console.log(`user or backup credentials after bitgo`); credentials.push( new Credential([ utils.createNewSig(BufferAvax.from('').toString('hex')), @@ -428,8 +416,6 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { ]) ); } else { - // TODO(CR-1073): remove log - console.log(`user or backup credentials before bitgo`); credentials.push( new Credential([ utils.createNewSig( @@ -440,7 +426,6 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { ); } } else { - // TODO(CR-1073): verify this else case for OVC credentials.push( new Credential( addressesIndex.map((i) => @@ -449,9 +434,6 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { ) ); } - } else { - // TODO(CR-1073): remove log - console.log(`reusing credentials from transaction`); } } }); @@ -542,9 +524,8 @@ export class PermissionlessValidatorTxBuilder extends TransactionBuilder { .map((a) => Address.fromBytes(a)[0]) ); - // TODO(CR-1073): check this value - // Shares 10,000 times percentage of reward taken from delegators - // https://docs.avax.network/reference/avalanchego/p-chain/txn-format#unsigned-add-validator-tx + // Shares 10,000 times percentage of reward taken from delegators + // https://docs.avax.network/reference/avalanchego/p-chain/txn-format#unsigned-add-validator-tx const shares = new Int(1e4 * 2); const addressMaps = [...this.transaction._fromAddresses] diff --git a/modules/sdk-coin-avaxp/src/lib/transactionBuilder.ts b/modules/sdk-coin-avaxp/src/lib/transactionBuilder.ts index 4da12bc1fa..6a209399fe 100644 --- a/modules/sdk-coin-avaxp/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-avaxp/src/lib/transactionBuilder.ts @@ -131,21 +131,12 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { return this; } - // TODO(CR-1073): - // Implement: - // buildImplementation - // signImplementation - // get transaction - // set transaction - // validateRawTransaction - /** @inheritdoc */ protected fromImplementation(rawTransaction: string): Transaction { const [tx] = pvmSerial.AddPermissionlessValidatorTx.fromBytes( Buffer.from(rawTransaction, 'hex'), avmSerial.getAVMManager().getDefaultCodec() ); - // TODO(CR-1073): check if initBuilder can only use UnsignedTx and pvmSerial.BaseTx is not required this.initBuilder(tx); return this._transaction; } diff --git a/modules/sdk-coin-avaxp/src/lib/utxoEngine.ts b/modules/sdk-coin-avaxp/src/lib/utxoEngine.ts index 7f7579c741..fb274e6788 100644 --- a/modules/sdk-coin-avaxp/src/lib/utxoEngine.ts +++ b/modules/sdk-coin-avaxp/src/lib/utxoEngine.ts @@ -1,4 +1,4 @@ -import { DecodedUtxoObj, SECP256K1_Transfer_Output } from './iface'; +import { DecodedUtxoObj, SECP256K1_STAKEABLE_LOCK_OUT, SECP256K1_Transfer_Output } from './iface'; import { BN, Buffer as BufferAvax } from 'avalanche'; import { Signature } from 'avalanche/dist/common'; import utils from './utils'; @@ -98,7 +98,12 @@ export function utxoToInput( let currentTotal: BN = new BN(0); const inputs = utxos - .filter((utxo) => utxo && utxo.outputID === SECP256K1_Transfer_Output) + .filter( + (utxo) => + utxo && + (utxo.outputID === SECP256K1_Transfer_Output || + (utxo.outputID === SECP256K1_STAKEABLE_LOCK_OUT && utxo.locktime === '0')) + ) .map((utxo) => { // validate the utxos const utxoAddresses: BufferAvax[] = utxo.addresses.map((a) => utils.parseAddress(a)); diff --git a/modules/sdk-coin-avaxp/test/resources/avaxp.ts b/modules/sdk-coin-avaxp/test/resources/avaxp.ts index a1235a86fe..b74b96b28a 100644 --- a/modules/sdk-coin-avaxp/test/resources/avaxp.ts +++ b/modules/sdk-coin-avaxp/test/resources/avaxp.ts @@ -622,7 +622,7 @@ export const BUILD_AND_SIGN_ADD_PERMISSIONLESS_VALIDATOR_SAMPLE = { '0xa94d6182edbd953516b262f17565a65d98f5741549cd70d2423abff750bb4b8d982d482376b189142ff8aa4705615fee14be6174610860e9c003aa4aeaa613b1732abf3cd0c9c42fa5856345644068c0d1f9fa1d9af32e20b14fca02983260bc', utxos: [ { - outputID: 7, + outputID: 22, amount: '98000000', txid: 's92SjoZQemgG97HocX9GgyFy6ZKmapgcgqQ3y5J2uwP3qWBUy', threshold: 2, From 34dacbcc1a2e4619503f5a93410b611f55bbc847 Mon Sep 17 00:00:00 2001 From: Ranjna Ganesh Ram Date: Mon, 13 Oct 2025 21:39:48 +0530 Subject: [PATCH 07/34] feat(sdk-coin-ada): fix ada build signature handling Ticket: WIN-7548 --- modules/sdk-coin-ada/src/lib/transactionBuilder.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/sdk-coin-ada/src/lib/transactionBuilder.ts b/modules/sdk-coin-ada/src/lib/transactionBuilder.ts index f093b17522..0afefe52ad 100644 --- a/modules/sdk-coin-ada/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-ada/src/lib/transactionBuilder.ts @@ -414,8 +414,12 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { const vkey = CardanoWasm.Vkey.new(CardanoWasm.PublicKey.from_bytes(Buffer.from(signature.publicKey.pub, 'hex'))); const ed255Sig = CardanoWasm.Ed25519Signature.from_bytes(signature.signature); vkeyWitnesses.add(CardanoWasm.Vkeywitness.new(vkey, ed255Sig)); + // Restoring the behaviour from the original buildImplementation + if (refreshSignatures) { + this._transaction.signature.push(signature.signature.toString('hex')); + } }); - if (vkeyWitnesses.len() === 0) { + if (!refreshSignatures && vkeyWitnesses.len() === 0) { const prv = CardanoWasm.PrivateKey.generate_ed25519(); const vkeyWitness = CardanoWasm.make_vkey_witness(txHash, prv); vkeyWitnesses.add(vkeyWitness); From f098b39ea0b921aacc36328047db1b4288e13fe4 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 13 Oct 2025 12:03:23 -0400 Subject: [PATCH 08/34] fix(utxo-lib): add tests for both PSBT and PSBT-lite formats Refactor tests to run for both standard PSBT and PSBT-lite formats, ensuring our implementation works with both input formats. The changes allow testing with both witnessUtxo and nonWitnessUtxo depending on the format. Issue: BTC-000 Co-authored-by: llm-git --- modules/utxo-lib/test/bitgo/psbt/Psbt.ts | 96 ++++++++++++++---------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/modules/utxo-lib/test/bitgo/psbt/Psbt.ts b/modules/utxo-lib/test/bitgo/psbt/Psbt.ts index 6156142e0b..5254e0b15f 100644 --- a/modules/utxo-lib/test/bitgo/psbt/Psbt.ts +++ b/modules/utxo-lib/test/bitgo/psbt/Psbt.ts @@ -745,47 +745,67 @@ describe('Update incomplete psbt', function () { signAllInputs(psbt); }); - const componentsOnEachInputScriptType = { - p2sh: ['nonWitnessUtxo', 'redeemScript', 'bip32Derivation'], - p2shP2wsh: ['witnessUtxo', 'bip32Derivation', 'redeemScript', 'witnessScript'], - p2wsh: ['witnessUtxo', 'witnessScript', 'bip32Derivation'], - p2tr: ['witnessUtxo', 'tapLeafScript', 'tapBip32Derivation'], - p2trMusig2: ['witnessUtxo', 'tapBip32Derivation', 'tapInternalKey', 'tapMerkleRoot', 'unknownKeyVals'], - p2shP2pk: ['redeemScript', 'nonWitnessUtxo'], - }; - - const p2trComponents = ['tapTree', 'tapInternalKey', 'tapBip32Derivation']; - const componentsOnEachOutputScriptType = { - p2sh: ['bip32Derivation', 'redeemScript'], - p2shP2wsh: ['bip32Derivation', 'witnessScript', 'redeemScript'], - p2wsh: ['bip32Derivation', 'witnessScript'], - p2tr: p2trComponents, - p2trMusig2: p2trComponents, - p2shP2pk: [], - }; - scriptTypes.forEach((scriptType, i) => { - componentsOnEachInputScriptType[scriptType].forEach((inputComponent) => { - it(`[${scriptType}] missing ${inputComponent} on input should succeed in fully signing unsigned psbt after update`, function () { - const psbt = removeFromPsbt(psbtHex, network, { input: { index: i, fieldToRemove: inputComponent } }); - const unspent = unspents[i]; - if (isWalletUnspent(unspent)) { - updateWalletUnspentForPsbt(psbt, i, unspent, rootWalletKeys, signer, cosigner); - } else { - const { redeemScript } = createOutputScriptP2shP2pk(replayProtectionKeyPair.publicKey); - assert.ok(redeemScript); - updateReplayProtectionUnspentToPsbt(psbt, i, unspent, redeemScript); - } - signAllInputs(psbt); - }); - }); + function runTest(txFormat: 'psbt' | 'psbt-lite') { + describe(`txFormat=${txFormat}`, function () { + const componentsOnEachInputScriptType = { + p2sh: [txFormat === 'psbt' ? 'nonWitnessUtxo' : 'witnessUtxo', 'redeemScript', 'bip32Derivation'], + p2shP2wsh: ['witnessUtxo', 'bip32Derivation', 'redeemScript', 'witnessScript'], + p2wsh: ['witnessUtxo', 'witnessScript', 'bip32Derivation'], + p2tr: ['witnessUtxo', 'tapLeafScript', 'tapBip32Derivation'], + p2trMusig2: ['witnessUtxo', 'tapBip32Derivation', 'tapInternalKey', 'tapMerkleRoot', 'unknownKeyVals'], + p2shP2pk: ['redeemScript', txFormat === 'psbt' ? 'nonWitnessUtxo' : 'witnessUtxo'], + }; - componentsOnEachOutputScriptType[scriptType].forEach((outputComponent) => { - it(`[${scriptType}] missing ${outputComponent} on output should produce same hex as fully hydrated after update`, function () { - const psbt = removeFromPsbt(psbtHex, network, { output: { index: i, fieldToRemove: outputComponent } }); - updateWalletOutputForPsbt(psbt, rootWalletKeys, i, outputs[i].chain, outputs[i].index); - assert.strictEqual(psbt.toHex(), psbtHex); + const p2trComponents = ['tapTree', 'tapInternalKey', 'tapBip32Derivation']; + const componentsOnEachOutputScriptType = { + p2sh: ['bip32Derivation', 'redeemScript'], + p2shP2wsh: ['bip32Derivation', 'witnessScript', 'redeemScript'], + p2wsh: ['bip32Derivation', 'witnessScript'], + p2tr: p2trComponents, + p2trMusig2: p2trComponents, + p2shP2pk: [], + }; + scriptTypes.forEach((scriptType, i) => { + componentsOnEachInputScriptType[scriptType].forEach((inputComponent) => { + it(`[${scriptType}] missing ${inputComponent} on input should succeed in fully signing unsigned psbt after update`, function () { + const psbt = removeFromPsbt(psbtHex, network, { + input: { index: i, fieldToRemove: inputComponent }, + }); + const unspent = unspents[i]; + if (txFormat === 'psbt-lite') { + // remove the prevTx for the unspent + delete (unspent as unknown as { prevTx?: Buffer }).prevTx; + } + if (isWalletUnspent(unspent)) { + updateWalletUnspentForPsbt(psbt, i, unspent, rootWalletKeys, signer, cosigner, { + skipNonWitnessUtxo: txFormat === 'psbt-lite', + }); + } else { + const { redeemScript } = createOutputScriptP2shP2pk(replayProtectionKeyPair.publicKey); + assert.ok(redeemScript); + updateReplayProtectionUnspentToPsbt(psbt, i, unspent, redeemScript, { + skipNonWitnessUtxo: txFormat === 'psbt-lite', + }); + } + signAllInputs(psbt); + }); + }); + + componentsOnEachOutputScriptType[scriptType].forEach((outputComponent) => { + it(`[${scriptType}] missing ${outputComponent} on output should produce same hex as fully hydrated after update`, function () { + const psbt = removeFromPsbt(psbtHex, network, { + output: { index: i, fieldToRemove: outputComponent }, + }); + updateWalletOutputForPsbt(psbt, rootWalletKeys, i, outputs[i].chain, outputs[i].index); + assert.strictEqual(psbt.toHex(), psbtHex); + }); + }); }); }); + } + + ['psbt', 'psbt-lite'].forEach((txFormat) => { + runTest(txFormat as 'psbt' | 'psbt-lite'); }); }); From ecdd44a7e6c3b4f612b335f06f70c1333ea3d7ae Mon Sep 17 00:00:00 2001 From: Rohit Saw Date: Tue, 14 Oct 2025 10:29:04 +0530 Subject: [PATCH 09/34] chore: wrw support for megaeth ticket: win-7516 --- modules/statics/src/allCoinsAndTokens.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/statics/src/allCoinsAndTokens.ts b/modules/statics/src/allCoinsAndTokens.ts index 09f1cceeb3..9efce31af9 100644 --- a/modules/statics/src/allCoinsAndTokens.ts +++ b/modules/statics/src/allCoinsAndTokens.ts @@ -2069,6 +2069,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -2086,6 +2088,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), canton( From 896a36d8df6639f9d066b0b6995d1af83a75eda3 Mon Sep 17 00:00:00 2001 From: N V Rakesh Reddy Date: Tue, 14 Oct 2025 12:58:18 +0530 Subject: [PATCH 10/34] chore: add tpolyx token without token name TICKET: WIN-7452 --- modules/statics/src/base.ts | 1 + modules/statics/src/coins/polyxTokens.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/statics/src/base.ts b/modules/statics/src/base.ts index 2df98ecbf6..97ca3284e5 100644 --- a/modules/statics/src/base.ts +++ b/modules/statics/src/base.ts @@ -3172,6 +3172,7 @@ export enum UnderlyingAsset { 'tpolyx:WEBINRASSET6' = 'tpolyx:WEBINRASSET6', 'tpolyx:WEBINRASSET7' = 'tpolyx:WEBINRASSET7', 'tpolyx:BULLRWA' = 'tpolyx:BULLRWA', + 'tpolyx:0x4a002922d38b8a7f87484b9c65a7ca0c' = 'tpolyx:0x4a002922d38b8a7f87484b9c65a7ca0c', // Polymesh mainnet tokens 'polyx:0xa0ce6bc4c60981e08eca6504656c99e6' = 'polyx:0xa0ce6bc4c60981e08eca6504656c99e6', diff --git a/modules/statics/src/coins/polyxTokens.ts b/modules/statics/src/coins/polyxTokens.ts index 94259d7570..fd0c7513aa 100644 --- a/modules/statics/src/coins/polyxTokens.ts +++ b/modules/statics/src/coins/polyxTokens.ts @@ -34,7 +34,6 @@ export const polyxTokens = [ UnderlyingAsset['tpolyx:RAND176TM'], POLYX_TOKEN_FEATURES ), - tpolyxToken( '4becde65-8d44-488f-bda9-74ca2d90b3dd', 'tpolyx:WEBINRASSET3', @@ -95,4 +94,14 @@ export const polyxTokens = [ UnderlyingAsset['tpolyx:BULLRWA'], POLYX_TOKEN_FEATURES ), + tpolyxToken( + '5ae194ea-6347-42b3-8eb6-d2d53c340114', + 'tpolyx:0x4a002922d38b8a7f87484b9c65a7ca0c', + '', + 6, + '', + '0x4a002922d38b8a7f87484b9c65a7ca0c', + UnderlyingAsset['tpolyx:0x4a002922d38b8a7f87484b9c65a7ca0c'], + POLYX_TOKEN_FEATURES + ), ]; From cae56ab1195c49654a9b1e28269b09b8c1171845 Mon Sep 17 00:00:00 2001 From: KaustubhPatange Date: Tue, 14 Oct 2025 11:32:21 +0530 Subject: [PATCH 11/34] feat(express): setup integration test Ticket: WP-6312 --- modules/express/test/lib/testutil.ts | 13 ++ .../test/unit/typedRoutes/createAddress.ts | 133 ++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/modules/express/test/lib/testutil.ts b/modules/express/test/lib/testutil.ts index 0cacfd32a7..886998f81d 100644 --- a/modules/express/test/lib/testutil.ts +++ b/modules/express/test/lib/testutil.ts @@ -1,6 +1,8 @@ /** * Utility functions for testing */ +import * as request from 'supertest'; +import { app as expressApp } from '../../src/expressApp'; // helper function to unlock a token for a specified time export function unlockToken(agent, accessToken, seconds) { @@ -12,3 +14,14 @@ export function unlockToken(agent, accessToken, seconds) { res.statusCode.should.equal(200); }); } + +export function setupAgent(): request.SuperAgentTest { + const args: any = { + debug: false, + env: 'test', + logfile: '/dev/null', + }; + + const app = expressApp(args); + return request.agent(app); +} diff --git a/modules/express/test/unit/typedRoutes/createAddress.ts b/modules/express/test/unit/typedRoutes/createAddress.ts index 3c9b7eb328..3a494f128f 100644 --- a/modules/express/test/unit/typedRoutes/createAddress.ts +++ b/modules/express/test/unit/typedRoutes/createAddress.ts @@ -6,6 +6,12 @@ import { PostCreateAddress, } from '../../../src/typedRoutes/api/v2/createAddress'; import { assertDecode } from './common'; +import 'should'; +import 'should-http'; +import 'should-sinon'; +import * as sinon from 'sinon'; +import { BitGo } from 'bitgo'; +import { setupAgent } from '../../lib/testutil'; /** * Helper function to extract path parameter names from a route path @@ -26,6 +32,133 @@ function getCodecParamNames(paramsCodec: Record): string[] { } describe('CreateAddress codec tests', function () { + describe('createAddress', function () { + const agent = setupAgent(); + + const walletId = '68c02f96aa757d9212bd1a536f123456'; + const coin = 'tbtc'; + + const mockResponse = { + id: '68ed4dbfe664aa98d171ac0f524ef111', + address: '2N632etYgykMhGrScEN7RpAthg64ACsTL6v', + chain: 0, + index: 1, + coin: 'tbtc', + wallet: '68c02f96aa757d9212bd1a536f123456', + label: 'My new address', + coinSpecific: { + redeemScript: + '522103ebc10ae7ca49f55228fd29dd32eadfcd289fb43082fabb8e0f3bcee9ab09853721039b1a9b93a2e8114d6627753fc37f115e721609b35187d74dc32e5adfa97992402102a704615d8eedaf2e0ff37f7e503615fb6765b8b147a97ac1d930b37e709755dc53ae', + }, + addressType: 'p2sh', + keychains: [ + { + id: '68c02f94aa757d9212bd19b783deb065', + pub: 'xpub661MyMwAqRbcGCSB6BrtvtRzb4Pebi5RLaC8dqZ8Zt2sJsWZ8dj7pXrLRfiGjYAD5PMV23dAxNQww8kggwKZUZtEhcjH1vPDhu4dUihbv2T', + ethAddress: '0x23f7b80a5f5dce2bfb9e09d40e37794cc8e2a3be', + source: 'user', + type: 'independent', + encryptedPrv: + '{"iv":"abc123xyz456==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"def789ghi012=","ct":"mockEncryptedPrivateKeyData1234567890"}', + }, + { + id: '68c02f94a36d5167fa49878f9553f40e', + pub: 'xpub661MyMwAqRbcFUMUdma6ot9QPBcBDiyJSo3CsyE53hjcZ9RgAH2oxcNViRTv9bUJrHeEiDhL2sLDa9kXgjSwL33Bca3ApQaG7nBJJc5enLr', + ethAddress: '0xfb1d696334a2632952ae25aead77be781df91e18', + source: 'backup', + type: 'independent', + encryptedPrv: + '{"iv":"uvw345qrs678==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"jkl901mno234=","ct":"mockEncryptedPrivateKeyDataBackup567890"}', + }, + { + id: '68c02f95aa757d9212bd19e7ee0744e4', + pub: 'xpub661MyMwAqRbcFZ1e1eeAuFnu8gBAM1Yd7bJUSEL7TRX3QQ6vbY6B5Uugf8E93eTfvcKRHHZUiqq7WLLerZdFkp2guAVG1Mkuqp6ZZqbQ53u', + ethAddress: '0xfad325e7f4b57549ff68395e0d42378046208a71', + source: 'bitgo', + type: 'independent', + isBitGo: true, + isTrust: false, + hsmType: 'institutional', + }, + ], + }; + + afterEach(function () { + sinon.restore(); + }); + + it('should successfully create a new wallet address', async function () { + const requestBody = { + label: 'My new address', + chain: 0, + allowSkipVerifyAddress: true, + }; + + // Create mock wallet with createAddress method + const mockWallet = { + createAddress: sinon.stub().resolves(mockResponse), + }; + + // Stub the wallets().get() chain + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/address`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('id', '68ed4dbfe664aa98d171ac0f524ef111'); + result.body.should.have.property('address', '2N632etYgykMhGrScEN7RpAthg64ACsTL6v'); + result.body.should.have.property('chain', 0); + result.body.should.have.property('index', 1); + result.body.should.have.property('coin', 'tbtc'); + result.body.should.have.property('wallet', walletId); + result.body.should.have.property('label', 'My new address'); + result.body.should.have.property('addressType', 'p2sh'); + result.body.should.have.property('keychains'); + result.body.keychains.should.be.Array(); + result.body.keychains.should.have.length(3); + + // Verify the keychain structure + result.body.keychains[0].should.have.property('source', 'user'); + result.body.keychains[1].should.have.property('source', 'backup'); + result.body.keychains[2].should.have.property('source', 'bitgo'); + result.body.keychains[2].should.have.property('isBitGo', true); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.wallets.calledOnce, true); + assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true); + assert.strictEqual( + mockWallet.createAddress.calledOnceWith( + sinon.match({ + coin: coin, + id: walletId, + label: 'My new address', + chain: 0, + allowSkipVerifyAddress: true, + }) + ), + true + ); + }); + }); + describe('CreateAddressParams', function () { it('should validate params with required coin and id', function () { const validParams = { From b72194f572bd16044225fdc47d46c980b0d0319e Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Tue, 14 Oct 2025 13:17:16 +0530 Subject: [PATCH 12/34] feat: added canton to account-lib Ticket: COIN-5908 --- Dockerfile | 6 +++--- modules/account-lib/package.json | 1 + modules/account-lib/src/index.ts | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index c9fde2693e..83977db46c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -72,6 +72,7 @@ COPY --from=builder /tmp/bitgo/modules/sdk-coin-baby /var/modules/sdk-coin-baby/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-bera /var/modules/sdk-coin-bera/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-bld /var/modules/sdk-coin-bld/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-bsc /var/modules/sdk-coin-bsc/ +COPY --from=builder /tmp/bitgo/modules/sdk-coin-canton /var/modules/sdk-coin-canton/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-celo /var/modules/sdk-coin-celo/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-coredao /var/modules/sdk-coin-coredao/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-coreum /var/modules/sdk-coin-coreum/ @@ -123,7 +124,6 @@ COPY --from=builder /tmp/bitgo/modules/sdk-coin-bsv /var/modules/sdk-coin-bsv/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-btc /var/modules/sdk-coin-btc/ COPY --from=builder /tmp/bitgo/modules/utxo-ord /var/modules/utxo-ord/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-btg /var/modules/sdk-coin-btg/ -COPY --from=builder /tmp/bitgo/modules/sdk-coin-canton /var/modules/sdk-coin-canton/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-dash /var/modules/sdk-coin-dash/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-doge /var/modules/sdk-coin-doge/ COPY --from=builder /tmp/bitgo/modules/sdk-coin-eos /var/modules/sdk-coin-eos/ @@ -169,6 +169,7 @@ cd /var/modules/sdk-coin-baby && yarn link && \ cd /var/modules/sdk-coin-bera && yarn link && \ cd /var/modules/sdk-coin-bld && yarn link && \ cd /var/modules/sdk-coin-bsc && yarn link && \ +cd /var/modules/sdk-coin-canton && yarn link && \ cd /var/modules/sdk-coin-celo && yarn link && \ cd /var/modules/sdk-coin-coredao && yarn link && \ cd /var/modules/sdk-coin-coreum && yarn link && \ @@ -220,7 +221,6 @@ cd /var/modules/sdk-coin-bsv && yarn link && \ cd /var/modules/sdk-coin-btc && yarn link && \ cd /var/modules/utxo-ord && yarn link && \ cd /var/modules/sdk-coin-btg && yarn link && \ -cd /var/modules/sdk-coin-canton && yarn link && \ cd /var/modules/sdk-coin-dash && yarn link && \ cd /var/modules/sdk-coin-doge && yarn link && \ cd /var/modules/sdk-coin-eos && yarn link && \ @@ -269,6 +269,7 @@ RUN cd /var/bitgo-express && \ yarn link @bitgo/sdk-coin-bera && \ yarn link @bitgo/sdk-coin-bld && \ yarn link @bitgo/sdk-coin-bsc && \ + yarn link @bitgo/sdk-coin-canton && \ yarn link @bitgo/sdk-coin-celo && \ yarn link @bitgo/sdk-coin-coredao && \ yarn link @bitgo/sdk-coin-coreum && \ @@ -320,7 +321,6 @@ RUN cd /var/bitgo-express && \ yarn link @bitgo/sdk-coin-btc && \ yarn link @bitgo/utxo-ord && \ yarn link @bitgo/sdk-coin-btg && \ - yarn link @bitgo/sdk-coin-canton && \ yarn link @bitgo/sdk-coin-dash && \ yarn link @bitgo/sdk-coin-doge && \ yarn link @bitgo/sdk-coin-eos && \ diff --git a/modules/account-lib/package.json b/modules/account-lib/package.json index d0d410a301..b82ff67042 100644 --- a/modules/account-lib/package.json +++ b/modules/account-lib/package.json @@ -40,6 +40,7 @@ "@bitgo/sdk-coin-bera": "^2.6.4", "@bitgo/sdk-coin-bld": "^3.5.4", "@bitgo/sdk-coin-bsc": "^22.8.4", + "@bitgo/sdk-coin-canton": "^1.2.0", "@bitgo/sdk-coin-celo": "^5.3.4", "@bitgo/sdk-coin-coredao": "^2.6.4", "@bitgo/sdk-coin-coreum": "^21.5.4", diff --git a/modules/account-lib/src/index.ts b/modules/account-lib/src/index.ts index 2547c2420e..4eaf3f19ae 100644 --- a/modules/account-lib/src/index.ts +++ b/modules/account-lib/src/index.ts @@ -203,6 +203,9 @@ export { Vet }; import * as CosmosSharedCoin from '@bitgo/sdk-coin-cosmos'; export { CosmosSharedCoin }; +import * as Canton from '@bitgo/sdk-coin-canton'; +export { Canton }; + import { validateAgainstMessageTemplates, MIDNIGHT_TNC_HASH } from './utils'; export { MIDNIGHT_TNC_HASH }; @@ -315,6 +318,8 @@ const coinBuilderMap = { tpolyx: Polyx.TransactionBuilderFactory, vet: Vet.TransactionBuilderFactory, tvet: Vet.TransactionBuilderFactory, + canton: Canton.TransactionBuilderFactory, + tcanton: Canton.TransactionBuilderFactory, }; const coinMessageBuilderFactoryMap = { From e736792bdd3278900aa9c4ee46bb34fadca3d285 Mon Sep 17 00:00:00 2001 From: Prabhsharan Singh Date: Tue, 14 Oct 2025 14:22:49 +0530 Subject: [PATCH 13/34] feat: ofc tokens for ton Ticket: [COIN-6043] --- modules/statics/src/ofc.ts | 110 +++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/modules/statics/src/ofc.ts b/modules/statics/src/ofc.ts index 52b7ec1bbc..91ddc15283 100644 --- a/modules/statics/src/ofc.ts +++ b/modules/statics/src/ofc.ts @@ -2286,3 +2286,113 @@ export function tofcHashToken( primaryKeyCurve ); } + +/** + * Factory function for ofc ton token instances. + * + * @param id uuid v4 + * @param name unique identifier of the coin + * @param fullName Complete human-readable name of the coin + * @param network Network object for this coin + * @param decimalPlaces Number of decimal places this coin supports (divisibility exponent) + * @param asset Asset which this coin represents. This is the same for both mainnet and testnet variants of a coin. + * @param kind Differentiates coins which represent fiat assets from those which represent crypto assets + * @param prefix? Optional coin prefix. Defaults to empty string + * @param suffix? Optional coin suffix. Defaults to coin name. + * @param isToken? Whether or not this account coin is a token of another coin + * @param features? Features of this coin. Defaults to the DEFAULT_FEATURES defined in `OfcCoin` + * @param primaryKeyCurve The elliptic curve for this chain/token + */ +export function ofcTonToken( + id: string, + name: string, + fullName: string, + decimalPlaces: number, + asset: UnderlyingAsset, + kind: CoinKind = CoinKind.CRYPTO, + features: CoinFeature[] = OfcCoin.DEFAULT_FEATURES, + prefix = '', + suffix: string = name.replace(/^ofc/, '').toUpperCase(), + network: OfcNetwork = Networks.main.ofc, + isToken = true, + addressCoin = 'ton', + primaryKeyCurve: KeyCurve = KeyCurve.Secp256k1 +) { + const filteredFeatures = getFilteredFeatures(suffix); + if (filteredFeatures.length > 0) { + features = filteredFeatures; + } + return Object.freeze( + new OfcCoin({ + id, + name, + fullName, + network, + prefix, + suffix, + features, + decimalPlaces, + isToken, + asset, + kind, + addressCoin, + primaryKeyCurve, + baseUnit: BaseUnit.TON, + }) + ); +} + +/** + * Factory function for testnet ofc ton token instances. + * + * @param id uuid v4 + * @param name unique identifier of the coin + * @param fullName Complete human-readable name of the coin + * @param network Network object for this coin + * @param decimalPlaces Number of decimal places this coin supports (divisibility exponent) + * @param asset Asset which this coin represents. This is the same for both mainnet and testnet variants of a coin. + * @param kind Differentiates coins which represent fiat assets from those which represent crypto assets + * @param prefix? Optional coin prefix. Defaults to empty string + * @param suffix? Optional coin suffix. Defaults to coin name. + * @param isToken? Whether or not this account coin is a token of another coin + * @param features? Features of this coin. Defaults to the DEFAULT_FEATURES defined in `OfcCoin` + * @param primaryKeyCurve The elliptic curve for this chain/token + */ +export function tofcTonToken( + id: string, + name: string, + fullName: string, + decimalPlaces: number, + asset: UnderlyingAsset, + kind: CoinKind = CoinKind.CRYPTO, + features: CoinFeature[] = OfcCoin.DEFAULT_FEATURES, + prefix = '', + suffix: string = name.replace(/^ofc/, '').toUpperCase(), + network: OfcNetwork = Networks.test.ofc, + isToken = true, + addressCoin = 'tton', + primaryKeyCurve: KeyCurve = KeyCurve.Secp256k1 +) { + const filteredFeatures = getFilteredFeatures(suffix); + if (filteredFeatures.length > 0) { + features = filteredFeatures; + } + return Object.freeze( + new OfcCoin({ + id, + name, + fullName, + network, + prefix, + suffix, + features, + decimalPlaces, + isToken, + asset, + kind, + addressCoin, + primaryKeyCurve, + baseUnit: BaseUnit.TON, + }) + ); +} From a4d7bc7f9ecc47179eb18a779840a71c0cff2b04 Mon Sep 17 00:00:00 2001 From: Prabhsharan Singh Date: Tue, 14 Oct 2025 14:59:50 +0530 Subject: [PATCH 14/34] feat: ofc tokens for ton Ticket: [COIN-6043] --- modules/statics/src/coins/ofcCoins.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/statics/src/coins/ofcCoins.ts b/modules/statics/src/coins/ofcCoins.ts index 9fcfa3f892..29ad9cf108 100644 --- a/modules/statics/src/coins/ofcCoins.ts +++ b/modules/statics/src/coins/ofcCoins.ts @@ -36,6 +36,8 @@ import { ofcHashToken, tofcHashToken, tofcaptToken, + ofcTonToken, + tofcTonToken, } from '../ofc'; import { UnderlyingAsset, CoinKind, CoinFeature } from '../base'; @@ -3459,4 +3461,12 @@ export const ofcCoins = [ 6, UnderlyingAsset['thash:ylds'] ), + ofcTonToken('c0e7396b-d21a-4b5a-b547-fdfe001cf3ba', 'ofcton:usdt', 'Ton USDT', 6, UnderlyingAsset['ton:usdt']), + tofcTonToken( + 'e7d516c1-b975-4905-b5d0-8460f6ea7eb9', + 'ofctton:ukwny-us', + 'Test Unknown TokenY-US', + 9, + UnderlyingAsset['tton:ukwny-us'] + ), ]; From 73ed13d974e7cc840c77678688b95b4a0ab2b726 Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Tue, 14 Oct 2025 16:14:22 +0530 Subject: [PATCH 15/34] fix(sdk-coin-canton): removed the non-required export Ticket: COIN-5918 --- modules/sdk-coin-canton/resources/hash/hash.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sdk-coin-canton/resources/hash/hash.js b/modules/sdk-coin-canton/resources/hash/hash.js index f50b260c84..0044c46744 100644 --- a/modules/sdk-coin-canton/resources/hash/hash.js +++ b/modules/sdk-coin-canton/resources/hash/hash.js @@ -44,7 +44,7 @@ async function encodeInt64(value) { view.setBigInt64(0, num, false); // true for little-endian return new Uint8Array(buffer); } -export async function encodeString(value = '') { +async function encodeString(value = '') { const utf8Bytes = new TextEncoder().encode(value); return encodeBytes(utf8Bytes); } From 138d63f0f36c8bad5c5dcd9bd5893a4038ebc3ac Mon Sep 17 00:00:00 2001 From: prithvishet2503 Date: Tue, 14 Oct 2025 16:26:35 +0530 Subject: [PATCH 16/34] chore: change the 0G network ID Ticket: WIN-7566 --- modules/statics/src/networks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/statics/src/networks.ts b/modules/statics/src/networks.ts index 48b59cceb7..b7cc44f47c 100644 --- a/modules/statics/src/networks.ts +++ b/modules/statics/src/networks.ts @@ -1573,8 +1573,8 @@ class OgTestnet extends Testnet implements EthereumNetwork { family = CoinFamily.OG; explorerUrl = 'https://chainscan-galileo.0g.ai/tx/'; accountExplorerUrl = 'https://chainscan-galileo.0g.ai/address/'; - chainId = 16601; - nativeCoinOperationHashPrefix = '16601'; + chainId = 16602; + nativeCoinOperationHashPrefix = '16602'; } class Xdc extends Mainnet implements EthereumNetwork { From b4f19cc59ca8ee80d01de958708020f32726a58d Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Tue, 14 Oct 2025 17:00:44 +0530 Subject: [PATCH 17/34] feat(sdk-coin-canton): removed non-required fields from builders Ticket: COIN-6047 --- modules/sdk-coin-canton/src/lib/iface.ts | 19 +--- .../src/lib/oneStepPreApprovalBuilder.ts | 86 +------------------ .../src/lib/walletInitBuilder.ts | 18 ---- modules/sdk-coin-canton/test/resources.ts | 6 -- .../oneStepEnablementBuilder.ts | 28 ++---- .../builder/walletInit/walletInitBuilder.ts | 4 +- 6 files changed, 10 insertions(+), 151 deletions(-) diff --git a/modules/sdk-coin-canton/src/lib/iface.ts b/modules/sdk-coin-canton/src/lib/iface.ts index 4df4130d14..24a79c56bd 100644 --- a/modules/sdk-coin-canton/src/lib/iface.ts +++ b/modules/sdk-coin-canton/src/lib/iface.ts @@ -49,7 +49,6 @@ export interface IPublicKey { } export interface WalletInitRequest { - synchronizer: string; partyHint: string; publicKey: IPublicKey; localParticipantObservationOnly: boolean; @@ -58,26 +57,10 @@ export interface WalletInitRequest { observingParticipantUids: string[]; } -interface PreApprovalCreateCommand { - templateId: string; - createArguments: { - receiver: string; - provider: string; - expectedDso: string; - }; -} - export interface OneStepEnablementRequest { commandId: string; - commands: [ - { - CreateCommand: PreApprovalCreateCommand; - } - ]; - disclosedContracts: []; - synchronizerId: string; + receiverId: string; verboseHashing: boolean; actAs: string[]; readAs: string[]; - packageIdSelectionPreference: string[]; } diff --git a/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts b/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts index 676c119265..7d80bfd992 100644 --- a/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts +++ b/modules/sdk-coin-canton/src/lib/oneStepPreApprovalBuilder.ts @@ -5,12 +5,8 @@ import { TransactionBuilder } from './transactionBuilder'; import { Transaction } from './transaction/transaction'; export class OneStepPreApprovalBuilder extends TransactionBuilder { - private _synchronizerId: string; private _commandId: string; - private _templateId: string; private _receiverPartyId: string; - private _providerPartyId: string; - private _expectedDso: string; constructor(_coinConfig: Readonly) { super(_coinConfig); } @@ -32,21 +28,6 @@ export class OneStepPreApprovalBuilder extends TransactionBuilder { this.transaction.prepareCommand = transaction; } - /** - * Sets the synchronizer ID for the pre-approval builder. - * - * @param id - The synchronizer identifier (must be a non-empty string). - * @returns The current builder instance for chaining. - * @throws Error if the synchronizer ID is empty. - */ - synchronizerId(id: string): this { - if (!id.trim()) { - throw new Error('synchronizer must be a non-empty string'); - } - this._synchronizerId = id.trim(); - return this; - } - /** * Sets the unique id for the 1-step enablement * Also sets the _id of the transaction @@ -65,21 +46,6 @@ export class OneStepPreApprovalBuilder extends TransactionBuilder { return this; } - /** - * Sets the template id for the 1-step enablement - * - * @param id - the template if of the form `#splice-wallet:Splice.Wallet.TransferPreapproval:TransferPreapprovalProposal` - * @returns The current builder instance for chaining. - * @throws Error if id is empty. - */ - templateId(id: string): this { - if (!id.trim()) { - throw new Error('templateId must be a non-empty string'); - } - this._templateId = id.trim(); - return this; - } - /** * Sets the receiver for the 1-step enablement * @@ -95,36 +61,6 @@ export class OneStepPreApprovalBuilder extends TransactionBuilder { return this; } - /** - * Sets the provider for the 1-step enablement - * - * @param id - the validator party id (address) - * @returns The current builder instance for chaining. - * @throws Error if id is empty. - */ - providerPartyId(id: string): this { - if (!id.trim()) { - throw new Error('providerPartyId must be a non-empty string'); - } - this._providerPartyId = id.trim(); - return this; - } - - /** - * Sets the dso id for the 1-step enablement - * - * @param id - the dso id of the validator - * @returns The current builder instance for chaining. - * @throws Error if id is empty. - */ - expectedDso(id: string): this { - if (!id.trim()) { - throw new Error('expectedDso must be a non-empty string'); - } - this._expectedDso = id.trim(); - return this; - } - /** * Builds and returns the OneStepEnablementRequest object from the builder's internal state. * @@ -139,24 +75,10 @@ export class OneStepPreApprovalBuilder extends TransactionBuilder { return { commandId: this._commandId, - commands: [ - { - CreateCommand: { - templateId: this._templateId, - createArguments: { - receiver: this._receiverPartyId, - provider: this._providerPartyId, - expectedDso: this._expectedDso, - }, - }, - }, - ], - disclosedContracts: [], - synchronizerId: this._synchronizerId, + receiverId: this._receiverPartyId, verboseHashing: false, actAs: [this._receiverPartyId], readAs: [], - packageIdSelectionPreference: [], }; } @@ -167,11 +89,7 @@ export class OneStepPreApprovalBuilder extends TransactionBuilder { * @throws {Error} If any required field is missing or invalid. */ private validate(): void { - if (!this._receiverPartyId) throw new Error('receiver partyId is missing'); - if (!this._providerPartyId) throw new Error('provider partyId is missing'); - if (!this._expectedDso) throw new Error('expectedDso is missing'); if (!this._commandId) throw new Error('commandId is missing'); - if (!this._templateId) throw new Error('templateId is missing'); - if (!this._synchronizerId) throw new Error('synchronizerId is missing'); + if (!this._receiverPartyId) throw new Error('receiver partyId is missing'); } } diff --git a/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts b/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts index 0eab8d7a0e..6939c5c103 100644 --- a/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts +++ b/modules/sdk-coin-canton/src/lib/walletInitBuilder.ts @@ -13,7 +13,6 @@ export class WalletInitBuilder extends BaseTransactionBuilder { private _transaction: WalletInitTransaction; private _publicKey: IPublicKey; - private _synchronizer: string; private _partyHint: string; private _localParticipantObservationOnly = false; private _otherConfirmingParticipantUids: string[] = []; @@ -109,21 +108,6 @@ export class WalletInitBuilder extends BaseTransactionBuilder { return this; } - /** - * Sets the synchronizer ID for the wallet initialization. - * - * @param id - The synchronizer identifier (must be a non-empty string). - * @returns The current builder instance for chaining. - * @throws Error if the synchronizer ID is empty. - */ - synchronizer(id: string): this { - if (!id.trim()) { - throw new Error('synchronizer must be a non-empty string'); - } - this._synchronizer = id.trim(); - return this; - } - /** * Sets the party hint (alias or name) used during wallet initialization. * @@ -220,7 +204,6 @@ export class WalletInitBuilder extends BaseTransactionBuilder { this.validate(); return { publicKey: this._publicKey, - synchronizer: this._synchronizer, partyHint: this._partyHint, localParticipantObservationOnly: this._localParticipantObservationOnly, otherConfirmingParticipantUids: this._otherConfirmingParticipantUids, @@ -243,7 +226,6 @@ export class WalletInitBuilder extends BaseTransactionBuilder { * @throws {Error} If any required field is missing or invalid. */ private validate(): void { - if (!this._synchronizer) throw new Error('Missing synchronizer'); if (!this._partyHint || this._partyHint.length > 5) throw new Error('Invalid partyHint'); if (!this._publicKey || !this._publicKey.keyData || !this._publicKey.format || !this._publicKey.keySpec) { throw new Error('Invalid publicKey'); diff --git a/modules/sdk-coin-canton/test/resources.ts b/modules/sdk-coin-canton/test/resources.ts index 01cff323de..b513d65356 100644 --- a/modules/sdk-coin-canton/test/resources.ts +++ b/modules/sdk-coin-canton/test/resources.ts @@ -34,19 +34,13 @@ export const PrepareSubmissionResponse = { }; export const WalletInitRequestData = { - synchronizer: 'global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', partyHint: '1220b', publicKey: 'zs4J2IrVpfYNHN0bR7EHS0Fb3rETUyyu2L2QwxucPjg=', }; export const OneStepEnablement = { - synchronizer: 'global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', partyId: 'ravi-test-party-1::12205b4e3537a95126d90604592344d8ad3c3ddccda4f79901954280ee19c576714d', - validatorPartyId: 'Bitgo-devnet-validator-1::1220a0a0f60b0e62b5d750c484b18c091dba23080c133d944614ba75a5858cba3045', - templateId: '#splice-wallet:Splice.Wallet.TransferPreapproval:TransferPreapprovalProposal', - expectedDsoId: 'DSO::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', commandId: '3935a06d-3b03-41be-99a5-95b2ecaabf7d', - synchronizerId: 'global-domain::1220be58c29e65de40bf273be1dc2b266d43a9a002ea5b18955aeef7aac881bb471a', }; export const OneStepPreApprovalPrepareResponse = { diff --git a/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts b/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts index 9a3404804d..574c4c8502 100644 --- a/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts +++ b/modules/sdk-coin-canton/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.ts @@ -18,31 +18,15 @@ describe('Wallet Pre-approval Enablement Builder', () => { const txBuilder = new OneStepPreApprovalBuilder(coins.get('tcanton')); const oneStepEnablementTx = new Transaction(coins.get('tcanton')); txBuilder.initBuilder(oneStepEnablementTx); - const { synchronizer, commandId, partyId, validatorPartyId, expectedDsoId, templateId, synchronizerId } = - OneStepEnablement; - txBuilder - .commandId(commandId) - .templateId(templateId) - .expectedDso(expectedDsoId) - .templateId(templateId) - .providerPartyId(validatorPartyId) - .receiverPartyId(partyId) - .synchronizerId(synchronizerId); + const { commandId, partyId } = OneStepEnablement; + txBuilder.commandId(commandId).receiverPartyId(partyId); const requestObj: OneStepEnablementRequest = txBuilder.toRequestObject(); should.exist(requestObj); - assert.equal(requestObj.synchronizerId, synchronizer); assert.equal(requestObj.commandId, commandId); - assert.equal(requestObj.commands.length, 1); - const command = requestObj.commands[0]; - should.exist(command); - const createCommand = command.CreateCommand; - should.exist(createCommand); - assert.equal(createCommand.templateId, templateId); - const createArguments = createCommand.createArguments; - should.exist(createArguments); - assert.equal(createArguments.expectedDso, expectedDsoId); - assert.equal(createArguments.provider, validatorPartyId); - assert.equal(createArguments.receiver, partyId); + assert.equal(requestObj.receiverId, partyId); + assert.equal(requestObj.actAs.length, 1); + const actAs = requestObj.actAs[0]; + assert.equal(actAs, partyId); }); it('should validate raw transaction', function () { diff --git a/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts b/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts index 1f5c92c44c..12d2ac8e34 100644 --- a/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts +++ b/modules/sdk-coin-canton/test/unit/builder/walletInit/walletInitBuilder.ts @@ -12,13 +12,11 @@ import { GenerateTopologyResponse, InvalidGenerateTopologyResponse, WalletInitRe describe('Wallet Initialization Builder', () => { it('should get the wallet init request object', function () { const txBuilder = new WalletInitBuilder(coins.get('tcanton')); - const { publicKey, synchronizer, partyHint } = WalletInitRequestData; + const { publicKey, partyHint } = WalletInitRequestData; txBuilder.publicKey(publicKey); - txBuilder.synchronizer(synchronizer); txBuilder.partyHint(partyHint); const requestObj: WalletInitRequest = txBuilder.toRequestObject(); should.exist(requestObj); - assert.equal(requestObj.synchronizer, synchronizer); assert.equal(requestObj.partyHint, partyHint); assert.equal(requestObj.localParticipantObservationOnly, false); assert.equal(requestObj.confirmationThreshold, 1); From 91c5d0b5d305678f75491da39ca2d54f3affbb32 Mon Sep 17 00:00:00 2001 From: Lokesh Chandra Date: Tue, 14 Oct 2025 17:52:56 +0530 Subject: [PATCH 18/34] test(express): added supertest for coin signtx Ticket: WP-6328 --- .../test/unit/typedRoutes/coinSignTx.ts | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) diff --git a/modules/express/test/unit/typedRoutes/coinSignTx.ts b/modules/express/test/unit/typedRoutes/coinSignTx.ts index b81faed62d..d8d0048c36 100644 --- a/modules/express/test/unit/typedRoutes/coinSignTx.ts +++ b/modules/express/test/unit/typedRoutes/coinSignTx.ts @@ -12,8 +12,273 @@ import { PostCoinSignTx, } from '../../../src/typedRoutes/api/v2/coinSignTx'; import { assertDecode } from './common'; +import 'should'; +import 'should-http'; +import 'should-sinon'; +import * as sinon from 'sinon'; +import { BitGo } from 'bitgo'; +import { setupAgent } from '../../lib/testutil'; describe('CoinSignTx codec tests', function () { + describe('coinSignTx', function () { + const agent = setupAgent(); + const coin = 'tbtc'; + + const mockFullySignedResponse = { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }; + + afterEach(function () { + sinon.restore(); + }); + + it('should successfully sign a transaction', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: '5a1341e7c8421dc90710673b3166bbd5', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + isLastSignature: true, + }; + + // Create mock coin with signTransaction method + const mockCoin = { + signTransaction: sinon.stub().resolves(mockFullySignedResponse), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txHex'); + assert.strictEqual(result.body.txHex, mockFullySignedResponse.txHex); + + // This ensures the response structure matches the typed definition + const decodedResponse = assertDecode(FullySignedTransactionResponse, result.body); + assert.strictEqual(decodedResponse.txHex, mockFullySignedResponse.txHex); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual( + mockCoin.signTransaction.calledOnceWith( + sinon.match({ + coin: coin, + txPrebuild: sinon.match.object, + prv: requestBody.prv, + isLastSignature: true, + }) + ), + true + ); + }); + + it('should successfully sign a half-signed transaction', async function () { + const requestBody = { + txPrebuild: { + txBase64: + 'AQAAAAFz2JT3Xvjk8jKcYcMrKR8tPMRm5+/Q6J2sMgtz7QDpAAAAAAD+////AoCWmAAAAAAAGXapFJA29QPQaHHwR3Uriuhw2A6tHkPgiKwAAAAAAAEBH9cQ2QAAAAAAAXapFCf/zr8zPrMftHGIRsOt0Cf+wdOyiKwA', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + const mockHalfSignedResponse = { + halfSigned: { + txBase64: + 'AQAAAAFz2JT3Xvjk8jKcYcMrKR8tPMRm5+/Q6J2sMgtz7QDpAAAAAAD+////AoCWmAAAAAAAGXapFJA29QPQaHHwR3Uriuhw2A6tHkPgiKwAAAAAAAEBH9cQ2QAAAAAAAXapFCf/zr8zPrMftHGIRsOt0Cf+wdOyiKwA', + }, + }; + + // Create mock coin with signTransaction method + const mockCoin = { + signTransaction: sinon.stub().resolves(mockHalfSignedResponse), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('halfSigned'); + result.body.halfSigned.should.have.property('txBase64'); + assert.strictEqual(result.body.halfSigned.txBase64, mockHalfSignedResponse.halfSigned.txBase64); + + // This ensures the response structure matches the typed definition + const decodedResponse = assertDecode(HalfSignedAccountTransactionResponse, result.body); + assert.strictEqual(decodedResponse.halfSigned.txBase64, mockHalfSignedResponse.halfSigned.txBase64); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.signTransaction.calledOnce, true); + }); + + it('should successfully return a transaction request ID', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + const mockTxRequestResponse = { + txRequestId: '5a1341e7c8421dc90710673b3166bbd5', + }; + + // Create mock coin with signTransaction method + const mockCoin = { + signTransaction: sinon.stub().resolves(mockTxRequestResponse), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txRequestId'); + assert.strictEqual(result.body.txRequestId, mockTxRequestResponse.txRequestId); + + // This ensures the response structure matches the typed definition + const decodedResponse = assertDecode(SignedTransactionRequestResponse, result.body); + assert.strictEqual(decodedResponse.txRequestId, mockTxRequestResponse.txRequestId); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.signTransaction.calledOnce, true); + }); + + it('should successfully return a TSS transaction request (Full TxRequestResponse)', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + const mockTxRequestFullResponse = { + txRequestId: '5a1341e7c8421dc90710673b3166bbd5', + walletId: '5a1341e7c8421dc90710673b3166bbd5', + walletType: 'hot', + version: 1, + state: 'pendingApproval', + date: '2023-01-01T00:00:00.000Z', + createdDate: '2023-01-01T00:00:00.000Z', + userId: '5a1341e7c8421dc90710673b3166bbd5', + initiatedBy: '5a1341e7c8421dc90710673b3166bbd5', + updatedBy: '5a1341e7c8421dc90710673b3166bbd5', + intents: [], + enterpriseId: '5a1341e7c8421dc90710673b3166bbd5', + intent: {}, + pendingApprovalId: '5a1341e7c8421dc90710673b3166bbd5', + policiesChecked: true, + signatureShares: [ + { + from: 'user', + to: 'bitgo', + share: 'abc123', + }, + ], + commitmentShares: [ + { + from: 'user', + to: 'bitgo', + share: 'abc123', + type: 'commitment', + }, + ], + txHashes: ['hash1', 'hash2'], + unsignedTxs: [ + { + serializedTxHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + signableHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + derivationPath: "m/44'/0'/0'/0/0", + }, + ], + apiVersion: 'lite', + latest: true, + }; + + // Create mock coin with signTransaction method + const mockCoin = { + signTransaction: sinon.stub().resolves(mockTxRequestFullResponse), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txRequestId'); + result.body.should.have.property('walletId'); + result.body.should.have.property('version'); + result.body.should.have.property('state'); + result.body.should.have.property('intents'); + result.body.should.have.property('latest'); + assert.strictEqual(result.body.txRequestId, mockTxRequestFullResponse.txRequestId); + assert.strictEqual(result.body.walletId, mockTxRequestFullResponse.walletId); + assert.strictEqual(result.body.version, mockTxRequestFullResponse.version); + assert.strictEqual(result.body.state, mockTxRequestFullResponse.state); + assert.strictEqual(result.body.latest, mockTxRequestFullResponse.latest); + + // Verify TSS-specific fields + result.body.should.have.property('signatureShares'); + result.body.should.have.property('commitmentShares'); + result.body.should.have.property('unsignedTxs'); + result.body.signatureShares.should.be.Array(); + result.body.signatureShares.should.have.length(1); + result.body.commitmentShares.should.be.Array(); + result.body.commitmentShares.should.have.length(1); + result.body.unsignedTxs.should.be.Array(); + result.body.unsignedTxs.should.have.length(1); + + // This ensures the TSS transaction request response structure matches the typed definition + const decodedResponse = assertDecode(TxRequestResponse, result.body); + assert.strictEqual(decodedResponse.txRequestId, mockTxRequestFullResponse.txRequestId); + assert.strictEqual(decodedResponse.walletId, mockTxRequestFullResponse.walletId); + assert.strictEqual(decodedResponse.version, mockTxRequestFullResponse.version); + assert.strictEqual(decodedResponse.state, mockTxRequestFullResponse.state); + assert.strictEqual(decodedResponse.latest, mockTxRequestFullResponse.latest); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.signTransaction.calledOnce, true); + }); + }); + describe('CoinSignTxParams', function () { it('should validate params with required coin', function () { const validParams = { From 431b86ae09944b2bfacf84e1c7cf3c17e8b60f58 Mon Sep 17 00:00:00 2001 From: Aditya Tiwari Date: Tue, 14 Oct 2025 18:53:07 +0530 Subject: [PATCH 19/34] chore(statics): remove rebase feature from vtho token Ticket: COIN-6055 --- modules/statics/src/coins/vetTokens.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/statics/src/coins/vetTokens.ts b/modules/statics/src/coins/vetTokens.ts index cd22821f59..d944fb097a 100644 --- a/modules/statics/src/coins/vetTokens.ts +++ b/modules/statics/src/coins/vetTokens.ts @@ -1,5 +1,5 @@ import { tvetToken, vetToken } from '../account'; -import { UnderlyingAsset, CoinFeature } from '../base'; +import { UnderlyingAsset } from '../base'; import { VET_TOKEN_FEATURES } from '../coinFeatures'; export const vetTokens = [ @@ -19,6 +19,6 @@ export const vetTokens = [ 18, '0x0000000000000000000000000000456e65726779', UnderlyingAsset['tvet:vtho'], - [...VET_TOKEN_FEATURES, CoinFeature.REBASE_TOKEN] + VET_TOKEN_FEATURES ), ]; From a43c22aba1ad1316a3d44191bb6961697b5a1feb Mon Sep 17 00:00:00 2001 From: Lokesh Chandra Date: Tue, 14 Oct 2025 22:03:00 +0530 Subject: [PATCH 20/34] test(express): added supertest for wallet signtsstx Ticket: WP-6334 --- .../test/unit/typedRoutes/walletTxSignTSS.ts | 776 ++++++++++++++++++ 1 file changed, 776 insertions(+) diff --git a/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts b/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts index 604a6ba4f9..de3943c821 100644 --- a/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts +++ b/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts @@ -12,8 +12,784 @@ import { PostWalletTxSignTSS, } from '../../../src/typedRoutes/api/v2/walletTxSignTSS'; import { assertDecode } from './common'; +import 'should'; +import 'should-http'; +import 'should-sinon'; +import * as sinon from 'sinon'; +import { BitGo } from 'bitgo'; +import { setupAgent } from '../../lib/testutil'; describe('WalletTxSignTSS codec tests', function () { + describe('walletTxSignTSS', function () { + const agent = setupAgent(); + const coin = 'tbtc'; + const walletId = '68c02f96aa757d9212bd1a536f123456'; + + const mockFullySignedResponse = { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }; + + afterEach(function () { + sinon.restore(); + }); + + it('should successfully sign a TSS wallet transaction', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + txRequestId: 'tx-req-5a1341e7c8421dc90710673b3166bbd5', + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + // Create mock wallet with signTransaction method + const mockWallet = { + signTransaction: sinon.stub().resolves(mockFullySignedResponse), + }; + + // Stub the wallets().get() chain + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txHex'); + assert.strictEqual(result.body.txHex, mockFullySignedResponse.txHex); + + // This ensures the response structure matches the typed definition + const decodedResponse = assertDecode(FullySignedTransactionResponse, result.body); + assert.strictEqual(decodedResponse.txHex, mockFullySignedResponse.txHex); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.wallets.calledOnce, true); + assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true); + assert.strictEqual(mockWallet.signTransaction.calledOnce, true); + }); + + it('should successfully sign a half-signed TSS wallet transaction', async function () { + const requestBody = { + txPrebuild: { + txBase64: + 'AQAAAAFz2JT3Xvjk8jKcYcMrKR8tPMRm5+/Q6J2sMgtz7QDpAAAAAAD+////AoCWmAAAAAAAGXapFJA29QPQaHHwR3Uriuhw2A6tHkPgiKwAAAAAAAEBH9cQ2QAAAAAAAXapFCf/zr8zPrMftHGIRsOt0Cf+wdOyiKwA', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const mockHalfSignedResponse = { + halfSigned: { + txBase64: + 'AQAAAAFz2JT3Xvjk8jKcYcMrKR8tPMRm5+/Q6J2sMgtz7QDpAAAAAAD+////AoCWmAAAAAAAGXapFJA29QPQaHHwR3Uriuhw2A6tHkPgiKwAAAAAAAEBH9cQ2QAAAAAAAXapFCf/zr8zPrMftHGIRsOt0Cf+wdOyiKwA', + }, + }; + + // Create mock wallet with signTransaction method + const mockWallet = { + signTransaction: sinon.stub().resolves(mockHalfSignedResponse), + }; + + // Stub the wallets().get() chain + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('halfSigned'); + result.body.halfSigned.should.have.property('txBase64'); + assert.strictEqual(result.body.halfSigned.txBase64, mockHalfSignedResponse.halfSigned.txBase64); + + // This ensures the response structure matches the typed definition + const decodedResponse = assertDecode(HalfSignedAccountTransactionResponse, result.body); + assert.strictEqual(decodedResponse.halfSigned.txBase64, mockHalfSignedResponse.halfSigned.txBase64); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.wallets.calledOnce, true); + assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true); + assert.strictEqual(mockWallet.signTransaction.calledOnce, true); + }); + + it('should successfully sign a half-signed UTXO transaction', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const mockHalfSignedUtxoResponse = { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f00000000484730440220abc123def456...', + }; + + // Create mock wallet with signTransaction method + const mockWallet = { + signTransaction: sinon.stub().resolves(mockHalfSignedUtxoResponse), + }; + + // Stub the wallets().get() chain + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txHex'); + assert.strictEqual(result.body.txHex, mockHalfSignedUtxoResponse.txHex); + + // This ensures the response structure matches the typed definition for UTXO half-signed + const decodedResponse = assertDecode(HalfSignedUtxoTransactionResponse, result.body); + assert.strictEqual(decodedResponse.txHex, mockHalfSignedUtxoResponse.txHex); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.wallets.calledOnce, true); + assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true); + assert.strictEqual(mockWallet.signTransaction.calledOnce, true); + }); + + it('should successfully return a TSS transaction request ID', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const mockTxRequestResponse = { + txRequestId: '5a1341e7c8421dc90710673b3166bbd5', + }; + + // Create mock wallet with signTransaction method + const mockWallet = { + signTransaction: sinon.stub().resolves(mockTxRequestResponse), + }; + + // Stub the wallets().get() chain + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txRequestId'); + assert.strictEqual(result.body.txRequestId, mockTxRequestResponse.txRequestId); + + // This ensures the response structure matches the typed definition + const decodedResponse = assertDecode(SignedTransactionRequestResponse, result.body); + assert.strictEqual(decodedResponse.txRequestId, mockTxRequestResponse.txRequestId); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.wallets.calledOnce, true); + assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true); + assert.strictEqual(mockWallet.signTransaction.calledOnce, true); + }); + + it('should successfully return a full TSS transaction request (TxRequestResponse)', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + txRequestId: 'tx-req-5a1341e7c8421dc90710673b3166bbd5', + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'full' as const, + multisigTypeVersion: 'MPCv2' as const, + }; + + const mockTxRequestFullResponse = { + txRequestId: '5a1341e7c8421dc90710673b3166bbd5', + walletId: walletId, + walletType: 'hot', + version: 1, + state: 'pendingUserSignature', + date: '2023-01-01T00:00:00.000Z', + createdDate: '2023-01-01T00:00:00.000Z', + userId: '5a1341e7c8421dc90710673b3166bbd5', + initiatedBy: '5a1341e7c8421dc90710673b3166bbd5', + updatedBy: '5a1341e7c8421dc90710673b3166bbd5', + intents: [], + enterpriseId: '5a1341e7c8421dc90710673b3166bbd5', + intent: {}, + pendingApprovalId: '5a1341e7c8421dc90710673b3166bbd5', + policiesChecked: true, + signatureShares: [ + { + from: 'user', + to: 'bitgo', + share: 'user_signature_share_abc123', + }, + ], + commitmentShares: [ + { + from: 'user', + to: 'bitgo', + share: 'user_commitment_share_abc123', + type: 'commitment', + }, + ], + txHashes: ['hash1_tss', 'hash2_tss'], + unsignedTxs: [ + { + serializedTxHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + signableHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + derivationPath: "m/44'/0'/0'/0/0", + }, + ], + apiVersion: 'full', + latest: true, + }; + + // Create mock wallet with signTransaction method + const mockWallet = { + signTransaction: sinon.stub().resolves(mockTxRequestFullResponse), + }; + + // Stub the wallets().get() chain + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + // Stub BitGo.prototype.coin to return our mock coin + const coinStub = sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify the response + assert.strictEqual(result.status, 200); + result.body.should.have.property('txRequestId'); + result.body.should.have.property('walletId'); + result.body.should.have.property('version'); + result.body.should.have.property('state'); + result.body.should.have.property('intents'); + result.body.should.have.property('latest'); + assert.strictEqual(result.body.txRequestId, mockTxRequestFullResponse.txRequestId); + assert.strictEqual(result.body.walletId, mockTxRequestFullResponse.walletId); + assert.strictEqual(result.body.version, mockTxRequestFullResponse.version); + assert.strictEqual(result.body.state, mockTxRequestFullResponse.state); + assert.strictEqual(result.body.latest, mockTxRequestFullResponse.latest); + + // Verify TSS-specific fields + result.body.should.have.property('signatureShares'); + result.body.should.have.property('commitmentShares'); + result.body.should.have.property('unsignedTxs'); + result.body.signatureShares.should.be.Array(); + result.body.signatureShares.should.have.length(1); + result.body.commitmentShares.should.be.Array(); + result.body.commitmentShares.should.have.length(1); + result.body.unsignedTxs.should.be.Array(); + result.body.unsignedTxs.should.have.length(1); + + // This ensures the TSS transaction request response structure matches the typed definition + const decodedResponse = assertDecode(TxRequestResponse, result.body); + assert.strictEqual(decodedResponse.txRequestId, mockTxRequestFullResponse.txRequestId); + assert.strictEqual(decodedResponse.walletId, mockTxRequestFullResponse.walletId); + assert.strictEqual(decodedResponse.version, mockTxRequestFullResponse.version); + assert.strictEqual(decodedResponse.state, mockTxRequestFullResponse.state); + assert.strictEqual(decodedResponse.latest, mockTxRequestFullResponse.latest); + + // Verify that the correct BitGoJS methods were called + assert.strictEqual(coinStub.calledOnceWith(coin), true); + assert.strictEqual(mockCoin.wallets.calledOnce, true); + assert.strictEqual(walletsGetStub.calledOnceWith({ id: walletId }), true); + assert.strictEqual(mockWallet.signTransaction.calledOnce, true); + }); + + // ========================================== + // ERROR AND EDGE CASE TESTS + // ========================================== + + describe('Error Cases', function () { + it('should handle wallet not found error', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + // Stub wallets().get() to reject with wallet not found error + const walletsGetStub = sinon.stub().rejects(new Error('Wallet not found')); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify error response + assert.strictEqual(result.status, 500); + result.body.should.have.property('error'); + }); + + it('should handle signTransaction failure', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'wrong_passphrase', + apiVersion: 'lite' as const, + }; + + // Create mock wallet where signTransaction fails + const mockWallet = { + signTransaction: sinon.stub().rejects(new Error('Invalid passphrase')), + }; + + const walletsGetStub = sinon.stub().resolves(mockWallet); + + const mockWallets = { + get: walletsGetStub, + }; + + const mockCoin = { + wallets: sinon.stub().returns(mockWallets), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify error response + assert.strictEqual(result.status, 500); + result.body.should.have.property('error'); + }); + + it('should handle invalid coin error', async function () { + const invalidCoin = 'invalid_coin_xyz'; + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + // Stub coin() to throw error for invalid coin + sinon.stub(BitGo.prototype, 'coin').throws(new Error(`Coin ${invalidCoin} is not supported`)); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${invalidCoin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify error response + assert.strictEqual(result.status, 500); + result.body.should.have.property('error'); + }); + }); + + describe('Invalid Request Body', function () { + it('should reject request with empty body', async function () { + // Make the request with empty body + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send({}); + + // io-ts validation should fail + // Note: Depending on your route config, this might be 400 or 500 + assert.ok(result.status >= 400); + }); + + it('should reject request with invalid txPrebuild type', async function () { + const requestBody = { + txPrebuild: 'invalid_string_instead_of_object', // Wrong type! + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + // Make the request + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail validation + assert.ok(result.status >= 400); + }); + + it('should handle request with invalid apiVersion', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'invalid_version', // Invalid value + }; + + // Make the request + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail validation + assert.ok(result.status >= 400); + }); + + it('should handle request with malformed JSON', async function () { + // Make the request with malformed JSON + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send('{ invalid json ]'); + + // Should fail parsing + assert.ok(result.status >= 400); + }); + }); + + describe('Edge Cases', function () { + it('should handle empty txPrebuild object', async function () { + const requestBody = { + txPrebuild: {}, // Empty object + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const mockWallet = { + signTransaction: sinon.stub().rejects(new Error('Missing transaction data')), + }; + + const walletsGetStub = sinon.stub().resolves(mockWallet); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle empty txPrebuild gracefully + assert.ok(result.status >= 400); + }); + + it('should handle very long wallet ID', async function () { + const veryLongWalletId = 'a'.repeat(1000); + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: veryLongWalletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const walletsGetStub = sinon.stub().rejects(new Error('Invalid wallet ID')); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${veryLongWalletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle gracefully + assert.ok(result.status >= 400); + }); + + it('should handle wallet ID with special characters', async function () { + const specialCharWalletId = '../../../etc/passwd'; + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const walletsGetStub = sinon.stub().rejects(new Error('Invalid wallet ID')); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${encodeURIComponent(specialCharWalletId)}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle special characters safely + assert.ok(result.status >= 400); + }); + + it('should handle txRequestId in both txPrebuild and body', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + txRequestId: 'tx-req-in-prebuild', + }, + txRequestId: 'tx-req-in-body', // Also in body + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + const mockWallet = { + signTransaction: sinon.stub().resolves(mockFullySignedResponse), + }; + + const walletsGetStub = sinon.stub().resolves(mockWallet); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle gracefully (accept or reject consistently) + assert.ok(result.status === 200 || result.status >= 400); + }); + + it('should handle missing walletPassphrase (edge case for TSS)', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + // Missing walletPassphrase - might be required for TSS wallets + apiVersion: 'lite' as const, + }; + + const mockWallet = { + signTransaction: sinon.stub().rejects(new Error('Wallet passphrase required')), + }; + + const walletsGetStub = sinon.stub().resolves(mockWallet); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail if passphrase is required + assert.ok(result.status >= 400); + }); + }); + + describe('Response Validation Edge Cases', function () { + it('should reject response with missing required field in FullySignedTransactionResponse', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + // Mock returns invalid response (missing txHex) + const invalidResponse = {}; + + const mockWallet = { + signTransaction: sinon.stub().resolves(invalidResponse), + }; + + const walletsGetStub = sinon.stub().resolves(mockWallet); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Even if SDK returns 200, response should fail codec validation + // This depends on where validation happens + assert.ok(result.status === 200 || result.status >= 400); + + // If status is 200 but response is invalid, codec validation should catch it + if (result.status === 200) { + assert.throws(() => { + assertDecode(FullySignedTransactionResponse, result.body); + }); + } + }); + + it('should reject response with wrong type in txHex field', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + walletId: walletId, + }, + walletPassphrase: 'test_passphrase_12345', + apiVersion: 'lite' as const, + }; + + // Mock returns invalid response (txHex is number instead of string) + const invalidResponse = { + txHex: 12345, // Wrong type! + }; + + const mockWallet = { + signTransaction: sinon.stub().resolves(invalidResponse), + }; + + const walletsGetStub = sinon.stub().resolves(mockWallet); + const mockWallets = { get: walletsGetStub }; + const mockCoin = { wallets: sinon.stub().returns(mockWallets) }; + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/wallet/${walletId}/signtxtss`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Response codec validation should catch type mismatch + if (result.status === 200) { + assert.throws(() => { + assertDecode(FullySignedTransactionResponse, result.body); + }); + } + }); + }); + }); + describe('WalletTxSignTSSParams', function () { it('should validate params with required coin and id', function () { const validParams = { From ecc0db9d8fe5b7206b5738e08504525832099a5a Mon Sep 17 00:00:00 2001 From: Parv Tiwari Date: Mon, 13 Oct 2025 17:24:10 +0530 Subject: [PATCH 21/34] feat: lightning on chain intent change non compulsory sats per vbyte, numBlocks added if satsPerVbyte not present we are going to estimate it TICKET: BTC-2638 --- .../src/wallet/lightning.ts | 4 +- .../lightning/lightningWithdrawRoutes.test.ts | 40 ++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/modules/abstract-lightning/src/wallet/lightning.ts b/modules/abstract-lightning/src/wallet/lightning.ts index 0ce42b7fc4..a0c0a28c8c 100644 --- a/modules/abstract-lightning/src/wallet/lightning.ts +++ b/modules/abstract-lightning/src/wallet/lightning.ts @@ -165,7 +165,8 @@ export interface ILightningWallet { * On chain withdrawal * @param {LightningOnchainWithdrawParams} params - Withdraw parameters * @param {LightningOnchainRecipient[]} params.recipients - The recipients to pay - * @param {bigint} params.satsPerVbyte - Value for sats per virtual byte + * @param {bigint} [params.satsPerVbyte] - Optional value for sats per virtual byte. If not present, it will be estimated. + * @param {number} [params.numBlocks] - Target blocks for the transaction to be confirmed * @param {string} params.passphrase - The wallet passphrase * @param {string} [params.sequenceId] - Optional sequence ID for the respective withdraw transfer * @param {string} [params.comment] - Optional comment for the respective withdraw transfer @@ -337,6 +338,7 @@ export class LightningWallet implements ILightningWallet { onchainRequest: { recipients: params.recipients, satsPerVbyte: params.satsPerVbyte, + numBlocks: params.numBlocks, }, intentType: 'payment', }, diff --git a/modules/express/test/unit/lightning/lightningWithdrawRoutes.test.ts b/modules/express/test/unit/lightning/lightningWithdrawRoutes.test.ts index d3d95406b4..1263536b5b 100644 --- a/modules/express/test/unit/lightning/lightningWithdrawRoutes.test.ts +++ b/modules/express/test/unit/lightning/lightningWithdrawRoutes.test.ts @@ -32,6 +32,7 @@ describe('Lightning Withdraw Routes', () => { }, ], satsPerVbyte: '15', + numBlocks: 3, passphrase: 'password123', }; @@ -85,10 +86,11 @@ describe('Lightning Withdraw Routes', () => { // we decode the amountMsat string to bigint, it should be in bigint format when passed to payInvoice should(firstArg).have.property('recipients', decodedRecipients); should(firstArg).have.property('satsPerVbyte', BigInt(inputParams.satsPerVbyte)); + should(firstArg).have.property('numBlocks', inputParams.numBlocks); should(firstArg).have.property('passphrase', inputParams.passphrase); }); - it('should throw an error if the satsPerVbyte is missing in the request params', async () => { + it('should not throw an error if the satsPerVbyte and/or numBlocks is missing in the request params', async () => { const inputParams = { recipients: [ { @@ -99,15 +101,43 @@ describe('Lightning Withdraw Routes', () => { passphrase: 'password123', }; + const expectedResponse: LightningOnchainWithdrawResponse = { + txRequestState: 'delivered', + txRequestId: '123', + withdrawStatus: { + status: 'delivered', + txid: 'tx123', + }, + }; + + const onchainWithdrawStub = sinon.stub().resolves(expectedResponse); + const mockLightningWallet = { + withdrawOnchain: onchainWithdrawStub, + }; + + // Mock the module import + const proxyquire = require('proxyquire'); + const lightningWithdrawRoutes = proxyquire('../../../src/lightning/lightningWithdrawRoutes', { + '@bitgo/abstract-lightning': { + getLightningWallet: () => mockLightningWallet, + }, + }); + + const walletStub = {}; + const coinStub = { + wallets: () => ({ get: sinon.stub().resolves(walletStub) }), + }; + const stubBitgo = sinon.createStubInstance(BitGo as any, { coin: coinStub }); + const req = mockRequestObject({ params: { id: 'testWalletId', coin }, body: inputParams, + bitgo: stubBitgo, }); - req.bitgo = bitgo; - await should(handleLightningWithdraw(req)).be.rejectedWith( - 'Invalid request body for withdrawing on chain lightning balance' - ); + const result = await lightningWithdrawRoutes.handleLightningWithdraw(req); + + should(result).deepEqual(expectedResponse); }); it('should throw an error if the recipients is missing in the request params', async () => { From ca817a637015a33584fd68dbf5c36592b6a13608 Mon Sep 17 00:00:00 2001 From: Parv Tiwari Date: Tue, 14 Oct 2025 22:54:02 +0530 Subject: [PATCH 22/34] feat: bump public types TICKET: BTC-2638 --- modules/abstract-lightning/package.json | 2 +- modules/bitgo/package.json | 2 +- modules/express/encryptedPrivKeys.json | 2 +- modules/express/package.json | 2 +- modules/sdk-coin-sol/package.json | 2 +- modules/sdk-core/package.json | 2 +- yarn.lock | 8 ++++---- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/abstract-lightning/package.json b/modules/abstract-lightning/package.json index c962e8707e..e56e3b251b 100644 --- a/modules/abstract-lightning/package.json +++ b/modules/abstract-lightning/package.json @@ -39,7 +39,7 @@ ] }, "dependencies": { - "@bitgo/public-types": "5.29.0", + "@bitgo/public-types": "5.31.0", "@bitgo/sdk-core": "^36.12.0", "@bitgo/statics": "^58.4.0", "@bitgo/utxo-lib": "^11.11.0", diff --git a/modules/bitgo/package.json b/modules/bitgo/package.json index f1ffb6d4d1..86778d9d8a 100644 --- a/modules/bitgo/package.json +++ b/modules/bitgo/package.json @@ -138,7 +138,7 @@ "superagent": "^9.0.1" }, "devDependencies": { - "@bitgo/public-types": "5.29.0", + "@bitgo/public-types": "5.31.0", "@bitgo/sdk-opensslbytes": "^2.1.0", "@bitgo/sdk-test": "^9.1.4", "@openpgp/web-stream-tools": "0.0.14", diff --git a/modules/express/encryptedPrivKeys.json b/modules/express/encryptedPrivKeys.json index 431b389c97..fa9742e4d4 100644 --- a/modules/express/encryptedPrivKeys.json +++ b/modules/express/encryptedPrivKeys.json @@ -1,3 +1,3 @@ { - "61f039aad587c2000745c687373e0fa9": "{\"iv\":\"W14so0ZwIVOO/5y4cl3H3g==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"Jeck6aR6egU=\",\"ct\":\"GfqFuIoLp5jOTSTTB1byjWlW4D/8WBTr35P2UDjud0b0nA0WnJVAytbNkTlSIsRemhXQrcwhA74/BwZ14zvU4Frtmt3D3tvqKtb4i1ZVPREpcsIbp9V/RC+E5acNX6+bUCMXVZMEuYEGtkDxNRSIGsRZkAeTFlg=\"}" + "61f039aad587c2000745c687373e0fa9": "{\"iv\":\"/Gnh+Ip1G+IOhy+Cms+umQ==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"FYnd1xwReTw=\",\"ct\":\"vgnCvdJ1Z9sqeV6urYxNsscwnkB/6eSPsZhzaW4Cuc7RKEY1uWNlleR0Tjtd8nlQuhsA5UXFpOID3lHHHjPDvB+jWtRm08I2F+HNGYuklWG12vIiSrY2KnkYRJkyCghn5Pq3iEimQb9M2kkwj5wf4EtfAiz9jsY=\"}" } \ No newline at end of file diff --git a/modules/express/package.json b/modules/express/package.json index ca9b6df9cf..be029ec493 100644 --- a/modules/express/package.json +++ b/modules/express/package.json @@ -58,7 +58,7 @@ "superagent": "^9.0.1" }, "devDependencies": { - "@bitgo/public-types": "5.29.0", + "@bitgo/public-types": "5.31.0", "@bitgo/sdk-lib-mpc": "^10.8.1", "@bitgo/sdk-test": "^9.1.4", "@types/argparse": "^1.0.36", diff --git a/modules/sdk-coin-sol/package.json b/modules/sdk-coin-sol/package.json index 8a4c531655..d6afd3e5c5 100644 --- a/modules/sdk-coin-sol/package.json +++ b/modules/sdk-coin-sol/package.json @@ -40,7 +40,7 @@ ] }, "dependencies": { - "@bitgo/public-types": "5.29.0", + "@bitgo/public-types": "5.31.0", "@bitgo/sdk-core": "^36.12.0", "@bitgo/sdk-lib-mpc": "^10.8.1", "@bitgo/statics": "^58.4.0", diff --git a/modules/sdk-core/package.json b/modules/sdk-core/package.json index b6500e9d1b..ef7a5f0eb7 100644 --- a/modules/sdk-core/package.json +++ b/modules/sdk-core/package.json @@ -40,7 +40,7 @@ ] }, "dependencies": { - "@bitgo/public-types": "5.29.0", + "@bitgo/public-types": "5.31.0", "@bitgo/sdk-lib-mpc": "^10.8.1", "@bitgo/secp256k1": "^1.5.0", "@bitgo/sjcl": "^1.0.1", diff --git a/yarn.lock b/yarn.lock index 3248be8426..d47859977b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -934,10 +934,10 @@ "@scure/base" "1.1.5" micro-eth-signer "0.7.2" -"@bitgo/public-types@5.29.0": - version "5.29.0" - resolved "https://registry.npmjs.org/@bitgo/public-types/-/public-types-5.29.0.tgz#4ceae8cf837359b0cb8808f417aef64ae2f52839" - integrity sha512-E1zKNPwDmMKoJq/WC0Igg4ftdGX5DUMu49hi1vqjkdMebFliHRrPiVTSiGwDkFj7kwZbaNORNMqS/Qv4WugV0g== +"@bitgo/public-types@5.31.0": + version "5.31.0" + resolved "https://registry.npmjs.org/@bitgo/public-types/-/public-types-5.31.0.tgz#1af37545bdaaf6bb65de6a9c47cb38817d16472c" + integrity sha512-4uiFZHcwVPwfDKLG/lNPy8zIfp8esVxAjXLWrx5LUHZBKguphWWgmx6RzP2LwFr6H4GZ7pxDO3xr7AF0RRL3Ug== dependencies: fp-ts "^2.0.0" io-ts "npm:@bitgo-forks/io-ts@2.1.4" From df6850bc1b6a86022566aa7d7bd9af81ac712180 Mon Sep 17 00:00:00 2001 From: Luis Covarrubias Date: Fri, 10 Oct 2025 15:59:07 -0700 Subject: [PATCH 23/34] feat: disallow EVM_COMPATIBLE_WP feature for OFC coin Ticket: BTC-0 TICKET: BTC-0 --- modules/statics/src/ofc.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/statics/src/ofc.ts b/modules/statics/src/ofc.ts index 52b7ec1bbc..4c92b40fb3 100644 --- a/modules/statics/src/ofc.ts +++ b/modules/statics/src/ofc.ts @@ -35,7 +35,9 @@ const DISALLOWED_FEATURES = [ CoinFeature.CHILD_PAYS_FOR_PARENT, CoinFeature.PAYGO, CoinFeature.SUPPORTS_TOKENS, + // OFC inherits features from the base asset but the features are not always applicable to OFC CoinFeature.SHARED_EVM_SIGNING, + CoinFeature.EVM_COMPATIBLE_WP, ]; const REQUIRED_FEATURES = [CoinFeature.ACCOUNT_MODEL, CoinFeature.REQUIRES_BIG_NUMBER]; From d99f3bf70807910f0eda7e51c3edff5e55230001 Mon Sep 17 00:00:00 2001 From: Lokesh Chandra Date: Wed, 15 Oct 2025 09:27:38 +0530 Subject: [PATCH 24/34] docs(express): added js doc Ticket: WP-6367 --- modules/express/src/typedRoutes/api/v1/acceptShare.ts | 1 + modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts | 1 + .../express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts | 1 + modules/express/src/typedRoutes/api/v1/createLocalKeyChain.ts | 1 + modules/express/src/typedRoutes/api/v1/deriveLocalKeyChain.ts | 1 + modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts | 1 + modules/express/src/typedRoutes/api/v1/pendingApproval.ts | 1 + modules/express/src/typedRoutes/api/v1/signTransaction.ts | 1 + modules/express/src/typedRoutes/api/v1/simpleCreate.ts | 1 + modules/express/src/typedRoutes/api/v2/coinSignTx.ts | 1 + modules/express/src/typedRoutes/api/v2/keychainLocal.ts | 1 + modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts | 1 + modules/express/src/typedRoutes/api/v2/lightningState.ts | 1 + modules/express/src/typedRoutes/api/v2/unlockWallet.ts | 1 + modules/express/src/typedRoutes/api/v2/verifyAddress.ts | 1 + modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts | 1 + modules/express/src/typedRoutes/api/v2/walletSignTx.ts | 1 + modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts | 1 + 18 files changed, 18 insertions(+) diff --git a/modules/express/src/typedRoutes/api/v1/acceptShare.ts b/modules/express/src/typedRoutes/api/v1/acceptShare.ts index bf0cd75ad9..1fc74f9147 100644 --- a/modules/express/src/typedRoutes/api/v1/acceptShare.ts +++ b/modules/express/src/typedRoutes/api/v1/acceptShare.ts @@ -22,6 +22,7 @@ export const AcceptShareRequestBody = { * When a wallet is shared with a user, they need to accept the share to gain access * to the wallet according to the permissions granted by the sharing user. * + * @tag express * @operationId express.v1.wallet.acceptShare */ export const PostAcceptShare = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts b/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts index 4de0160d9c..3f48390030 100644 --- a/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts +++ b/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts @@ -71,6 +71,7 @@ export const ConsolidateUnspentsResponse = t.array( * multiple inputs to a single output. This is useful for reducing the number of UTXOs in a wallet, * which can improve performance and reduce transaction fees. * + * @tag express * @operationId express.v1.wallet.consolidateunspents */ export const PutConsolidateUnspents = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts b/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts index bfd51364ee..880522147f 100644 --- a/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts +++ b/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts @@ -59,6 +59,7 @@ export const ConstructPendingApprovalTxResponse = t.type({ * For transaction request type approvals, either a wallet passphrase or xprv must be provided to sign the transaction. * You can optionally specify fee-related parameters to customize the transaction fee. * + * @tag express * @operationId express.v1.pendingapproval.constructTx */ export const PutConstructPendingApprovalTx = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/createLocalKeyChain.ts b/modules/express/src/typedRoutes/api/v1/createLocalKeyChain.ts index b1cfdafc10..ef4a9475dd 100644 --- a/modules/express/src/typedRoutes/api/v1/createLocalKeyChain.ts +++ b/modules/express/src/typedRoutes/api/v1/createLocalKeyChain.ts @@ -33,6 +33,7 @@ export const CreateLocalKeyChainResponse = t.type({ * For security reasons, it is highly recommended that you encrypt and destroy * the original xprv immediately to prevent theft. * + * @tag express * @operationId express.v1.keychain.local */ export const PostCreateLocalKeyChain = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/deriveLocalKeyChain.ts b/modules/express/src/typedRoutes/api/v1/deriveLocalKeyChain.ts index ef8f649402..eaa4112c73 100644 --- a/modules/express/src/typedRoutes/api/v1/deriveLocalKeyChain.ts +++ b/modules/express/src/typedRoutes/api/v1/deriveLocalKeyChain.ts @@ -44,6 +44,7 @@ export const DeriveLocalKeyChainResponse = t.type({ * both the derived xprv and xpub are returned. If xpub is provided, only the * derived xpub is returned. * + * @tag express * @operationId express.v1.keychain.derive */ export const PostDeriveLocalKeyChain = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts b/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts index 54bd94e71a..576b5e4a89 100644 --- a/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts +++ b/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts @@ -59,6 +59,7 @@ export const FanoutUnspentsResponse = t.type({ * multiple inputs to multiple outputs. This is useful for increasing the number of UTXOs * in a wallet, which can improve transaction parallelization. * + * @tag express * @operationId express.v1.wallet.fanoutunspents */ export const PutFanoutUnspents = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/pendingApproval.ts b/modules/express/src/typedRoutes/api/v1/pendingApproval.ts index 9fe2131a4d..7490377f86 100644 --- a/modules/express/src/typedRoutes/api/v1/pendingApproval.ts +++ b/modules/express/src/typedRoutes/api/v1/pendingApproval.ts @@ -28,6 +28,7 @@ export const pendingApprovalRequestBody = { * Handles various approval scenarios including transaction approvals, policy rule changes, * and user change requests. * + * @tag express * @operationId express.v1.pendingapprovals */ diff --git a/modules/express/src/typedRoutes/api/v1/signTransaction.ts b/modules/express/src/typedRoutes/api/v1/signTransaction.ts index 5a99d34f68..2145fb8f71 100644 --- a/modules/express/src/typedRoutes/api/v1/signTransaction.ts +++ b/modules/express/src/typedRoutes/api/v1/signTransaction.ts @@ -31,6 +31,7 @@ export const signTransactionRequestBody = { * signTransaction * Sign a previously created transaction with a keychain * + * @tag express * @operationId express.v1.wallet.signTransaction */ export const PostSignTransaction = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v1/simpleCreate.ts b/modules/express/src/typedRoutes/api/v1/simpleCreate.ts index b3f47f7ecf..a1928f68ba 100644 --- a/modules/express/src/typedRoutes/api/v1/simpleCreate.ts +++ b/modules/express/src/typedRoutes/api/v1/simpleCreate.ts @@ -31,6 +31,7 @@ export const SimpleCreateRequestBody = { * 4. Creates the BitGo key on the service * 5. Creates the wallet on BitGo with the 3 public keys above * + * @tag express * @operationId express.v1.wallet.simplecreate */ export const PostSimpleCreate = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/coinSignTx.ts b/modules/express/src/typedRoutes/api/v2/coinSignTx.ts index b6e15079e2..85c2c68c84 100644 --- a/modules/express/src/typedRoutes/api/v2/coinSignTx.ts +++ b/modules/express/src/typedRoutes/api/v2/coinSignTx.ts @@ -137,6 +137,7 @@ export const CoinSignTxResponse = { * - pubKeys: Public keys for multi-signature transactions * - isEvmBasedCrossChainRecovery: For EVM cross-chain recovery * + * @tag express * @operationId express.v2.coin.signtx */ export const PostCoinSignTx = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/keychainLocal.ts b/modules/express/src/typedRoutes/api/v2/keychainLocal.ts index a903755057..2a04acb235 100644 --- a/modules/express/src/typedRoutes/api/v2/keychainLocal.ts +++ b/modules/express/src/typedRoutes/api/v2/keychainLocal.ts @@ -33,6 +33,7 @@ export const KeychainLocalResponse = { * * For security reasons, it is highly recommended that you encrypt and destroy the original xprv immediately to prevent theft. * + * @tag express * @operationId express.keychain.local */ export const PostKeychainLocal = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts b/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts index bd40c98c67..d8ed0a64fb 100644 --- a/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts +++ b/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts @@ -36,6 +36,7 @@ export const LightningInitWalletResponse = { * Lightning - This is only used for self-custody lightning. Initialize a newly created Lightning Network Daemon (LND) for the first time. * Returns the updated wallet with the encrypted admin macaroon in the `coinSpecific` response field. * + * @tag express * @operationId express.lightning.initWallet */ export const PostLightningInitWallet = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/lightningState.ts b/modules/express/src/typedRoutes/api/v2/lightningState.ts index 5c38159052..fea0e823cc 100644 --- a/modules/express/src/typedRoutes/api/v2/lightningState.ts +++ b/modules/express/src/typedRoutes/api/v2/lightningState.ts @@ -32,6 +32,7 @@ export const LightningStateResponse = { * * This is only used for self-custody lightning. Get the current state of the lightning node. * + * @tag express * @operationId express.lightning.getState */ export const GetLightningState = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/unlockWallet.ts b/modules/express/src/typedRoutes/api/v2/unlockWallet.ts index 722428adf3..2f655c20a3 100644 --- a/modules/express/src/typedRoutes/api/v2/unlockWallet.ts +++ b/modules/express/src/typedRoutes/api/v2/unlockWallet.ts @@ -42,6 +42,7 @@ export const UnlockLightningWalletResponse = { * * This is only used for self-custody lightning. Unlock the Lightning Network Daemon (LND) node with the given wallet password. * + * @tag express * @operationId express.lightning.unlockWallet */ export const PostUnlockLightningWallet = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/verifyAddress.ts b/modules/express/src/typedRoutes/api/v2/verifyAddress.ts index 725cf524fa..f8a8206af2 100644 --- a/modules/express/src/typedRoutes/api/v2/verifyAddress.ts +++ b/modules/express/src/typedRoutes/api/v2/verifyAddress.ts @@ -30,6 +30,7 @@ export const VerifyAddressV2Body = { * Returns whether the address is valid for the specified coin. * For UTXO coins, an optional legacy script hash flag can be provided to allow previous script hash versions. * + * @tag express * @operationId express.verifycoinaddress */ export const PostVerifyCoinAddress = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts b/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts index 290a1eb4d8..9525633528 100644 --- a/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts +++ b/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts @@ -63,6 +63,7 @@ export const RecoverTokenResponse = t.type({ * * Note: This endpoint is only supported for ETH family wallets. * + * @tag express * @operationId express.v2.wallet.recovertoken */ export const PostWalletRecoverToken = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/walletSignTx.ts b/modules/express/src/typedRoutes/api/v2/walletSignTx.ts index c378f7970b..d7d9c5553d 100644 --- a/modules/express/src/typedRoutes/api/v2/walletSignTx.ts +++ b/modules/express/src/typedRoutes/api/v2/walletSignTx.ts @@ -155,6 +155,7 @@ export const WalletSignTxResponse = { * - sequenceId: Sequence ID for transactions * - isEvmBasedCrossChainRecovery: For EVM cross-chain recovery * + * @tag express * @operationId express.v2.wallet.signtx */ export const PostWalletSignTx = httpRoute({ diff --git a/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts b/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts index 1a8249dc3f..5c874ba15b 100644 --- a/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts +++ b/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts @@ -157,6 +157,7 @@ export const WalletTxSignTSSResponse = { * - sequenceId: Sequence ID for transactions * - isEvmBasedCrossChainRecovery: For EVM cross-chain recovery * + * @tag express * @operationId express.v2.wallet.signtxtss */ export const PostWalletTxSignTSS = httpRoute({ From 9672c67a40bf5f9db5646ccccce3b1e80bbbdb20 Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Wed, 15 Oct 2025 09:01:03 +0530 Subject: [PATCH 25/34] fix(sdk-coin-canton): fix issue with beta dependency bumps Ticket: COIN-6061 --- modules/sdk-coin-canton/package.json | 14 +++++++ .../sdk-coin-canton/resources/hash/hash.js | 3 +- .../resources/proto/damlTransaction.js | 8 ++-- .../resources/proto/damlTransactionNode.js | 6 +-- .../proto/damlTransactionNodeSeed.js | 4 +- .../resources/proto/metadata.js | 10 ++--- .../metadata/metadataGlobalKeyMappingEntry.js | 8 ++-- .../proto/metadata/metadataInputContract.js | 6 +-- .../proto/metadata/metadataSubmitterInfo.js | 4 +- .../resources/proto/node/empty.js | 4 +- .../resources/proto/node/globalKey.js | 8 ++-- .../resources/proto/node/identifier.js | 4 +- .../resources/proto/node/node.js | 24 +++++++---- .../resources/proto/node/timestamp.js | 6 +-- .../resources/proto/node/value.js | 42 ++++++++++++------- .../resources/proto/preparedTransaction.js | 8 ++-- 16 files changed, 98 insertions(+), 61 deletions(-) diff --git a/modules/sdk-coin-canton/package.json b/modules/sdk-coin-canton/package.json index 18b4880458..6618a885f9 100644 --- a/modules/sdk-coin-canton/package.json +++ b/modules/sdk-coin-canton/package.json @@ -4,6 +4,20 @@ "description": "BitGo SDK coin library for Canton", "main": "./dist/src/index.js", "types": "./dist/src/index.d.ts", + "exports": { + ".": { + "require": "./dist/src/index.js", + "types": "./dist/src/index.d.ts" + }, + "./resources/proto/preparedTransaction": { + "require": "./dist/resources/proto/preparedTransaction.js", + "types": "./dist/resources/proto/preparedTransaction.d.ts" + }, + "./resources/hash/hash": { + "require": "./dist/resources/hash/hash.js", + "types": "./dist/resources/hash/hash.d.ts" + } + }, "scripts": { "build": "npm run prepare", "build-ts": "yarn tsc --build --incremental --verbose .", diff --git a/modules/sdk-coin-canton/resources/hash/hash.js b/modules/sdk-coin-canton/resources/hash/hash.js index 0044c46744..e1cb0102a4 100644 --- a/modules/sdk-coin-canton/resources/hash/hash.js +++ b/modules/sdk-coin-canton/resources/hash/hash.js @@ -292,6 +292,7 @@ async function encodePreparedTransaction(preparedTransaction) { const metadataHash = await hashMetadata(preparedTransaction.metadata); return mkByteArray(PREPARED_TRANSACTION_HASH_PURPOSE, HASHING_SCHEME_VERSION, transactionHash, metadataHash); } -export async function computePreparedTransaction(preparedTransaction) { +async function computePreparedTransaction(preparedTransaction) { return sha256(await encodePreparedTransaction(preparedTransaction)); } +module.exports.computePreparedTransaction = computePreparedTransaction; diff --git a/modules/sdk-coin-canton/resources/proto/damlTransaction.js b/modules/sdk-coin-canton/resources/proto/damlTransaction.js index 1ace6b6ec6..4f72d12c10 100644 --- a/modules/sdk-coin-canton/resources/proto/damlTransaction.js +++ b/modules/sdk-coin-canton/resources/proto/damlTransaction.js @@ -1,6 +1,6 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { DamlTransaction_Node } from './damlTransactionNode.js'; -import { DamlTransaction_NodeSeed } from './damlTransactionNodeSeed.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { DamlTransaction_Node } = require('./damlTransactionNode.js'); +const { DamlTransaction_NodeSeed } = require('./damlTransactionNodeSeed.js'); class DamlTransaction$Type extends MessageType { constructor() { @@ -97,4 +97,4 @@ class DamlTransaction$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.DamlTransaction */ -export const DamlTransaction = new DamlTransaction$Type(); +module.exports.DamlTransaction = new DamlTransaction$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/damlTransactionNode.js b/modules/sdk-coin-canton/resources/proto/damlTransactionNode.js index 840fc903a1..720aa5d1a3 100644 --- a/modules/sdk-coin-canton/resources/proto/damlTransactionNode.js +++ b/modules/sdk-coin-canton/resources/proto/damlTransactionNode.js @@ -1,5 +1,5 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { Node } from './node/node.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { Node } = require('./node/node.js'); class DamlTransaction_Node$Type extends MessageType { constructor() { @@ -68,4 +68,4 @@ class DamlTransaction_Node$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.DamlTransaction.Node */ -export const DamlTransaction_Node = new DamlTransaction_Node$Type(); +module.exports.DamlTransaction_Node = new DamlTransaction_Node$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/damlTransactionNodeSeed.js b/modules/sdk-coin-canton/resources/proto/damlTransactionNodeSeed.js index fa14cff7cd..ada26a3387 100644 --- a/modules/sdk-coin-canton/resources/proto/damlTransactionNodeSeed.js +++ b/modules/sdk-coin-canton/resources/proto/damlTransactionNodeSeed.js @@ -1,4 +1,4 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); class DamlTransaction_NodeSeed$Type extends MessageType { constructor() { @@ -53,4 +53,4 @@ class DamlTransaction_NodeSeed$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.DamlTransaction.NodeSeed */ -export const DamlTransaction_NodeSeed = new DamlTransaction_NodeSeed$Type(); +module.exports.DamlTransaction_NodeSeed = new DamlTransaction_NodeSeed$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/metadata.js b/modules/sdk-coin-canton/resources/proto/metadata.js index d2d529f21a..ccb63496aa 100644 --- a/modules/sdk-coin-canton/resources/proto/metadata.js +++ b/modules/sdk-coin-canton/resources/proto/metadata.js @@ -1,7 +1,7 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { Metadata_GlobalKeyMappingEntry } from './metadata/metadataGlobalKeyMappingEntry.js'; -import { Metadata_InputContract } from './metadata/metadataInputContract.js'; -import { Metadata_SubmitterInfo } from './metadata/metadataSubmitterInfo.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { Metadata_GlobalKeyMappingEntry } = require('./metadata/metadataGlobalKeyMappingEntry.js'); +const { Metadata_InputContract } = require('./metadata/metadataInputContract.js'); +const { Metadata_SubmitterInfo } = require('./metadata/metadataSubmitterInfo.js'); class Metadata$Type extends MessageType { constructor() { @@ -186,4 +186,4 @@ class Metadata$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.Metadata */ -export const Metadata = new Metadata$Type(); +module.exports.Metadata = new Metadata$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/metadata/metadataGlobalKeyMappingEntry.js b/modules/sdk-coin-canton/resources/proto/metadata/metadataGlobalKeyMappingEntry.js index e3fde10dfc..33ec86b35d 100644 --- a/modules/sdk-coin-canton/resources/proto/metadata/metadataGlobalKeyMappingEntry.js +++ b/modules/sdk-coin-canton/resources/proto/metadata/metadataGlobalKeyMappingEntry.js @@ -1,6 +1,6 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { Value } from '../node/value.js'; -import { GlobalKey } from '../node/globalKey.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { Value } = require('../node/value.js'); +const { GlobalKey } = require('../node/globalKey.js'); class Metadata_GlobalKeyMappingEntry$Type extends MessageType { constructor() { @@ -50,4 +50,4 @@ class Metadata_GlobalKeyMappingEntry$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.Metadata.GlobalKeyMappingEntry */ -export const Metadata_GlobalKeyMappingEntry = new Metadata_GlobalKeyMappingEntry$Type(); +module.exports.Metadata_GlobalKeyMappingEntry = new Metadata_GlobalKeyMappingEntry$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/metadata/metadataInputContract.js b/modules/sdk-coin-canton/resources/proto/metadata/metadataInputContract.js index 0ff427e1ba..3310798d55 100644 --- a/modules/sdk-coin-canton/resources/proto/metadata/metadataInputContract.js +++ b/modules/sdk-coin-canton/resources/proto/metadata/metadataInputContract.js @@ -1,5 +1,5 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { Create } from '../node/node.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { Create } = require('../node/node.js'); class Metadata_InputContract$Type extends MessageType { constructor() { @@ -77,4 +77,4 @@ class Metadata_InputContract$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.Metadata.InputContract */ -export const Metadata_InputContract = new Metadata_InputContract$Type(); +module.exports.Metadata_InputContract = new Metadata_InputContract$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/metadata/metadataSubmitterInfo.js b/modules/sdk-coin-canton/resources/proto/metadata/metadataSubmitterInfo.js index 5f55d5df94..cd3dbb158d 100644 --- a/modules/sdk-coin-canton/resources/proto/metadata/metadataSubmitterInfo.js +++ b/modules/sdk-coin-canton/resources/proto/metadata/metadataSubmitterInfo.js @@ -1,4 +1,4 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); class Metadata_SubmitterInfo$Type extends MessageType { constructor() { @@ -59,4 +59,4 @@ class Metadata_SubmitterInfo$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.Metadata.SubmitterInfo */ -export const Metadata_SubmitterInfo = new Metadata_SubmitterInfo$Type(); +module.exports.Metadata_SubmitterInfo = new Metadata_SubmitterInfo$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/node/empty.js b/modules/sdk-coin-canton/resources/proto/node/empty.js index cf6ba063bb..5e112e65c0 100644 --- a/modules/sdk-coin-canton/resources/proto/node/empty.js +++ b/modules/sdk-coin-canton/resources/proto/node/empty.js @@ -1,4 +1,4 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial } from '@protobuf-ts/runtime'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial } = require('@protobuf-ts/runtime'); class Empty$Type extends MessageType { constructor() { @@ -33,4 +33,4 @@ class Empty$Type extends MessageType { /** * @generated MessageType for protobuf message google.protobuf.Empty */ -export const Empty = new Empty$Type(); +module.exports.Empty = new Empty$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/node/globalKey.js b/modules/sdk-coin-canton/resources/proto/node/globalKey.js index 9a8d0e594b..d2309a2635 100644 --- a/modules/sdk-coin-canton/resources/proto/node/globalKey.js +++ b/modules/sdk-coin-canton/resources/proto/node/globalKey.js @@ -1,6 +1,6 @@ -import { MessageType, reflectionMergePartial, UnknownFieldHandler, WireType } from '@protobuf-ts/runtime'; -import { Value } from './value.js'; -import { Identifier } from './identifier.js'; +const { MessageType, reflectionMergePartial, UnknownFieldHandler, WireType } = require('@protobuf-ts/runtime'); +const { Value } = require('./value.js'); +const { Identifier } = require('./identifier.js'); class GlobalKey$Type extends MessageType { constructor() { @@ -78,4 +78,4 @@ class GlobalKey$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.GlobalKey */ -export const GlobalKey = new GlobalKey$Type(); +module.exports.GlobalKey = new GlobalKey$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/node/identifier.js b/modules/sdk-coin-canton/resources/proto/node/identifier.js index 4522d3dabd..4dfd6f5dee 100644 --- a/modules/sdk-coin-canton/resources/proto/node/identifier.js +++ b/modules/sdk-coin-canton/resources/proto/node/identifier.js @@ -1,4 +1,4 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); class Identifier$Type extends MessageType { constructor() { @@ -70,4 +70,4 @@ class Identifier$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.Identifier */ -export const Identifier = new Identifier$Type(); +module.exports.Identifier = new Identifier$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/node/node.js b/modules/sdk-coin-canton/resources/proto/node/node.js index 9cd862dc55..ebc3d3fb8c 100644 --- a/modules/sdk-coin-canton/resources/proto/node/node.js +++ b/modules/sdk-coin-canton/resources/proto/node/node.js @@ -1,6 +1,6 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { Value } from './value.js'; -import { Identifier } from './identifier.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { Value } = require('./value.js'); +const { Identifier } = require('./identifier.js'); class Fetch$Type extends MessageType { constructor() { @@ -146,7 +146,7 @@ class Fetch$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.transaction.v1.Fetch */ -export const Fetch = new Fetch$Type(); +const Fetch = new Fetch$Type(); // @generated message type with reflection information, may provide speed optimized methods class Exercise$Type extends MessageType { constructor() { @@ -367,7 +367,7 @@ class Exercise$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.transaction.v1.Exercise */ -export const Exercise = new Exercise$Type(); +const Exercise = new Exercise$Type(); // @generated message type with reflection information, may provide speed optimized methods class Create$Type extends MessageType { constructor() { @@ -490,7 +490,7 @@ class Create$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.transaction.v1.Create */ -export const Create = new Create$Type(); +const Create = new Create$Type(); // @generated message type with reflection information, may provide speed optimized methods class Rollback$Type extends MessageType { constructor() { @@ -540,7 +540,7 @@ class Rollback$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.transaction.v1.Rollback */ -export const Rollback = new Rollback$Type(); +const Rollback = new Rollback$Type(); // @generated message type with reflection information, may provide speed optimized methods class Node$Type extends MessageType { constructor() { @@ -653,4 +653,12 @@ class Node$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.interactive.transaction.v1.Node */ -export const Node = new Node$Type(); +const Node = new Node$Type(); + +module.exports = { + Fetch, + Exercise, + Create, + Rollback, + Node, +}; diff --git a/modules/sdk-coin-canton/resources/proto/node/timestamp.js b/modules/sdk-coin-canton/resources/proto/node/timestamp.js index 15462022da..3331ad23e7 100644 --- a/modules/sdk-coin-canton/resources/proto/node/timestamp.js +++ b/modules/sdk-coin-canton/resources/proto/node/timestamp.js @@ -1,11 +1,11 @@ -import { +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType, PbLong, typeofJsonValue, -} from '@protobuf-ts/runtime'; +} = require('@protobuf-ts/runtime'); class Timestamp$Type extends MessageType { constructor() { @@ -142,4 +142,4 @@ class Timestamp$Type extends MessageType { /** * @generated MessageType for protobuf message google.protobuf.Timestamp */ -export const Timestamp = new Timestamp$Type(); +module.exports.Timestamp = new Timestamp$Type(); diff --git a/modules/sdk-coin-canton/resources/proto/node/value.js b/modules/sdk-coin-canton/resources/proto/node/value.js index f85a871f52..aff71a9ad5 100644 --- a/modules/sdk-coin-canton/resources/proto/node/value.js +++ b/modules/sdk-coin-canton/resources/proto/node/value.js @@ -1,6 +1,6 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { Empty } from './empty.js'; -import { Identifier } from './identifier.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { Empty } = require('./empty.js'); +const { Identifier } = require('./identifier.js'); class Value$Type extends MessageType { constructor() { @@ -289,7 +289,7 @@ class Value$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.Value */ -export const Value = new Value$Type(); +const Value = new Value$Type(); class Optional$Type extends MessageType { constructor() { @@ -330,7 +330,7 @@ class Optional$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.Optional */ -export const Optional = new Optional$Type(); +const Optional = new Optional$Type(); class List$Type extends MessageType { constructor() { @@ -380,7 +380,7 @@ class List$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.List */ -export const List = new List$Type(); +const List = new List$Type(); class TextMap$Type extends MessageType { constructor() { @@ -434,7 +434,7 @@ class TextMap$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.TextMap */ -export const TextMap = new TextMap$Type(); +const TextMap = new TextMap$Type(); class TextMap_Entry$Type extends MessageType { constructor() { @@ -484,7 +484,7 @@ class TextMap_Entry$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.TextMap.Entry */ -export const TextMap_Entry = new TextMap_Entry$Type(); +const TextMap_Entry = new TextMap_Entry$Type(); class GenMap$Type extends MessageType { constructor() { @@ -538,7 +538,7 @@ class GenMap$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.GenMap */ -export const GenMap = new GenMap$Type(); +const GenMap = new GenMap$Type(); class GenMap_Entry$Type extends MessageType { constructor() { @@ -588,7 +588,7 @@ class GenMap_Entry$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.GenMap.Entry */ -export const GenMap_Entry = new GenMap_Entry$Type(); +const GenMap_Entry = new GenMap_Entry$Type(); class Record$Type extends MessageType { constructor() { @@ -649,7 +649,7 @@ class Record$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.Record */ -export const Record = new Record$Type(); +const Record = new Record$Type(); class RecordField$Type extends MessageType { constructor() { @@ -704,7 +704,7 @@ class RecordField$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.RecordField */ -export const RecordField = new RecordField$Type(); +const RecordField = new RecordField$Type(); class Variant$Type extends MessageType { constructor() { @@ -766,7 +766,7 @@ class Variant$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.Variant */ -export const Variant = new Variant$Type(); +const Variant = new Variant$Type(); class Enum$Type extends MessageType { constructor() { @@ -821,4 +821,18 @@ class Enum$Type extends MessageType { /** * @generated MessageType for protobuf message com.daml.ledger.api.v2.Enum */ -export const Enum = new Enum$Type(); +const Enum = new Enum$Type(); + +module.exports = { + Value, + Optional, + List, + TextMap, + TextMap_Entry, + GenMap, + GenMap_Entry, + Record, + RecordField, + Variant, + Enum, +}; diff --git a/modules/sdk-coin-canton/resources/proto/preparedTransaction.js b/modules/sdk-coin-canton/resources/proto/preparedTransaction.js index d819280050..d621f17bd2 100644 --- a/modules/sdk-coin-canton/resources/proto/preparedTransaction.js +++ b/modules/sdk-coin-canton/resources/proto/preparedTransaction.js @@ -1,6 +1,6 @@ -import { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } from '@protobuf-ts/runtime'; -import { DamlTransaction } from './damlTransaction.js'; -import { Metadata } from './metadata.js'; +const { MessageType, UnknownFieldHandler, reflectionMergePartial, WireType } = require('@protobuf-ts/runtime'); +const { DamlTransaction } = require('./damlTransaction.js'); +const { Metadata } = require('./metadata.js'); class PreparedTransaction$Type extends MessageType { constructor() { @@ -63,4 +63,4 @@ class PreparedTransaction$Type extends MessageType { } } -export const PreparedTransaction = new PreparedTransaction$Type(); +module.exports.PreparedTransaction = new PreparedTransaction$Type(); From c079baef3d8fcc3041f1d940b3439741d6dce0cb Mon Sep 17 00:00:00 2001 From: Lokesh Chandra Date: Wed, 15 Oct 2025 10:29:18 +0530 Subject: [PATCH 26/34] test(express): added error and edge case tests Ticket: WP-6328 --- .../test/unit/typedRoutes/coinSignTx.ts | 360 ++++++++++++++++++ 1 file changed, 360 insertions(+) diff --git a/modules/express/test/unit/typedRoutes/coinSignTx.ts b/modules/express/test/unit/typedRoutes/coinSignTx.ts index d8d0048c36..6a59928ee2 100644 --- a/modules/express/test/unit/typedRoutes/coinSignTx.ts +++ b/modules/express/test/unit/typedRoutes/coinSignTx.ts @@ -277,6 +277,366 @@ describe('CoinSignTx codec tests', function () { assert.strictEqual(coinStub.calledOnceWith(coin), true); assert.strictEqual(mockCoin.signTransaction.calledOnce, true); }); + + describe('Error Cases', function () { + it('should handle invalid coin error', async function () { + const invalidCoin = 'invalid_coin_xyz'; + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + // Stub coin() to throw error for invalid coin + sinon.stub(BitGo.prototype, 'coin').throws(new Error(`Coin ${invalidCoin} is not supported`)); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${invalidCoin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify error response + assert.strictEqual(result.status, 500); + result.body.should.have.property('error'); + }); + + it('should handle signTransaction failure', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'invalid_private_key', + }; + + // Create mock coin where signTransaction fails + const mockCoin = { + signTransaction: sinon.stub().rejects(new Error('Invalid private key')), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify error response + assert.strictEqual(result.status, 500); + result.body.should.have.property('error'); + }); + + it('should handle missing transaction data error', async function () { + const requestBody = { + txPrebuild: {}, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + // Create mock coin where signTransaction fails due to missing data + const mockCoin = { + signTransaction: sinon.stub().rejects(new Error('Missing transaction data')), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + // Make the request to Express + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Verify error response + assert.strictEqual(result.status, 500); + result.body.should.have.property('error'); + }); + }); + + describe('Invalid Request Body', function () { + it('should reject request with empty body', async function () { + // Make the request with empty body + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send({}); + + // io-ts validation should fail or SDK should reject + // Note: Depending on route config, this might be 400 or 500 + assert.ok(result.status >= 400); + }); + + it('should reject request with invalid txPrebuild type', async function () { + const requestBody = { + txPrebuild: 'invalid_string_instead_of_object', // Wrong type! + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + // Make the request + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail validation + assert.ok(result.status >= 400); + }); + + it('should reject request with invalid field types', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 12345, // Number instead of string! + isLastSignature: 'true', // String instead of boolean! + }; + + // Make the request + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail validation + assert.ok(result.status >= 400); + }); + + it('should handle request with malformed JSON', async function () { + // Make the request with malformed JSON + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send('{ invalid json ]'); + + // Should fail parsing + assert.ok(result.status >= 400); + }); + }); + + describe('Edge Cases', function () { + it('should handle empty txPrebuild object', async function () { + const requestBody = { + txPrebuild: {}, // Empty object + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + const mockCoin = { + signTransaction: sinon.stub().rejects(new Error('Missing transaction data')), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle empty txPrebuild gracefully + assert.ok(result.status >= 400); + }); + + it('should handle very long private key', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'x'.repeat(10000), // Extremely long private key + }; + + const mockCoin = { + signTransaction: sinon.stub().rejects(new Error('Invalid private key format')), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle gracefully + assert.ok(result.status >= 400); + }); + + it('should handle missing prv for certain transaction types', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + // Missing prv - some transaction types might not require it + }; + + const mockCoin = { + signTransaction: sinon.stub().rejects(new Error('Private key required for signing')), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail if prv is required + assert.ok(result.status >= 400); + }); + + it('should handle coin parameter with special characters', async function () { + const specialCoin = '../../../etc/passwd'; + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + sinon.stub(BitGo.prototype, 'coin').throws(new Error('Invalid coin identifier')); + + const result = await agent + .post(`/api/v2/${encodeURIComponent(specialCoin)}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle special characters safely + assert.ok(result.status >= 400); + }); + + it('should handle request with both txHex and txBase64', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + txBase64: + 'AQAAAAFz2JT3Xvjk8jKcYcMrKR8tPMRm5+/Q6J2sMgtz7QDpAAAAAAD+////AoCWmAAAAAAAGXapFJA29QPQaHHwR3Uriuhw2A6tHkPgiKwAAAAAAAEBH9cQ2QAAAAAAAXapFCf/zr8zPrMftHGIRsOt0Cf+wdOyiKwA', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + const mockCoin = { + signTransaction: sinon.stub().resolves(mockFullySignedResponse), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should handle gracefully (accept or reject consistently) + assert.ok(result.status === 200 || result.status >= 400); + }); + + it('should handle request with invalid signingStep value', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + signingStep: 'invalidStep', // Not one of: signerNonce, signerSignature, cosignerNonce + }; + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Should fail validation + assert.ok(result.status >= 400); + }); + }); + + describe('Response Validation Edge Cases', function () { + it('should reject response with missing required field in FullySignedTransactionResponse', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + // Mock returns invalid response (missing txHex) + const invalidResponse = {}; + + const mockCoin = { + signTransaction: sinon.stub().resolves(invalidResponse), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Even if SDK returns 200, response should fail codec validation + // This depends on where validation happens + assert.ok(result.status === 200 || result.status >= 400); + + // If status is 200 but response is invalid, codec validation should catch it + if (result.status === 200) { + assert.throws(() => { + assertDecode(FullySignedTransactionResponse, result.body); + }); + } + }); + + it('should reject response with wrong type in txHex field', async function () { + const requestBody = { + txPrebuild: { + txHex: + '0100000001c7dad3d9607a23c45a6c1c5ad7bce02acff71a0f21eb4a72a59d0c0e19402d0f0000000000ffffffff0180a21900000000001976a914c918e1b36f2c72b1aaef94dbb7f578a4b68b542788ac00000000', + }, + prv: 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2', + }; + + // Mock returns invalid response (txHex is number instead of string) + const invalidResponse = { + txHex: 12345, // Wrong type! + }; + + const mockCoin = { + signTransaction: sinon.stub().resolves(invalidResponse), + }; + + sinon.stub(BitGo.prototype, 'coin').returns(mockCoin as any); + + const result = await agent + .post(`/api/v2/${coin}/signtx`) + .set('Authorization', 'Bearer test_access_token_12345') + .set('Content-Type', 'application/json') + .send(requestBody); + + // Response codec validation should catch type mismatch + if (result.status === 200) { + assert.throws(() => { + assertDecode(FullySignedTransactionResponse, result.body); + }); + } + }); + }); }); describe('CoinSignTxParams', function () { From 64d72657683633f7a7f0c0b141e3115d91494773 Mon Sep 17 00:00:00 2001 From: Nayan Das Date: Wed, 15 Oct 2025 12:44:51 +0530 Subject: [PATCH 27/34] feat: add WRW support for multiple EVM coins Ticket: WIN-7490 --- modules/statics/src/allCoinsAndTokens.ts | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/modules/statics/src/allCoinsAndTokens.ts b/modules/statics/src/allCoinsAndTokens.ts index 9efce31af9..02a3828665 100644 --- a/modules/statics/src/allCoinsAndTokens.ts +++ b/modules/statics/src/allCoinsAndTokens.ts @@ -1396,6 +1396,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1412,6 +1414,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1514,6 +1518,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1530,6 +1536,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1546,6 +1554,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1562,6 +1572,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1614,6 +1626,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1630,6 +1644,8 @@ export const allCoinsAndTokens = [ CoinFeature.SHARED_EVM_SDK, CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1715,6 +1731,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -1732,6 +1750,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -2001,6 +2021,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, CoinFeature.SUPPORTS_ERC20, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -2018,6 +2040,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -2035,6 +2059,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( @@ -2052,6 +2078,8 @@ export const allCoinsAndTokens = [ CoinFeature.EVM_COMPATIBLE_IMS, CoinFeature.EVM_COMPATIBLE_UI, CoinFeature.EVM_COMPATIBLE_WP, + CoinFeature.EVM_NON_BITGO_RECOVERY, + CoinFeature.EVM_UNSIGNED_SWEEP_RECOVERY, ] ), account( From fcdebce615b2c8dc32bf3f33fdd76ff6d31226a3 Mon Sep 17 00:00:00 2001 From: Ravi Hegde Date: Wed, 15 Oct 2025 18:09:53 +0530 Subject: [PATCH 28/34] feat(sdk-coin-canton): export the wallet init transaction Ticket: COIN-6079 --- modules/sdk-coin-canton/src/lib/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/sdk-coin-canton/src/lib/index.ts b/modules/sdk-coin-canton/src/lib/index.ts index a189e2813a..61fd90fa1c 100644 --- a/modules/sdk-coin-canton/src/lib/index.ts +++ b/modules/sdk-coin-canton/src/lib/index.ts @@ -5,5 +5,6 @@ export { KeyPair } from './keyPair'; export { Transaction } from './transaction/transaction'; export { TransactionBuilder } from './transactionBuilder'; export { TransactionBuilderFactory } from './transactionBuilderFactory'; +export { WalletInitTransaction } from './walletInitialization/walletInitTransaction'; export { Utils, Interface }; From 23d04cf129f9bf1c5c98a497518454b260a4f558 Mon Sep 17 00:00:00 2001 From: Derek Chen Date: Wed, 15 Oct 2025 10:09:23 -0400 Subject: [PATCH 29/34] feat(sdk-coin-arbeth): support message signing for walletconnect Ticket: SC-3506 --- modules/sdk-coin-arbeth/src/arbeth.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/sdk-coin-arbeth/src/arbeth.ts b/modules/sdk-coin-arbeth/src/arbeth.ts index ce299d3a14..77ab5b957b 100644 --- a/modules/sdk-coin-arbeth/src/arbeth.ts +++ b/modules/sdk-coin-arbeth/src/arbeth.ts @@ -32,6 +32,16 @@ export class Arbeth extends AbstractEthLikeNewCoins { return 'ecdsa'; } + /** @inheritDoc */ + supportsMessageSigning(): boolean { + return true; + } + + /** @inheritDoc */ + supportsSigningTypedData(): boolean { + return true; + } + /** * Make a query to Arbiscan for information such as balance, token balance, solidity calls * @param {Object} query key-value pairs of parameters to append after /api From e8700b2e59ed50204afcbb3051c6bc9e6e3c34f0 Mon Sep 17 00:00:00 2001 From: Lokesh Chandra Date: Wed, 15 Oct 2025 19:44:23 +0530 Subject: [PATCH 30/34] refactor(express): changed route path as per openapi Ticket: WP-6367 --- modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts | 2 +- .../src/typedRoutes/api/v1/constructPendingApprovalTx.ts | 2 +- modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts | 2 +- modules/express/src/typedRoutes/api/v2/coinSignTx.ts | 2 +- modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts | 2 +- modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts | 2 +- modules/express/src/typedRoutes/api/v2/walletSignTx.ts | 2 +- modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts | 2 +- modules/express/test/unit/typedRoutes/coinSignTx.ts | 2 +- modules/express/test/unit/typedRoutes/consolidateUnspents.ts | 2 +- .../express/test/unit/typedRoutes/constructPendingApprovalTx.ts | 2 +- modules/express/test/unit/typedRoutes/fanoutUnspents.ts | 2 +- modules/express/test/unit/typedRoutes/walletRecoverToken.ts | 2 +- modules/express/test/unit/typedRoutes/walletSignTx.ts | 2 +- modules/express/test/unit/typedRoutes/walletTxSignTSS.ts | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts b/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts index 3f48390030..96525c58ca 100644 --- a/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts +++ b/modules/express/src/typedRoutes/api/v1/consolidateUnspents.ts @@ -75,7 +75,7 @@ export const ConsolidateUnspentsResponse = t.array( * @operationId express.v1.wallet.consolidateunspents */ export const PutConsolidateUnspents = httpRoute({ - path: '/api/v1/wallet/:id/consolidateunspents', + path: '/api/v1/wallet/{id}/consolidateunspents', method: 'PUT', request: httpRequest({ params: ConsolidateUnspentsRequestParams, diff --git a/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts b/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts index 880522147f..bbdbfb8af3 100644 --- a/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts +++ b/modules/express/src/typedRoutes/api/v1/constructPendingApprovalTx.ts @@ -63,7 +63,7 @@ export const ConstructPendingApprovalTxResponse = t.type({ * @operationId express.v1.pendingapproval.constructTx */ export const PutConstructPendingApprovalTx = httpRoute({ - path: '/api/v1/pendingapprovals/:id/constructTx', + path: '/api/v1/pendingapprovals/{id}/constructTx', method: 'PUT', request: httpRequest({ params: ConstructPendingApprovalTxRequestParams, diff --git a/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts b/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts index 576b5e4a89..0c57342280 100644 --- a/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts +++ b/modules/express/src/typedRoutes/api/v1/fanoutUnspents.ts @@ -63,7 +63,7 @@ export const FanoutUnspentsResponse = t.type({ * @operationId express.v1.wallet.fanoutunspents */ export const PutFanoutUnspents = httpRoute({ - path: '/api/v1/wallet/:id/fanoutunspents', + path: '/api/v1/wallet/{id}/fanoutunspents', method: 'PUT', request: httpRequest({ params: FanoutUnspentsRequestParams, diff --git a/modules/express/src/typedRoutes/api/v2/coinSignTx.ts b/modules/express/src/typedRoutes/api/v2/coinSignTx.ts index 85c2c68c84..fb69678dc5 100644 --- a/modules/express/src/typedRoutes/api/v2/coinSignTx.ts +++ b/modules/express/src/typedRoutes/api/v2/coinSignTx.ts @@ -141,7 +141,7 @@ export const CoinSignTxResponse = { * @operationId express.v2.coin.signtx */ export const PostCoinSignTx = httpRoute({ - path: '/api/v2/:coin/signtx', + path: '/api/v2/{coin}/signtx', method: 'POST', request: httpRequest({ params: CoinSignTxParams, diff --git a/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts b/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts index d8ed0a64fb..da67f9a20c 100644 --- a/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts +++ b/modules/express/src/typedRoutes/api/v2/lightningInitWallet.ts @@ -40,7 +40,7 @@ export const LightningInitWalletResponse = { * @operationId express.lightning.initWallet */ export const PostLightningInitWallet = httpRoute({ - path: '/api/v2/:coin/wallet/:walletId/initwallet', + path: '/api/v2/{coin}/wallet/{walletId}/initwallet', method: 'POST', request: httpRequest({ params: LightningInitWalletParams, body: LightningInitWalletBody }), response: LightningInitWalletResponse, diff --git a/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts b/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts index 9525633528..872a6adaa8 100644 --- a/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts +++ b/modules/express/src/typedRoutes/api/v2/walletRecoverToken.ts @@ -67,7 +67,7 @@ export const RecoverTokenResponse = t.type({ * @operationId express.v2.wallet.recovertoken */ export const PostWalletRecoverToken = httpRoute({ - path: '/api/v2/:coin/wallet/:id/recovertoken', + path: '/api/v2/{coin}/wallet/{id}/recovertoken', method: 'POST', request: httpRequest({ params: RecoverTokenParams, diff --git a/modules/express/src/typedRoutes/api/v2/walletSignTx.ts b/modules/express/src/typedRoutes/api/v2/walletSignTx.ts index d7d9c5553d..6b78b48b4b 100644 --- a/modules/express/src/typedRoutes/api/v2/walletSignTx.ts +++ b/modules/express/src/typedRoutes/api/v2/walletSignTx.ts @@ -159,7 +159,7 @@ export const WalletSignTxResponse = { * @operationId express.v2.wallet.signtx */ export const PostWalletSignTx = httpRoute({ - path: '/api/v2/:coin/wallet/:id/signtx', + path: '/api/v2/{coin}/wallet/{id}/signtx', method: 'POST', request: httpRequest({ params: WalletSignTxParams, diff --git a/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts b/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts index 5c874ba15b..c66ec29e92 100644 --- a/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts +++ b/modules/express/src/typedRoutes/api/v2/walletTxSignTSS.ts @@ -161,7 +161,7 @@ export const WalletTxSignTSSResponse = { * @operationId express.v2.wallet.signtxtss */ export const PostWalletTxSignTSS = httpRoute({ - path: '/api/v2/:coin/wallet/:id/signtxtss', + path: '/api/v2/{coin}/wallet/{id}/signtxtss', method: 'POST', request: httpRequest({ params: WalletTxSignTSSParams, diff --git a/modules/express/test/unit/typedRoutes/coinSignTx.ts b/modules/express/test/unit/typedRoutes/coinSignTx.ts index 6a59928ee2..ce77afa031 100644 --- a/modules/express/test/unit/typedRoutes/coinSignTx.ts +++ b/modules/express/test/unit/typedRoutes/coinSignTx.ts @@ -980,7 +980,7 @@ describe('CoinSignTx codec tests', function () { describe('PostCoinSignTx route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PostCoinSignTx.path, '/api/v2/:coin/signtx'); + assert.strictEqual(PostCoinSignTx.path, '/api/v2/{coin}/signtx'); }); it('should have the correct HTTP method', function () { diff --git a/modules/express/test/unit/typedRoutes/consolidateUnspents.ts b/modules/express/test/unit/typedRoutes/consolidateUnspents.ts index a1e5bbe9c2..186f0753e9 100644 --- a/modules/express/test/unit/typedRoutes/consolidateUnspents.ts +++ b/modules/express/test/unit/typedRoutes/consolidateUnspents.ts @@ -640,7 +640,7 @@ describe('ConsolidateUnspents codec tests', function () { describe('PutConsolidateUnspents route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PutConsolidateUnspents.path, '/api/v1/wallet/:id/consolidateunspents'); + assert.strictEqual(PutConsolidateUnspents.path, '/api/v1/wallet/{id}/consolidateunspents'); }); it('should have the correct HTTP method', function () { diff --git a/modules/express/test/unit/typedRoutes/constructPendingApprovalTx.ts b/modules/express/test/unit/typedRoutes/constructPendingApprovalTx.ts index 21a59dd8d9..26f5b43e54 100644 --- a/modules/express/test/unit/typedRoutes/constructPendingApprovalTx.ts +++ b/modules/express/test/unit/typedRoutes/constructPendingApprovalTx.ts @@ -284,7 +284,7 @@ describe('ConstructPendingApprovalTx codec tests', function () { describe('PutConstructPendingApprovalTx route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PutConstructPendingApprovalTx.path, '/api/v1/pendingapprovals/:id/constructTx'); + assert.strictEqual(PutConstructPendingApprovalTx.path, '/api/v1/pendingapprovals/{id}/constructTx'); }); it('should have the correct HTTP method', function () { diff --git a/modules/express/test/unit/typedRoutes/fanoutUnspents.ts b/modules/express/test/unit/typedRoutes/fanoutUnspents.ts index f1436f312f..4be3452b5b 100644 --- a/modules/express/test/unit/typedRoutes/fanoutUnspents.ts +++ b/modules/express/test/unit/typedRoutes/fanoutUnspents.ts @@ -373,7 +373,7 @@ describe('FanoutUnspents codec tests', function () { describe('PutFanoutUnspents route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PutFanoutUnspents.path, '/api/v1/wallet/:id/fanoutunspents'); + assert.strictEqual(PutFanoutUnspents.path, '/api/v1/wallet/{id}/fanoutunspents'); }); it('should have the correct HTTP method', function () { diff --git a/modules/express/test/unit/typedRoutes/walletRecoverToken.ts b/modules/express/test/unit/typedRoutes/walletRecoverToken.ts index 30de0a0ab9..8bd41ba07f 100644 --- a/modules/express/test/unit/typedRoutes/walletRecoverToken.ts +++ b/modules/express/test/unit/typedRoutes/walletRecoverToken.ts @@ -563,7 +563,7 @@ describe('WalletRecoverToken codec tests', function () { describe('PostWalletRecoverToken route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PostWalletRecoverToken.path, '/api/v2/:coin/wallet/:id/recovertoken'); + assert.strictEqual(PostWalletRecoverToken.path, '/api/v2/{coin}/wallet/{id}/recovertoken'); }); it('should have the correct HTTP method', function () { diff --git a/modules/express/test/unit/typedRoutes/walletSignTx.ts b/modules/express/test/unit/typedRoutes/walletSignTx.ts index cf29792e6d..f648563e1b 100644 --- a/modules/express/test/unit/typedRoutes/walletSignTx.ts +++ b/modules/express/test/unit/typedRoutes/walletSignTx.ts @@ -664,7 +664,7 @@ describe('WalletSignTx codec tests', function () { describe('PostWalletSignTx route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PostWalletSignTx.path, '/api/v2/:coin/wallet/:id/signtx'); + assert.strictEqual(PostWalletSignTx.path, '/api/v2/{coin}/wallet/{id}/signtx'); }); it('should have the correct HTTP method', function () { diff --git a/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts b/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts index de3943c821..5b74455270 100644 --- a/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts +++ b/modules/express/test/unit/typedRoutes/walletTxSignTSS.ts @@ -1451,7 +1451,7 @@ describe('WalletTxSignTSS codec tests', function () { describe('PostWalletTxSignTSS route definition', function () { it('should have the correct path', function () { - assert.strictEqual(PostWalletTxSignTSS.path, '/api/v2/:coin/wallet/:id/signtxtss'); + assert.strictEqual(PostWalletTxSignTSS.path, '/api/v2/{coin}/wallet/{id}/signtxtss'); }); it('should have the correct HTTP method', function () { From b6d7524b06568c51626fce231a119e15abe86365 Mon Sep 17 00:00:00 2001 From: Derek Chen Date: Tue, 14 Oct 2025 15:31:11 -0400 Subject: [PATCH 31/34] feat(sdk-coin-sol): inject durable nonce for versioned transactions Ticket: SC-3491 --- .../src/lib/customInstructionBuilder.ts | 94 +++++++++++++++- .../test/unit/versionedTransaction.ts | 104 ++++++++++++++++++ 2 files changed, 193 insertions(+), 5 deletions(-) diff --git a/modules/sdk-coin-sol/src/lib/customInstructionBuilder.ts b/modules/sdk-coin-sol/src/lib/customInstructionBuilder.ts index 170dc05abe..ec455ff41f 100644 --- a/modules/sdk-coin-sol/src/lib/customInstructionBuilder.ts +++ b/modules/sdk-coin-sol/src/lib/customInstructionBuilder.ts @@ -1,6 +1,6 @@ import { BaseCoin as CoinConfig } from '@bitgo/statics'; import { BuildTransactionError, SolInstruction, SolVersionedInstruction, TransactionType } from '@bitgo/sdk-core'; -import { PublicKey } from '@solana/web3.js'; +import { PublicKey, SystemProgram, SYSVAR_RECENT_BLOCKHASHES_PUBKEY } from '@solana/web3.js'; import { Transaction } from './transaction'; import { TransactionBuilder } from './transactionBuilder'; import { InstructionBuilderTypes } from './constants'; @@ -103,17 +103,44 @@ export class CustomInstructionBuilder extends TransactionBuilder { throw new BuildTransactionError('staticAccountKeys must be a non-empty array'); } - this.addCustomInstructions(data.versionedInstructions); + if (!data.messageHeader || typeof data.messageHeader !== 'object') { + throw new BuildTransactionError('messageHeader must be a valid object'); + } + if ( + typeof data.messageHeader.numRequiredSignatures !== 'number' || + data.messageHeader.numRequiredSignatures < 0 + ) { + throw new BuildTransactionError('messageHeader.numRequiredSignatures must be a non-negative number'); + } + if ( + typeof data.messageHeader.numReadonlySignedAccounts !== 'number' || + data.messageHeader.numReadonlySignedAccounts < 0 + ) { + throw new BuildTransactionError('messageHeader.numReadonlySignedAccounts must be a non-negative number'); + } + if ( + typeof data.messageHeader.numReadonlyUnsignedAccounts !== 'number' || + data.messageHeader.numReadonlyUnsignedAccounts < 0 + ) { + throw new BuildTransactionError('messageHeader.numReadonlyUnsignedAccounts must be a non-negative number'); + } + + let processedData = data; + if (this._nonceInfo && this._nonceInfo.params) { + processedData = this.injectNonceAdvanceInstruction(data); + } + + this.addCustomInstructions(processedData.versionedInstructions); if (!this._transaction) { this._transaction = new Transaction(this._coinConfig); } - this._transaction.setVersionedTransactionData(data); + this._transaction.setVersionedTransactionData(processedData); this._transaction.setTransactionType(TransactionType.CustomTx); - if (!this._sender && data.staticAccountKeys.length > 0) { - this._sender = data.staticAccountKeys[0]; + if (!this._sender && processedData.staticAccountKeys.length > 0) { + this._sender = processedData.staticAccountKeys[0]; } return this; @@ -125,6 +152,63 @@ export class CustomInstructionBuilder extends TransactionBuilder { } } + /** + * Inject nonce advance instruction into versioned transaction data for durable nonce support. + * Reorders accounts so signers appear first (required by Solana MessageV0 format). + * @param data - Original versioned transaction data + * @returns Modified versioned transaction data with nonce advance instruction + * @private + */ + private injectNonceAdvanceInstruction(data: VersionedTransactionData): VersionedTransactionData { + const { walletNonceAddress, authWalletAddress } = this._nonceInfo!.params; + const SYSTEM_PROGRAM = SystemProgram.programId.toBase58(); + const SYSVAR_RECENT_BLOCKHASHES = SYSVAR_RECENT_BLOCKHASHES_PUBKEY.toBase58(); + + const numSigners = data.messageHeader.numRequiredSignatures; + const originalSigners = data.staticAccountKeys.slice(0, numSigners); + const originalNonSigners = data.staticAccountKeys.slice(numSigners); + + if (!originalSigners.includes(authWalletAddress)) { + originalSigners.push(authWalletAddress); + } + + const nonSigners = [...originalNonSigners]; + const allKeys = [...originalSigners, ...originalNonSigners]; + + if (!allKeys.includes(SYSTEM_PROGRAM)) nonSigners.push(SYSTEM_PROGRAM); + if (!allKeys.includes(walletNonceAddress)) nonSigners.push(walletNonceAddress); + if (!allKeys.includes(SYSVAR_RECENT_BLOCKHASHES)) nonSigners.push(SYSVAR_RECENT_BLOCKHASHES); + + const newStaticAccountKeys = [...originalSigners, ...nonSigners]; + + const nonceAdvanceInstruction: SolVersionedInstruction = { + programIdIndex: newStaticAccountKeys.indexOf(SYSTEM_PROGRAM), + accountKeyIndexes: [ + newStaticAccountKeys.indexOf(walletNonceAddress), + newStaticAccountKeys.indexOf(SYSVAR_RECENT_BLOCKHASHES), + newStaticAccountKeys.indexOf(authWalletAddress), + ], + data: '6vx8P', // SystemProgram AdvanceNonceAccount (0x04000000) in base58 + }; + + const indexMap = new Map(data.staticAccountKeys.map((key, oldIdx) => [oldIdx, newStaticAccountKeys.indexOf(key)])); + const remappedInstructions = data.versionedInstructions.map((inst) => ({ + programIdIndex: indexMap.get(inst.programIdIndex) ?? inst.programIdIndex, + accountKeyIndexes: inst.accountKeyIndexes.map((idx) => indexMap.get(idx) ?? idx), + data: inst.data, + })); + + return { + ...data, + versionedInstructions: [nonceAdvanceInstruction, ...remappedInstructions], + staticAccountKeys: newStaticAccountKeys, + messageHeader: { + ...data.messageHeader, + numRequiredSignatures: originalSigners.length, + }, + }; + } + /** * Clear all custom instructions and versioned transaction data * @returns This builder instance diff --git a/modules/sdk-coin-sol/test/unit/versionedTransaction.ts b/modules/sdk-coin-sol/test/unit/versionedTransaction.ts index 7e43e38cc0..462bca29f0 100644 --- a/modules/sdk-coin-sol/test/unit/versionedTransaction.ts +++ b/modules/sdk-coin-sol/test/unit/versionedTransaction.ts @@ -128,4 +128,108 @@ describe('Sol Jupiter Swap Transaction', () => { ); } }); + + it('should automatically inject nonce advance instruction when using durable nonce with versioned transactions', async function () { + // Simple transaction with one memo instruction + const versionedTransactionData = { + versionedInstructions: [ + { + programIdIndex: 1, + accountKeyIndexes: [0], + data: base58.encode(Buffer.from('Hello Versioned Tx', 'utf-8')), + }, + ], + addressLookupTables: [], + staticAccountKeys: [testData.authAccount.pub, 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'], + messageHeader: { + numRequiredSignatures: 1, + numReadonlySignedAccounts: 0, + numReadonlyUnsignedAccounts: 0, + }, + }; + + const durableNonceParams = { + walletNonceAddress: 'GHtXQBsoZHVnNFa9YevAzxNzQBz7CV5hj6bSe3u52W9n', + authWalletAddress: '8Y7RM6JfcX4ASSNBkrkrmScq3Z9UWV4CJBwtfSNgqTN2', + }; + + const factory = getBuilderFactory('tsol'); + const txBuilder = factory.getCustomInstructionBuilder(); + + // Providing durableNonceParams triggers automatic nonce advance injection + txBuilder.nonce(testData.blockHashes.validBlockHashes[0], durableNonceParams); + txBuilder.fromVersionedTransactionData(versionedTransactionData); + + const tx = (await txBuilder.build()) as Transaction; + const builtData = tx.getVersionedTransactionData(); + + should.exist(builtData); + + // Nonce advance instruction should be prepended + builtData!.versionedInstructions.length.should.equal(2); + const nonceInstruction = builtData!.versionedInstructions[0]; + nonceInstruction.accountKeyIndexes.length.should.equal(3); + + // numRequiredSignatures should be updated to include nonce authority + const numSigners = builtData!.messageHeader.numRequiredSignatures; + numSigners.should.equal(2); + + // Both fee payer and nonce authority should be in signer section + const signerKeys = builtData!.staticAccountKeys.slice(0, numSigners); + signerKeys.should.containEql(testData.authAccount.pub); + signerKeys.should.containEql(durableNonceParams.authWalletAddress); + + // Fee payer must remain at index 0 + builtData!.staticAccountKeys[0].should.equal(testData.authAccount.pub); + + // Required accounts for nonce advance should be added + builtData!.staticAccountKeys.should.containEql(durableNonceParams.walletNonceAddress); + builtData!.staticAccountKeys.should.containEql('11111111111111111111111111111111'); + builtData!.staticAccountKeys.should.containEql('SysvarRecentB1ockHashes11111111111111111111'); + + // Original instruction indices should be remapped after account reordering + const originalInstruction = builtData!.versionedInstructions[1]; + originalInstruction.programIdIndex.should.equal( + builtData!.staticAccountKeys.indexOf('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr') + ); + originalInstruction.accountKeyIndexes[0].should.equal( + builtData!.staticAccountKeys.indexOf(testData.authAccount.pub) + ); + }); + + it('should not inject nonce advance when using regular nonce (no durableNonceParams)', async function () { + const versionedTransactionData = { + versionedInstructions: [ + { + programIdIndex: 1, + accountKeyIndexes: [0], + data: base58.encode(Buffer.from('Hello', 'utf-8')), + }, + ], + addressLookupTables: [], + staticAccountKeys: [testData.authAccount.pub, 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'], + messageHeader: { + numRequiredSignatures: 1, + numReadonlySignedAccounts: 0, + numReadonlyUnsignedAccounts: 0, + }, + }; + + const factory = getBuilderFactory('tsol'); + const txBuilder = factory.getCustomInstructionBuilder(); + + // Regular nonce without durableNonceParams should not trigger injection + txBuilder.nonce(testData.blockHashes.validBlockHashes[0]); + txBuilder.fromVersionedTransactionData(versionedTransactionData); + + const tx = (await txBuilder.build()) as Transaction; + const builtData = tx.getVersionedTransactionData(); + + should.exist(builtData); + + // Transaction should remain unchanged + builtData!.versionedInstructions.length.should.equal(1); + builtData!.messageHeader.numRequiredSignatures.should.equal(1); + builtData!.staticAccountKeys.length.should.equal(2); + }); }); From a47e0b11a50594c351b0800514857f271ba6a5f2 Mon Sep 17 00:00:00 2001 From: Peter Pong Date: Tue, 14 Oct 2025 16:11:00 -0400 Subject: [PATCH 32/34] chore(sdk-coin-celo): remove unused files and functions BREAKING CHANGE: * Removed modules/sdk-coin-celo/src/lib/types.ts - entire file deleted * Removed deserialize() function from modules/sdk-coin-celo/src/lib/utils.ts These components were unused and removing them reduces bundle size and dependency overhead. If you were importing these directly, you'll need to use alternative implementations. BG-0000 --- modules/sdk-coin-celo/package.json | 7 +- modules/sdk-coin-celo/src/lib/types.ts | 265 -------- modules/sdk-coin-celo/src/lib/utils.ts | 50 +- scripts/check-package-dependencies.ts | 2 - yarn.lock | 889 +------------------------ 5 files changed, 38 insertions(+), 1175 deletions(-) delete mode 100644 modules/sdk-coin-celo/src/lib/types.ts diff --git a/modules/sdk-coin-celo/package.json b/modules/sdk-coin-celo/package.json index a0e7331fc3..9a61142fc6 100644 --- a/modules/sdk-coin-celo/package.json +++ b/modules/sdk-coin-celo/package.json @@ -44,15 +44,10 @@ "@bitgo/sdk-coin-eth": "^25.3.4", "@bitgo/sdk-core": "^36.12.0", "@bitgo/statics": "^58.4.0", - "@celo/connect": "^2.0.0", - "@celo/contractkit": "^2.0.0", - "@celo/wallet-base": "^2.0.0", - "@celo/wallet-local": "^2.0.0", "@ethereumjs/common": "^2.6.5", "bignumber.js": "^9.0.0", "ethereumjs-abi": "^0.6.5", - "ethereumjs-util": "7.1.5", - "ethers": "^5.1.3" + "ethereumjs-util": "7.1.5" }, "devDependencies": { "@bitgo/sdk-api": "^1.70.1", diff --git a/modules/sdk-coin-celo/src/lib/types.ts b/modules/sdk-coin-celo/src/lib/types.ts deleted file mode 100644 index 31b8d9ef56..0000000000 --- a/modules/sdk-coin-celo/src/lib/types.ts +++ /dev/null @@ -1,265 +0,0 @@ -import BigNumber from 'bignumber.js'; -import { LocalWallet } from '@celo/wallet-local'; -import { - addHexPrefix, - toBuffer, - bufferToHex, - bufferToInt, - rlp, - rlphash, - ecrecover, - publicToAddress, - unpadBuffer, -} from 'ethereumjs-util'; -import { CeloTx, EncodedTransaction } from '@celo/connect'; -import { EthLikeTransactionData, ETHTransactionType, KeyPair, LegacyTxData } from '@bitgo/sdk-coin-eth'; - -export class CeloTransaction { - private raw: Buffer[]; - private _from: Buffer; - private _senderPubKey?; - private _signatures: Buffer[]; - private _feeCurrency: Buffer = toBuffer('0x'); - private _gatewayFeeRecipient: Buffer = toBuffer('0x'); - private _gatewayFee: Buffer = toBuffer('0x'); - nonce: Buffer; - gasLimit: Buffer; - gasPrice: Buffer; - data: Buffer; - value: Buffer; - to: Buffer = toBuffer([]); - v: Buffer = toBuffer([]); - r: Buffer = toBuffer([]); - s: Buffer = toBuffer([]); - - // TODO: validate if this needs to be moved to Utils class - /** - * Clean hex formatted values ensuring they have an even length - * - * @param numberValue Hex formatted number value. Example '0x01' - * @returns sanitized value - */ - private sanitizeHexString(numberValue) { - if (numberValue === '0x0' || numberValue == '') { - return '0x'; - } else if (numberValue.length % 2 === 0) { - return numberValue; - } - return '0x0' + numberValue.slice(2); - } - - constructor(tx: LegacyTxData) { - this.nonce = unpadBuffer(toBuffer(tx.nonce)); - this.gasLimit = toBuffer(this.sanitizeHexString(tx.gasLimit)); - this.gasPrice = toBuffer(this.sanitizeHexString(tx.gasPrice)); - this.data = toBuffer(this.sanitizeHexString(tx.data)); - this.value = toBuffer(this.sanitizeHexString(tx.value)); - if (tx.to) { - this.to = toBuffer(tx.to); - } - if (tx.v) { - this.v = toBuffer(tx.v); - } - if (tx.r) { - this.r = toBuffer(tx.r); - } - if (tx.s) { - this.s = toBuffer(tx.s); - } - if (tx.from) { - this._from = toBuffer(tx.from); - } - this.initRaw(); - } - - private initRaw() { - this.raw = [ - this.nonce, - this.gasPrice, - this.gasLimit, - this._feeCurrency, - this._gatewayFeeRecipient, - this._gatewayFee, - this.to, - this.value, - this.data, - this.v, - this.r, - this.s, - ]; - } - - hash(includeSignature?: boolean): Buffer { - let items; - if (includeSignature) { - items = this.raw; - } else { - items = this.raw - .slice(0, 9) - .concat([toBuffer(this.getChainId()), unpadBuffer(toBuffer(0)), unpadBuffer(toBuffer(0))]); - } - return rlphash(items); - } - - getSenderAddress(): Buffer { - if (this._from) { - return this._from; - } - const pubKey = this.getSenderPublicKey(); - this._from = publicToAddress(pubKey); - return this._from; - } - - getSenderPublicKey() { - if (this.verifySignature()) { - // If the signature was verified successfully the _senderPubKey field is defined - return this._senderPubKey; - } - throw new Error('Invalid Signature'); - } - - serialize(): Buffer { - return rlp.encode(this.raw); - } - - sign(privateKey: Buffer): void { - this._signatures = [this.v, this.r, this.s, privateKey]; - } - - verifySignature(): boolean { - const msgHash = this.hash(false); - try { - const chainId = this.getChainId(); - const v = bufferToInt(this.v) - (2 * chainId + 35); - this._senderPubKey = ecrecover(msgHash, v + 27, this.r, this.s); - } catch (e) { - return false; - } - return !!this._senderPubKey; - } - - getChainId(): number { - let chainId = bufferToInt(this.v); - if (this.r.length && this.s.length) { - chainId = (chainId - 35) >> 1; - } - return chainId; - } -} - -export class CeloTransactionData implements EthLikeTransactionData { - private tx: CeloTransaction; - private deployedAddress?: string; - - constructor(tx: CeloTransaction, deployedAddress?: string) { - this.tx = tx; - this.deployedAddress = deployedAddress; - } - - public static fromJson(tx: LegacyTxData): CeloTransactionData { - const chainId = addHexPrefix(new BigNumber(Number(tx.chainId)).toString(16)); - return new CeloTransactionData( - new CeloTransaction({ - _type: ETHTransactionType.LEGACY, - nonce: tx.nonce, - to: tx.to, - gasPrice: addHexPrefix(new BigNumber(tx.gasPrice).toString(16)), - gasLimit: addHexPrefix(new BigNumber(tx.gasLimit).toString(16)), - value: addHexPrefix(new BigNumber(tx.value).toString(16)), - data: tx.data === '0x' ? '' : tx.data, - from: tx.from, - s: tx.s, - r: tx.r, - v: tx.v || chainId, - }), - tx.deployedAddress - ); - } - - async sign(keyPair: KeyPair) { - const privateKey = addHexPrefix(keyPair.getKeys().prv as string); - const data = CeloTransactionData.txJsonToCeloTx(this.toJson(), keyPair.getAddress()); - const celoLocalWallet = new LocalWallet(); - celoLocalWallet.addAccount(privateKey); - const rawTransaction = await celoLocalWallet.signTransaction(data); - - const nonceBigNumber = new BigNumber(rawTransaction.tx.nonce); - rawTransaction.tx.nonce = addHexPrefix(nonceBigNumber.toString(16)); - rawTransaction.raw = data.data === undefined ? '' : data.data; - rawTransaction.tx.gas = rawTransaction.tx.gas; - this.tx = new CeloTransaction(CeloTransactionData.encodedTxToJson(rawTransaction)); - this.tx.sign(toBuffer(privateKey)); - } - - /** @inheritdoc */ - toJson(): LegacyTxData { - const result: LegacyTxData = { - _type: ETHTransactionType.LEGACY, - nonce: bufferToInt(this.tx.nonce), - gasPrice: new BigNumber(bufferToHex(this.tx.gasPrice), 16).toString(10), - gasLimit: new BigNumber(bufferToHex(this.tx.gasLimit), 16).toString(10), - value: this.tx.value.length === 0 ? '0' : new BigNumber(bufferToHex(this.tx.value), 16).toString(10), - data: bufferToHex(this.tx.data), - id: addHexPrefix(bufferToHex(this.tx.hash(true))), - }; - - if (this.tx.to && this.tx.to.length) { - result.to = bufferToHex(this.tx.to); - } - - if (this.tx.verifySignature()) { - result.from = bufferToHex(this.tx.getSenderAddress()); - } - - const chainId = this.tx.getChainId(); - if (chainId) { - result.chainId = chainId.toString(); - } - - if (this.deployedAddress) { - result.deployedAddress = this.deployedAddress; - } - - this.setSignatureFields(result); - - return result; - } - - private setSignatureFields(result: LegacyTxData): void { - if (this.tx.v && this.tx.v.length) { - result.v = bufferToHex(this.tx.v); - } - - if (this.tx.r && this.tx.r.length) { - result.r = bufferToHex(this.tx.r); - } - - if (this.tx.s && this.tx.s.length) { - result.s = bufferToHex(this.tx.s); - } - } - - /** @inheritdoc */ - toSerialized(): string { - return addHexPrefix(this.tx.serialize().toString('hex')); - } - - private static txJsonToCeloTx(txJson: LegacyTxData, signer: string): CeloTx { - // the celo library requires you to specify the signer address with the from field - return Object.assign({}, txJson, { - chainId: txJson.chainId === undefined ? 0 : parseInt(txJson.chainId, 10), - gas: txJson.gasLimit, - from: signer, - }); - } - - private static encodedTxToJson(encodedTx: EncodedTransaction): LegacyTxData { - return { - ...encodedTx.tx, - _type: ETHTransactionType.LEGACY, - nonce: parseInt(encodedTx.tx.nonce, 16), - gasLimit: encodedTx.tx.gas, - data: encodedTx.raw, - }; - } -} diff --git a/modules/sdk-coin-celo/src/lib/utils.ts b/modules/sdk-coin-celo/src/lib/utils.ts index f7768224cd..7372a409fb 100644 --- a/modules/sdk-coin-celo/src/lib/utils.ts +++ b/modules/sdk-coin-celo/src/lib/utils.ts @@ -1,56 +1,8 @@ import { NetworkType } from '@bitgo/statics'; import EthereumCommon from '@ethereumjs/common'; -import { recoverTransaction } from '@celo/wallet-base'; -import * as ethers from 'ethers'; -import BigNumber from 'bignumber.js'; -import { ETHTransactionType, LegacyTxData } from '@bitgo/sdk-coin-eth'; -import { InvalidTransactionError, ParseTransactionError } from '@bitgo/sdk-core'; +import { InvalidTransactionError } from '@bitgo/sdk-core'; import { mainnetCommon, testnetCommon } from './resources'; -/** - * Celo transaction deserialization based on code - * from @celo/contractkit/lib/utils/signing-utils - * github: https://github.com/celo-org/celo-monorepo/tree/master/packages/contractkit - * - * @param {string} serializedTx the serialized transaction - * @returns {LegacyTxData} the deserialized transaction - */ -export function deserialize(serializedTx: string): LegacyTxData { - try { - const decodedTx = ethers.utils.RLP.decode(serializedTx); - decodedTx.splice(3, 3); // remove unused feeCurrency, gatewayFeeRecipient and gatewayFee - const [nonce, gasPrice, gasLimit, to, value, data, v, r, s] = decodedTx; - let chainId = v; - let from; - if (r !== '0x' && s !== '0x') { - const [tx, sender] = recoverTransaction(serializedTx); - from = sender; - chainId = tx.chainId; - } - const celoTx: LegacyTxData = { - _type: ETHTransactionType.LEGACY, - nonce: nonce.toLowerCase() === '0x' ? 0 : parseInt(nonce, 16), - gasPrice: gasPrice.toLowerCase() === '0x' ? '0' : new BigNumber(gasPrice, 16).toString(), - gasLimit: gasLimit.toLowerCase() === '0x' ? '0' : new BigNumber(gasLimit, 16).toString(), - value: value.toLowerCase() === '0x' ? '0' : new BigNumber(value, 16).toString(), - data, - chainId, - from, - v, - r, - s, - }; - - if (to !== '0x') { - celoTx.to = to; - } - - return celoTx; - } catch { - throw new ParseTransactionError('Invalid serialized transaction'); - } -} - const commons: Map = new Map([ [NetworkType.MAINNET, mainnetCommon], [NetworkType.TESTNET, testnetCommon], diff --git a/scripts/check-package-dependencies.ts b/scripts/check-package-dependencies.ts index feccf22f58..88f0b52265 100644 --- a/scripts/check-package-dependencies.ts +++ b/scripts/check-package-dependencies.ts @@ -21,8 +21,6 @@ const options = { 'express-serve-static-core', // Required for sdk-coin-ada '@emurgo/cardano-serialization-lib-browser', - // Required for sdk-coin-celo inner dependencies - '@celo/contractkit', // Webpack - not detected by depcheck '@testing-library/cypress', 'css-loader', diff --git a/yarn.lock b/yarn.lock index 3248be8426..e2832d9b4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -990,87 +990,6 @@ resolved "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.0.tgz#4b3f07af047f984c082de34b116e765cb9af975f" integrity sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w== -"@celo/base@2.3.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@celo/base/-/base-2.3.0.tgz" - integrity sha512-Jo81eVGCPcKpUw9G4/uFE2x2TeYpS6BhEpmzmrkL86AU+EC93ES9UUlCcCpFSVRfoiHldIGp2QzyU+kAYap//Q== - -"@celo/connect@2.3.0", "@celo/connect@^2.0.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@celo/connect/-/connect-2.3.0.tgz" - integrity sha512-p4oPU7ZafhaBXlX189I2jDTC9t5O9ayUywTsJMkSbsfz/q3RalTl+/YWM1m8twF2VdilAjOR1GiObbVVkYQLNQ== - dependencies: - "@celo/base" "2.3.0" - "@celo/utils" "2.3.0" - "@types/debug" "^4.1.5" - "@types/utf8" "^2.1.6" - bignumber.js "^9.0.0" - debug "^4.1.1" - utf8 "3.0.0" - -"@celo/contractkit@^2.0.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@celo/contractkit/-/contractkit-2.3.0.tgz" - integrity sha512-mctnQBp7GZAsuV4I47kTK3fBtjoL4uqd0LZ8wUmck+COJT9yW3DuQjPQwQvBxN6InKET9IeUmTuoTW4oAbW/FQ== - dependencies: - "@celo/base" "2.3.0" - "@celo/connect" "2.3.0" - "@celo/utils" "2.3.0" - "@celo/wallet-local" "2.3.0" - "@types/bn.js" "^5.1.0" - "@types/debug" "^4.1.5" - bignumber.js "^9.0.0" - cross-fetch "^3.0.6" - debug "^4.1.1" - fp-ts "2.1.1" - io-ts "2.0.1" - semver "^7.3.5" - web3 "1.3.6" - -"@celo/utils@2.3.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@celo/utils/-/utils-2.3.0.tgz" - integrity sha512-K4Ga1rpYyFTTyhopHUHdeNehJN4qYT+cdf2BPgc6wS4AsI/G8vq91tmXOBJNL1oPVIbnW7MOp51IKJP51/zdhA== - dependencies: - "@celo/base" "2.3.0" - "@types/bn.js" "^5.1.0" - "@types/elliptic" "^6.4.9" - "@types/ethereumjs-util" "^5.2.0" - "@types/node" "^10.12.18" - bignumber.js "^9.0.0" - elliptic "^6.5.4" - ethereumjs-util "^5.2.0" - io-ts "2.0.1" - web3-eth-abi "1.3.6" - web3-utils "1.3.6" - -"@celo/wallet-base@2.3.0", "@celo/wallet-base@^2.0.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@celo/wallet-base/-/wallet-base-2.3.0.tgz" - integrity sha512-C5+t5Sx39Riul1EATPMq0bqWyHCAqoIRW4fU/5FrML+OYvpH+3SAIjJuxoD4vdj3gZZBWockg32PFp0TNb6e4g== - dependencies: - "@celo/base" "2.3.0" - "@celo/connect" "2.3.0" - "@celo/utils" "2.3.0" - "@types/debug" "^4.1.5" - "@types/ethereumjs-util" "^5.2.0" - bignumber.js "^9.0.0" - debug "^4.1.1" - eth-lib "^0.2.8" - ethereumjs-util "^5.2.0" - -"@celo/wallet-local@2.3.0", "@celo/wallet-local@^2.0.0": - version "2.3.0" - resolved "https://registry.npmjs.org/@celo/wallet-local/-/wallet-local-2.3.0.tgz" - integrity sha512-B2rg6DmKnHP98ixkIRH7I4aNFZVcj4e7wmB9z2LB08wAiuBFS4qsGp4ciplLb+AQuwbUSe8SpRSuKYxKUTQmFA== - dependencies: - "@celo/connect" "2.3.0" - "@celo/utils" "2.3.0" - "@celo/wallet-base" "2.3.0" - "@types/ethereumjs-util" "^5.2.0" - eth-lib "^0.2.8" - ethereumjs-util "^5.2.0" - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" @@ -1959,21 +1878,6 @@ async "^3.2.4" ethereum-cryptography "^1.1.2" -"@ethersproject/abi@5.0.7": - version "5.0.7" - resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.7.tgz" - integrity sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw== - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/abi@5.6.4": version "5.6.4" resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.4.tgz" @@ -2063,7 +1967,7 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/rlp" "^5.6.1" -"@ethersproject/address@5.8.0", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.6.1", "@ethersproject/address@^5.8.0": +"@ethersproject/address@5.8.0", "@ethersproject/address@^5.6.1", "@ethersproject/address@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz" integrity sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== @@ -2113,7 +2017,7 @@ "@ethersproject/logger" "^5.6.0" bn.js "^5.2.1" -"@ethersproject/bignumber@5.8.0", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.0.8", "@ethersproject/bignumber@^5.6.0", "@ethersproject/bignumber@^5.6.2", "@ethersproject/bignumber@^5.8.0": +"@ethersproject/bignumber@5.8.0", "@ethersproject/bignumber@^5.0.8", "@ethersproject/bignumber@^5.6.0", "@ethersproject/bignumber@^5.6.2", "@ethersproject/bignumber@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz" integrity sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== @@ -2129,7 +2033,7 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/bytes@5.8.0", "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.0.5", "@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.8.0": +"@ethersproject/bytes@5.8.0", "@ethersproject/bytes@^5.0.5", "@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz" integrity sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== @@ -2143,7 +2047,7 @@ dependencies: "@ethersproject/bignumber" "^5.6.2" -"@ethersproject/constants@5.8.0", "@ethersproject/constants@^5.0.4", "@ethersproject/constants@^5.0.5", "@ethersproject/constants@^5.6.1", "@ethersproject/constants@^5.8.0": +"@ethersproject/constants@5.8.0", "@ethersproject/constants@^5.0.5", "@ethersproject/constants@^5.6.1", "@ethersproject/constants@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz" integrity sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== @@ -2196,7 +2100,7 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/hash@5.8.0", "@ethersproject/hash@^5.0.4", "@ethersproject/hash@^5.6.1", "@ethersproject/hash@^5.8.0": +"@ethersproject/hash@5.8.0", "@ethersproject/hash@^5.6.1", "@ethersproject/hash@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz" integrity sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== @@ -2293,7 +2197,7 @@ "@ethersproject/bytes" "^5.6.1" js-sha3 "0.8.0" -"@ethersproject/keccak256@5.8.0", "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.8.0": +"@ethersproject/keccak256@5.8.0", "@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz" integrity sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== @@ -2306,7 +2210,7 @@ resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz" integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== -"@ethersproject/logger@5.8.0", "@ethersproject/logger@^5.0.5", "@ethersproject/logger@^5.6.0", "@ethersproject/logger@^5.8.0": +"@ethersproject/logger@5.8.0", "@ethersproject/logger@^5.6.0", "@ethersproject/logger@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz" integrity sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== @@ -2348,7 +2252,7 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/properties@5.8.0", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.6.0", "@ethersproject/properties@^5.8.0": +"@ethersproject/properties@5.8.0", "@ethersproject/properties@^5.6.0", "@ethersproject/properties@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz" integrity sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== @@ -2514,7 +2418,7 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/strings@5.8.0", "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.6.1", "@ethersproject/strings@^5.8.0": +"@ethersproject/strings@5.8.0", "@ethersproject/strings@^5.6.1", "@ethersproject/strings@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz" integrity sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== @@ -2538,7 +2442,7 @@ "@ethersproject/rlp" "^5.6.1" "@ethersproject/signing-key" "^5.6.2" -"@ethersproject/transactions@5.8.0", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.8.0": +"@ethersproject/transactions@5.8.0", "@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.8.0": version "5.8.0" resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz" integrity sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== @@ -5050,11 +4954,6 @@ resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz#aa51a6c1946df2c5a11494a2cdb9318e026db16c" integrity sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g== -"@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" @@ -5474,13 +5373,6 @@ dependencies: tslib "^2.8.0" -"@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz" @@ -5618,7 +5510,7 @@ dependencies: "@types/node" "*" -"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5", "@types/bn.js@^4.11.6": +"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.6": version "4.11.6" resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz" integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== @@ -5699,7 +5591,7 @@ dependencies: "@types/node" "*" -"@types/debug@^4.1.4", "@types/debug@^4.1.5": +"@types/debug@^4.1.4": version "4.1.12" resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz" integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== @@ -5742,14 +5634,6 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== -"@types/ethereumjs-util@^5.2.0": - version "5.2.0" - resolved "https://registry.npmjs.org/@types/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz" - integrity sha512-qwQgQqXXTRv2h2AlJef+tMEszLFkCB9dWnrJYIdAwqjubERXEc/geB+S3apRw0yQyTVnsBf8r6BhlrE8vx+3WQ== - dependencies: - "@types/bn.js" "*" - "@types/node" "*" - "@types/eventsource@^1.1.2": version "1.1.15" resolved "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz" @@ -6010,12 +5894,7 @@ dependencies: undici-types "~7.10.0" -"@types/node@^10.12.18": - version "10.17.60" - resolved "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== - -"@types/node@^12.12.54", "@types/node@^12.12.6", "@types/node@^12.12.7": +"@types/node@^12.12.54", "@types/node@^12.12.7": version "12.20.55" resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== @@ -6292,11 +6171,6 @@ resolved "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz" integrity sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg== -"@types/utf8@^2.1.6": - version "2.1.6" - resolved "https://registry.npmjs.org/@types/utf8/-/utf8-2.1.6.tgz" - integrity sha512-pRs2gYF5yoKYrgSaira0DJqVg2tFuF+Qjp838xS7K+mJyY2jJzjsrl6y17GbIa4uMRogMbxs+ghNCvKg6XyNrA== - "@types/uuid@^8.3.4": version "8.3.4" resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz" @@ -7712,7 +7586,7 @@ bluebird@^1.2.4: resolved "https://registry.npmjs.org/bluebird/-/bluebird-1.2.4.tgz" integrity sha512-nI6OoUVWcq6gV6kmgdaXpOMfBJhL9iq/pns0ORINhX3f51L9P87F5uvh9luqZuswURSQaN3082OfpwSDwA1KBw== -bluebird@^3.5.0, bluebird@^3.7.2: +bluebird@^3.7.2: version "3.7.2" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -7737,7 +7611,7 @@ bn.js@5.2.1: resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: version "4.12.2" resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== @@ -7747,7 +7621,7 @@ bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== -body-parser@1.20.3, body-parser@^1.16.0, body-parser@^1.19.0, body-parser@^1.20.3: +body-parser@1.20.3, body-parser@^1.19.0, body-parser@^1.20.3: version "1.20.3" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz" integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== @@ -8058,17 +7932,12 @@ buffer-layout@^1.2.2: resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer-to-arraybuffer@^0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz" - integrity sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ== - buffer-xor@^1.0.2, buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== -buffer@4.9.2, buffer@6.0.3, buffer@^5.0.2, buffer@^5.0.5, buffer@^5.1.0, buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0, buffer@^5.7.1, buffer@^6.0.2, buffer@^6.0.3, buffer@~6.0.3: +buffer@4.9.2, buffer@6.0.3, buffer@^5.0.2, buffer@^5.1.0, buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0, buffer@^5.7.1, buffer@^6.0.2, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -8203,19 +8072,6 @@ cacheable-lookup@^5.0.3: resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== -cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - cacheable-request@^7.0.2: version "7.0.4" resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz" @@ -8526,17 +8382,6 @@ ci-info@^4.0.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz#c39b1013f8fdbd28cd78e62318357d02da160cd7" integrity sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ== -cids@^0.7.1: - version "0.7.5" - resolved "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz" - integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== - dependencies: - buffer "^5.5.0" - class-is "^1.1.0" - multibase "~0.6.0" - multicodec "^1.0.0" - multihashes "~0.4.15" - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.6" resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz" @@ -8545,11 +8390,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.4" safe-buffer "^5.2.1" -class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz" - integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== - clean-css@^4.2.3: version "4.2.4" resolved "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz" @@ -8938,15 +8778,6 @@ content-disposition@0.5.4: dependencies: safe-buffer "5.2.1" -content-hash@^2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz" - integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== - dependencies: - cids "^0.7.1" - multicodec "^0.5.5" - multihashes "^0.4.15" - content-type@^1.0.2, content-type@~1.0.4, content-type@~1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" @@ -9067,7 +8898,7 @@ cookie@0.7.1, cookie@^0.7.1, cookie@~0.7.2: resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== -cookiejar@^2.1.0, cookiejar@^2.1.1, cookiejar@^2.1.4: +cookiejar@^2.1.0, cookiejar@^2.1.4: version "2.1.4" resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz" integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== @@ -9107,7 +8938,7 @@ core-util-is@~1.0.0: resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@^2.8.1, cors@~2.8.5: +cors@~2.8.5: version "2.8.5" resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== @@ -9532,7 +9363,7 @@ debounce@^1.2.1: resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9, debug@^2.2.0, debug@^2.6.9: +debug@2.6.9, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -9585,18 +9416,6 @@ decamelize@^4.0.0: resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -decode-uri-component@^0.2.0: - version "0.2.2" - resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz" - integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== - -decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" - integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== - dependencies: - mimic-response "^1.0.0" - decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" @@ -9670,11 +9489,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - defer-to-connect@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" @@ -9975,11 +9789,6 @@ dom-serializer@^2.0.0: domhandler "^5.0.2" entities "^4.2.0" -dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - domain-browser@^4.16.0: version "4.23.0" resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-4.23.0.tgz" @@ -10097,11 +9906,6 @@ duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: dependencies: readable-stream "^2.0.2" -duplexer3@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz" - integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== - duplexer@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" @@ -10174,7 +9978,7 @@ electron-to-chromium@^1.5.211: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz#f434187f227fb7e67bfcf8243b959cf3ce14013e" integrity sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q== -elliptic@6.5.4, elliptic@6.6.1, elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5, elliptic@^6.5.7, elliptic@^6.6.1: +elliptic@6.5.4, elliptic@6.6.1, elliptic@^6.4.1, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4, elliptic@^6.5.5, elliptic@^6.5.7, elliptic@^6.6.1: version "6.6.1" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== @@ -10459,7 +10263,7 @@ es-to-primitive@^1.3.0: is-date-object "^1.0.5" is-symbol "^1.0.4" -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.53, es5-ext@^0.10.62, es5-ext@^0.10.63, es5-ext@^0.10.64, es5-ext@~0.10.14, es5-ext@~0.10.2: +es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.53, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14, es5-ext@~0.10.2: version "0.10.64" resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz" integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== @@ -10846,35 +10650,6 @@ etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -eth-ens-namehash@2.0.8: - version "2.0.8" - resolved "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz" - integrity sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw== - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - -eth-lib@0.2.8, eth-lib@^0.2.8: - version "0.2.8" - resolved "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz" - integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - -eth-lib@^0.1.26: - version "0.1.29" - resolved "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz" - integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - nano-json-stream-parser "^0.1.2" - servify "^0.1.12" - ws "^3.0.0" - xhr-request-promise "^0.1.2" - ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz" @@ -10924,19 +10699,6 @@ ethereumjs-abi@^0.6.5: bn.js "^4.11.8" ethereumjs-util "^6.0.0" -ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz" - integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== - -ethereumjs-tx@^2.1.1: - version "2.1.2" - resolved "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - ethereumjs-util@7.1.5, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz" @@ -10948,19 +10710,6 @@ ethereumjs-util@7.1.5, ethereumjs-util@^7.1.5: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethereumjs-util@^5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz" - integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" - ethereumjs-util@^6.0.0: version "6.2.1" resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz" @@ -11067,7 +10816,7 @@ ethjs-unit@0.1.6: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: +ethjs-util@0.1.6, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -11088,11 +10837,6 @@ eventemitter2@6.4.7: resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz" integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== -eventemitter3@4.0.4: - version "4.0.4" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz" - integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== - eventemitter3@5.0.1, eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" @@ -11240,7 +10984,7 @@ exponential-backoff@^3.1.1, exponential-backoff@^3.1.2: resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz" integrity sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA== -express@4.21.2, express@^4.14.0, express@^4.21.2: +express@4.21.2, express@^4.21.2: version "4.21.2" resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== @@ -11713,11 +11457,6 @@ forwarded@0.2.0: resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fp-ts@2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-2.1.1.tgz" - integrity sha512-YcWhMdDCFCja0MmaDroTgNu+NWWrrnUEn92nvDgrtVy9Z71YFnhNVIghoHPt8gs82ijoMzFGeWKvArbyICiJgw== - fp-ts@2.16.2: version "2.16.2" resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.2.tgz" @@ -11774,15 +11513,6 @@ fs-extra@^11.2.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^4.0.2: - version "4.0.3" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" @@ -11940,13 +11670,6 @@ get-stream@6.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== -get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" @@ -12181,14 +11904,6 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -global@~4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/global/-/global-4.4.0.tgz" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - globals@^13.20.0, globals@^13.6.0, globals@^13.9.0: version "13.24.0" resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" @@ -12232,24 +11947,7 @@ gopd@^1.0.1, gopd@^1.2.0: resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -got@9.6.0: - version "9.6.0" - resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - -got@^11.8.5, got@^11.8.6: +got@^11.8.6: version "11.8.6" resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz" integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== @@ -12653,11 +12351,6 @@ http-errors@~1.6.1, http-errors@~1.6.2: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-https@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz" - integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== - http-parser-js@>=0.5.1: version "0.5.10" resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz#b3277bd6d7ed5588e20ea73bf724fcbe44609075" @@ -12820,13 +12513,6 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz" - integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== - dependencies: - punycode "2.1.0" - ieee754@1.1.13: version "1.1.13" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz" @@ -13043,7 +12729,7 @@ io-ts-types@^0.5.15, io-ts-types@^0.5.16, io-ts-types@^0.5.19: resolved "https://registry.npmjs.org/io-ts-types/-/io-ts-types-0.5.19.tgz" integrity sha512-kQOYYDZG5vKre+INIDZbLeDJe+oM+4zLpUkjXyTMyUfoCpjJNyi29ZLkuEAwcPufaYo3yu/BsemZtbdD+NtRfQ== -io-ts@2.0.1, io-ts@2.1.3, "io-ts@npm:@bitgo-forks/io-ts@2.1.4": +io-ts@2.1.3, "io-ts@npm:@bitgo-forks/io-ts@2.1.4": version "2.1.4" resolved "https://registry.npmjs.org/@bitgo-forks/io-ts/-/io-ts-2.1.4.tgz" integrity sha512-jCt3WPfDM+wM0SJMGJkY0TS6JmaQ78ATAYtsppJYJfts8geOS/N/UftwAROXwv6azKAMz8uo163t6dWWwfsYug== @@ -13199,11 +12885,6 @@ is-fullwidth-code-point@^4.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz" integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== -is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - is-generator-function@^1.0.10, is-generator-function@^1.0.7: version "1.1.0" resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz" @@ -13769,11 +13450,6 @@ js-sha3@0.8.0, js-sha3@^0.8.0: resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz" - integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== - js-sha512@0.8.0, js-sha512@^0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz" @@ -13867,11 +13543,6 @@ json-bigint@^1.0.0: dependencies: bignumber.js "^9.0.0" -json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz" - integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== - json-buffer@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" @@ -14152,13 +13823,6 @@ key-encoder@^2.0.3: bn.js "^4.11.8" elliptic "^6.4.1" -keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - keyv@^4.0.0, keyv@^4.5.3: version "4.5.4" resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" @@ -14683,11 +14347,6 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" -lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - lowercase-keys@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" @@ -15052,7 +14711,7 @@ mime-db@1.52.0: resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@^2.1.25, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.25, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -15086,7 +14745,7 @@ mimic-fn@^4.0.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== -mimic-response@^1.0.0, mimic-response@^1.0.1: +mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== @@ -15096,13 +14755,6 @@ mimic-response@^3.1.0: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz" - integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== - dependencies: - dom-walk "^0.1.0" - min-indent@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" @@ -15310,18 +14962,6 @@ minizlib@^3.0.1, minizlib@^3.1.0: dependencies: minipass "^7.1.2" -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz" - integrity sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w== - dependencies: - mkdirp "*" - -mkdirp@*: - version "3.0.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - mkdirp@^0.5.4, mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" @@ -15360,11 +15000,6 @@ mocha@10.6.0: yargs-parser "^20.2.9" yargs-unparser "^2.0.0" -mock-fs@^4.1.0: - version "4.14.0" - resolved "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz" - integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== - mock-property@~1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/mock-property/-/mock-property-1.0.3.tgz" @@ -15449,22 +15084,6 @@ msrcrypto@^1.5.6: resolved "https://registry.npmjs.org/msrcrypto/-/msrcrypto-1.5.8.tgz" integrity sha512-ujZ0TRuozHKKm6eGbKHfXef7f+esIhEckmThVnz7RNyiOJd7a6MXj2JGBoL9cnPDW+JMG16MoTUh5X+XXjI66Q== -multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz" - integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - -multibase@~0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz" - integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - multicast-dns@^7.2.5: version "7.2.5" resolved "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz" @@ -15473,30 +15092,6 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" -multicodec@^0.5.5: - version "0.5.7" - resolved "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz" - integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== - dependencies: - varint "^5.0.0" - -multicodec@^1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz" - integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== - dependencies: - buffer "^5.6.0" - varint "^5.0.0" - -multihashes@^0.4.15, multihashes@~0.4.15: - version "0.4.21" - resolved "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz" - integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== - dependencies: - buffer "^5.5.0" - multibase "^0.7.0" - varint "^5.0.0" - multimatch@5.0.0, multimatch@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz" @@ -15523,11 +15118,6 @@ nan@2.14.0: resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== -nano-json-stream-parser@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz" - integrity sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== - nanoassert@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz" @@ -15836,11 +15426,6 @@ normalize-range@^0.1.2: resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== -normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" @@ -16131,7 +15716,7 @@ nyc@^15.0.0, nyc@^15.1.0: test-exclude "^6.0.0" yargs "^15.0.2" -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -16213,13 +15798,6 @@ object.values@^1.2.1: define-properties "^1.2.1" es-object-atoms "^1.0.0" -oboe@2.1.5: - version "2.1.5" - resolved "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz" - integrity sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA== - dependencies: - http-https "^1.0.0" - obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" @@ -16372,11 +15950,6 @@ ox@0.9.3: abitype "^1.0.9" eventemitter3 "5.0.1" -p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" @@ -16704,11 +16277,6 @@ parse-conflict-json@^4.0.0: just-diff "^6.0.0" just-diff-apply "^5.2.0" -parse-headers@^2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz" - integrity sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A== - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" @@ -17335,11 +16903,6 @@ prelude-ls@~1.1.2: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz" - integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== - prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" @@ -17627,11 +17190,6 @@ punycode@1.3.2: resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== -punycode@2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz" - integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== - punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" @@ -17708,15 +17266,6 @@ qs@6.14.0, qs@^6.11.0, qs@^6.11.2, qs@^6.12.3, qs@^6.5.1: dependencies: side-channel "^1.1.0" -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - querystring-es3@^0.2.1, querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz" @@ -18166,7 +17715,7 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" -request@^2.79.0, "request@npm:@cypress/request@3.0.9": +"request@npm:@cypress/request@3.0.9": version "3.0.9" resolved "https://registry.npmjs.org/@cypress/request/-/request-3.0.9.tgz#8ed6e08fea0c62998b5552301023af7268f11625" integrity sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw== @@ -18276,13 +17825,6 @@ resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz" - integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== - dependencies: - lowercase-keys "^1.0.0" - responselike@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz" @@ -18405,7 +17947,7 @@ ripple-keypairs@2.0.0, ripple-keypairs@^2.0.0: "@xrplf/isomorphic" "^1.0.0" ripple-address-codec "^5.0.0" -rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.3, rlp@^2.2.4: version "2.2.7" resolved "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== @@ -18584,7 +18126,7 @@ schema-utils@^4.0.0, schema-utils@^4.2.0, schema-utils@^4.3.0, schema-utils@^4.3 ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: +scrypt-js@3.0.1, scrypt-js@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== @@ -18690,17 +18232,6 @@ serve-static@1.16.2: parseurl "~1.3.3" send "0.19.0" -servify@^0.1.12: - version "0.1.12" - resolved "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz" - integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== - dependencies: - body-parser "^1.16.0" - cors "^2.8.1" - express "^4.14.0" - request "^2.79.0" - xhr "^2.3.3" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" @@ -18978,15 +18509,6 @@ simple-concat@^1.0.0: resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== -simple-get@^2.7.0: - version "2.8.2" - resolved "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz" - integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== - dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" - sinon@^13.0.1: version "13.0.2" resolved "https://registry.npmjs.org/sinon/-/sinon-13.0.2.tgz" @@ -19496,11 +19018,6 @@ strict-event-emitter-types@^2.0.0: resolved "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz" integrity sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA== -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz" - integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== - string-argv@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz" @@ -19818,23 +19335,6 @@ svg-pathdata@^6.0.3: resolved "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz" integrity sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw== -swarm-js@^0.1.40: - version "0.1.42" - resolved "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz" - integrity sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ== - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^11.8.5" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request "^1.0.1" - symbol-observable@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz" @@ -19906,7 +19406,7 @@ tar-stream@~2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@6.2.1, tar@^4.0.2, tar@^6.1.11, tar@^6.1.2: +tar@6.2.1, tar@^6.1.11, tar@^6.1.2: version "6.2.1" resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== @@ -20036,11 +19536,6 @@ thunky@^1.0.2: resolved "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz" - integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== - timers-browserify@^1.0.1: version "1.4.2" resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz" @@ -20115,11 +19610,6 @@ to-buffer@^1.2.0: safe-buffer "^5.2.1" typed-array-buffer "^1.0.3" -to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" @@ -20554,11 +20044,6 @@ undeclared-identifiers@^1.1.2: simple-concat "^1.0.0" xtend "^4.0.1" -underscore@1.12.1: - version "1.12.1" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz" - integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== - underscore@~1.13.2: version "1.13.7" resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz" @@ -20704,18 +20189,6 @@ urijs@^1.19.1: resolved "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz" integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== -url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz" - integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== - dependencies: - prepend-http "^2.0.0" - -url-set-query@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz" - integrity sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg== - url@0.10.3: version "0.10.3" resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz" @@ -20756,7 +20229,7 @@ utf-8-validate@^5.0.2: dependencies: node-gyp-build "^4.3.0" -utf8@3.0.0, utf8@^3.0.0: +utf8@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== @@ -20814,11 +20287,6 @@ utrie@^1.0.2: dependencies: base64-arraybuffer "^1.0.2" -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - uuid@8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz" @@ -20867,11 +20335,6 @@ validator@^13.7.0: resolved "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz#246594be5671dc09daa35caec5689fcd18c6e7e4" integrity sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A== -varint@^5.0.0: - version "5.0.2" - resolved "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz" - integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== - varuint-bitcoin@^1.0.1, varuint-bitcoin@^1.0.4, varuint-bitcoin@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz" @@ -20976,78 +20439,6 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== -web3-bzz@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.3.6.tgz" - integrity sha512-ibHdx1wkseujFejrtY7ZyC0QxQ4ATXjzcNUpaLrvM6AEae8prUiyT/OloG9FWDgFD2CPLwzKwfSQezYQlANNlw== - dependencies: - "@types/node" "^12.12.6" - got "9.6.0" - swarm-js "^0.1.40" - underscore "1.12.1" - -web3-core-helpers@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.3.6.tgz" - integrity sha512-nhtjA2ZbkppjlxTSwG0Ttu6FcPkVu1rCN5IFAOVpF/L0SEt+jy+O5l90+cjDq0jAYvlBwUwnbh2mR9hwDEJCNA== - dependencies: - underscore "1.12.1" - web3-eth-iban "1.3.6" - web3-utils "1.3.6" - -web3-core-method@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.3.6.tgz" - integrity sha512-RyegqVGxn0cyYW5yzAwkPlsSEynkdPiegd7RxgB4ak1eKk2Cv1q2x4C7D2sZjeeCEF+q6fOkVmo2OZNqS2iQxg== - dependencies: - "@ethersproject/transactions" "^5.0.0-beta.135" - underscore "1.12.1" - web3-core-helpers "1.3.6" - web3-core-promievent "1.3.6" - web3-core-subscriptions "1.3.6" - web3-utils "1.3.6" - -web3-core-promievent@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.3.6.tgz" - integrity sha512-Z+QzfyYDTXD5wJmZO5wwnRO8bAAHEItT1XNSPVb4J1CToV/I/SbF7CuF8Uzh2jns0Cm1109o666H7StFFvzVKw== - dependencies: - eventemitter3 "4.0.4" - -web3-core-requestmanager@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.3.6.tgz" - integrity sha512-2rIaeuqeo7QN1Eex7aXP0ZqeteJEPWXYFS/M3r3LXMiV8R4STQBKE+//dnHJXoo2ctzEB5cgd+7NaJM8S3gPyA== - dependencies: - underscore "1.12.1" - util "^0.12.0" - web3-core-helpers "1.3.6" - web3-providers-http "1.3.6" - web3-providers-ipc "1.3.6" - web3-providers-ws "1.3.6" - -web3-core-subscriptions@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.3.6.tgz" - integrity sha512-wi9Z9X5X75OKvxAg42GGIf81ttbNR2TxzkAsp1g+nnp5K8mBwgZvXrIsDuj7Z7gx72Y45mWJADCWjk/2vqNu8g== - dependencies: - eventemitter3 "4.0.4" - underscore "1.12.1" - web3-core-helpers "1.3.6" - -web3-core@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-core/-/web3-core-1.3.6.tgz" - integrity sha512-gkLDM4T1Sc0T+HZIwxrNrwPg0IfWI0oABSglP2X5ZbBAYVUeEATA0o92LWV8BeF+okvKXLK1Fek/p6axwM/h3Q== - dependencies: - "@types/bn.js" "^4.11.5" - "@types/node" "^12.12.6" - bignumber.js "^9.0.0" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-core-requestmanager "1.3.6" - web3-utils "1.3.6" - web3-errors@^1.1.4, web3-errors@^1.2.0: version "1.3.1" resolved "https://registry.npmjs.org/web3-errors/-/web3-errors-1.3.1.tgz" @@ -21055,153 +20446,12 @@ web3-errors@^1.1.4, web3-errors@^1.2.0: dependencies: web3-types "^1.10.0" -web3-eth-abi@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.3.6.tgz" - integrity sha512-Or5cRnZu6WzgScpmbkvC6bfNxR26hqiKK4i8sMPFeTUABQcb/FU3pBj7huBLYbp9dH+P5W79D2MqwbWwjj9DoQ== - dependencies: - "@ethersproject/abi" "5.0.7" - underscore "1.12.1" - web3-utils "1.3.6" - -web3-eth-accounts@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.3.6.tgz" - integrity sha512-Ilr0hG6ONbCdSlVKffasCmNwftD5HsNpwyQASevocIQwHdTlvlwO0tb3oGYuajbKOaDzNTwXfz25bttAEoFCGA== - dependencies: - crypto-browserify "3.12.0" - eth-lib "0.2.8" - ethereumjs-common "^1.3.2" - ethereumjs-tx "^2.1.1" - scrypt-js "^3.0.1" - underscore "1.12.1" - uuid "3.3.2" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-utils "1.3.6" - -web3-eth-contract@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.3.6.tgz" - integrity sha512-8gDaRrLF2HCg+YEZN1ov0zN35vmtPnGf3h1DxmJQK5Wm2lRMLomz9rsWsuvig3UJMHqZAQKD7tOl3ocJocQsmA== - dependencies: - "@types/bn.js" "^4.11.5" - underscore "1.12.1" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-core-promievent "1.3.6" - web3-core-subscriptions "1.3.6" - web3-eth-abi "1.3.6" - web3-utils "1.3.6" - -web3-eth-ens@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.3.6.tgz" - integrity sha512-n27HNj7lpSkRxTgSx+Zo7cmKAgyg2ElFilaFlUu/X2CNH23lXfcPm2bWssivH9z0ndhg0OyR4AYFZqPaqDHkJA== - dependencies: - content-hash "^2.5.2" - eth-ens-namehash "2.0.8" - underscore "1.12.1" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-promievent "1.3.6" - web3-eth-abi "1.3.6" - web3-eth-contract "1.3.6" - web3-utils "1.3.6" - -web3-eth-iban@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.3.6.tgz" - integrity sha512-nfMQaaLA/zsg5W4Oy/EJQbs8rSs1vBAX6b/35xzjYoutXlpHMQadujDx2RerTKhSHqFXSJeQAfE+2f6mdhYkRQ== - dependencies: - bn.js "^4.11.9" - web3-utils "1.3.6" - -web3-eth-personal@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.3.6.tgz" - integrity sha512-pOHU0+/h1RFRYoh1ehYBehRbcKWP4OSzd4F7mDljhHngv6W8ewMHrAN8O1ol9uysN2MuCdRE19qkRg5eNgvzFQ== - dependencies: - "@types/node" "^12.12.6" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-net "1.3.6" - web3-utils "1.3.6" - -web3-eth@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-eth/-/web3-eth-1.3.6.tgz" - integrity sha512-9+rnywRRpyX3C4hfsAQXPQh6vHh9XzQkgLxo3gyeXfbhbShUoq2gFVuy42vsRs//6JlsKdyZS7Z3hHPHz2wreA== - dependencies: - underscore "1.12.1" - web3-core "1.3.6" - web3-core-helpers "1.3.6" - web3-core-method "1.3.6" - web3-core-subscriptions "1.3.6" - web3-eth-abi "1.3.6" - web3-eth-accounts "1.3.6" - web3-eth-contract "1.3.6" - web3-eth-ens "1.3.6" - web3-eth-iban "1.3.6" - web3-eth-personal "1.3.6" - web3-net "1.3.6" - web3-utils "1.3.6" - -web3-net@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-net/-/web3-net-1.3.6.tgz" - integrity sha512-KhzU3wMQY/YYjyMiQzbaLPt2kut88Ncx2iqjy3nw28vRux3gVX0WOCk9EL/KVJBiAA/fK7VklTXvgy9dZnnipw== - dependencies: - web3-core "1.3.6" - web3-core-method "1.3.6" - web3-utils "1.3.6" - -web3-providers-http@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.3.6.tgz" - integrity sha512-OQkT32O1A06dISIdazpGLveZcOXhEo5cEX6QyiSQkiPk/cjzDrXMw4SKZOGQbbS1+0Vjizm1Hrp7O8Vp2D1M5Q== - dependencies: - web3-core-helpers "1.3.6" - xhr2-cookies "1.1.0" - -web3-providers-ipc@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.3.6.tgz" - integrity sha512-+TVsSd2sSVvVgHG4s6FXwwYPPT91boKKcRuEFXqEfAbUC5t52XOgmyc2LNiD9LzPhed65FbV4LqICpeYGUvSwA== - dependencies: - oboe "2.1.5" - underscore "1.12.1" - web3-core-helpers "1.3.6" - -web3-providers-ws@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.3.6.tgz" - integrity sha512-bk7MnJf5or0Re2zKyhR3L3CjGululLCHXx4vlbc/drnaTARUVvi559OI5uLytc/1k5HKUUyENAxLvetz2G1dnQ== - dependencies: - eventemitter3 "4.0.4" - underscore "1.12.1" - web3-core-helpers "1.3.6" - websocket "^1.0.32" - -web3-shh@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3-shh/-/web3-shh-1.3.6.tgz" - integrity sha512-9zRo415O0iBslxBnmu9OzYjNErzLnzOsy+IOvSpIreLYbbAw0XkDWxv3SfcpKnTIWIACBR4AYMIxmmyi5iB3jw== - dependencies: - web3-core "1.3.6" - web3-core-method "1.3.6" - web3-core-subscriptions "1.3.6" - web3-net "1.3.6" - web3-types@^1.10.0, web3-types@^1.5.0, web3-types@^1.6.0: version "1.10.0" resolved "https://registry.npmjs.org/web3-types/-/web3-types-1.10.0.tgz" integrity sha512-0IXoaAFtFc8Yin7cCdQfB9ZmjafrbP6BO0f0KT/khMhXKUpoJ6yShrVhiNpyRBo8QQjuOagsWzwSK2H49I7sbw== -web3-utils@1.3.6, web3-utils@4.2.1: +web3-utils@4.2.1: version "4.2.1" resolved "https://registry.npmjs.org/web3-utils/-/web3-utils-4.2.1.tgz#326bc6e9e4d047f7b38ba68bee1399c4f9f621e3" integrity sha512-Fk29BlEqD9Q9Cnw4pBkKw7czcXiRpsSco/BzEUl4ye0ZTSHANQFfjsfQmNm4t7uY11u6Ah+8F3tNjBeU4CA80A== @@ -21223,19 +20473,6 @@ web3-validator@^2.0.4: web3-types "^1.6.0" zod "^3.21.4" -web3@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/web3/-/web3-1.3.6.tgz" - integrity sha512-jEpPhnL6GDteifdVh7ulzlPrtVQeA30V9vnki9liYlUvLV82ZM7BNOQJiuzlDePuE+jZETZSP/0G/JlUVt6pOA== - dependencies: - web3-bzz "1.3.6" - web3-core "1.3.6" - web3-eth "1.3.6" - web3-eth-personal "1.3.6" - web3-net "1.3.6" - web3-shh "1.3.6" - web3-utils "1.3.6" - webcrypto-core@^1.8.0: version "1.8.1" resolved "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz" @@ -21436,18 +20673,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -websocket@^1.0.32: - version "1.0.35" - resolved "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz" - integrity sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.63" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - whatwg-fetch@^3.4.1: version "3.6.20" resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz" @@ -21678,7 +20903,7 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@5.2.4, ws@^3.0.0: +ws@5.2.4: version "5.2.4" resolved "https://registry.npmjs.org/ws/-/ws-5.2.4.tgz#c7bea9f1cfb5f410de50e70e82662e562113f9a7" integrity sha512-fFCejsuC8f9kOSu9FYaOw8CdO68O3h5v0lg4p74o8JqWpwTf9tniOD+nOB78aWoVSS6WptVUmDrp/KPsMVBWFQ== @@ -21714,43 +20939,6 @@ wsl-utils@^0.1.0: dependencies: is-wsl "^3.1.0" -xhr-request-promise@^0.1.2: - version "0.1.3" - resolved "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz" - integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== - dependencies: - xhr-request "^1.1.0" - -xhr-request@^1.0.1, xhr-request@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz" - integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== - dependencies: - buffer-to-arraybuffer "^0.0.5" - object-assign "^4.1.1" - query-string "^5.0.1" - simple-get "^2.7.0" - timed-out "^4.0.1" - url-set-query "^1.0.0" - xhr "^2.0.4" - -xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz" - integrity sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g== - dependencies: - cookiejar "^2.1.1" - -xhr@^2.0.4, xhr@^2.3.3: - version "2.6.0" - resolved "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz" - integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - xml2js@0.6.2: version "0.6.2" resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz" @@ -21815,11 +21003,6 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz" - integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== - yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" From ec54517775411f750e4cc9797d25be3c37580203 Mon Sep 17 00:00:00 2001 From: Noel Hawat Date: Wed, 15 Oct 2025 11:22:20 -0400 Subject: [PATCH 33/34] fix(sdk-core): skip STX stake related tx TICKET: SC-3504 --- modules/sdk-core/src/bitgo/staking/stakingWallet.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/sdk-core/src/bitgo/staking/stakingWallet.ts b/modules/sdk-core/src/bitgo/staking/stakingWallet.ts index 574aadb0df..4e38f9c135 100644 --- a/modules/sdk-core/src/bitgo/staking/stakingWallet.ts +++ b/modules/sdk-core/src/bitgo/staking/stakingWallet.ts @@ -289,10 +289,12 @@ export class StakingWallet implements IStakingWallet { // default to verifying a transaction unless explicitly skipped // skipping the verification for btc undelegate because it is just single sig // TODO: SC-3183 (add trx staking verification) + // TODO: SC-3508 (add STX staking verification) const skipVerification = (signOptions.transactionVerificationOptions?.skipTransactionVerification || this.isBtcUndelegate(transaction) || - this.isTrxStaking(transaction)) ?? + this.isTrxStaking(transaction) || + this.isStx()) ?? false; if (!isStakingTxRequestPrebuildResult(builtTx.result) && !skipVerification) { await this.validateBuiltStakingTransaction(builtTx.transaction, builtTx); @@ -452,8 +454,7 @@ export class StakingWallet implements IStakingWallet { if ( buildParams?.type && (explainedTransaction as any).type !== undefined && - ((this.isStx() && TransactionType.ContractCall !== (explainedTransaction as any).type) || // for STX the tx type should always ContractCall - (!this.isStx() && TransactionType[buildParams.type] !== (explainedTransaction as any).type)) + TransactionType[buildParams.type] !== (explainedTransaction as any).type ) { mismatchErrors.push( `Transaction type mismatch. Expected: '${buildParams.type}', Got: '${(explainedTransaction as any).type}'` From f5eac7918b83aa1949944141d24b51d24a3cd414 Mon Sep 17 00:00:00 2001 From: Pengyu Chen Date: Wed, 15 Oct 2025 13:39:37 -0600 Subject: [PATCH 34/34] fix(deps): update account-lib to canton version Ticket: WP-6380 --- modules/account-lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/account-lib/package.json b/modules/account-lib/package.json index bd3074e69d..a3afa0fefe 100644 --- a/modules/account-lib/package.json +++ b/modules/account-lib/package.json @@ -40,7 +40,7 @@ "@bitgo/sdk-coin-bera": "^2.6.5", "@bitgo/sdk-coin-bld": "^3.5.5", "@bitgo/sdk-coin-bsc": "^22.8.5", - "@bitgo/sdk-coin-canton": "^1.2.0", + "@bitgo/sdk-coin-canton": "^1.3.0", "@bitgo/sdk-coin-celo": "^5.3.5", "@bitgo/sdk-coin-coredao": "^2.6.5", "@bitgo/sdk-coin-coreum": "^21.5.5",