@bitgo/wasm-utxo 1.22.0 → 1.24.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,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,6 +1,7 @@
1
1
  export * as address from "./address.js";
2
2
  export * as ast from "./ast/index.js";
3
3
  export * as bip322 from "./bip322/index.js";
4
+ export * as inscriptions from "./inscriptions.js";
4
5
  export * as utxolibCompat from "./utxolibCompat.js";
5
6
  export * as fixedScriptWallet from "./fixedScriptWallet/index.js";
6
7
  export * as bip32 from "./bip32.js";
@@ -11,6 +12,7 @@ export { Dimensions } from "./fixedScriptWallet/Dimensions.js";
11
12
  export type { CoinName } from "./coinName.js";
12
13
  export type { Triple } from "./triple.js";
13
14
  export type { AddressFormat } from "./address.js";
15
+ export type { TapLeafScript, PreparedInscriptionRevealData } from "./inscriptions.js";
14
16
  export type DescriptorPkType = "derivable" | "definite" | "string";
15
17
  export type ScriptContext = "tap" | "segwitv0" | "legacy";
16
18
  export type SignPsbtResult = {
@@ -7,6 +7,7 @@ void wasm;
7
7
  export * as address from "./address.js";
8
8
  export * as ast from "./ast/index.js";
9
9
  export * as bip322 from "./bip322/index.js";
10
+ export * as inscriptions from "./inscriptions.js";
10
11
  export * as utxolibCompat from "./utxolibCompat.js";
11
12
  export * as fixedScriptWallet from "./fixedScriptWallet/index.js";
12
13
  export * as bip32 from "./bip32.js";
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Inscription support for Bitcoin Ordinals
3
+ *
4
+ * This module provides functionality for creating and signing inscription
5
+ * reveal transactions following the Ordinals protocol.
6
+ *
7
+ * @see https://docs.ordinals.com/inscriptions.html
8
+ */
9
+ import { Transaction } from "./transaction.js";
10
+ import { type ECPairArg } from "./ecpair.js";
11
+ /**
12
+ * Taproot leaf script data needed for spending
13
+ */
14
+ export type TapLeafScript = {
15
+ /** Leaf version (typically 0xc0 for TapScript) */
16
+ leafVersion: number;
17
+ /** The compiled script bytes */
18
+ script: Uint8Array;
19
+ /** Control block for script path spending */
20
+ controlBlock: Uint8Array;
21
+ };
22
+ /**
23
+ * Prepared data for an inscription reveal transaction
24
+ */
25
+ export type PreparedInscriptionRevealData = {
26
+ /** The commit output script (P2TR, network-agnostic) */
27
+ outputScript: Uint8Array;
28
+ /** Estimated virtual size of the reveal transaction */
29
+ revealTransactionVSize: number;
30
+ /** Tap leaf script for spending the commit output */
31
+ tapLeafScript: TapLeafScript;
32
+ };
33
+ /**
34
+ * Create inscription reveal data including the commit output script and tap leaf script
35
+ *
36
+ * This function creates all the data needed to perform an inscription:
37
+ * 1. A P2TR output script for the commit transaction (network-agnostic)
38
+ * 2. The tap leaf script needed to spend from that output
39
+ * 3. An estimate of the reveal transaction's virtual size for fee calculation
40
+ *
41
+ * @param key - The key pair (ECPairArg: Uint8Array, ECPair, or WasmECPair). The x-only public key will be extracted.
42
+ * @param contentType - MIME type of the inscription (e.g., "text/plain", "image/png")
43
+ * @param inscriptionData - The inscription data bytes
44
+ * @returns PreparedInscriptionRevealData containing output script, vsize estimate, and tap leaf script
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const revealData = createInscriptionRevealData(
49
+ * ecpair,
50
+ * "text/plain",
51
+ * new TextEncoder().encode("Hello, Ordinals!"),
52
+ * );
53
+ * // Use address.fromOutputScriptWithCoin() to get address for a specific network
54
+ * console.log(`Estimated reveal vsize: ${revealData.revealTransactionVSize}`);
55
+ * ```
56
+ */
57
+ export declare function createInscriptionRevealData(key: ECPairArg, contentType: string, inscriptionData: Uint8Array): PreparedInscriptionRevealData;
58
+ /**
59
+ * Sign a reveal transaction
60
+ *
61
+ * Creates and signs the reveal transaction that spends from the commit output
62
+ * and sends the inscription to the recipient.
63
+ *
64
+ * @param key - The private key (ECPairArg: Uint8Array, ECPair, or WasmECPair)
65
+ * @param tapLeafScript - The tap leaf script from createInscriptionRevealData
66
+ * @param commitTx - The commit transaction
67
+ * @param commitOutputScript - The commit output script (P2TR)
68
+ * @param recipientOutputScript - Where to send the inscription (output script)
69
+ * @param outputValueSats - Value in satoshis for the inscription output
70
+ * @returns The signed PSBT as bytes
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const psbtBytes = signRevealTransaction(
75
+ * privateKey,
76
+ * revealData.tapLeafScript,
77
+ * commitTx,
78
+ * revealData.outputScript,
79
+ * recipientOutputScript,
80
+ * 10000n, // 10,000 sats
81
+ * );
82
+ * ```
83
+ */
84
+ export declare function signRevealTransaction(key: ECPairArg, tapLeafScript: TapLeafScript, commitTx: Transaction, commitOutputScript: Uint8Array, recipientOutputScript: Uint8Array, outputValueSats: bigint): Uint8Array;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Inscription support for Bitcoin Ordinals
3
+ *
4
+ * This module provides functionality for creating and signing inscription
5
+ * reveal transactions following the Ordinals protocol.
6
+ *
7
+ * @see https://docs.ordinals.com/inscriptions.html
8
+ */
9
+ import { InscriptionsNamespace } from "./wasm/wasm_utxo.js";
10
+ import { ECPair } from "./ecpair.js";
11
+ /**
12
+ * Create inscription reveal data including the commit output script and tap leaf script
13
+ *
14
+ * This function creates all the data needed to perform an inscription:
15
+ * 1. A P2TR output script for the commit transaction (network-agnostic)
16
+ * 2. The tap leaf script needed to spend from that output
17
+ * 3. An estimate of the reveal transaction's virtual size for fee calculation
18
+ *
19
+ * @param key - The key pair (ECPairArg: Uint8Array, ECPair, or WasmECPair). The x-only public key will be extracted.
20
+ * @param contentType - MIME type of the inscription (e.g., "text/plain", "image/png")
21
+ * @param inscriptionData - The inscription data bytes
22
+ * @returns PreparedInscriptionRevealData containing output script, vsize estimate, and tap leaf script
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const revealData = createInscriptionRevealData(
27
+ * ecpair,
28
+ * "text/plain",
29
+ * new TextEncoder().encode("Hello, Ordinals!"),
30
+ * );
31
+ * // Use address.fromOutputScriptWithCoin() to get address for a specific network
32
+ * console.log(`Estimated reveal vsize: ${revealData.revealTransactionVSize}`);
33
+ * ```
34
+ */
35
+ export function createInscriptionRevealData(key, contentType, inscriptionData) {
36
+ // Convert to ECPair and extract x-only public key (strip parity byte from compressed pubkey)
37
+ const ecpair = ECPair.from(key);
38
+ const compressedPubkey = ecpair.publicKey;
39
+ const xOnlyPubkey = compressedPubkey.slice(1); // Remove first byte (parity)
40
+ // Call snake_case WASM method (traits output camelCase)
41
+ return InscriptionsNamespace.create_inscription_reveal_data(xOnlyPubkey, contentType, inscriptionData);
42
+ }
43
+ /**
44
+ * Sign a reveal transaction
45
+ *
46
+ * Creates and signs the reveal transaction that spends from the commit output
47
+ * and sends the inscription to the recipient.
48
+ *
49
+ * @param key - The private key (ECPairArg: Uint8Array, ECPair, or WasmECPair)
50
+ * @param tapLeafScript - The tap leaf script from createInscriptionRevealData
51
+ * @param commitTx - The commit transaction
52
+ * @param commitOutputScript - The commit output script (P2TR)
53
+ * @param recipientOutputScript - Where to send the inscription (output script)
54
+ * @param outputValueSats - Value in satoshis for the inscription output
55
+ * @returns The signed PSBT as bytes
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const psbtBytes = signRevealTransaction(
60
+ * privateKey,
61
+ * revealData.tapLeafScript,
62
+ * commitTx,
63
+ * revealData.outputScript,
64
+ * recipientOutputScript,
65
+ * 10000n, // 10,000 sats
66
+ * );
67
+ * ```
68
+ */
69
+ export function signRevealTransaction(key, tapLeafScript, commitTx, commitOutputScript, recipientOutputScript, outputValueSats) {
70
+ // Convert to ECPair to get private key bytes
71
+ const ecpair = ECPair.from(key);
72
+ const privateKey = ecpair.privateKey;
73
+ if (!privateKey) {
74
+ throw new Error("ECPair must have a private key for signing");
75
+ }
76
+ // Call snake_case WASM method
77
+ return InscriptionsNamespace.sign_reveal_transaction(privateKey, tapLeafScript, commitTx.wasm, commitOutputScript, recipientOutputScript, outputValueSats);
78
+ }
@@ -479,6 +479,15 @@ export class FixedScriptWalletNamespace {
479
479
  free(): void;
480
480
  [Symbol.dispose](): void;
481
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;
482
491
  /**
483
492
  * Check if a network supports a given fixed-script wallet script type
484
493
  *
@@ -498,6 +507,42 @@ export class FixedScriptWalletNamespace {
498
507
  static address(keys: WasmRootWalletKeys, chain: number, index: number, network: any, address_format?: string | null): string;
499
508
  }
500
509
 
510
+ export class InscriptionsNamespace {
511
+ private constructor();
512
+ free(): void;
513
+ [Symbol.dispose](): void;
514
+ /**
515
+ * Sign a reveal transaction
516
+ *
517
+ * # Arguments
518
+ * * `private_key` - The private key (32 bytes)
519
+ * * `tap_leaf_script` - The tap leaf script object from `create_inscription_reveal_data`
520
+ * * `commit_tx` - The commit transaction
521
+ * * `commit_output_script` - The commit output script (P2TR)
522
+ * * `recipient_output_script` - Where to send the inscription (output script)
523
+ * * `output_value_sats` - Value in satoshis for the inscription output
524
+ *
525
+ * # Returns
526
+ * The signed PSBT as bytes
527
+ */
528
+ static sign_reveal_transaction(private_key: Uint8Array, tap_leaf_script: any, commit_tx: WasmTransaction, commit_output_script: Uint8Array, recipient_output_script: Uint8Array, output_value_sats: bigint): Uint8Array;
529
+ /**
530
+ * Create inscription reveal data including the commit output script and tap leaf script
531
+ *
532
+ * # Arguments
533
+ * * `x_only_pubkey` - The x-only public key (32 bytes)
534
+ * * `content_type` - MIME type of the inscription (e.g., "text/plain", "image/png")
535
+ * * `inscription_data` - The inscription data bytes
536
+ *
537
+ * # Returns
538
+ * An object containing:
539
+ * - `output_script`: The commit output script (P2TR, network-agnostic)
540
+ * - `reveal_transaction_vsize`: Estimated vsize of the reveal transaction
541
+ * - `tap_leaf_script`: Object with `leaf_version`, `script`, and `control_block`
542
+ */
543
+ static create_inscription_reveal_data(x_only_pubkey: Uint8Array, content_type: string, inscription_data: Uint8Array): any;
544
+ }
545
+
501
546
  export class UtxolibCompatNamespace {
502
547
  private constructor();
503
548
  free(): void;
@@ -654,9 +699,27 @@ export class WasmDimensions {
654
699
  */
655
700
  has_segwit(): boolean;
656
701
  /**
657
- * Create dimensions for a single output from script bytes
702
+ * Get input virtual size (min or max)
703
+ *
704
+ * # Arguments
705
+ * * `size` - "min" or "max", defaults to "max"
706
+ */
707
+ get_input_vsize(size?: string | null): number;
708
+ /**
709
+ * Get input weight only (min or max)
710
+ *
711
+ * # Arguments
712
+ * * `size` - "min" or "max", defaults to "max"
713
+ */
714
+ get_input_weight(size?: string | null): number;
715
+ /**
716
+ * Get output virtual size
658
717
  */
659
- static from_output_script(script: Uint8Array): WasmDimensions;
718
+ get_output_vsize(): number;
719
+ /**
720
+ * Get output weight
721
+ */
722
+ get_output_weight(): number;
660
723
  /**
661
724
  * Create dimensions for a single input from script type string
662
725
  *
@@ -665,6 +728,17 @@ export class WasmDimensions {
665
728
  * "p2trMusig2KeyPath", "p2trMusig2ScriptPath", "p2shP2pk"
666
729
  */
667
730
  static from_input_script_type(script_type: string): WasmDimensions;
731
+ /**
732
+ * Create dimensions for a single output from script type string
733
+ *
734
+ * # Arguments
735
+ * * `script_type` - One of: "p2sh", "p2shP2wsh", "p2wsh", "p2tr"/"p2trLegacy", "p2trMusig2"
736
+ */
737
+ static from_output_script_type(script_type: string): WasmDimensions;
738
+ /**
739
+ * Create dimensions for a single output from script length
740
+ */
741
+ static from_output_script_length(length: number): WasmDimensions;
668
742
  /**
669
743
  * Combine with another Dimensions instance
670
744
  */
@@ -673,6 +747,10 @@ export class WasmDimensions {
673
747
  * Create empty dimensions (zero weight)
674
748
  */
675
749
  static empty(): WasmDimensions;
750
+ /**
751
+ * Multiply dimensions by a scalar
752
+ */
753
+ times(n: number): WasmDimensions;
676
754
  /**
677
755
  * Create dimensions from a BitGoPsbt
678
756
  *