Skip to content

Commit f370430

Browse files
Merge pull request #8103 from BitGo/BTC-2650.remove-utxo-lib-from-descriptor.inlined
feat(abstract-utxo): use wasm-utxo instead of utxo-lib
2 parents 2743446 + c2fb2d5 commit f370430

21 files changed

Lines changed: 106 additions & 93 deletions

modules/abstract-utxo/src/descriptor/NamedDescriptor.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import * as t from 'io-ts';
2-
import { Descriptor, DescriptorPkType } from '@bitgo/wasm-utxo';
3-
import { BIP32Interface, networks } from '@bitgo/utxo-lib';
4-
import { signMessage, verifyMessage } from '@bitgo/sdk-core';
2+
import { Descriptor, DescriptorPkType, bip32, message } from '@bitgo/wasm-utxo';
53

64
export const NamedDescriptor = t.intersection(
75
[
@@ -27,32 +25,36 @@ export type NamedDescriptorNative = NamedDescriptor<Descriptor>;
2725
export function createNamedDescriptorWithSignature(
2826
name: string,
2927
descriptor: string | Descriptor,
30-
signingKey: BIP32Interface
28+
signingKey: bip32.BIP32Interface
3129
): NamedDescriptor {
3230
if (typeof descriptor === 'string') {
3331
descriptor = Descriptor.fromString(descriptor, 'derivable');
3432
}
3533
const value = descriptor.toString();
36-
const signature = signMessage(value, signingKey, networks.bitcoin).toString('hex');
34+
const signature = Buffer.from(message.signMessage(value, signingKey.privateKey!)).toString('hex');
3735
return { name, value, signatures: [signature] };
3836
}
3937

4038
export function toNamedDescriptorNative(e: NamedDescriptor, pkType: DescriptorPkType): NamedDescriptorNative {
4139
return { ...e, value: Descriptor.fromString(e.value, pkType) };
4240
}
4341

44-
export function hasValidSignature(descriptor: string | Descriptor, key: BIP32Interface, signatures: string[]): boolean {
42+
export function hasValidSignature(
43+
descriptor: string | Descriptor,
44+
key: bip32.BIP32Interface,
45+
signatures: string[]
46+
): boolean {
4547
if (typeof descriptor === 'string') {
4648
descriptor = Descriptor.fromString(descriptor, 'derivable');
4749
}
4850

49-
const message = descriptor.toString();
51+
const descriptorString = descriptor.toString();
5052
return signatures.some((signature) => {
51-
return verifyMessage(message, key, Buffer.from(signature, 'hex'), networks.bitcoin);
53+
return message.verifyMessage(descriptorString, key.publicKey, Buffer.from(signature, 'hex'));
5254
});
5355
}
5456

55-
export function assertHasValidSignature(namedDescriptor: NamedDescriptor, key: BIP32Interface): void {
57+
export function assertHasValidSignature(namedDescriptor: NamedDescriptor, key: bip32.BIP32Interface): void {
5658
if (!hasValidSignature(namedDescriptor.value, key, namedDescriptor.signatures ?? [])) {
5759
throw new Error(`Descriptor ${namedDescriptor.name} does not have a valid signature (key=${key.toBase58()})`);
5860
}

modules/abstract-utxo/src/descriptor/builder/builder.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { BIP32Interface } from '@bitgo/utxo-lib';
2-
import { Descriptor } from '@bitgo/wasm-utxo';
1+
import { bip32, Descriptor } from '@bitgo/wasm-utxo';
32

43
type DescriptorWithKeys<TName extends string> = {
54
name: TName;
6-
keys: BIP32Interface[];
5+
keys: bip32.BIP32Interface[];
76
path: string;
87
};
98

@@ -17,14 +16,14 @@ export type DescriptorBuilder =
1716
*/
1817
| (DescriptorWithKeys<'ShWsh2Of3CltvDrop' | 'Wsh2Of3CltvDrop'> & { locktime: number });
1918

20-
function toXPub(k: BIP32Interface | string): string {
19+
function toXPub(k: bip32.BIP32Interface | string): string {
2120
if (typeof k === 'string') {
2221
return k;
2322
}
2423
return k.neutered().toBase58();
2524
}
2625

27-
function multi(m: number, n: number, keys: BIP32Interface[] | string[], path: string): string {
26+
function multi(m: number, n: number, keys: bip32.BIP32Interface[] | string[], path: string): string {
2827
if (n < m) {
2928
throw new Error(`Cannot create ${m} of ${n} multisig`);
3029
}

modules/abstract-utxo/src/descriptor/builder/parse.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { BIP32Interface, bip32 } from '@bitgo/secp256k1';
2-
import { Descriptor } from '@bitgo/wasm-utxo';
1+
import { BIP32, bip32, Descriptor } from '@bitgo/wasm-utxo';
32

43
import { DescriptorBuilder, getDescriptorFromBuilder } from './builder';
54

@@ -26,7 +25,7 @@ function unwrapNode(node: unknown, path: string[]): unknown {
2625

2726
function parseMulti(node: unknown): {
2827
threshold: number;
29-
keys: BIP32Interface[];
28+
keys: bip32.BIP32Interface[];
3029
path: string;
3130
} {
3231
if (!Array.isArray(node)) {
@@ -54,7 +53,7 @@ function parseMulti(node: unknown): {
5453
});
5554
return {
5655
threshold,
57-
keys: keyWithPath.map((k) => bip32.fromBase58(k.xpub)),
56+
keys: keyWithPath.map((k) => BIP32.fromBase58(k.xpub)),
5857
path: paths[0],
5958
};
6059
}

modules/abstract-utxo/src/descriptor/createWallet/createDescriptors.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import { BIP32Interface } from '@bitgo/utxo-lib';
1+
import { bip32 } from '@bitgo/wasm-utxo';
22

33
import { createNamedDescriptorWithSignature, NamedDescriptor } from '../NamedDescriptor';
44
import { getDescriptorFromBuilder, DescriptorBuilder } from '../builder';
55

6-
export type DescriptorFromKeys = (userKey: BIP32Interface, cosigners: BIP32Interface[]) => NamedDescriptor[];
6+
export type DescriptorFromKeys = (
7+
userKey: bip32.BIP32Interface,
8+
cosigners: bip32.BIP32Interface[]
9+
) => NamedDescriptor[];
710

811
/**
912
* 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
1417
*/
1518
function createExternalInternalPair(
1619
builder: DescriptorBuilder,
17-
userKey: BIP32Interface
20+
userKey: bip32.BIP32Interface
1821
): [NamedDescriptor, NamedDescriptor] {
1922
if (userKey.isNeutered()) {
2023
throw new Error('User key must be private');

modules/abstract-utxo/src/descriptor/validatePolicy.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { EnvironmentName, Triple } from '@bitgo/sdk-core';
2-
import * as utxolib from '@bitgo/utxo-lib';
3-
import { descriptorWallet } from '@bitgo/wasm-utxo';
2+
import { bip32, descriptorWallet } from '@bitgo/wasm-utxo';
43

54
import type { DescriptorMap } from '../wasmUtil';
65

76
import { parseDescriptor } from './builder';
87
import { hasValidSignature, NamedDescriptor, NamedDescriptorNative, toNamedDescriptorNative } from './NamedDescriptor';
98

10-
export type KeyTriple = Triple<utxolib.BIP32Interface>;
9+
export type KeyTriple = Triple<bip32.BIP32Interface>;
1110

1211
export interface DescriptorValidationPolicy {
1312
name: string;

modules/abstract-utxo/test/unit/descriptor/NamedDescriptor.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import assert from 'assert';
22

3-
import { getFixture, getKeyTriple } from '@bitgo/utxo-core/testutil';
3+
import * as testutils from '@bitgo/wasm-utxo/testutils';
44

55
import { assertHasValidSignature, createNamedDescriptorWithSignature } from '../../../src/descriptor/NamedDescriptor';
66
import { getDescriptorFromBuilder } from '../../../src/descriptor/builder';
77

88
describe('NamedDescriptor', function () {
99
it('creates named descriptor with signature', async function () {
10-
const keys = getKeyTriple();
10+
const keys = testutils.getKeyTriple('default');
1111
const namedDescriptor = createNamedDescriptorWithSignature(
1212
'foo',
1313
getDescriptorFromBuilder({ name: 'Wsh2Of2', keys, path: '0/*' }),
1414
keys[0]
1515
);
1616
assert.deepStrictEqual(
17-
await getFixture(__dirname + '/fixtures/NamedDescriptorWithSignature.json', namedDescriptor),
17+
await testutils.getFixture(__dirname + '/fixtures/NamedDescriptorWithSignature.json', namedDescriptor),
1818
namedDescriptor
1919
);
2020
assertHasValidSignature(namedDescriptor, keys[0]);

modules/abstract-utxo/test/unit/descriptor/builder.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as assert from 'assert';
22

3-
import { getKeyTriple } from '@bitgo/utxo-core/testutil';
3+
import * as testutils from '@bitgo/wasm-utxo/testutils';
44

55
import { parseDescriptor, DescriptorBuilder, getDescriptorFromBuilder } from '../../../src/descriptor/builder';
66

77
function getDescriptorBuilderForType(name: DescriptorBuilder['name']): DescriptorBuilder {
8-
const keys = getKeyTriple().map((k) => k.neutered());
8+
const keys = testutils.getKeyTriple('default').map((k) => k.neutered());
99
switch (name) {
1010
case 'Wsh2Of2':
1111
case 'Wsh2Of3':
@@ -25,12 +25,19 @@ function getDescriptorBuilderForType(name: DescriptorBuilder['name']): Descripto
2525
}
2626
}
2727

28+
function toComparable(builder: DescriptorBuilder): Record<string, unknown> {
29+
return {
30+
...builder,
31+
keys: builder.keys.map((k) => k.toBase58()),
32+
};
33+
}
34+
2835
function describeForName(n: DescriptorBuilder['name']) {
2936
describe(`DescriptorBuilder ${n}`, () => {
3037
it('parses descriptor template', () => {
3138
const builder = getDescriptorBuilderForType(n);
3239
const descriptor = getDescriptorFromBuilder(builder);
33-
assert.deepStrictEqual(builder, parseDescriptor(descriptor));
40+
assert.deepStrictEqual(toComparable(builder), toComparable(parseDescriptor(descriptor)));
3441
});
3542
});
3643
}

modules/abstract-utxo/test/unit/descriptor/createWallet/createDescriptors.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import assert from 'assert';
22

3-
import { getFixture, getKeyTriple } from '@bitgo/utxo-core/testutil';
3+
import * as testutils from '@bitgo/wasm-utxo/testutils';
44

55
import { assertHasValidSignature } from '../../../../src/descriptor/NamedDescriptor';
66
import { DefaultWsh2Of3 } from '../../../../src/descriptor/createWallet';
77

88
describe('createDescriptors', function () {
99
it('should create standard named descriptors', async function () {
10-
const keys = getKeyTriple();
10+
const keys = testutils.getKeyTriple('default');
1111
const namedDescriptors = DefaultWsh2Of3(keys[0], keys.slice(1));
1212
assert.deepStrictEqual(
1313
namedDescriptors,
14-
await getFixture(__dirname + '/fixtures/DefaultWsh2Of3.json', namedDescriptors)
14+
await testutils.getFixture(__dirname + '/fixtures/DefaultWsh2Of3.json', namedDescriptors)
1515
);
1616
for (const namedDescriptor of namedDescriptors) {
1717
assertHasValidSignature(namedDescriptor, keys[0]);
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
[
22
{
33
"name": "Wsh2Of3/external",
4-
"value": "wsh(multi(2,xpub661MyMwAqRbcFXS2qwsTkaFc7PEpwDXWgY1Hx2MS7XywhW24sTjQzxiUgnGNW5v6DsW9Z8JcAqf8a22v21jDSA3DwLbbpt2ra3WbP83QNvP/0/*,xpub661MyMwAqRbcGfiaWcoeKLerFu3qRfy6zSYAwnmxSKW8JSauRajFsAsRHs2pV4q5rxkb4ynx4Bm8t54McTCp8V27s7XsdpD8T4s56etpjro/0/*,xpub661MyMwAqRbcH4HzWiCwmYajy1SXZngxHvpYDNEX4xjrDAneAm6rnpPuPPXcBRsSgxupDBmH2tzPHkikNrnLbsvTHemPFHSFbZxonZcCwFi/0/*))#x382fygz",
4+
"value": "wsh(multi(2,xpub661MyMwAqRbcGZfgedgcQiBJpkHoZ37k6uotUVLoC6Px4Y46Yrdmy1CUogcJMoAsosY381gPjhGe9jFx1uYAcxy2gTHh9YFP32tUWycqHnV/0/*,xpub661MyMwAqRbcF8FoYWukS8eTn2gVEojzwf5DYETpB8uqC8t5sqDCEFnuJ39DaPjLRerBDK9QqSMvSYpT4WSugCVbUK5HEevSKAu1wUkVWsS/0/*,xpub661MyMwAqRbcFdScyinA4JpCViqkKsd37MQ6fwuZQQ4shdaGRRX9a8bWvR9QC1AFqKongweJJfyrm7uCoWmCw7UixwGZkZnCT2mchFr7cQb/0/*))#ve5dkda0",
55
"signatures": [
6-
"20f303b798a75260ce7934e8fff7d8da12fd1b99dbd74879596c201d6acc344cbd151291c25d3d5fba428e844a6eb63a45f645deb2a5ae44e51d968614d4de9a39"
6+
"1fe5bd14b540ae1c21110d49afb650d6fdc48621165e5e24012ffef42e97a38b0d1d9e9955692b9d8be4919b977438c4cde4d366a5e7ce5237fc9f01b4154dc4e1"
77
]
88
},
99
{
1010
"name": "Wsh2Of3/internal",
11-
"value": "wsh(multi(2,xpub661MyMwAqRbcFXS2qwsTkaFc7PEpwDXWgY1Hx2MS7XywhW24sTjQzxiUgnGNW5v6DsW9Z8JcAqf8a22v21jDSA3DwLbbpt2ra3WbP83QNvP/1/*,xpub661MyMwAqRbcGfiaWcoeKLerFu3qRfy6zSYAwnmxSKW8JSauRajFsAsRHs2pV4q5rxkb4ynx4Bm8t54McTCp8V27s7XsdpD8T4s56etpjro/1/*,xpub661MyMwAqRbcH4HzWiCwmYajy1SXZngxHvpYDNEX4xjrDAneAm6rnpPuPPXcBRsSgxupDBmH2tzPHkikNrnLbsvTHemPFHSFbZxonZcCwFi/1/*))#73gjjc7a",
11+
"value": "wsh(multi(2,xpub661MyMwAqRbcGZfgedgcQiBJpkHoZ37k6uotUVLoC6Px4Y46Yrdmy1CUogcJMoAsosY381gPjhGe9jFx1uYAcxy2gTHh9YFP32tUWycqHnV/1/*,xpub661MyMwAqRbcF8FoYWukS8eTn2gVEojzwf5DYETpB8uqC8t5sqDCEFnuJ39DaPjLRerBDK9QqSMvSYpT4WSugCVbUK5HEevSKAu1wUkVWsS/1/*,xpub661MyMwAqRbcFdScyinA4JpCViqkKsd37MQ6fwuZQQ4shdaGRRX9a8bWvR9QC1AFqKongweJJfyrm7uCoWmCw7UixwGZkZnCT2mchFr7cQb/1/*))#5em4d3ts",
1212
"signatures": [
13-
"1fd2b2d9e294e9fe56ccba37d9992220c9bc16bb4c05fbd4f700de2eff1ae1dc051d1b3573304c470a61d5f5c4fa652a785cf9a69865b44da7059701bc9ee8173f"
13+
"2001654c1ce7a8c94dc510c0cd25a0eee5d06da44e146b3c18546084206f53bbec194e14bc4ffd97eedad97a2176db0e4215323a30f683b8fd8bebcd135f19687e"
1414
]
1515
}
1616
]

modules/abstract-utxo/test/unit/descriptor/descriptorWallet.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import assert from 'assert';
22

3-
import { getDefaultXPubs, getDescriptorMap } from '@bitgo/utxo-core/testutil/descriptor';
3+
import * as testutils from '@bitgo/wasm-utxo/testutils';
44

55
import { getDescriptorMapFromWallet, isDescriptorWallet } from '../../../src/descriptor';
66
import { UtxoWallet } from '../../../src/wallet';
77
import { toBip32Triple } from '../../../src/keychains';
88
import { policyAllowAll } from '../../../src/descriptor/validatePolicy';
99

10+
const { getDefaultXPubs, getDescriptorMap } = testutils.descriptor;
11+
1012
describe('isDescriptorWalletData', function () {
1113
const descriptorMap = getDescriptorMap('Wsh2Of3');
1214
it('should return true for valid DescriptorWalletData', function () {

0 commit comments

Comments
 (0)