Skip to content

Commit ac76231

Browse files
Merge pull request #8857 from BitGo/otto/abstract-utxo-foundation
refactor(abstract-utxo): delete unreachable utxolib explainPsbt path
2 parents 8b739da + 3454b9d commit ac76231

16 files changed

Lines changed: 95 additions & 1179 deletions

modules/abstract-utxo/src/abstractUtxoCoin.ts

Lines changed: 16 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { randomBytes } from 'crypto';
33

44
import _ from 'lodash';
55
import * as utxolib from '@bitgo/utxo-lib';
6-
import { BIP32, fixedScriptWallet } from '@bitgo/wasm-utxo';
6+
import { BIP32, fixedScriptWallet, hasPsbtMagic } from '@bitgo/wasm-utxo';
77
import { bitgo, getMainnet } from '@bitgo/utxo-lib';
88
import {
99
AddressCoinSpecific,
@@ -86,13 +86,8 @@ import {
8686
UtxoCoinNameMainnet,
8787
} from './names';
8888
import { assertFixedScriptWalletAddress } from './address/fixedScript';
89-
import { isSdkBackend, ParsedTransaction, SdkBackend } from './transaction/types';
90-
import {
91-
decodeDescriptorPsbt,
92-
decodePsbtWith,
93-
encodeTransaction,
94-
stringToBufferTryFormats,
95-
} from './transaction/decode';
89+
import { ParsedTransaction } from './transaction/types';
90+
import { decodeDescriptorPsbt, decodePsbt, encodeTransaction, stringToBufferTryFormats } from './transaction/decode';
9691
import { fetchKeychains, toBip32Triple, UtxoKeychain } from './keychains';
9792
import { verifyKeySignature, verifyUserPublicKey, verifyUserPublicKeyAsync } from './verifyKey';
9893
import { getPolicyForEnv } from './descriptor/validatePolicy';
@@ -250,7 +245,6 @@ export interface ExplainTransactionOptions<TNumber extends number | bigint = num
250245
feeInfo?: string;
251246
pubs?: Triple<string>;
252247
customChangeXpubs?: Triple<string>;
253-
decodeWith?: SdkBackend;
254248
}
255249

256250
export interface DecoratedExplainTransactionOptions<TNumber extends number | bigint = number>
@@ -263,7 +257,6 @@ export type UtxoNetwork = utxolib.Network;
263257
export interface TransactionPrebuild<TNumber extends number | bigint = number> extends BaseTransactionPrebuild {
264258
txInfo?: TransactionInfo<TNumber>;
265259
blockHeight?: number;
266-
decodeWith?: SdkBackend;
267260
/**
268261
* PSBT-lite hex present only in pending approval flows, where another user's send fixed the format.
269262
* Not set in regular /tx/build responses (where the caller controls the build parameters).
@@ -332,7 +325,6 @@ type UtxoBaseSignTransactionOptions<TNumber extends number | bigint = number> =
332325
walletId?: string;
333326
txHex: string;
334327
txInfo?: TransactionInfo<TNumber>;
335-
decodeWith?: SdkBackend;
336328
};
337329
/** xpubs triple for wallet (user, backup, bitgo). Required only when txPrebuild.txHex is not a PSBT */
338330
pubs?: Triple<string>;
@@ -421,10 +413,7 @@ export interface SignPsbtResponse {
421413
psbt: string;
422414
}
423415

424-
export abstract class AbstractUtxoCoin
425-
extends BaseCoin
426-
implements Musig2Participant<utxolib.bitgo.UtxoPsbt>, Musig2Participant<fixedScriptWallet.BitGoPsbt>
427-
{
416+
export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Participant<fixedScriptWallet.BitGoPsbt> {
428417
abstract name: UtxoCoinName;
429418

430419
/**
@@ -438,23 +427,11 @@ export abstract class AbstractUtxoCoin
438427

439428
public readonly amountType: 'number' | 'bigint';
440429

441-
protected supportedTxFormats: { psbt: boolean; legacy: boolean } = {
442-
psbt: true,
443-
legacy: false,
444-
};
445-
446-
protected supportedSdkBackends: { utxolib: boolean; 'wasm-utxo': boolean } = {
447-
utxolib: false,
448-
'wasm-utxo': true,
449-
};
450-
451430
protected constructor(bitgo: BitGoBase, amountType: 'number' | 'bigint' = 'number') {
452431
super(bitgo);
453432
this.amountType = amountType;
454433
}
455434

456-
defaultSdkBackend: SdkBackend = 'wasm-utxo';
457-
458435
/**
459436
* @deprecated - will be removed when we drop support for utxolib
460437
* Use `name` property instead.
@@ -628,65 +605,29 @@ export abstract class AbstractUtxoCoin
628605
return utxolib.bitgo.createTransactionFromHex<TNumber>(hex, this.network, this.amountType);
629606
}
630607

631-
decodeTransaction<TNumber extends number | bigint>(
632-
input: Buffer | string,
633-
decodeWith: SdkBackend = this.defaultSdkBackend
634-
): DecodedTransaction<TNumber> {
635-
if (typeof input === 'string') {
636-
const buffer = stringToBufferTryFormats(input, ['hex', 'base64']);
637-
return this.decodeTransaction(buffer, decodeWith);
638-
}
639-
640-
if (utxolib.bitgo.isPsbt(input)) {
641-
if (this.supportedSdkBackends[decodeWith] !== true) {
642-
throw new Error(`SDK support for decodeWith=${decodeWith} is not available on this environment.`);
643-
}
644-
645-
if (!this.supportedTxFormats.psbt) {
646-
throw new ErrorDeprecatedTxFormat('psbt');
647-
}
648-
return decodePsbtWith(input, this.name, decodeWith);
649-
} else {
650-
// Legacy format transactions are deprecated. This will be an unconditional error in the future.
651-
if (!this.supportedTxFormats.legacy) {
652-
throw new ErrorDeprecatedTxFormat('legacy');
653-
}
654-
if (decodeWith !== 'utxolib') {
655-
console.error('received decodeWith hint %s, ignoring for legacy transaction', decodeWith);
656-
}
657-
return utxolib.bitgo.createTransactionFromBuffer(input, this.network, {
658-
amountType: this.amountType,
659-
});
608+
decodeTransaction(input: Buffer | string): fixedScriptWallet.BitGoPsbt {
609+
const buffer = typeof input === 'string' ? stringToBufferTryFormats(input, ['hex', 'base64']) : input;
610+
if (!hasPsbtMagic(buffer)) {
611+
throw new ErrorDeprecatedTxFormat('legacy');
660612
}
613+
return decodePsbt(buffer, this.name);
661614
}
662615

663-
decodeTransactionAsPsbt(input: Buffer | string): utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt {
664-
const decoded = this.decodeTransaction(input);
665-
if (decoded instanceof fixedScriptWallet.BitGoPsbt || decoded instanceof utxolib.bitgo.UtxoPsbt) {
666-
return decoded;
667-
}
668-
throw new Error('expected psbt but got transaction');
616+
decodeTransactionAsPsbt(input: Buffer | string): fixedScriptWallet.BitGoPsbt {
617+
return this.decodeTransaction(input);
669618
}
670619

671-
decodeTransactionFromPrebuild<TNumber extends number | bigint>(prebuild: {
620+
decodeTransactionFromPrebuild(prebuild: {
672621
txHex?: string;
673622
txBase64?: string;
674623
/** See TransactionPrebuild.txHexPsbt — only present in pending approval flows. */
675624
txHexPsbt?: string;
676-
decodeWith?: string;
677-
}): DecodedTransaction<TNumber> {
625+
}): fixedScriptWallet.BitGoPsbt {
678626
const string = prebuild.txHexPsbt ?? prebuild.txHex ?? prebuild.txBase64;
679627
if (!string) {
680628
throw new Error('missing required txHex or txBase64 property');
681629
}
682-
let { decodeWith } = prebuild;
683-
if (decodeWith !== undefined) {
684-
if (typeof decodeWith !== 'string' || !isSdkBackend(decodeWith)) {
685-
console.error('decodeWith %s is not a valid value, using default', decodeWith);
686-
decodeWith = undefined;
687-
}
688-
}
689-
return this.decodeTransaction(string, decodeWith);
630+
return this.decodeTransaction(string);
690631
}
691632

692633
/**
@@ -845,26 +786,13 @@ export abstract class AbstractUtxoCoin
845786
* @param psbt all MuSig2 inputs should contain user MuSig2 nonce
846787
* @param walletId
847788
*/
848-
async getMusig2Nonces(psbt: utxolib.bitgo.UtxoPsbt, walletId: string): Promise<utxolib.bitgo.UtxoPsbt>;
849-
async getMusig2Nonces(psbt: fixedScriptWallet.BitGoPsbt, walletId: string): Promise<fixedScriptWallet.BitGoPsbt>;
850-
async getMusig2Nonces<T extends utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt>(
851-
psbt: T,
852-
walletId: string
853-
): Promise<T>;
854-
async getMusig2Nonces<T extends utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt>(
855-
psbt: T,
856-
walletId: string
857-
): Promise<T> {
789+
async getMusig2Nonces(psbt: fixedScriptWallet.BitGoPsbt, walletId: string): Promise<fixedScriptWallet.BitGoPsbt> {
858790
const buffer = encodeTransaction(psbt);
859791
const response = await this.bitgo
860792
.post(this.url('/wallet/' + walletId + '/tx/signpsbt'))
861793
.send({ psbt: buffer.toString('hex') })
862794
.result();
863-
if (psbt instanceof utxolib.bitgo.UtxoPsbt) {
864-
return decodePsbtWith(response.psbt, this.name, 'utxolib') as T;
865-
} else {
866-
return decodePsbtWith(response.psbt, this.name, 'wasm-utxo') as T;
867-
}
795+
return decodePsbt(response.psbt, this.name);
868796
}
869797

870798
/**

modules/abstract-utxo/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export * from './config';
44
export * from './names';
55
export * from './recovery';
66
export * from './transaction/fixedScript/replayProtection';
7-
export * from './transaction/fixedScript/signLegacyTransaction';
87
export * from './unspent';
98

109
export { UtxoWallet } from './wallet';

modules/abstract-utxo/src/transaction/decode.ts

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { fixedScriptWallet, hasPsbtMagic, Psbt as WasmPsbt, utxolibCompat } from
33

44
import { getNetworkFromCoinName, UtxoCoinName } from '../names';
55

6-
import { SdkBackend, BitGoPsbt } from './types';
6+
import { BitGoPsbt } from './types';
77

88
type BufferEncoding = 'hex' | 'base64';
99

@@ -31,39 +31,11 @@ function toNetworkName(coinName: UtxoCoinName): utxolibCompat.UtxolibName {
3131
return networkName;
3232
}
3333

34-
export function decodePsbtWith(
35-
psbt: string | Buffer,
36-
coinName: UtxoCoinName,
37-
backend: 'utxolib'
38-
): utxolib.bitgo.UtxoPsbt;
39-
export function decodePsbtWith(
40-
psbt: string | Buffer,
41-
coinName: UtxoCoinName,
42-
backend: 'wasm-utxo'
43-
): fixedScriptWallet.BitGoPsbt;
44-
export function decodePsbtWith(
45-
psbt: string | Buffer,
46-
coinName: UtxoCoinName,
47-
backend: SdkBackend
48-
): utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt;
49-
export function decodePsbtWith(
50-
psbt: string | Buffer,
51-
coinName: UtxoCoinName,
52-
backend: SdkBackend
53-
): utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt {
34+
export function decodePsbt(psbt: string | Buffer, coinName: UtxoCoinName): BitGoPsbt {
5435
if (typeof psbt === 'string') {
5536
psbt = Buffer.from(psbt, 'hex');
5637
}
57-
if (backend === 'utxolib') {
58-
const network = getNetworkFromCoinName(coinName);
59-
return utxolib.bitgo.createPsbtFromBuffer(psbt, network);
60-
} else {
61-
return fixedScriptWallet.BitGoPsbt.fromBytes(psbt, toNetworkName(coinName));
62-
}
63-
}
64-
65-
export function decodePsbt(psbt: string | Buffer, coinName: UtxoCoinName): BitGoPsbt {
66-
return decodePsbtWith(psbt, coinName, 'wasm-utxo');
38+
return fixedScriptWallet.BitGoPsbt.fromBytes(psbt, toNetworkName(coinName));
6739
}
6840

6941
export type PrebuildLike = {
@@ -90,14 +62,6 @@ export function decodeDescriptorPsbt(prebuild: PrebuildLike): WasmPsbt {
9062
return WasmPsbt.deserialize(bytes);
9163
}
9264

93-
export function encodeTransaction(
94-
transaction: utxolib.bitgo.UtxoTransaction<bigint | number> | utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt
95-
): Buffer {
96-
if (transaction instanceof utxolib.bitgo.UtxoTransaction) {
97-
return transaction.toBuffer();
98-
} else if (transaction instanceof utxolib.bitgo.UtxoPsbt) {
99-
return transaction.toBuffer();
100-
} else {
101-
return Buffer.from(transaction.serialize());
102-
}
65+
export function encodeTransaction(transaction: fixedScriptWallet.BitGoPsbt): Buffer {
66+
return Buffer.from(transaction.serialize());
10367
}
Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as utxolib from '@bitgo/utxo-lib';
21
import { fixedScriptWallet, Psbt as WasmPsbt } from '@bitgo/wasm-utxo';
32
import { isTriple, IWallet, Triple } from '@bitgo/sdk-core';
43

@@ -9,11 +8,7 @@ import { UtxoCoinName } from '../names';
98
import type { Unspent } from '../unspent';
109

1110
import { getReplayProtectionPubkeys } from './fixedScript/replayProtection';
12-
import type {
13-
TransactionExplanationUtxolibLegacy,
14-
TransactionExplanationUtxolibPsbt,
15-
TransactionExplanationWasm,
16-
} from './fixedScript/explainTransaction';
11+
import type { TransactionExplanationUtxolibPsbt, TransactionExplanationWasm } from './fixedScript/explainTransaction';
1712
import * as fixedScript from './fixedScript';
1813
import * as descriptor from './descriptor';
1914

@@ -22,16 +17,15 @@ import * as descriptor from './descriptor';
2217
* change amounts, and transaction outputs.
2318
*/
2419
export function explainTx<TNumber extends number | bigint>(
25-
tx: utxolib.bitgo.UtxoTransaction<TNumber> | utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt | WasmPsbt,
20+
tx: fixedScriptWallet.BitGoPsbt | WasmPsbt,
2621
params: {
2722
wallet?: IWallet;
2823
pubs?: string[];
2924
customChangeXpubs?: Triple<string>;
3025
txInfo?: { unspents?: Unspent<TNumber>[] };
31-
changeInfo?: fixedScript.ChangeAddressInfo[];
3226
},
3327
coinName: UtxoCoinName
34-
): TransactionExplanationUtxolibLegacy | TransactionExplanationUtxolibPsbt | TransactionExplanationWasm {
28+
): TransactionExplanationUtxolibPsbt | TransactionExplanationWasm {
3529
if (params.wallet && isDescriptorWallet(params.wallet)) {
3630
if (!(tx instanceof WasmPsbt)) {
3731
throw new Error('descriptor wallets require PSBT format transactions');
@@ -43,19 +37,12 @@ export function explainTx<TNumber extends number | bigint>(
4337
const descriptors = getDescriptorMapFromWallet(params.wallet, walletKeys, getPolicyForEnv(params.wallet.bitgo.env));
4438
return descriptor.explainPsbt(tx, descriptors, coinName);
4539
}
46-
if (tx instanceof utxolib.bitgo.UtxoPsbt) {
47-
return fixedScript.explainPsbt(tx, { ...params, customChangePubs: params.customChangeXpubs }, coinName);
48-
} else if (tx instanceof fixedScriptWallet.BitGoPsbt) {
40+
if (tx instanceof fixedScriptWallet.BitGoPsbt) {
4941
const pubs = params.pubs;
5042
if (!pubs) {
5143
throw new Error('pub triple is required');
5244
}
53-
const walletXpubs: Triple<string> | undefined =
54-
pubs instanceof utxolib.bitgo.RootWalletKeys
55-
? (pubs.triple.map((k) => k.neutered().toBase58()) as Triple<string>)
56-
: isTriple(pubs)
57-
? (pubs as Triple<string>)
58-
: undefined;
45+
const walletXpubs: Triple<string> | undefined = isTriple(pubs) ? (pubs as Triple<string>) : undefined;
5946
if (!walletXpubs) {
6047
throw new Error('pub triple must be valid triple or RootWalletKeys');
6148
}
@@ -68,6 +55,6 @@ export function explainTx<TNumber extends number | bigint>(
6855
} else if (tx instanceof WasmPsbt) {
6956
throw new Error('descriptor Psbt is only supported for descriptor wallets');
7057
} else {
71-
return fixedScript.explainLegacyTx(tx, params, coinName);
58+
throw new Error('unsupported transaction type');
7259
}
7360
}

0 commit comments

Comments
 (0)