From 103f99159933f33667ac1d27a5a00402d94b6714 Mon Sep 17 00:00:00 2001 From: Otto Allmendinger Date: Mon, 2 Feb 2026 10:28:47 +0100 Subject: [PATCH] feat(wasm-utxo): add version info embedding in PSBTs Add methods to set and get wasm-utxo version information in PSBTs. This allows identification of which library version processed a PSBT by embedding the semantic version and git hash in proprietary fields. Issue: BTC-2992 Co-authored-by: llm-git --- .../js/fixedScriptWallet/BitGoPsbt.ts | 54 +++++++++++++++++++ .../wasm-utxo/js/fixedScriptWallet/index.ts | 1 + .../src/fixed_script_wallet/bitgo_psbt/mod.rs | 17 ++++++ .../src/wasm/fixed_script_wallet/mod.rs | 25 +++++++++ 4 files changed, 97 insertions(+) diff --git a/packages/wasm-utxo/js/fixedScriptWallet/BitGoPsbt.ts b/packages/wasm-utxo/js/fixedScriptWallet/BitGoPsbt.ts index cf221ee..7ebd0c9 100644 --- a/packages/wasm-utxo/js/fixedScriptWallet/BitGoPsbt.ts +++ b/packages/wasm-utxo/js/fixedScriptWallet/BitGoPsbt.ts @@ -51,6 +51,16 @@ export type CreateEmptyOptions = { lockTime?: number; }; +/** + * Version information embedded in PSBTs by wasm-utxo + */ +export type WasmUtxoVersionInfo = { + /** The semantic version of wasm-utxo (e.g., "0.0.2") */ + version: string; + /** The git commit hash at build time */ + gitHash: string; +}; + export type AddInputOptions = { /** Previous transaction ID (hex string) */ txid: string; @@ -409,6 +419,50 @@ export class BitGoPsbt { return this._wasm.lock_time(); } + /** + * Set wasm-utxo version information in the PSBT's proprietary fields + * + * This embeds the wasm-utxo version and git hash into the PSBT's global + * proprietary fields, allowing identification of which library version + * processed the PSBT. The version info is automatically embedded during + * serialization by default, but this method can be called explicitly + * if needed. + * + * @example + * ```typescript + * psbt.setVersionInfo(); + * const info = psbt.getVersionInfo(); + * console.log(`Built with wasm-utxo ${info?.version} (${info?.gitHash})`); + * ``` + */ + setVersionInfo(): void { + this._wasm.set_version_info(); + } + + /** + * Get wasm-utxo version information from the PSBT's proprietary fields + * + * Returns the version and git hash that was embedded in the PSBT by + * wasm-utxo during processing. Returns undefined if no version info + * is present (e.g., PSBT was created by another library). + * + * @returns Version info object with `version` and `gitHash`, or undefined + * + * @example + * ```typescript + * const info = psbt.getVersionInfo(); + * if (info) { + * console.log(`PSBT created by wasm-utxo ${info.version}`); + * } else { + * console.log("PSBT was not processed by wasm-utxo"); + * } + * ``` + */ + getVersionInfo(): WasmUtxoVersionInfo | undefined { + const info = this._wasm.get_version_info(); + return info === undefined ? undefined : (info as WasmUtxoVersionInfo); + } + /** * Parse transaction with wallet keys to identify wallet inputs/outputs * @param walletKeys - The wallet keys to use for identification diff --git a/packages/wasm-utxo/js/fixedScriptWallet/index.ts b/packages/wasm-utxo/js/fixedScriptWallet/index.ts index e1891cc..dd6204f 100644 --- a/packages/wasm-utxo/js/fixedScriptWallet/index.ts +++ b/packages/wasm-utxo/js/fixedScriptWallet/index.ts @@ -28,6 +28,7 @@ export { type AddOutputOptions, type AddWalletInputOptions, type AddWalletOutputOptions, + type WasmUtxoVersionInfo, } from "./BitGoPsbt.js"; // Zcash-specific PSBT subclass diff --git a/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs b/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs index 0b0088d..de54a78 100644 --- a/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs +++ b/packages/wasm-utxo/src/fixed_script_wallet/bitgo_psbt/mod.rs @@ -1236,6 +1236,23 @@ impl BitGoPsbt { self.psbt_mut().proprietary.insert(key, value); } + /// Get version information from the PSBT's proprietary fields + /// + /// Returns the wasm-utxo version and git hash that was embedded in the PSBT, + /// or None if no version info is present. + pub fn get_version_info(&self) -> Option { + use miniscript::bitcoin::psbt::raw::ProprietaryKey; + let key = ProprietaryKey { + prefix: BITGO.to_vec(), + subtype: ProprietaryKeySubtype::WasmUtxoVersion as u8, + key: vec![], + }; + self.psbt() + .proprietary + .get(&key) + .and_then(|value| WasmUtxoVersionInfo::from_bytes(value).ok()) + } + pub fn finalize_input( &mut self, secp: &secp256k1::Secp256k1, diff --git a/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs b/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs index f9bd3a0..bccd551 100644 --- a/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs +++ b/packages/wasm-utxo/src/wasm/fixed_script_wallet/mod.rs @@ -615,6 +615,31 @@ impl BitGoPsbt { } } + /// Set wasm-utxo version information in the PSBT's proprietary fields + /// + /// This embeds the wasm-utxo version and git hash into the PSBT's global + /// proprietary fields, allowing identification of which library version + /// processed the PSBT. + pub fn set_version_info(&mut self) { + self.psbt.set_version_info(); + } + + /// Get wasm-utxo version information from the PSBT's proprietary fields + /// + /// Returns an object with `version` and `gitHash` fields, or undefined + /// if no version info is present in the PSBT. + pub fn get_version_info(&self) -> JsValue { + match self.psbt.get_version_info() { + Some(info) => { + let obj = js_sys::Object::new(); + js_sys::Reflect::set(&obj, &"version".into(), &info.version.into()).unwrap(); + js_sys::Reflect::set(&obj, &"gitHash".into(), &info.git_hash.into()).unwrap(); + obj.into() + } + None => JsValue::UNDEFINED, + } + } + /// Parse transaction with wallet keys to identify wallet inputs/outputs pub fn parse_transaction_with_wallet_keys( &self,