Skip to content

Commit 75ccf91

Browse files
Merge pull request #264 from BitGo/BTC-0.hydrate-networktx
feat(wasm-utxo): add PSBT fromNetworkFormat
2 parents e9ae38d + 9405b00 commit 75ccf91

8 files changed

Lines changed: 994 additions & 595 deletions

File tree

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

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,19 +193,22 @@ export class BitGoPsbt extends PsbtBase<WasmBitGoPsbt> implements IPsbtWithAddre
193193
/**
194194
* Convert a half-signed legacy transaction to a psbt-lite.
195195
*
196+
* @deprecated Use `fromNetworkFormat()` instead. Signature-count enforcement
197+
* (exactly 1 sig per wallet input) is moving to the caller.
198+
*
196199
* Extracts partial signatures from scriptSig/witness and creates a PSBT
197200
* with proper wallet metadata (bip32Derivation, scripts, witnessUtxo).
198201
* Only supports p2sh, p2shP2wsh, and p2wsh inputs (not taproot).
199202
*
200203
* Supports both Bitcoin-like coins (BTC, LTC, DOGE) and Dash (DASH).
201-
* Zcash is NOT supported; use ZcashBitGoPsbt.fromHalfSignedLegacyTransaction instead.
204+
* Zcash is NOT supported; use ZcashBitGoPsbt.fromNetworkFormat instead.
202205
*
203206
* @param txBytesOrTx - Transaction bytes or decoded transaction instance (Bitcoin-like or Dash)
204207
* @param network - Network name
205208
* @param walletKeys - The wallet's root keys
206209
* @param unspents - Chain, index, and value for each input
207210
* @param _options - Reserved for future use and signature compatibility with subclasses
208-
* @throws Error if transaction is Zcash (use ZcashBitGoPsbt.fromHalfSignedLegacyTransaction instead)
211+
* @throws Error if transaction is Zcash (use ZcashBitGoPsbt.fromNetworkFormat instead)
209212
*/
210213
static fromHalfSignedLegacyTransaction(
211214
txBytesOrTx: Uint8Array | Transaction | DashTransaction,
@@ -243,6 +246,47 @@ export class BitGoPsbt extends PsbtBase<WasmBitGoPsbt> implements IPsbtWithAddre
243246
return new BitGoPsbt(wasm);
244247
}
245248

249+
/**
250+
* Convert a network-format transaction to a PSBT.
251+
*
252+
* Accepts both the half-signed legacy format (5-slot scriptSig/witness with OP_0
253+
* placeholders) and the fully-signed network format (compact 4-item form). The
254+
* resulting PSBT will contain all partial signatures present in the transaction.
255+
*
256+
* Use this when you don't know ahead of time whether the transaction is half-signed
257+
* or fully-signed. For Zcash, use ZcashBitGoPsbt.fromNetworkFormat() instead.
258+
*
259+
* @param txBytesOrTx - Transaction bytes or decoded Transaction/DashTransaction
260+
* @param network - Network name
261+
* @param walletKeys - The wallet's root keys
262+
* @param unspents - Chain, index, and value for each input
263+
*/
264+
static fromNetworkFormat(
265+
txBytesOrTx: Uint8Array | Transaction | DashTransaction,
266+
network: NetworkName,
267+
walletKeys: WalletKeysArg,
268+
unspents: HydrationUnspent[],
269+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
270+
_options?: unknown,
271+
): BitGoPsbt {
272+
const keys = RootWalletKeys.from(walletKeys);
273+
274+
const tx =
275+
txBytesOrTx instanceof Uint8Array
276+
? Transaction.fromBytes(txBytesOrTx, toCoinName(network))
277+
: txBytesOrTx;
278+
279+
if (tx instanceof ZcashTransaction) {
280+
throw new Error("Use ZcashBitGoPsbt.fromNetworkFormat() for Zcash transactions");
281+
}
282+
283+
const wasm: WasmBitGoPsbt =
284+
tx instanceof DashTransaction
285+
? WasmBitGoPsbt.from_network_format_dash(tx.wasm, network, keys.wasm, unspents)
286+
: WasmBitGoPsbt.from_network_format(tx.wasm, network, keys.wasm, unspents);
287+
return new BitGoPsbt(wasm);
288+
}
289+
246290
/**
247291
* Add an input to the PSBT
248292
*

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

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,14 @@ export class ZcashBitGoPsbt extends BitGoPsbt {
145145
}
146146

147147
/**
148-
* Reconstruct a Zcash PSBT from a half-signed legacy transaction
148+
* Reconstruct a Zcash PSBT from a network-format transaction (unsigned, half-signed, or fully-signed).
149149
*
150-
* This is the inverse of `getHalfSignedLegacyFormat()` for Zcash. It decodes the Zcash wire
151-
* format (which includes version_group_id, expiry_height, and sapling fields), extracts
152-
* partial signatures, and reconstructs a proper Zcash PSBT with consensus metadata.
150+
* This is the Zcash equivalent of `BitGoPsbt.fromNetworkFormat()`. It decodes the Zcash wire
151+
* format (which includes version_group_id, expiry_height, and sapling fields), extracts any
152+
* partial signatures present, and reconstructs a proper Zcash PSBT with consensus metadata.
153+
*
154+
* Use this as the modern replacement for `fromHalfSignedLegacyTransaction`. Signature-count
155+
* discovery (unsigned / half-signed / fully-signed) is left to the caller.
153156
*
154157
* Supports two modes for determining consensus_branch_id:
155158
* - **Recommended**: Pass `blockHeight` to auto-determine consensus_branch_id via network upgrade activation heights
@@ -161,28 +164,53 @@ export class ZcashBitGoPsbt extends BitGoPsbt {
161164
* @param unspents - Chain, index, and value for each input
162165
* @param options - Either `{ blockHeight: number }` or `{ consensusBranchId: number }`
163166
* @returns A ZcashBitGoPsbt instance
167+
*/
168+
static fromNetworkFormat(
169+
txBytesOrTx: Uint8Array | ITransaction,
170+
network: ZcashNetworkName,
171+
walletKeys: WalletKeysArg,
172+
unspents: HydrationUnspent[],
173+
options: { blockHeight: number } | { consensusBranchId: number },
174+
): ZcashBitGoPsbt {
175+
const keys = RootWalletKeys.from(walletKeys);
176+
const tx =
177+
txBytesOrTx instanceof Uint8Array
178+
? ZcashTransaction.fromBytes(txBytesOrTx)
179+
: (txBytesOrTx as ZcashTransaction);
180+
181+
if ("blockHeight" in options) {
182+
const wasm = WasmBitGoPsbt.from_network_format_zcash_with_block_height(
183+
tx.wasm,
184+
network,
185+
keys.wasm,
186+
unspents,
187+
options.blockHeight,
188+
);
189+
return new ZcashBitGoPsbt(wasm);
190+
} else {
191+
const wasm = WasmBitGoPsbt.from_network_format_zcash_with_branch_id(
192+
tx.wasm,
193+
network,
194+
keys.wasm,
195+
unspents,
196+
options.consensusBranchId,
197+
);
198+
return new ZcashBitGoPsbt(wasm);
199+
}
200+
}
201+
202+
/**
203+
* Reconstruct a Zcash PSBT from a half-signed legacy transaction.
164204
*
165-
* @example
166-
* ```typescript
167-
* // Round-trip with block height (recommended)
168-
* const legacyBytes = psbt.getHalfSignedLegacyFormat();
169-
* const reconstructed = ZcashBitGoPsbt.fromHalfSignedLegacyTransaction(
170-
* legacyBytes,
171-
* "zec",
172-
* walletKeys,
173-
* unspents,
174-
* { blockHeight: 1687105 } // NU5 activation height
175-
* );
205+
* @deprecated Use `fromNetworkFormat()` instead. Signature-count enforcement
206+
* (exactly 1 sig per wallet input) is moving to the caller.
176207
*
177-
* // Or with explicit consensus branch ID
178-
* const reconstructed = ZcashBitGoPsbt.fromHalfSignedLegacyTransaction(
179-
* legacyBytes,
180-
* "zec",
181-
* walletKeys,
182-
* unspents,
183-
* { consensusBranchId: 0xC2D6D0B4 } // NU5 branch ID
184-
* );
185-
* ```
208+
* @param txBytesOrTx - Either serialized Zcash transaction bytes or a decoded ZcashTransaction instance
209+
* @param network - Zcash network name ("zcash", "zcashTest", "zec", "tzec")
210+
* @param walletKeys - The wallet's root keys
211+
* @param unspents - Chain, index, and value for each input
212+
* @param options - Either `{ blockHeight: number }` or `{ consensusBranchId: number }`
213+
* @returns A ZcashBitGoPsbt instance
186214
*/
187215
static fromHalfSignedLegacyTransaction(
188216
txBytesOrTx: Uint8Array | ITransaction,
@@ -198,7 +226,7 @@ export class ZcashBitGoPsbt extends BitGoPsbt {
198226
: (txBytesOrTx as ZcashTransaction);
199227

200228
if ("blockHeight" in options) {
201-
const wasm = WasmBitGoPsbt.from_half_signed_legacy_transaction_zcash_with_block_height(
229+
const wasm = WasmBitGoPsbt.from_network_format_zcash_with_block_height(
202230
tx.wasm,
203231
network,
204232
keys.wasm,
@@ -207,7 +235,7 @@ export class ZcashBitGoPsbt extends BitGoPsbt {
207235
);
208236
return new ZcashBitGoPsbt(wasm);
209237
} else {
210-
const wasm = WasmBitGoPsbt.from_half_signed_legacy_transaction_zcash_with_branch_id(
238+
const wasm = WasmBitGoPsbt.from_network_format_zcash_with_branch_id(
211239
tx.wasm,
212240
network,
213241
keys.wasm,

0 commit comments

Comments
 (0)