Skip to content

Commit f2e2b13

Browse files
OttoAllmendingerllm-git
andcommitted
feat(utxo-staking): add test that validates unbonding output
Add a test to verify that the unbonding PSBT output matches the expected script derived from the staking descriptor and unbonding time. Issue: BTC-2319 Co-authored-by: llm-git <[email protected]>
1 parent 5869f53 commit f2e2b13

File tree

1 file changed

+44
-11
lines changed

1 file changed

+44
-11
lines changed

modules/utxo-staking/test/unit/babylon/undelegation.ts

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import assert from 'assert';
12
import { promises as fs } from 'fs';
23

34
import * as t from 'io-ts';
@@ -7,29 +8,33 @@ import * as utxolib from '@bitgo/utxo-lib';
78
import { ast, Descriptor } from '@bitgo/wasm-miniscript';
89
import { PartialSig } from 'bip174/src/lib/interfaces';
910

11+
import { BabylonDescriptorBuilder } from '../../../src/babylon';
1012
import {
1113
toPartialSig,
1214
UndelegationResponse,
1315
assertValidSignatures,
1416
toUnbondingPsbtWithSignatures,
1517
} from '../../../src/babylon/undelegation';
18+
import { parseStakingDescriptor } from '../../../src/babylon/parseDescriptor';
1619
import { assertTransactionEqualsFixture } from '../fixtures.utils';
1720

18-
async function getFixture(txid: string): Promise<UndelegationResponse> {
21+
const BtcDelegation = t.type({
22+
unbonding_time: t.number,
23+
undelegation_response: UndelegationResponse,
24+
});
25+
26+
type BtcDelegation = t.TypeOf<typeof BtcDelegation>;
27+
28+
async function getFixture(txid: string): Promise<BtcDelegation> {
1929
// As returned by https://babylon.nodes.guru/api#/Query/BTCDelegation
20-
const BtcDelegationResponse = t.type(
21-
{
22-
btc_delegation: t.type({ undelegation_response: UndelegationResponse }),
23-
},
24-
'BtcDelegationResponse'
25-
);
30+
const BtcDelegationResponse = t.type({ btc_delegation: BtcDelegation }, 'BtcDelegationResponse');
2631
const filename = __dirname + `/../../fixtures/babylon/rpc/btc_delegation/testnet.${txid}.json`;
2732
const data = JSON.parse(await fs.readFile(filename, 'utf8'));
2833
const result = BtcDelegationResponse.decode(data);
2934
if (isLeft(result)) {
3035
throw new Error(`Failed to decode fixture data for txid ${txid}: ${PathReporter.report(result).join(', ')}`);
3136
}
32-
return result.right.btc_delegation.undelegation_response;
37+
return result.right.btc_delegation;
3338
}
3439

3540
type DescriptorLike = Descriptor | ast.DescriptorNode | string;
@@ -42,16 +47,17 @@ function toDescriptor(descriptor: DescriptorLike): Descriptor {
4247

4348
function runTest(network: utxolib.Network, txid: string, descriptor: Descriptor): void {
4449
describe(`Unbonding transaction ${txid}`, function () {
50+
let fixture: BtcDelegation;
4551
let psbt: utxolib.bitgo.UtxoPsbt;
4652
let signatures: PartialSig[];
4753

4854
before('should create a PSBT from the unbonding transaction', async function () {
49-
const fixture = await getFixture(txid);
50-
const txBuffer = Buffer.from(fixture.unbonding_tx_hex, 'hex');
55+
fixture = await getFixture(txid);
56+
const txBuffer = Buffer.from(fixture.undelegation_response.unbonding_tx_hex, 'hex');
5157
const tx = utxolib.bitgo.createTransactionFromBuffer(txBuffer, network, {
5258
amountType: 'bigint',
5359
});
54-
signatures = fixture.covenant_unbonding_sig_list.map((sig) => toPartialSig(sig));
60+
signatures = fixture.undelegation_response.covenant_unbonding_sig_list.map((sig) => toPartialSig(sig));
5561

5662
psbt = toUnbondingPsbtWithSignatures(
5763
tx,
@@ -75,6 +81,33 @@ function runTest(network: utxolib.Network, txid: string, descriptor: Descriptor)
7581
psbt
7682
);
7783
});
84+
85+
it('can spend from unbonding output', async function () {
86+
const parsed = parseStakingDescriptor(descriptor);
87+
assert(parsed);
88+
89+
const descriptorBuilder = new BabylonDescriptorBuilder(
90+
parsed.stakerKey,
91+
parsed.finalityProviderKeys,
92+
parsed.covenantKeys,
93+
parsed.covenantThreshold,
94+
parsed.stakingTimeLock,
95+
fixture.unbonding_time
96+
);
97+
98+
assert.deepStrictEqual(
99+
descriptorBuilder.getUnbondingMiniscriptNode(),
100+
parsed.unbondingMiniscriptNode,
101+
'Unbonding miniscript node does not match expected value'
102+
);
103+
104+
assert(psbt.txOutputs.length === 1, 'Unbonding transaction should have exactly one output');
105+
106+
assert.deepStrictEqual(
107+
psbt.txOutputs[0].script,
108+
Buffer.from(descriptorBuilder.getUnbondingDescriptor().scriptPubkey())
109+
);
110+
});
78111
});
79112
}
80113

0 commit comments

Comments
 (0)