Skip to content

Commit 0ef3d03

Browse files
OttoAllmendingerllm-git
andcommitted
feat(abstract-utxo): add transaction decoding utils
Refactor transaction decoding logic into separate helper functions to support both utxolib and wasm-utxo backends. Extract string-to-buffer conversion into a reusable utility function. Issue: BTC-2806 Co-authored-by: llm-git <llm-git@ttll.de>
1 parent 8f06705 commit 0ef3d03

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

modules/abstract-utxo/src/abstractUtxoCoin.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import { assertDescriptorWalletAddress, getDescriptorMapFromWallet, isDescriptor
7676
import { getChainFromNetwork, getFamilyFromNetwork, getFullNameFromNetwork } from './names';
7777
import { assertFixedScriptWalletAddress } from './address/fixedScript';
7878
import { ParsedTransaction } from './transaction/types';
79+
import { decodePsbtWith, stringToBufferTryFormats } from './transaction/decode';
7980
import { toBip32Triple, UtxoKeychain } from './keychains';
8081
import { verifyKeySignature, verifyUserPublicKey } from './verifyKey';
8182
import { getPolicyForEnv } from './descriptor/validatePolicy';
@@ -524,22 +525,12 @@ export abstract class AbstractUtxoCoin extends BaseCoin {
524525

525526
decodeTransaction<TNumber extends number | bigint>(input: Buffer | string): DecodedTransaction<TNumber> {
526527
if (typeof input === 'string') {
527-
for (const format of ['hex', 'base64'] as const) {
528-
const buffer = Buffer.from(input, format);
529-
const bufferToString = buffer.toString(format);
530-
if (
531-
(format === 'base64' && bufferToString === input) ||
532-
(format === 'hex' && bufferToString === input.toLowerCase())
533-
) {
534-
return this.decodeTransaction(buffer);
535-
}
536-
}
537-
538-
throw new Error('input must be a valid hex or base64 string');
528+
const buffer = stringToBufferTryFormats(input, ['hex', 'base64']);
529+
return this.decodeTransaction(buffer);
539530
}
540531

541532
if (utxolib.bitgo.isPsbt(input)) {
542-
return utxolib.bitgo.createPsbtFromBuffer(input, this.network);
533+
return decodePsbtWith(input, this.network, 'utxolib');
543534
} else {
544535
return utxolib.bitgo.createTransactionFromBuffer(input, this.network, {
545536
amountType: this.amountType,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import * as utxolib from '@bitgo/utxo-lib';
2+
import { fixedScriptWallet, utxolibCompat } from '@bitgo/wasm-utxo';
3+
4+
import { SdkBackend } from './types';
5+
6+
type BufferEncoding = 'hex' | 'base64';
7+
8+
export function stringToBufferTryFormats(input: string, formats: BufferEncoding[] = ['hex', 'base64']): Buffer {
9+
for (const format of formats) {
10+
const buffer = Buffer.from(input, format);
11+
const bufferToString = buffer.toString(format);
12+
if (
13+
(format === 'base64' && bufferToString === input) ||
14+
(format === 'hex' && bufferToString === input.toLowerCase())
15+
) {
16+
return buffer;
17+
}
18+
}
19+
20+
throw new Error('input must be a valid hex or base64 string');
21+
}
22+
23+
function toNetworkName(network: utxolib.Network): utxolibCompat.UtxolibName {
24+
const networkName = utxolib.getNetworkName(network);
25+
if (!networkName) {
26+
throw new Error(`Invalid network: ${network}`);
27+
}
28+
return networkName;
29+
}
30+
31+
export function decodePsbtWith(
32+
psbt: string | Buffer,
33+
network: utxolib.Network,
34+
backend: 'utxolib'
35+
): utxolib.bitgo.UtxoPsbt;
36+
export function decodePsbtWith(
37+
psbt: string | Buffer,
38+
network: utxolib.Network,
39+
backend: 'wasm-utxo'
40+
): fixedScriptWallet.BitGoPsbt;
41+
export function decodePsbtWith(
42+
psbt: string | Buffer,
43+
network: utxolib.Network,
44+
backend: SdkBackend
45+
): utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt;
46+
export function decodePsbtWith(
47+
psbt: string | Buffer,
48+
network: utxolib.Network,
49+
backend: SdkBackend
50+
): utxolib.bitgo.UtxoPsbt | fixedScriptWallet.BitGoPsbt {
51+
if (typeof psbt === 'string') {
52+
psbt = Buffer.from(psbt, 'hex');
53+
}
54+
if (backend === 'utxolib') {
55+
return utxolib.bitgo.createPsbtFromBuffer(psbt, network);
56+
} else {
57+
return fixedScriptWallet.BitGoPsbt.fromBytes(psbt, toNetworkName(network));
58+
}
59+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type { UtxoNamedKeychains } from '../keychains';
44

55
import type { CustomChangeOptions } from './fixedScript';
66

7+
export type SdkBackend = 'utxolib' | 'wasm-utxo';
8+
79
export type DecodedTransaction<TNumber extends number | bigint> =
810
| utxolib.bitgo.UtxoTransaction<TNumber>
911
| utxolib.bitgo.UtxoPsbt;

0 commit comments

Comments
 (0)