From c2fb2d5ab3e8bb42cc17b942d4c4e957c624bb5a Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Tue, 10 Feb 2026 12:18:27 +0100 Subject: [PATCH] feat(abstract-utxo): use wasm-utxo instead of utxo-lib Replace utxo-lib with wasm-utxo for all descriptor-related functionality, including BIP32 interfaces, message signing/verification, and PSBT handling. Issue: BTC-2650 Co-authored-by: llm-git --- .../src/descriptor/NamedDescriptor.ts | 20 +++++----- .../src/descriptor/builder/builder.ts | 9 ++--- .../src/descriptor/builder/parse.ts | 7 ++-- .../createWallet/createDescriptors.ts | 9 +++-- .../src/descriptor/validatePolicy.ts | 5 +-- .../test/unit/descriptor/NamedDescriptor.ts | 6 +-- .../test/unit/descriptor/builder.ts | 13 +++++-- .../createWallet/createDescriptors.ts | 6 +-- .../createWallet/fixtures/DefaultWsh2Of3.json | 8 ++-- .../test/unit/descriptor/descriptorWallet.ts | 4 +- .../NamedDescriptorWithSignature.json | 4 +- .../test/unit/descriptorAddress.ts | 4 +- .../transaction/descriptor/explainPsbt.ts | 9 ++--- .../transaction/descriptor/fixtures.utils.ts | 4 +- .../descriptor/fixtures/explainPsbt.a.json | 6 +-- .../fixtures/parseWithExternalRecipient.json | 8 ++-- .../fixtures/parseWithInternalRecipient.json | 8 ++-- .../fixtures/parseWithoutRecipients.json | 8 ++-- .../test/unit/transaction/descriptor/parse.ts | 39 +++++++++---------- .../test/unit/transaction/descriptor/sign.ts | 10 ++--- .../transaction/descriptor/validatePolicy.ts | 12 +++--- 21 files changed, 106 insertions(+), 93 deletions(-) diff --git a/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts b/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts index f00ad30678..0f7cae4173 100644 --- a/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts +++ b/modules/abstract-utxo/src/descriptor/NamedDescriptor.ts @@ -1,7 +1,5 @@ import * as t from 'io-ts'; -import { Descriptor, DescriptorPkType } from '@bitgo/wasm-utxo'; -import { BIP32Interface, networks } from '@bitgo/utxo-lib'; -import { signMessage, verifyMessage } from '@bitgo/sdk-core'; +import { Descriptor, DescriptorPkType, bip32, message } from '@bitgo/wasm-utxo'; export const NamedDescriptor = t.intersection( [ @@ -27,13 +25,13 @@ export type NamedDescriptorNative = NamedDescriptor; export function createNamedDescriptorWithSignature( name: string, descriptor: string | Descriptor, - signingKey: BIP32Interface + signingKey: bip32.BIP32Interface ): NamedDescriptor { if (typeof descriptor === 'string') { descriptor = Descriptor.fromString(descriptor, 'derivable'); } const value = descriptor.toString(); - const signature = signMessage(value, signingKey, networks.bitcoin).toString('hex'); + const signature = Buffer.from(message.signMessage(value, signingKey.privateKey!)).toString('hex'); return { name, value, signatures: [signature] }; } @@ -41,18 +39,22 @@ export function toNamedDescriptorNative(e: NamedDescriptor, pkType: DescriptorPk return { ...e, value: Descriptor.fromString(e.value, pkType) }; } -export function hasValidSignature(descriptor: string | Descriptor, key: BIP32Interface, signatures: string[]): boolean { +export function hasValidSignature( + descriptor: string | Descriptor, + key: bip32.BIP32Interface, + signatures: string[] +): boolean { if (typeof descriptor === 'string') { descriptor = Descriptor.fromString(descriptor, 'derivable'); } - const message = descriptor.toString(); + const descriptorString = descriptor.toString(); return signatures.some((signature) => { - return verifyMessage(message, key, Buffer.from(signature, 'hex'), networks.bitcoin); + return message.verifyMessage(descriptorString, key.publicKey, Buffer.from(signature, 'hex')); }); } -export function assertHasValidSignature(namedDescriptor: NamedDescriptor, key: BIP32Interface): void { +export function assertHasValidSignature(namedDescriptor: NamedDescriptor, key: bip32.BIP32Interface): void { if (!hasValidSignature(namedDescriptor.value, key, namedDescriptor.signatures ?? [])) { throw new Error(`Descriptor ${namedDescriptor.name} does not have a valid signature (key=${key.toBase58()})`); } diff --git a/modules/abstract-utxo/src/descriptor/builder/builder.ts b/modules/abstract-utxo/src/descriptor/builder/builder.ts index 2f811e40dd..090b524820 100644 --- a/modules/abstract-utxo/src/descriptor/builder/builder.ts +++ b/modules/abstract-utxo/src/descriptor/builder/builder.ts @@ -1,9 +1,8 @@ -import { BIP32Interface } from '@bitgo/utxo-lib'; -import { Descriptor } from '@bitgo/wasm-utxo'; +import { bip32, Descriptor } from '@bitgo/wasm-utxo'; type DescriptorWithKeys = { name: TName; - keys: BIP32Interface[]; + keys: bip32.BIP32Interface[]; path: string; }; @@ -17,14 +16,14 @@ export type DescriptorBuilder = */ | (DescriptorWithKeys<'ShWsh2Of3CltvDrop' | 'Wsh2Of3CltvDrop'> & { locktime: number }); -function toXPub(k: BIP32Interface | string): string { +function toXPub(k: bip32.BIP32Interface | string): string { if (typeof k === 'string') { return k; } return k.neutered().toBase58(); } -function multi(m: number, n: number, keys: BIP32Interface[] | string[], path: string): string { +function multi(m: number, n: number, keys: bip32.BIP32Interface[] | string[], path: string): string { if (n < m) { throw new Error(`Cannot create ${m} of ${n} multisig`); } diff --git a/modules/abstract-utxo/src/descriptor/builder/parse.ts b/modules/abstract-utxo/src/descriptor/builder/parse.ts index ce2680ca3c..685b6ea354 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, bip32 } from '@bitgo/secp256k1'; -import { Descriptor } from '@bitgo/wasm-utxo'; +import { BIP32, bip32, Descriptor } from '@bitgo/wasm-utxo'; import { DescriptorBuilder, getDescriptorFromBuilder } from './builder'; @@ -26,7 +25,7 @@ function unwrapNode(node: unknown, path: string[]): unknown { function parseMulti(node: unknown): { threshold: number; - keys: BIP32Interface[]; + keys: bip32.BIP32Interface[]; path: string; } { if (!Array.isArray(node)) { @@ -54,7 +53,7 @@ function parseMulti(node: unknown): { }); return { threshold, - keys: keyWithPath.map((k) => bip32.fromBase58(k.xpub)), + keys: keyWithPath.map((k) => BIP32.fromBase58(k.xpub)), path: paths[0], }; } diff --git a/modules/abstract-utxo/src/descriptor/createWallet/createDescriptors.ts b/modules/abstract-utxo/src/descriptor/createWallet/createDescriptors.ts index 5751e73583..8112e8abe1 100644 --- a/modules/abstract-utxo/src/descriptor/createWallet/createDescriptors.ts +++ b/modules/abstract-utxo/src/descriptor/createWallet/createDescriptors.ts @@ -1,9 +1,12 @@ -import { BIP32Interface } from '@bitgo/utxo-lib'; +import { bip32 } from '@bitgo/wasm-utxo'; import { createNamedDescriptorWithSignature, NamedDescriptor } from '../NamedDescriptor'; import { getDescriptorFromBuilder, DescriptorBuilder } from '../builder'; -export type DescriptorFromKeys = (userKey: BIP32Interface, cosigners: BIP32Interface[]) => NamedDescriptor[]; +export type DescriptorFromKeys = ( + userKey: bip32.BIP32Interface, + cosigners: bip32.BIP32Interface[] +) => NamedDescriptor[]; /** * Create a pair of external and internal descriptors for a 2-of-3 multisig wallet. @@ -14,7 +17,7 @@ export type DescriptorFromKeys = (userKey: BIP32Interface, cosigners: BIP32Inter */ function createExternalInternalPair( builder: DescriptorBuilder, - userKey: BIP32Interface + userKey: bip32.BIP32Interface ): [NamedDescriptor, NamedDescriptor] { if (userKey.isNeutered()) { throw new Error('User key must be private'); diff --git a/modules/abstract-utxo/src/descriptor/validatePolicy.ts b/modules/abstract-utxo/src/descriptor/validatePolicy.ts index 2f90ed235a..0df5f38bf6 100644 --- a/modules/abstract-utxo/src/descriptor/validatePolicy.ts +++ b/modules/abstract-utxo/src/descriptor/validatePolicy.ts @@ -1,13 +1,12 @@ import { EnvironmentName, Triple } from '@bitgo/sdk-core'; -import * as utxolib from '@bitgo/utxo-lib'; -import { descriptorWallet } from '@bitgo/wasm-utxo'; +import { bip32, descriptorWallet } from '@bitgo/wasm-utxo'; import type { DescriptorMap } from '../wasmUtil'; import { parseDescriptor } from './builder'; import { hasValidSignature, NamedDescriptor, NamedDescriptorNative, toNamedDescriptorNative } from './NamedDescriptor'; -export type KeyTriple = Triple; +export type KeyTriple = Triple; export interface DescriptorValidationPolicy { name: string; diff --git a/modules/abstract-utxo/test/unit/descriptor/NamedDescriptor.ts b/modules/abstract-utxo/test/unit/descriptor/NamedDescriptor.ts index 39100a786d..478b9a2d0a 100644 --- a/modules/abstract-utxo/test/unit/descriptor/NamedDescriptor.ts +++ b/modules/abstract-utxo/test/unit/descriptor/NamedDescriptor.ts @@ -1,20 +1,20 @@ import assert from 'assert'; -import { getFixture, getKeyTriple } from '@bitgo/utxo-core/testutil'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { assertHasValidSignature, createNamedDescriptorWithSignature } from '../../../src/descriptor/NamedDescriptor'; import { getDescriptorFromBuilder } from '../../../src/descriptor/builder'; describe('NamedDescriptor', function () { it('creates named descriptor with signature', async function () { - const keys = getKeyTriple(); + const keys = testutils.getKeyTriple('default'); const namedDescriptor = createNamedDescriptorWithSignature( 'foo', getDescriptorFromBuilder({ name: 'Wsh2Of2', keys, path: '0/*' }), keys[0] ); assert.deepStrictEqual( - await getFixture(__dirname + '/fixtures/NamedDescriptorWithSignature.json', namedDescriptor), + await testutils.getFixture(__dirname + '/fixtures/NamedDescriptorWithSignature.json', namedDescriptor), namedDescriptor ); assertHasValidSignature(namedDescriptor, keys[0]); diff --git a/modules/abstract-utxo/test/unit/descriptor/builder.ts b/modules/abstract-utxo/test/unit/descriptor/builder.ts index 4b3bfe230a..a10b852995 100644 --- a/modules/abstract-utxo/test/unit/descriptor/builder.ts +++ b/modules/abstract-utxo/test/unit/descriptor/builder.ts @@ -1,11 +1,11 @@ import * as assert from 'assert'; -import { getKeyTriple } from '@bitgo/utxo-core/testutil'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { parseDescriptor, DescriptorBuilder, getDescriptorFromBuilder } from '../../../src/descriptor/builder'; function getDescriptorBuilderForType(name: DescriptorBuilder['name']): DescriptorBuilder { - const keys = getKeyTriple().map((k) => k.neutered()); + const keys = testutils.getKeyTriple('default').map((k) => k.neutered()); switch (name) { case 'Wsh2Of2': case 'Wsh2Of3': @@ -25,12 +25,19 @@ function getDescriptorBuilderForType(name: DescriptorBuilder['name']): Descripto } } +function toComparable(builder: DescriptorBuilder): Record { + return { + ...builder, + keys: builder.keys.map((k) => k.toBase58()), + }; +} + function describeForName(n: DescriptorBuilder['name']) { describe(`DescriptorBuilder ${n}`, () => { it('parses descriptor template', () => { const builder = getDescriptorBuilderForType(n); const descriptor = getDescriptorFromBuilder(builder); - assert.deepStrictEqual(builder, parseDescriptor(descriptor)); + assert.deepStrictEqual(toComparable(builder), toComparable(parseDescriptor(descriptor))); }); }); } diff --git a/modules/abstract-utxo/test/unit/descriptor/createWallet/createDescriptors.ts b/modules/abstract-utxo/test/unit/descriptor/createWallet/createDescriptors.ts index ce1f507801..55c80386bc 100644 --- a/modules/abstract-utxo/test/unit/descriptor/createWallet/createDescriptors.ts +++ b/modules/abstract-utxo/test/unit/descriptor/createWallet/createDescriptors.ts @@ -1,17 +1,17 @@ import assert from 'assert'; -import { getFixture, getKeyTriple } from '@bitgo/utxo-core/testutil'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { assertHasValidSignature } from '../../../../src/descriptor/NamedDescriptor'; import { DefaultWsh2Of3 } from '../../../../src/descriptor/createWallet'; describe('createDescriptors', function () { it('should create standard named descriptors', async function () { - const keys = getKeyTriple(); + const keys = testutils.getKeyTriple('default'); const namedDescriptors = DefaultWsh2Of3(keys[0], keys.slice(1)); assert.deepStrictEqual( namedDescriptors, - await getFixture(__dirname + '/fixtures/DefaultWsh2Of3.json', namedDescriptors) + await testutils.getFixture(__dirname + '/fixtures/DefaultWsh2Of3.json', namedDescriptors) ); for (const namedDescriptor of namedDescriptors) { assertHasValidSignature(namedDescriptor, keys[0]); diff --git a/modules/abstract-utxo/test/unit/descriptor/createWallet/fixtures/DefaultWsh2Of3.json b/modules/abstract-utxo/test/unit/descriptor/createWallet/fixtures/DefaultWsh2Of3.json index cb18d84c77..977443341e 100644 --- a/modules/abstract-utxo/test/unit/descriptor/createWallet/fixtures/DefaultWsh2Of3.json +++ b/modules/abstract-utxo/test/unit/descriptor/createWallet/fixtures/DefaultWsh2Of3.json @@ -1,16 +1,16 @@ [ { "name": "Wsh2Of3/external", - "value": "wsh(multi(2,xpub661MyMwAqRbcFXS2qwsTkaFc7PEpwDXWgY1Hx2MS7XywhW24sTjQzxiUgnGNW5v6DsW9Z8JcAqf8a22v21jDSA3DwLbbpt2ra3WbP83QNvP/0/*,xpub661MyMwAqRbcGfiaWcoeKLerFu3qRfy6zSYAwnmxSKW8JSauRajFsAsRHs2pV4q5rxkb4ynx4Bm8t54McTCp8V27s7XsdpD8T4s56etpjro/0/*,xpub661MyMwAqRbcH4HzWiCwmYajy1SXZngxHvpYDNEX4xjrDAneAm6rnpPuPPXcBRsSgxupDBmH2tzPHkikNrnLbsvTHemPFHSFbZxonZcCwFi/0/*))#x382fygz", + "value": "wsh(multi(2,xpub661MyMwAqRbcGZfgedgcQiBJpkHoZ37k6uotUVLoC6Px4Y46Yrdmy1CUogcJMoAsosY381gPjhGe9jFx1uYAcxy2gTHh9YFP32tUWycqHnV/0/*,xpub661MyMwAqRbcF8FoYWukS8eTn2gVEojzwf5DYETpB8uqC8t5sqDCEFnuJ39DaPjLRerBDK9QqSMvSYpT4WSugCVbUK5HEevSKAu1wUkVWsS/0/*,xpub661MyMwAqRbcFdScyinA4JpCViqkKsd37MQ6fwuZQQ4shdaGRRX9a8bWvR9QC1AFqKongweJJfyrm7uCoWmCw7UixwGZkZnCT2mchFr7cQb/0/*))#ve5dkda0", "signatures": [ - "20f303b798a75260ce7934e8fff7d8da12fd1b99dbd74879596c201d6acc344cbd151291c25d3d5fba428e844a6eb63a45f645deb2a5ae44e51d968614d4de9a39" + "1fe5bd14b540ae1c21110d49afb650d6fdc48621165e5e24012ffef42e97a38b0d1d9e9955692b9d8be4919b977438c4cde4d366a5e7ce5237fc9f01b4154dc4e1" ] }, { "name": "Wsh2Of3/internal", - "value": "wsh(multi(2,xpub661MyMwAqRbcFXS2qwsTkaFc7PEpwDXWgY1Hx2MS7XywhW24sTjQzxiUgnGNW5v6DsW9Z8JcAqf8a22v21jDSA3DwLbbpt2ra3WbP83QNvP/1/*,xpub661MyMwAqRbcGfiaWcoeKLerFu3qRfy6zSYAwnmxSKW8JSauRajFsAsRHs2pV4q5rxkb4ynx4Bm8t54McTCp8V27s7XsdpD8T4s56etpjro/1/*,xpub661MyMwAqRbcH4HzWiCwmYajy1SXZngxHvpYDNEX4xjrDAneAm6rnpPuPPXcBRsSgxupDBmH2tzPHkikNrnLbsvTHemPFHSFbZxonZcCwFi/1/*))#73gjjc7a", + "value": "wsh(multi(2,xpub661MyMwAqRbcGZfgedgcQiBJpkHoZ37k6uotUVLoC6Px4Y46Yrdmy1CUogcJMoAsosY381gPjhGe9jFx1uYAcxy2gTHh9YFP32tUWycqHnV/1/*,xpub661MyMwAqRbcF8FoYWukS8eTn2gVEojzwf5DYETpB8uqC8t5sqDCEFnuJ39DaPjLRerBDK9QqSMvSYpT4WSugCVbUK5HEevSKAu1wUkVWsS/1/*,xpub661MyMwAqRbcFdScyinA4JpCViqkKsd37MQ6fwuZQQ4shdaGRRX9a8bWvR9QC1AFqKongweJJfyrm7uCoWmCw7UixwGZkZnCT2mchFr7cQb/1/*))#5em4d3ts", "signatures": [ - "1fd2b2d9e294e9fe56ccba37d9992220c9bc16bb4c05fbd4f700de2eff1ae1dc051d1b3573304c470a61d5f5c4fa652a785cf9a69865b44da7059701bc9ee8173f" + "2001654c1ce7a8c94dc510c0cd25a0eee5d06da44e146b3c18546084206f53bbec194e14bc4ffd97eedad97a2176db0e4215323a30f683b8fd8bebcd135f19687e" ] } ] diff --git a/modules/abstract-utxo/test/unit/descriptor/descriptorWallet.ts b/modules/abstract-utxo/test/unit/descriptor/descriptorWallet.ts index 0eb11a96e8..948dcbe138 100644 --- a/modules/abstract-utxo/test/unit/descriptor/descriptorWallet.ts +++ b/modules/abstract-utxo/test/unit/descriptor/descriptorWallet.ts @@ -1,12 +1,14 @@ import assert from 'assert'; -import { getDefaultXPubs, getDescriptorMap } from '@bitgo/utxo-core/testutil/descriptor'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { getDescriptorMapFromWallet, isDescriptorWallet } from '../../../src/descriptor'; import { UtxoWallet } from '../../../src/wallet'; import { toBip32Triple } from '../../../src/keychains'; import { policyAllowAll } from '../../../src/descriptor/validatePolicy'; +const { getDefaultXPubs, getDescriptorMap } = testutils.descriptor; + describe('isDescriptorWalletData', function () { const descriptorMap = getDescriptorMap('Wsh2Of3'); it('should return true for valid DescriptorWalletData', function () { diff --git a/modules/abstract-utxo/test/unit/descriptor/fixtures/NamedDescriptorWithSignature.json b/modules/abstract-utxo/test/unit/descriptor/fixtures/NamedDescriptorWithSignature.json index 6df8301879..822d4be4b8 100644 --- a/modules/abstract-utxo/test/unit/descriptor/fixtures/NamedDescriptorWithSignature.json +++ b/modules/abstract-utxo/test/unit/descriptor/fixtures/NamedDescriptorWithSignature.json @@ -1,7 +1,7 @@ { "name": "foo", - "value": "wsh(multi(2,xpub661MyMwAqRbcFXS2qwsTkaFc7PEpwDXWgY1Hx2MS7XywhW24sTjQzxiUgnGNW5v6DsW9Z8JcAqf8a22v21jDSA3DwLbbpt2ra3WbP83QNvP/0/*,xpub661MyMwAqRbcGfiaWcoeKLerFu3qRfy6zSYAwnmxSKW8JSauRajFsAsRHs2pV4q5rxkb4ynx4Bm8t54McTCp8V27s7XsdpD8T4s56etpjro/0/*))#qd26atvj", + "value": "wsh(multi(2,xpub661MyMwAqRbcGZfgedgcQiBJpkHoZ37k6uotUVLoC6Px4Y46Yrdmy1CUogcJMoAsosY381gPjhGe9jFx1uYAcxy2gTHh9YFP32tUWycqHnV/0/*,xpub661MyMwAqRbcF8FoYWukS8eTn2gVEojzwf5DYETpB8uqC8t5sqDCEFnuJ39DaPjLRerBDK9QqSMvSYpT4WSugCVbUK5HEevSKAu1wUkVWsS/0/*))#uduawd88", "signatures": [ - "20c5eac59397664cc8cdf07b92b85bc55f6d91051aac522a78f7d1ab72043543cd17c3436e11d96d3326274754812c3dd0e693c6330a6cdab1e3e53d618a066091" + "203743318c66496fd3d8be965ceff76c8d975436eb5ee8f8ae2115ae29ee0d60b971445de6984348318fe044b68d08327df55d44ec03c463f27ed209dea107a641" ] } diff --git a/modules/abstract-utxo/test/unit/descriptorAddress.ts b/modules/abstract-utxo/test/unit/descriptorAddress.ts index feee8c8346..402e34b23f 100644 --- a/modules/abstract-utxo/test/unit/descriptorAddress.ts +++ b/modules/abstract-utxo/test/unit/descriptorAddress.ts @@ -1,7 +1,7 @@ import * as assert from 'node:assert'; -import * as utxolib from '@bitgo/utxo-lib'; import { address as wasmAddress, CoinName } from '@bitgo/wasm-utxo'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { IWallet, WalletCoinSpecific } from '@bitgo/sdk-core'; import { descriptor as utxod } from '../../src'; @@ -15,7 +15,7 @@ export function getDescriptorAddress(d: string, index: number, coinName: CoinNam describe('descriptor wallets', function () { const coin = getUtxoCoin('tbtc'); - const xpubs = utxolib.testutil.getKeyTriple('setec astronomy').map((k) => k.neutered().toBase58()); + const xpubs = testutils.getKeyTriple('setec astronomy').map((k) => k.neutered().toBase58()); function withChecksum(descriptor: string): string { return utxod.Descriptor.fromString(descriptor, 'derivable').toString(); diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/explainPsbt.ts b/modules/abstract-utxo/test/unit/transaction/descriptor/explainPsbt.ts index 4919d4570e..f5111bf134 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/explainPsbt.ts +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/explainPsbt.ts @@ -1,15 +1,14 @@ import assert from 'assert'; -import { getKeyTriple } from '@bitgo/utxo-core/testutil'; -import { getDescriptorMap, mockPsbtDefaultWithDescriptorTemplate } from '@bitgo/utxo-core/testutil/descriptor'; import { descriptorWallet } from '@bitgo/wasm-utxo'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import type { TransactionExplanation } from '../../../../src/transaction/fixedScript/explainTransaction'; import { explainPsbt } from '../../../../src/transaction/descriptor'; -import { toWasmPsbt } from '../../../../src/wasmUtil'; import { getFixtureRoot } from './fixtures.utils'; +const { getDescriptorMap, mockPsbtDefaultWithDescriptorTemplate } = testutils.descriptor; const { assertEqualFixture } = getFixtureRoot(__dirname + '/fixtures'); function assertSignatureCount(expl: TransactionExplanation, signatures: number, inputSignatures: number[]) { @@ -21,8 +20,8 @@ function assertSignatureCount(expl: TransactionExplanation, signatures: number, describe('explainPsbt', function () { it('has expected values', async function () { - const psbt = toWasmPsbt(mockPsbtDefaultWithDescriptorTemplate('Wsh2Of3')); - const keys = getKeyTriple('a'); + const psbt = mockPsbtDefaultWithDescriptorTemplate('Wsh2Of3'); + const keys = testutils.getKeyTriple('a'); const descriptorMap = getDescriptorMap('Wsh2Of3', keys); await assertEqualFixture('explainPsbt.a.json', explainPsbt(psbt, descriptorMap, 'btc')); descriptorWallet.signWithKey(psbt, keys[0]); diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures.utils.ts b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures.utils.ts index 2fba2828cd..be4bd3f4f4 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures.utils.ts +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures.utils.ts @@ -1,7 +1,9 @@ import assert from 'assert'; import path from 'path'; -import { getFixture, jsonNormalize } from '@bitgo/utxo-core/testutil'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; + +const { getFixture, jsonNormalize } = testutils; interface FixtureRoot { assertEqualFixture(name: string, v: unknown): Promise; diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/explainPsbt.a.json b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/explainPsbt.a.json index b97e9e9968..6d3bd20ea3 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/explainPsbt.a.json +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/explainPsbt.a.json @@ -5,17 +5,17 @@ ], "signatures": 0, "locktime": 0, - "id": "b9b272a1f0407ea461aca2da115b3399311f424949653c37d5c0023102add158", + "id": "3ffdea969f3486a8c3bddee13349663e5eb25729bfb805ac662b6ebcd9df3f9a", "outputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000" } ], "outputAmount": "400000", "changeOutputs": [ { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000" } ], diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithExternalRecipient.json b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithExternalRecipient.json index ab6e85e3a1..e0e48a6637 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithExternalRecipient.json +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithExternalRecipient.json @@ -1,26 +1,26 @@ { "outputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000", "external": true }, { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000", "external": false } ], "changeOutputs": [ { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000", "external": false } ], "explicitExternalOutputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000", "external": true } diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithInternalRecipient.json b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithInternalRecipient.json index 0f8cf3700d..be490a2c51 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithInternalRecipient.json +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithInternalRecipient.json @@ -1,19 +1,19 @@ { "outputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000", "external": true }, { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000", "external": false } ], "changeOutputs": [ { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000", "external": false } @@ -22,7 +22,7 @@ "explicitExternalSpendAmount": "0", "implicitExternalOutputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000", "external": true } diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithoutRecipients.json b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithoutRecipients.json index 0f8cf3700d..be490a2c51 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithoutRecipients.json +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/fixtures/parseWithoutRecipients.json @@ -1,19 +1,19 @@ { "outputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000", "external": true }, { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000", "external": false } ], "changeOutputs": [ { - "address": "bc1q2yau645jl7k577lmanqn9a0ulcgcqm0wrrmx09dppd3kcwguvyzqk86umj", + "address": "bc1qs86wxj8uk6hwd9sa3glcr3u2a49y8lq2r2ess5rs9ajzgnvwjgtsqeu5j7", "amount": "400000", "external": false } @@ -22,7 +22,7 @@ "explicitExternalSpendAmount": "0", "implicitExternalOutputs": [ { - "address": "bc1qvn279lx29cg843u77p3c37npay7w4uc4xw5d92xxa92z8gd3lkuq4w8477", + "address": "bc1qxnay2ql0dtu8873435w2eg37lxvwj0vhf77702me7sdv3pn795fqk5j2ng", "amount": "400000", "external": true } diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/parse.ts b/modules/abstract-utxo/test/unit/transaction/descriptor/parse.ts index e1252fd929..fdc4957c23 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/parse.ts +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/parse.ts @@ -1,19 +1,12 @@ import assert from 'assert'; -import { Descriptor, descriptorWallet } from '@bitgo/wasm-utxo'; -import { - getDefaultXPubs, - getDescriptor, - getDescriptorMap, - mockPsbtDefault, -} from '@bitgo/utxo-core/testutil/descriptor'; -import { toPlainObject } from '@bitgo/utxo-core/testutil'; +import { Descriptor, Psbt, descriptorWallet } from '@bitgo/wasm-utxo'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { ParsedOutputsBigInt, toBaseParsedTransactionOutputsFromPsbt, } from '../../../../src/transaction/descriptor/parse'; -import type { UtxoLibPsbt } from '../../../../src/wasmUtil'; import { AggregateValidationError, assertExpectedOutputDifference, @@ -25,6 +18,8 @@ import { BaseOutput } from '../../../../src/transaction/types'; import { getFixtureRoot } from './fixtures.utils'; +const { getDefaultXPubs, getDescriptor, getDescriptorMap, mockPsbtDefault } = testutils.descriptor; +const { toPlainObject } = testutils; const { assertEqualFixture } = getFixtureRoot(__dirname + '/fixtures'); type OutputWithValue = { @@ -72,7 +67,7 @@ describe('parse', function () { return recipient(descriptorOther, index, value); } - function getBaseParsedTransaction(psbt: UtxoLibPsbt, recipients: OutputWithValue[]): ParsedOutputsBigInt { + function getBaseParsedTransaction(psbt: Psbt, recipients: OutputWithValue[]): ParsedOutputsBigInt { return toBaseParsedTransactionOutputsFromPsbt( psbt, getDescriptorMap('Wsh2Of3', getDefaultXPubs('a')), @@ -81,21 +76,25 @@ describe('parse', function () { ); } + const psbtOutputs = psbt.getOutputsWithAddress('btc'); + const psbtOutput0 = psbtOutputs[0]; + const psbtOutput1 = psbtOutputs[1]; + describe('toBase', function () { it('should return the correct BaseParsedTransactionOutputs', async function () { await assertEqualFixture('parseWithoutRecipients.json', toPlainObject(getBaseParsedTransaction(psbt, []))); await assertEqualFixture( 'parseWithExternalRecipient.json', - toPlainObject(getBaseParsedTransaction(psbt, [psbt.txOutputs[0]])) + toPlainObject(getBaseParsedTransaction(psbt, [psbtOutput0])) ); await assertEqualFixture( 'parseWithInternalRecipient.json', - toPlainObject(getBaseParsedTransaction(psbt, [psbt.txOutputs[1]])) + toPlainObject(getBaseParsedTransaction(psbt, [psbtOutput1])) ); await assertEqualFixture( 'parseWithExternalRecipient.json', // max recipient: ignore actual value - toPlainObject(getBaseParsedTransaction(psbt, [toMaxOutput(psbt.txOutputs[0])])) + toPlainObject(getBaseParsedTransaction(psbt, [toMaxOutput(psbtOutput0)])) ); }); @@ -128,21 +127,21 @@ describe('parse', function () { it('should throw expected error: no recipient requested', function () { assertValidationError( () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [])), - new AggregateValidationError([implicitOutputError(psbt.txOutputs[0])]) + new AggregateValidationError([implicitOutputError(psbtOutput0)]) ); }); it('should throw expected error: only internal recipient requested', function () { assertValidationError( - () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [psbt.txOutputs[1]])), - new AggregateValidationError([implicitOutputError(psbt.txOutputs[0])]) + () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [psbtOutput1])), + new AggregateValidationError([implicitOutputError(psbtOutput0)]) ); }); it('should throw expected error: only internal max recipient requested', function () { assertValidationError( - () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [toMaxOutput(psbt.txOutputs[1])])), - new AggregateValidationError([implicitOutputError(psbt.txOutputs[0])]) + () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [toMaxOutput(psbtOutput1)])), + new AggregateValidationError([implicitOutputError(psbtOutput0)]) ); }); @@ -150,7 +149,7 @@ describe('parse', function () { const recipient = externalRecipient(99); assertValidationError( () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [recipient])), - new AggregateValidationError([missingOutputError(recipient), implicitOutputError(psbt.txOutputs[0])]) + new AggregateValidationError([missingOutputError(recipient), implicitOutputError(psbtOutput0)]) ); }); @@ -158,7 +157,7 @@ describe('parse', function () { const recipient = internalRecipient(99); assertValidationError( () => assertExpectedOutputDifference(getBaseParsedTransaction(psbt, [recipient])), - new AggregateValidationError([missingOutputError(recipient), implicitOutputError(psbt.txOutputs[0])]) + new AggregateValidationError([missingOutputError(recipient), implicitOutputError(psbtOutput0)]) ); }); }); diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/sign.ts b/modules/abstract-utxo/test/unit/transaction/descriptor/sign.ts index 250ef621eb..43214ec2a0 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/sign.ts +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/sign.ts @@ -1,12 +1,12 @@ import assert from 'assert'; -import { getKeyTriple } from '@bitgo/utxo-core/testutil'; -import { getDescriptorMap, mockPsbtDefaultWithDescriptorTemplate } from '@bitgo/utxo-core/testutil/descriptor'; import { Psbt } from '@bitgo/wasm-utxo'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; import { signPsbt } from '../../../../src/transaction/descriptor'; import { ErrorUnknownInput } from '../../../../src/transaction/descriptor/signPsbt'; -import { toWasmPsbt } from '../../../../src/wasmUtil'; + +const { getDescriptorMap, mockPsbtDefaultWithDescriptorTemplate } = testutils.descriptor; function assertInputHasValidSignatures(psbt: Psbt, inputIndex: number) { assert(psbt.hasPartialSignatures(inputIndex)); @@ -18,8 +18,8 @@ function assertInputHasValidSignatures(psbt: Psbt, inputIndex: number) { } describe('sign', function () { - const psbtUnsigned = toWasmPsbt(mockPsbtDefaultWithDescriptorTemplate('Wsh2Of3')); - const keychain = getKeyTriple('a'); + const psbtUnsigned = mockPsbtDefaultWithDescriptorTemplate('Wsh2Of3'); + const keychain = testutils.getKeyTriple('a'); const descriptorMap = getDescriptorMap('Wsh2Of3', keychain); const emptyDescriptorMap = new Map(); diff --git a/modules/abstract-utxo/test/unit/transaction/descriptor/validatePolicy.ts b/modules/abstract-utxo/test/unit/transaction/descriptor/validatePolicy.ts index 07abbb57b4..3b94a38670 100644 --- a/modules/abstract-utxo/test/unit/transaction/descriptor/validatePolicy.ts +++ b/modules/abstract-utxo/test/unit/transaction/descriptor/validatePolicy.ts @@ -1,10 +1,9 @@ import assert from 'assert'; import { Triple } from '@bitgo/sdk-core'; -import { BIP32Interface } from '@bitgo/utxo-lib'; -import { getKeyTriple } from '@bitgo/utxo-core/testutil'; +import { bip32 } from '@bitgo/wasm-utxo'; +import * as testutils from '@bitgo/wasm-utxo/testutils'; -import { DescriptorTemplate, getDescriptor } from '../../../../../utxo-core/src/testutil/descriptor'; import { assertDescriptorPolicy, DescriptorPolicyValidationError, @@ -18,10 +17,13 @@ import { toNamedDescriptorNative, } from '../../../../src/descriptor'; +type DescriptorTemplate = testutils.descriptor.DescriptorTemplate; +const { getDescriptor } = testutils.descriptor; + function testAssertDescriptorPolicy( ds: NamedDescriptor[], p: DescriptorValidationPolicy, - k: Triple, + k: Triple, expectedError: DescriptorPolicyValidationError | null ) { const f = () => @@ -38,7 +40,7 @@ function testAssertDescriptorPolicy( } describe('assertDescriptorPolicy', function () { - const keys = getKeyTriple(); + const keys = testutils.getKeyTriple('default'); function getNamedDescriptorSigned(name: DescriptorTemplate): NamedDescriptor { return createNamedDescriptorWithSignature(name, getDescriptor(name), keys[0]); }