Skip to content

Commit 0221dd7

Browse files
Merge pull request #243 from BitGo/BTC-2992.base-classes
refactor(wasm-utxo): extract base classes for PSBT and transaction
2 parents 871430e + 1956ff4 commit 0221dd7

11 files changed

Lines changed: 503 additions & 627 deletions

File tree

packages/wasm-utxo/js/descriptorWallet/Psbt.ts

Lines changed: 5 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,22 @@ import {
33
type WasmBIP32,
44
type WasmECPair,
55
type WrapDescriptor,
6-
type PsbtInputData,
7-
type PsbtOutputData,
86
type PsbtOutputDataWithAddress,
97
} from "../wasm/wasm_utxo.js";
108
import type { IPsbt } from "../psbt.js";
11-
import type { PsbtKvKey } from "../fixedScriptWallet/BitGoKeySubtype.js";
129
import type { CoinName } from "../coinName.js";
13-
import type { BIP32 } from "../bip32.js";
1410
import { Transaction } from "../transaction.js";
11+
import { PsbtBase } from "../psbtBase.js";
1512

1613
export type SignPsbtResult = {
1714
[inputIndex: number]: [pubkey: string][];
1815
};
1916

20-
export class Psbt implements IPsbt {
21-
private _wasm: WasmPsbt;
22-
17+
export class Psbt extends PsbtBase<WasmPsbt> implements IPsbt {
2318
constructor(versionOrWasm?: number | WasmPsbt, lockTime?: number) {
24-
if (versionOrWasm instanceof WasmPsbt) {
25-
this._wasm = versionOrWasm;
26-
} else {
27-
this._wasm = new WasmPsbt(versionOrWasm, lockTime);
28-
}
19+
super(
20+
versionOrWasm instanceof WasmPsbt ? versionOrWasm : new WasmPsbt(versionOrWasm, lockTime),
21+
);
2922
}
3023

3124
/** @internal Access the underlying WASM instance */
@@ -45,48 +38,12 @@ export class Psbt implements IPsbt {
4538

4639
// -- Serialization --
4740

48-
serialize(): Uint8Array {
49-
return this._wasm.serialize();
50-
}
51-
5241
clone(): Psbt {
5342
return new Psbt(this._wasm.clone());
5443
}
5544

5645
// -- IPsbt: introspection --
5746

58-
inputCount(): number {
59-
return this._wasm.input_count();
60-
}
61-
62-
outputCount(): number {
63-
return this._wasm.output_count();
64-
}
65-
66-
version(): number {
67-
return this._wasm.version();
68-
}
69-
70-
lockTime(): number {
71-
return this._wasm.lock_time();
72-
}
73-
74-
unsignedTxId(): string {
75-
return this._wasm.unsigned_tx_id();
76-
}
77-
78-
getInputs(): PsbtInputData[] {
79-
return this._wasm.get_inputs() as PsbtInputData[];
80-
}
81-
82-
getOutputs(): PsbtOutputData[] {
83-
return this._wasm.get_outputs() as PsbtOutputData[];
84-
}
85-
86-
getGlobalXpubs(): BIP32[] {
87-
return this._wasm.get_global_xpubs() as BIP32[];
88-
}
89-
9047
getOutputsWithAddress(coin: CoinName): PsbtOutputDataWithAddress[] {
9148
return this._wasm.get_outputs_with_address(coin) as PsbtOutputDataWithAddress[];
9249
}
@@ -122,38 +79,6 @@ export class Psbt implements IPsbt {
12279
return this._wasm.add_output(script, value);
12380
}
12481

125-
removeInput(index: number): void {
126-
this._wasm.remove_input(index);
127-
}
128-
129-
removeOutput(index: number): void {
130-
this._wasm.remove_output(index);
131-
}
132-
133-
setKV(key: PsbtKvKey, value: Uint8Array): void {
134-
this._wasm.set_kv(key, value);
135-
}
136-
137-
getKV(key: PsbtKvKey): Uint8Array | undefined {
138-
return this._wasm.get_kv(key) ?? undefined;
139-
}
140-
141-
setInputKV(index: number, key: PsbtKvKey, value: Uint8Array): void {
142-
this._wasm.set_input_kv(index, key, value);
143-
}
144-
145-
getInputKV(index: number, key: PsbtKvKey): Uint8Array | undefined {
146-
return this._wasm.get_input_kv(index, key) ?? undefined;
147-
}
148-
149-
setOutputKV(index: number, key: PsbtKvKey, value: Uint8Array): void {
150-
this._wasm.set_output_kv(index, key, value);
151-
}
152-
153-
getOutputKV(index: number, key: PsbtKvKey): Uint8Array | undefined {
154-
return this._wasm.get_output_kv(index, key) ?? undefined;
155-
}
156-
15782
// -- Descriptor updates --
15883

15984
updateInputWithDescriptor(inputIndex: number, descriptor: WrapDescriptor): void {

packages/wasm-utxo/js/fixedScriptWallet/BitGoPsbt.ts

Lines changed: 5 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import {
22
BitGoPsbt as WasmBitGoPsbt,
33
FixedScriptWalletNamespace,
4-
WasmBIP32,
5-
type PsbtInputData,
6-
type PsbtOutputData,
74
type PsbtOutputDataWithAddress,
85
} from "../wasm/wasm_utxo.js";
96
import type { IPsbtWithAddress } from "../psbt.js";
7+
import { PsbtBase } from "../psbtBase.js";
108
import { type WalletKeysArg, RootWalletKeys } from "./RootWalletKeys.js";
119
import { type ReplayProtectionArg, ReplayProtection } from "./ReplayProtection.js";
1210
import { type BIP32Arg, BIP32, isBIP32Arg } from "../bip32.js";
1311
import { type ECPairArg, ECPair } from "../ecpair.js";
1412
import type { UtxolibName } from "../utxolibCompat.js";
1513
import type { CoinName } from "../coinName.js";
1614
import type { InputScriptType } from "./scriptType.js";
17-
import type { PsbtKvKey } from "./BitGoKeySubtype.js";
1815
import {
1916
Transaction,
2017
DashTransaction,
@@ -133,8 +130,10 @@ export type HydrationUnspent = {
133130
value: bigint;
134131
};
135132

136-
export class BitGoPsbt implements IPsbtWithAddress {
137-
protected constructor(protected _wasm: WasmBitGoPsbt) {}
133+
export class BitGoPsbt extends PsbtBase<WasmBitGoPsbt> implements IPsbtWithAddress {
134+
protected constructor(wasm: WasmBitGoPsbt) {
135+
super(wasm);
136+
}
138137

139138
/**
140139
* Get the underlying WASM instance
@@ -532,64 +531,6 @@ export class BitGoPsbt implements IPsbtWithAddress {
532531
);
533532
}
534533

535-
removeInput(index: number): void {
536-
this._wasm.remove_input(index);
537-
}
538-
539-
removeOutput(index: number): void {
540-
this._wasm.remove_output(index);
541-
}
542-
543-
/**
544-
* Get the unsigned transaction ID
545-
* @returns The unsigned transaction ID
546-
*/
547-
unsignedTxId(): string {
548-
return this._wasm.unsigned_txid();
549-
}
550-
551-
/**
552-
* Get the transaction version
553-
* @returns The transaction version number
554-
*/
555-
version(): number {
556-
return this._wasm.version();
557-
}
558-
559-
lockTime(): number {
560-
return this._wasm.lock_time();
561-
}
562-
563-
/** Set an arbitrary KV pair on the PSBT global map. */
564-
setKV(key: PsbtKvKey, value: Uint8Array): void {
565-
this._wasm.set_kv(key, value);
566-
}
567-
568-
/** Get a KV value from the PSBT global map. Returns `undefined` if not present. */
569-
getKV(key: PsbtKvKey): Uint8Array | undefined {
570-
return this._wasm.get_kv(key) ?? undefined;
571-
}
572-
573-
/** Set an arbitrary KV pair on a specific PSBT input. */
574-
setInputKV(index: number, key: PsbtKvKey, value: Uint8Array): void {
575-
this._wasm.set_input_kv(index, key, value);
576-
}
577-
578-
/** Get a KV value from a specific PSBT input. Returns `undefined` if not present. */
579-
getInputKV(index: number, key: PsbtKvKey): Uint8Array | undefined {
580-
return this._wasm.get_input_kv(index, key) ?? undefined;
581-
}
582-
583-
/** Set an arbitrary KV pair on a specific PSBT output. */
584-
setOutputKV(index: number, key: PsbtKvKey, value: Uint8Array): void {
585-
this._wasm.set_output_kv(index, key, value);
586-
}
587-
588-
/** Get a KV value from a specific PSBT output. Returns `undefined` if not present. */
589-
getOutputKV(index: number, key: PsbtKvKey): Uint8Array | undefined {
590-
return this._wasm.get_output_kv(index, key) ?? undefined;
591-
}
592-
593534
/**
594535
* Parse transaction with wallet keys to identify wallet inputs/outputs
595536
* @param walletKeys - The wallet keys to use for identification
@@ -850,15 +791,6 @@ export class BitGoPsbt implements IPsbtWithAddress {
850791
return this._wasm.verify_replay_protection_signature(inputIndex, rp.wasm);
851792
}
852793

853-
/**
854-
* Serialize the PSBT to bytes
855-
*
856-
* @returns The serialized PSBT as a byte array
857-
*/
858-
serialize(): Uint8Array {
859-
return this._wasm.serialize();
860-
}
861-
862794
/**
863795
* Generate and store MuSig2 nonces for all MuSig2 inputs
864796
*
@@ -983,43 +915,6 @@ export class BitGoPsbt implements IPsbtWithAddress {
983915
return this._wasm.extract_half_signed_legacy_tx();
984916
}
985917

986-
/**
987-
* Get the number of inputs in the PSBT
988-
* @returns The number of inputs
989-
*/
990-
inputCount(): number {
991-
return this._wasm.input_count();
992-
}
993-
994-
outputCount(): number {
995-
return this._wasm.output_count();
996-
}
997-
998-
/**
999-
* Get all PSBT inputs as an array
1000-
*
1001-
* Returns raw PSBT input data including witness_utxo and derivation info.
1002-
* For parsed transaction data with address identification, use
1003-
* parseTransactionWithWalletKeys() instead.
1004-
*
1005-
* @returns Array of PsbtInputData objects
1006-
*/
1007-
getInputs(): PsbtInputData[] {
1008-
return this._wasm.get_inputs() as PsbtInputData[];
1009-
}
1010-
1011-
/**
1012-
* Get all PSBT outputs as an array
1013-
*
1014-
* Returns raw PSBT output data without address resolution.
1015-
* For output data with addresses, use getOutputsWithAddress().
1016-
*
1017-
* @returns Array of PsbtOutputData objects
1018-
*/
1019-
getOutputs(): PsbtOutputData[] {
1020-
return this._wasm.get_outputs() as PsbtOutputData[];
1021-
}
1022-
1023918
/**
1024919
* Get all PSBT outputs with resolved address strings
1025920
*
@@ -1039,14 +934,6 @@ export class BitGoPsbt implements IPsbtWithAddress {
1039934
getOutputsWithAddress(): PsbtOutputDataWithAddress[] {
1040935
return this._wasm.get_outputs_with_address() as PsbtOutputDataWithAddress[];
1041936
}
1042-
1043-
/**
1044-
* Returns the unordered global xpubs from this PSBT as BIP32 instances.
1045-
*/
1046-
getGlobalXpubs(): BIP32[] {
1047-
const result = this._wasm.get_global_xpubs() as WasmBIP32[];
1048-
return result.map((w) => BIP32.fromWasm(w));
1049-
}
1050937
}
1051938

1052939
/**

packages/wasm-utxo/js/psbtBase.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import type { PsbtInputData, PsbtOutputData, WasmBIP32 } from "./wasm/wasm_utxo.js";
2+
import { BIP32 } from "./bip32.js";
3+
import type { PsbtKvKey } from "./fixedScriptWallet/BitGoKeySubtype.js";
4+
5+
interface WasmPsbtBase {
6+
input_count(): number;
7+
output_count(): number;
8+
version(): number;
9+
lock_time(): number;
10+
unsigned_tx_id(): string;
11+
serialize(): Uint8Array;
12+
get_inputs(): unknown;
13+
get_outputs(): unknown;
14+
get_global_xpubs(): unknown;
15+
remove_input(index: number): void;
16+
remove_output(index: number): void;
17+
set_kv(key: unknown, value: Uint8Array): void;
18+
get_kv(key: unknown): Uint8Array | null | undefined;
19+
set_input_kv(index: number, key: unknown, value: Uint8Array): void;
20+
get_input_kv(index: number, key: unknown): Uint8Array | null | undefined;
21+
set_output_kv(index: number, key: unknown, value: Uint8Array): void;
22+
get_output_kv(index: number, key: unknown): Uint8Array | null | undefined;
23+
}
24+
25+
export abstract class PsbtBase<W extends WasmPsbtBase> {
26+
protected _wasm: W;
27+
28+
constructor(wasm: W) {
29+
this._wasm = wasm;
30+
}
31+
32+
inputCount(): number {
33+
return this._wasm.input_count();
34+
}
35+
outputCount(): number {
36+
return this._wasm.output_count();
37+
}
38+
version(): number {
39+
return this._wasm.version();
40+
}
41+
lockTime(): number {
42+
return this._wasm.lock_time();
43+
}
44+
unsignedTxId(): string {
45+
return this._wasm.unsigned_tx_id();
46+
}
47+
serialize(): Uint8Array {
48+
return this._wasm.serialize();
49+
}
50+
getInputs(): PsbtInputData[] {
51+
return this._wasm.get_inputs() as PsbtInputData[];
52+
}
53+
getOutputs(): PsbtOutputData[] {
54+
return this._wasm.get_outputs() as PsbtOutputData[];
55+
}
56+
getGlobalXpubs(): BIP32[] {
57+
return (this._wasm.get_global_xpubs() as WasmBIP32[]).map((w) => BIP32.fromWasm(w));
58+
}
59+
removeInput(index: number): void {
60+
this._wasm.remove_input(index);
61+
}
62+
removeOutput(index: number): void {
63+
this._wasm.remove_output(index);
64+
}
65+
setKV(key: PsbtKvKey, value: Uint8Array): void {
66+
this._wasm.set_kv(key, value);
67+
}
68+
getKV(key: PsbtKvKey): Uint8Array | undefined {
69+
return this._wasm.get_kv(key) ?? undefined;
70+
}
71+
setInputKV(index: number, key: PsbtKvKey, value: Uint8Array): void {
72+
this._wasm.set_input_kv(index, key, value);
73+
}
74+
getInputKV(index: number, key: PsbtKvKey): Uint8Array | undefined {
75+
return this._wasm.get_input_kv(index, key) ?? undefined;
76+
}
77+
setOutputKV(index: number, key: PsbtKvKey, value: Uint8Array): void {
78+
this._wasm.set_output_kv(index, key, value);
79+
}
80+
getOutputKV(index: number, key: PsbtKvKey): Uint8Array | undefined {
81+
return this._wasm.get_output_kv(index, key) ?? undefined;
82+
}
83+
}

0 commit comments

Comments
 (0)