Skip to content

Commit e0b09a5

Browse files
chore(utxo-coredao): add fixture from testnet3
Be able to provide pubkey buffers as well TICKET: BTC-1578
1 parent 791f9e4 commit e0b09a5

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

modules/utxo-coredao/src/descriptor.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,27 @@ import { BIP32Interface } from '@bitgo/utxo-lib';
55
*/
66
export type ScriptType = 'sh' | 'sh-wsh';
77

8+
function asDescriptorKey(key: BIP32Interface | Buffer, neutered: boolean): string {
9+
if (Buffer.isBuffer(key)) {
10+
return key.toString('hex');
11+
}
12+
return (neutered ? key.neutered() : key).toBase58() + '/*';
13+
}
14+
815
/**
916
* Create a multi-sig descriptor to produce a coredao staking address
1017
* @param scriptType segwit or legacy
1118
* @param locktime locktime for CLTV
1219
* @param m Total number of keys required to unlock
13-
* @param orderedKeys
20+
* @param orderedKeys If Bip32Interfaces, these are xprvs or xpubs and are derivable.
21+
* If they are buffers, then they are pub/prv keys and are not derivable.
1422
* @param neutered If true, neuter the keys. Default to true
1523
*/
1624
export function createMultiSigDescriptor(
1725
scriptType: ScriptType,
1826
locktime: number,
1927
m: number,
20-
orderedKeys: BIP32Interface[],
28+
orderedKeys: (BIP32Interface | Buffer)[],
2129
neutered = true
2230
): string {
2331
if (m > orderedKeys.length || m < 1) {
@@ -28,8 +36,7 @@ export function createMultiSigDescriptor(
2836
if (locktime <= 0) {
2937
throw new Error(`locktime (${locktime}) must be greater than 0`);
3038
}
31-
32-
const xpubs = orderedKeys.map((key) => (neutered ? key.neutered() : key).toBase58() + '/*');
33-
const inner = `and_v(r:after(${locktime}),multi(${m},${xpubs.join(',')}))`;
39+
const keys = orderedKeys.map((key) => asDescriptorKey(key, neutered));
40+
const inner = `and_v(r:after(${locktime}),multi(${m},${keys.join(',')}))`;
3441
return scriptType === 'sh' ? `sh(${inner})` : `sh(wsh(${inner}))`;
3542
}

modules/utxo-coredao/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './opReturn';
2+
export * from './descriptor';

modules/utxo-coredao/test/unit/descriptor.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Descriptor } from '@bitgo/wasm-miniscript';
44

55
import { createMultiSigDescriptor } from '../../src/descriptor';
66
import { finalizePsbt, getFixture, updateInputWithDescriptor } from './utils';
7+
import { decodeTimelock } from '../../src';
78

89
describe('descriptor', function () {
910
const baseFixturePath = 'test/fixtures/descriptor/';
@@ -114,4 +115,36 @@ describe('descriptor', function () {
114115
runTestForParams('sh', 2, [key1, key2]);
115116
runTestForParams('sh-wsh', 2, [key1, key2]);
116117
runTestForParams('sh', 3, [key1, key2, key3]);
118+
119+
it('should recreate the script used in testnet staking transaction', function () {
120+
// Source: https://mempool.space/testnet/address/2MxTi2EhHKgdJFKRTBttVGGxir9ZzjmKCXw
121+
// 2 of 2 multisig
122+
const timelock = 'fce4cb66';
123+
const pubkey1 = '03ecb6d4b7f5d56962e547fc52dd588359f5729c0ba856d6978b84723895a16691';
124+
const pubkey2 = '024aaea25d82b1db2be030a05b641d6302e48ed652b1ca9cb08a67267fcbb56747';
125+
const redeemScriptASM = [
126+
'OP_PUSHBYTES_4',
127+
timelock,
128+
'OP_CLTV',
129+
'OP_DROP',
130+
'OP_PUSHNUM_2',
131+
'OP_PUSHBYTES_33',
132+
pubkey1,
133+
'OP_PUSHBYTES_33',
134+
pubkey2,
135+
'OP_PUSHNUM_2',
136+
'OP_CHECKMULTISIG',
137+
].join(' ');
138+
139+
const decodedTimelock = decodeTimelock(Buffer.from(timelock, 'hex'));
140+
const descriptor = createMultiSigDescriptor(
141+
'sh',
142+
decodedTimelock,
143+
2,
144+
[Buffer.from(pubkey1, 'hex'), Buffer.from(pubkey2, 'hex')],
145+
false
146+
);
147+
const descriptorASM = Descriptor.fromString(descriptor, 'definite').toAsmString();
148+
assert.deepStrictEqual(redeemScriptASM, descriptorASM);
149+
});
117150
});

0 commit comments

Comments
 (0)