Skip to content

Commit eb91975

Browse files
OttoAllmendingerllm-git
andcommitted
feat(abstract-utxo): enforce deprecated tx format restrictions
Update `supportedTxFormats` default to disallow legacy format for user inputs while maintaining backward compatibility for internal operations like PSBT finalization. Update tests to reflect new restrictions and skip deprecated legacy format test cases. Issue: BTC-2768 Co-authored-by: llm-git <llm-git@ttll.de>
1 parent b2eed2b commit eb91975

4 files changed

Lines changed: 20 additions & 28 deletions

File tree

modules/abstract-utxo/src/abstractUtxoCoin.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ export abstract class AbstractUtxoCoin
411411

412412
public readonly amountType: 'number' | 'bigint';
413413

414+
protected readonly supportedTxFormats: { readonly psbt: boolean; readonly legacy: boolean } = {
415+
psbt: true,
416+
legacy: false,
417+
};
418+
414419
protected constructor(bitgo: BitGoBase, amountType: 'number' | 'bigint' = 'number') {
415420
super(bitgo);
416421
this.amountType = amountType;
@@ -587,8 +592,15 @@ export abstract class AbstractUtxoCoin
587592
}
588593

589594
if (utxolib.bitgo.isPsbt(input)) {
595+
if (!this.supportedTxFormats.psbt) {
596+
throw new ErrorDeprecatedTxFormat('psbt');
597+
}
590598
return decodePsbtWith(input, this.name, decodeWith);
591599
} else {
600+
// Legacy format transactions are deprecated. This will be an unconditional error in the future.
601+
if (!this.supportedTxFormats.legacy) {
602+
throw new ErrorDeprecatedTxFormat('legacy');
603+
}
592604
if (decodeWith !== 'utxolib') {
593605
console.error('received decodeWith hint %s, ignoring for legacy transaction', decodeWith);
594606
}

modules/abstract-utxo/test/unit/customSigner.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,4 @@ describe('UTXO Custom Signer Function', function () {
8383
sinon.assert.calledOnce(customSigningFunction as sinon.SinonStub);
8484
scope.done();
8585
});
86-
87-
it('should use a custom signing function if provided for Tx without taprootKeyPathSpend input', async function () {
88-
const tx = utxoLib.testutil.constructTxnBuilder(
89-
[{ scriptType: 'p2wsh', value: BigInt(1000) }],
90-
[{ scriptType: 'p2sh', value: BigInt(900) }],
91-
basecoin.network,
92-
rootWalletKey,
93-
'unsigned'
94-
);
95-
const scope = nocks({ txHex: tx.buildIncomplete().toHex() });
96-
const result = await wallet.sendMany({ recipients, customSigningFunction });
97-
98-
assertHasProperty(result, 'ok', true);
99-
sinon.assert.calledOnce(customSigningFunction as sinon.SinonStub);
100-
scope.done();
101-
});
10286
});

modules/abstract-utxo/test/unit/signTransaction.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import nock = require('nock');
66
import { testutil } from '@bitgo/utxo-lib';
77
import { common, Triple } from '@bitgo/sdk-core';
88

9-
import { getReplayProtectionPubkeys } from '../../src';
9+
import { getReplayProtectionPubkeys, ErrorDeprecatedTxFormat } from '../../src';
1010
import type { Unspent } from '../../src/unspent';
1111

1212
import { getUtxoWallet, getDefaultWalletKeys, getUtxoCoin, keychainsBase58, defaultBitGo } from './util';
@@ -170,7 +170,7 @@ describe('signTransaction', function () {
170170
}
171171
});
172172

173-
it('customSigningFunction flow - Network Tx', async function () {
173+
it('customSigningFunction flow - Network Tx should reject legacy format', async function () {
174174
const inputs: testutil.TxnInput<bigint>[] = testutil.txnInputScriptTypes
175175
.filter((v) => v !== 'p2shP2pk')
176176
.map((scriptType) => ({
@@ -182,9 +182,10 @@ describe('signTransaction', function () {
182182
const txBuilder = testutil.constructTxnBuilder(inputs, outputs, coin.network, rootWalletKeys, 'unsigned');
183183
const unspents = inputs.map((v, i) => testutil.toTxnUnspent(v, i, coin.network, rootWalletKeys));
184184

185-
for (const v of [false, true]) {
186-
await signTransaction(txBuilder.buildIncomplete(), v, unspents);
187-
}
185+
// Legacy format transactions are now deprecated and should throw ErrorDeprecatedTxFormat
186+
await assert.rejects(async () => {
187+
await signTransaction(txBuilder.buildIncomplete(), false, unspents);
188+
}, ErrorDeprecatedTxFormat);
188189
});
189190

190191
it('fails on PSBT cache miss', async function () {

modules/abstract-utxo/test/unit/transaction.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,7 @@ function run<TNumber extends number | bigint = number>(
271271
testPsbtValidSignatures(tx, signedBy);
272272
return;
273273
}
274-
const unspents =
275-
txFormat === 'psbt'
276-
? getUnspentsForPsbt().map((u) => ({ ...u, value: bitgo.toTNumber(u.value, amountType) as TNumber }))
277-
: getUnspents();
274+
const unspents = getUnspents();
278275
const prevOutputs = unspents.map(
279276
(u): utxolib.TxOutput<TNumber> => ({
280277
script: Buffer.from(wasmAddress.toOutputScriptWithCoin(u.address, coin.name)),
@@ -418,9 +415,7 @@ function run<TNumber extends number | bigint = number>(
418415
}
419416

420417
function runTestForCoin(coin: AbstractUtxoCoin) {
421-
(['legacy', 'psbt'] as const).forEach((txFormat) => {
422-
run(coin, getScriptTypes(coin, txFormat), txFormat, { decodeWith: 'wasm-utxo' });
423-
});
418+
run(coin, getScriptTypes(coin, 'psbt'), 'psbt', { decodeWith: 'wasm-utxo' });
424419
}
425420

426421
describe('Transaction Suite', function () {

0 commit comments

Comments
 (0)