@bitgo/wasm-utxo 1.21.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ import type { OutputScriptType } from "./scriptType.js";
2
+ /** All valid chain codes as a const tuple */
3
+ export declare const chainCodes: readonly [0, 1, 10, 11, 20, 21, 30, 31, 40, 41];
4
+ /** A valid chain code value */
5
+ export type ChainCode = (typeof chainCodes)[number];
6
+ /** Whether a chain is for receiving (external) or change (internal) addresses */
7
+ export type Scope = "internal" | "external";
8
+ /**
9
+ * ChainCode namespace with utility functions for working with chain codes.
10
+ */
11
+ export declare const ChainCode: {
12
+ /**
13
+ * Check if a value is a valid chain code.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * if (ChainCode.is(maybeChain)) {
18
+ * // maybeChain is now typed as ChainCode
19
+ * const scope = ChainCode.scope(maybeChain);
20
+ * }
21
+ * ```
22
+ */
23
+ is(n: unknown): n is ChainCode;
24
+ /**
25
+ * Get the chain code for a script type and scope.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const externalP2wsh = ChainCode.value("p2wsh", "external"); // 20
30
+ * const internalP2tr = ChainCode.value("p2trLegacy", "internal"); // 31
31
+ * ```
32
+ */
33
+ value(scriptType: OutputScriptType | "p2tr", scope: Scope): ChainCode;
34
+ /**
35
+ * Get the scope (external/internal) for a chain code.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * ChainCode.scope(0); // "external"
40
+ * ChainCode.scope(1); // "internal"
41
+ * ChainCode.scope(20); // "external"
42
+ * ```
43
+ */
44
+ scope(chainCode: ChainCode): Scope;
45
+ /**
46
+ * Get the script type for a chain code.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * ChainCode.scriptType(0); // "p2sh"
51
+ * ChainCode.scriptType(20); // "p2wsh"
52
+ * ChainCode.scriptType(40); // "p2trMusig2"
53
+ * ```
54
+ */
55
+ scriptType(chainCode: ChainCode): OutputScriptType;
56
+ };
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Chain code utilities for BitGo fixed-script wallets.
3
+ *
4
+ * Chain codes define the derivation path component for different script types
5
+ * and scopes (external/internal) in the format `m/0/0/{chain}/{index}`.
6
+ */
7
+ import { FixedScriptWalletNamespace } from "../wasm/wasm_utxo.js";
8
+ /** All valid chain codes as a const tuple */
9
+ export const chainCodes = [0, 1, 10, 11, 20, 21, 30, 31, 40, 41];
10
+ // Build static lookup tables once at module load time
11
+ const chainCodeSet = new Set(chainCodes);
12
+ const chainToMeta = new Map();
13
+ const scriptTypeToChain = new Map();
14
+ // Initialize from WASM (called once at load time)
15
+ function assertChainCode(n) {
16
+ if (!chainCodeSet.has(n)) {
17
+ throw new Error(`Invalid chain code from WASM: ${n}`);
18
+ }
19
+ return n;
20
+ }
21
+ function assertScope(s) {
22
+ if (s !== "internal" && s !== "external") {
23
+ throw new Error(`Invalid scope from WASM: ${s}`);
24
+ }
25
+ return s;
26
+ }
27
+ for (const tuple of FixedScriptWalletNamespace.chain_code_table()) {
28
+ if (!Array.isArray(tuple) || tuple.length !== 3) {
29
+ throw new Error(`Invalid chain_code_table entry: expected [number, string, string]`);
30
+ }
31
+ const [rawCode, rawScriptType, rawScope] = tuple;
32
+ if (typeof rawCode !== "number") {
33
+ throw new Error(`Invalid chain code type: ${typeof rawCode}`);
34
+ }
35
+ if (typeof rawScriptType !== "string") {
36
+ throw new Error(`Invalid scriptType type: ${typeof rawScriptType}`);
37
+ }
38
+ if (typeof rawScope !== "string") {
39
+ throw new Error(`Invalid scope type: ${typeof rawScope}`);
40
+ }
41
+ const code = assertChainCode(rawCode);
42
+ const scriptType = rawScriptType;
43
+ const scope = assertScope(rawScope);
44
+ chainToMeta.set(code, { scope, scriptType });
45
+ let entry = scriptTypeToChain.get(scriptType);
46
+ if (!entry) {
47
+ entry = {};
48
+ scriptTypeToChain.set(scriptType, entry);
49
+ }
50
+ entry[scope] = code;
51
+ }
52
+ /**
53
+ * ChainCode namespace with utility functions for working with chain codes.
54
+ */
55
+ export const ChainCode = {
56
+ /**
57
+ * Check if a value is a valid chain code.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * if (ChainCode.is(maybeChain)) {
62
+ * // maybeChain is now typed as ChainCode
63
+ * const scope = ChainCode.scope(maybeChain);
64
+ * }
65
+ * ```
66
+ */
67
+ is(n) {
68
+ return typeof n === "number" && chainCodeSet.has(n);
69
+ },
70
+ /**
71
+ * Get the chain code for a script type and scope.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const externalP2wsh = ChainCode.value("p2wsh", "external"); // 20
76
+ * const internalP2tr = ChainCode.value("p2trLegacy", "internal"); // 31
77
+ * ```
78
+ */
79
+ value(scriptType, scope) {
80
+ // legacy alias for p2trLegacy
81
+ if (scriptType === "p2tr") {
82
+ scriptType = "p2trLegacy";
83
+ }
84
+ const entry = scriptTypeToChain.get(scriptType);
85
+ if (!entry) {
86
+ throw new Error(`Invalid scriptType: ${scriptType}`);
87
+ }
88
+ return entry[scope];
89
+ },
90
+ /**
91
+ * Get the scope (external/internal) for a chain code.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * ChainCode.scope(0); // "external"
96
+ * ChainCode.scope(1); // "internal"
97
+ * ChainCode.scope(20); // "external"
98
+ * ```
99
+ */
100
+ scope(chainCode) {
101
+ const meta = chainToMeta.get(chainCode);
102
+ if (!meta)
103
+ throw new Error(`Invalid chainCode: ${chainCode}`);
104
+ return meta.scope;
105
+ },
106
+ /**
107
+ * Get the script type for a chain code.
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * ChainCode.scriptType(0); // "p2sh"
112
+ * ChainCode.scriptType(20); // "p2wsh"
113
+ * ChainCode.scriptType(40); // "p2trMusig2"
114
+ * ```
115
+ */
116
+ scriptType(chainCode) {
117
+ const meta = chainToMeta.get(chainCode);
118
+ if (!meta)
119
+ throw new Error(`Invalid chainCode: ${chainCode}`);
120
+ return meta.scriptType;
121
+ },
122
+ };
@@ -4,6 +4,7 @@ export { ReplayProtection, type ReplayProtectionArg } from "./ReplayProtection.j
4
4
  export { outputScript, address } from "./address.js";
5
5
  export { Dimensions } from "./Dimensions.js";
6
6
  export { type OutputScriptType, type InputScriptType, type ScriptType } from "./scriptType.js";
7
+ export { ChainCode, chainCodes, type Scope } from "./chains.js";
7
8
  export { BitGoPsbt, type NetworkName, type ScriptId, type ParsedInput, type ParsedOutput, type ParsedTransaction, type SignPath, type CreateEmptyOptions, type AddInputOptions, type AddOutputOptions, type AddWalletInputOptions, type AddWalletOutputOptions, } from "./BitGoPsbt.js";
8
9
  export { ZcashBitGoPsbt, type ZcashNetworkName, type CreateEmptyZcashOptions, } from "./ZcashBitGoPsbt.js";
9
10
  import type { ScriptType } from "./scriptType.js";
@@ -3,6 +3,7 @@ export { RootWalletKeys } from "./RootWalletKeys.js";
3
3
  export { ReplayProtection } from "./ReplayProtection.js";
4
4
  export { outputScript, address } from "./address.js";
5
5
  export { Dimensions } from "./Dimensions.js";
6
+ export { ChainCode, chainCodes } from "./chains.js";
6
7
  // Bitcoin-like PSBT (for all non-Zcash networks)
7
8
  export { BitGoPsbt, } from "./BitGoPsbt.js";
8
9
  // Zcash-specific PSBT subclass
@@ -1,5 +1,6 @@
1
1
  export * as address from "./address.js";
2
2
  export * as ast from "./ast/index.js";
3
+ export * as bip322 from "./bip322/index.js";
3
4
  export * as utxolibCompat from "./utxolibCompat.js";
4
5
  export * as fixedScriptWallet from "./fixedScriptWallet/index.js";
5
6
  export * as bip32 from "./bip32.js";
@@ -6,6 +6,7 @@ void wasm;
6
6
  // and to make imports more explicit (e.g., `import { address } from '@bitgo/wasm-utxo'`)
7
7
  export * as address from "./address.js";
8
8
  export * as ast from "./ast/index.js";
9
+ export * as bip322 from "./bip322/index.js";
9
10
  export * as utxolibCompat from "./utxolibCompat.js";
10
11
  export * as fixedScriptWallet from "./fixedScriptWallet/index.js";
11
12
  export * as bip32 from "./bip32.js";
@@ -9,6 +9,106 @@ export class AddressNamespace {
9
9
  static from_output_script_with_coin(script: Uint8Array, coin: string, format?: string | null): string;
10
10
  }
11
11
 
12
+ export class Bip322Namespace {
13
+ private constructor();
14
+ free(): void;
15
+ [Symbol.dispose](): void;
16
+ /**
17
+ * Add a BIP-0322 message input to an existing BitGoPsbt
18
+ *
19
+ * If this is the first input, also adds the OP_RETURN output.
20
+ * The PSBT must have version 0 per BIP-0322 specification.
21
+ *
22
+ * # Arguments
23
+ * * `psbt` - The BitGoPsbt to add the input to
24
+ * * `message` - The message to sign
25
+ * * `chain` - The wallet chain (e.g., 10 for external, 20 for internal)
26
+ * * `index` - The address index
27
+ * * `wallet_keys` - The wallet's root keys
28
+ * * `signer` - Optional signer key name for taproot (e.g., "user", "backup", "bitgo")
29
+ * * `cosigner` - Optional cosigner key name for taproot
30
+ * * `tag` - Optional custom tag for message hashing
31
+ *
32
+ * # Returns
33
+ * The index of the added input
34
+ */
35
+ static add_bip322_input(psbt: BitGoPsbt, message: string, chain: number, index: number, wallet_keys: WasmRootWalletKeys, signer?: string | null, cosigner?: string | null, tag?: string | null): number;
36
+ /**
37
+ * Verify a single input of a BIP-0322 transaction proof
38
+ *
39
+ * # Arguments
40
+ * * `tx` - The signed transaction
41
+ * * `input_index` - The index of the input to verify
42
+ * * `message` - The message that was signed
43
+ * * `chain` - The wallet chain
44
+ * * `index` - The address index
45
+ * * `wallet_keys` - The wallet's root keys
46
+ * * `network` - Network name
47
+ * * `tag` - Optional custom tag for message hashing
48
+ *
49
+ * # Throws
50
+ * Throws an error if verification fails
51
+ */
52
+ static verify_bip322_tx_input(tx: WasmTransaction, input_index: number, message: string, chain: number, index: number, wallet_keys: WasmRootWalletKeys, network: string, tag?: string | null): void;
53
+ /**
54
+ * Verify a single input of a BIP-0322 PSBT proof
55
+ *
56
+ * # Arguments
57
+ * * `psbt` - The signed BitGoPsbt
58
+ * * `input_index` - The index of the input to verify
59
+ * * `message` - The message that was signed
60
+ * * `chain` - The wallet chain
61
+ * * `index` - The address index
62
+ * * `wallet_keys` - The wallet's root keys
63
+ * * `tag` - Optional custom tag for message hashing
64
+ *
65
+ * # Returns
66
+ * An array of signer names ("user", "backup", "bitgo") that have valid signatures
67
+ *
68
+ * # Throws
69
+ * Throws an error if verification fails or no valid signatures found
70
+ */
71
+ static verify_bip322_psbt_input(psbt: BitGoPsbt, input_index: number, message: string, chain: number, index: number, wallet_keys: WasmRootWalletKeys, tag?: string | null): string[];
72
+ /**
73
+ * Verify a single input of a BIP-0322 transaction proof using pubkeys directly
74
+ *
75
+ * # Arguments
76
+ * * `tx` - The signed transaction
77
+ * * `input_index` - The index of the input to verify
78
+ * * `message` - The message that was signed
79
+ * * `pubkeys` - Array of 3 hex-encoded pubkeys [user, backup, bitgo]
80
+ * * `script_type` - One of: "p2sh", "p2shP2wsh", "p2wsh", "p2tr", "p2trMusig2"
81
+ * * `is_script_path` - For taproot types, whether script path was used
82
+ * * `tag` - Optional custom tag for message hashing
83
+ *
84
+ * # Returns
85
+ * An array of pubkey indices (0, 1, 2) that have valid signatures
86
+ *
87
+ * # Throws
88
+ * Throws an error if verification fails
89
+ */
90
+ static verify_bip322_tx_input_with_pubkeys(tx: WasmTransaction, input_index: number, message: string, pubkeys: string[], script_type: string, is_script_path?: boolean | null, tag?: string | null): Uint32Array;
91
+ /**
92
+ * Verify a single input of a BIP-0322 PSBT proof using pubkeys directly
93
+ *
94
+ * # Arguments
95
+ * * `psbt` - The signed BitGoPsbt
96
+ * * `input_index` - The index of the input to verify
97
+ * * `message` - The message that was signed
98
+ * * `pubkeys` - Array of 3 hex-encoded pubkeys [user, backup, bitgo]
99
+ * * `script_type` - One of: "p2sh", "p2shP2wsh", "p2wsh", "p2tr", "p2trMusig2"
100
+ * * `is_script_path` - For taproot types, whether script path was used
101
+ * * `tag` - Optional custom tag for message hashing
102
+ *
103
+ * # Returns
104
+ * An array of pubkey indices (0, 1, 2) that have valid signatures
105
+ *
106
+ * # Throws
107
+ * Throws an error if verification fails or no valid signatures found
108
+ */
109
+ static verify_bip322_psbt_input_with_pubkeys(psbt: BitGoPsbt, input_index: number, message: string, pubkeys: string[], script_type: string, is_script_path?: boolean | null, tag?: string | null): Uint32Array;
110
+ }
111
+
12
112
  export class BitGoPsbt {
13
113
  private constructor();
14
114
  free(): void;
@@ -379,6 +479,15 @@ export class FixedScriptWalletNamespace {
379
479
  free(): void;
380
480
  [Symbol.dispose](): void;
381
481
  static output_script(keys: WasmRootWalletKeys, chain: number, index: number, network: any): Uint8Array;
482
+ /**
483
+ * Get all chain code metadata for building TypeScript lookup tables
484
+ *
485
+ * Returns an array of [chainCode, scriptType, scope] tuples where:
486
+ * - chainCode: u32 (0, 1, 10, 11, 20, 21, 30, 31, 40, 41)
487
+ * - scriptType: string ("p2sh", "p2shP2wsh", "p2wsh", "p2trLegacy", "p2trMusig2")
488
+ * - scope: string ("external" or "internal")
489
+ */
490
+ static chain_code_table(): any;
382
491
  /**
383
492
  * Check if a network supports a given fixed-script wallet script type
384
493
  *
@@ -553,6 +662,28 @@ export class WasmDimensions {
553
662
  * Whether any inputs are segwit (affects overhead calculation)
554
663
  */
555
664
  has_segwit(): boolean;
665
+ /**
666
+ * Get input virtual size (min or max)
667
+ *
668
+ * # Arguments
669
+ * * `size` - "min" or "max", defaults to "max"
670
+ */
671
+ get_input_vsize(size?: string | null): number;
672
+ /**
673
+ * Get input weight only (min or max)
674
+ *
675
+ * # Arguments
676
+ * * `size` - "min" or "max", defaults to "max"
677
+ */
678
+ get_input_weight(size?: string | null): number;
679
+ /**
680
+ * Get output virtual size
681
+ */
682
+ get_output_vsize(): number;
683
+ /**
684
+ * Get output weight
685
+ */
686
+ get_output_weight(): number;
556
687
  /**
557
688
  * Create dimensions for a single output from script bytes
558
689
  */
@@ -573,6 +704,10 @@ export class WasmDimensions {
573
704
  * Create empty dimensions (zero weight)
574
705
  */
575
706
  static empty(): WasmDimensions;
707
+ /**
708
+ * Multiply dimensions by a scalar
709
+ */
710
+ times(n: number): WasmDimensions;
576
711
  /**
577
712
  * Create dimensions from a BitGoPsbt
578
713
  *