Skip to content

Commit 1607e90

Browse files
committed
test(wasm-utxo): add sign+finalize roundtrip for sBTC reclaim leaf
Ticket: CSHLD-882
1 parent 4764677 commit 1607e90

1 file changed

Lines changed: 50 additions & 2 deletions

File tree

packages/wasm-utxo/test/psbtFromDescriptor.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BIP32Interface, ECPair, ECPairInterface } from "@bitgo/utxo-lib";
33
import { getKey } from "@bitgo/utxo-lib/dist/src/testutil";
44

55
import { DescriptorNode, formatNode } from "../js/ast/index.js";
6-
import { mockPsbtDefault } from "./psbtFromDescriptor.util.js";
6+
import { mockPsbtDefault, PsbtParams } from "./psbtFromDescriptor.util.js";
77
import { Descriptor, Transaction } from "../js/index.js";
88
import { toWrappedPsbt } from "./psbt.util.js";
99

@@ -38,9 +38,11 @@ function describeSignDescriptor(
3838
{
3939
signBip32 = [],
4040
signECPair = [],
41+
psbtParams,
4142
}: {
4243
signBip32?: BIP32Interface[][];
4344
signECPair?: ECPairInterface[][];
45+
psbtParams?: Partial<PsbtParams>;
4446
},
4547
) {
4648
describe(`psbt with descriptor ${name}`, function () {
@@ -51,6 +53,7 @@ function describeSignDescriptor(
5153
formatNode({ wpkh: toKeyWithPath(external) }),
5254
"derivable",
5355
),
56+
params: psbtParams,
5457
});
5558

5659
function getSigResult(keys: (BIP32Interface | ECPairInterface)[]) {
@@ -155,14 +158,48 @@ describeSignDescriptor(
155158
{ signECPair: [[toECPair(a)]] },
156159
);
157160

161+
// sBTC taproot: NUMS internal key + deposit leaf (payload_drop + protocol signers key)
162+
// and reclaim leaf (2-of-3 multi_a behind r:older(1)). Reclaim path is the one signable
163+
// by user keys; sequence=1 satisfies older(1).
164+
const SBTC_UNSPENDABLE = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0";
165+
const SBTC_SIGNERS_KEY = "c9c2312ca406dcb8eed50b829b5292f5fb3e846db0a556af61cc53834ce75421";
166+
const SBTC_PAYLOAD_HEX = "0000000000013880051ad206838b7981a116c334e8cb1b950afb73eb54a5";
167+
const sbtcDescriptorNode: DescriptorNode = {
168+
tr: [
169+
SBTC_UNSPENDABLE,
170+
[
171+
{ and_v: [{ payload_drop: SBTC_PAYLOAD_HEX }, { pk: SBTC_SIGNERS_KEY }] },
172+
{
173+
and_v: [
174+
{ "r:older": 1 },
175+
{ multi_a: [2, toKeyWithPath(a), toKeyWithPath(b), toKeyWithPath(c)] },
176+
],
177+
},
178+
],
179+
],
180+
};
181+
182+
describeSignDescriptor("P2trSBTC", fromNodes(sbtcDescriptorNode, "derivable"), {
183+
signBip32: [
184+
[a, b],
185+
[b, a],
186+
],
187+
psbtParams: { sequence: 1 },
188+
});
189+
158190
describe("WrapPsbt extractTransaction", function () {
159-
function signFinalizeExtract(descriptor: Descriptor, signKeys: BIP32Interface[]) {
191+
function signFinalizeExtract(
192+
descriptor: Descriptor,
193+
signKeys: BIP32Interface[],
194+
psbtParams?: Partial<PsbtParams>,
195+
) {
160196
const psbt = mockPsbtDefault({
161197
descriptorSelf: descriptor,
162198
descriptorOther: Descriptor.fromString(
163199
formatNode({ wpkh: toKeyWithPath(external) }),
164200
"derivable",
165201
),
202+
params: psbtParams,
166203
});
167204
const wrappedPsbt = toWrappedPsbt(psbt);
168205
for (const key of signKeys) {
@@ -202,6 +239,17 @@ describe("WrapPsbt extractTransaction", function () {
202239
assert.ok(tx.toBytes().length > 0);
203240
});
204241

242+
it("should extract transaction from finalized P2trSBTC PSBT", function () {
243+
const tx = signFinalizeExtract(fromNodes(sbtcDescriptorNode, "derivable"), [a, b], {
244+
sequence: 1,
245+
});
246+
247+
assert.strictEqual(typeof tx.getId(), "string");
248+
assert.strictEqual(tx.getId().length, 64);
249+
assert.ok(tx.getVSize() > 0);
250+
assert.ok(tx.toBytes().length > 0);
251+
});
252+
205253
it("should produce consistent txid across repeated calls", function () {
206254
const tx = signFinalizeExtract(
207255
fromNodes(

0 commit comments

Comments
 (0)