Skip to content

Commit 7e7d78c

Browse files
OttoAllmendingerllm-git
andcommitted
feat(wasm-utxo): add optional addressFormat parameter to address function
Add support for specifying the address format when generating addresses in the fixedScriptWallet module. This allows controlling the output format (e.g., cashaddr for BCH/ECASH) when needed. Added JSDoc documentation explaining the addressFormat parameter usage and the available format options for Bitcoin Cash and eCash networks. Issue: BTC-2652 Co-authored-by: llm-git <[email protected]>
1 parent f1c03fd commit 7e7d78c

File tree

4 files changed

+54
-8
lines changed

4 files changed

+54
-8
lines changed

packages/wasm-utxo/js/address.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { AddressNamespace } from "./wasm/wasm_utxo";
22
import type { CoinName } from "./coinName";
33

4+
/**
5+
* Most coins only have one unambiguous address format (base58check and bech32/bech32m)
6+
* For Bitcoin Cash and eCash, we can select between base58check and cashaddr.
7+
*/
48
export type AddressFormat = "default" | "cashaddr";
59

610
export function toOutputScriptWithCoin(address: string, coin: CoinName): Uint8Array {

packages/wasm-utxo/js/fixedScriptWallet.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FixedScriptWalletNamespace } from "./wasm/wasm_utxo";
22
import type { UtxolibNetwork, UtxolibRootWalletKeys } from "./utxolibCompat";
33
import { Triple } from "./triple";
4+
import { AddressFormat } from "./address";
45

56
export type WalletKeys =
67
/** Just an xpub triple, will assume default derivation prefixes */
@@ -18,12 +19,21 @@ export function outputScript(keys: WalletKeys, chain: number, index: number): Ui
1819
/**
1920
* Create the address for a given wallet keys and chain and index and network.
2021
* Wrapper for outputScript that also encodes the script to an address.
22+
* @param keys - The wallet keys to use.
23+
* @param chain - The chain to use.
24+
* @param index - The index to use.
25+
* @param network - The network to use.
26+
* @param addressFormat - The address format to use.
27+
* Only relevant for Bitcoin Cash and eCash networks, where:
28+
* - "default" means base58check,
29+
* - "cashaddr" means cashaddr.
2130
*/
2231
export function address(
2332
keys: WalletKeys,
2433
chain: number,
2534
index: number,
2635
network: UtxolibNetwork,
36+
addressFormat?: AddressFormat,
2737
): string {
28-
return FixedScriptWalletNamespace.address(keys, chain, index, network);
38+
return FixedScriptWalletNamespace.address(keys, chain, index, network, addressFormat);
2939
}

packages/wasm-utxo/src/fixed_script_wallet/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,20 @@ impl FixedScriptWalletNamespace {
4242
chain: u32,
4343
index: u32,
4444
network: JsValue,
45+
address_format: Option<String>,
4546
) -> Result<String, WasmMiniscriptError> {
4647
let network = Network::try_from_js_value(&network)?;
4748
let wallet_keys = RootWalletKeys::from_jsvalue(&keys)?;
4849
let chain = Chain::try_from(chain)
4950
.map_err(|e| WasmMiniscriptError::new(&format!("Invalid chain: {}", e)))?;
5051
let scripts = WalletScripts::from_wallet_keys(&wallet_keys, chain, index);
5152
let script = scripts.output_script();
53+
let address_format = AddressFormat::from_optional_str(address_format.as_deref())
54+
.map_err(|e| WasmMiniscriptError::new(&format!("Invalid address format: {}", e)))?;
5255
let address = crate::address::utxolib_compat::from_output_script_with_network(
5356
&script,
5457
&network,
55-
AddressFormat::Default,
58+
address_format,
5659
)
5760
.map_err(|e| WasmMiniscriptError::new(&format!("Failed to generate address: {}", e)))?;
5861
Ok(address.to_string())

packages/wasm-utxo/test/fixedScript/address.ts

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import assert from "node:assert";
22

33
import * as utxolib from "@bitgo/utxo-lib";
44

5-
import { fixedScriptWallet } from "../../js";
5+
import { AddressFormat, fixedScriptWallet } from "../../js";
66

77
type Triple<T> = [T, T, T];
88

@@ -11,6 +11,7 @@ function getAddressUtxoLib(
1111
chain: number,
1212
index: number,
1313
network: utxolib.Network,
14+
addressFormat: AddressFormat,
1415
): string {
1516
if (!utxolib.bitgo.isChainCode(chain)) {
1617
throw new Error(`Invalid chain code: ${chain}`);
@@ -21,11 +22,21 @@ function getAddressUtxoLib(
2122
derived.publicKeys,
2223
utxolib.bitgo.outputScripts.scriptTypeForChain(chain),
2324
);
24-
const address = utxolib.address.fromOutputScript(script.scriptPubKey, network);
25+
const address = utxolib.addressFormat.fromOutputScriptWithFormat(
26+
script.scriptPubKey,
27+
addressFormat,
28+
network,
29+
);
2530
return address;
2631
}
2732

28-
function runTest(network: utxolib.Network, derivationPrefixes?: Triple<string>) {
33+
function runTest(
34+
network: utxolib.Network,
35+
{
36+
derivationPrefixes,
37+
addressFormat,
38+
}: { derivationPrefixes?: Triple<string>; addressFormat?: AddressFormat } = {},
39+
) {
2940
describe(`address for network ${utxolib.getNetworkName(network)}, derivationPrefixes=${Boolean(derivationPrefixes)}`, function () {
3041
const keyTriple = utxolib.testutil.getKeyTriple("wasm");
3142

@@ -41,8 +52,20 @@ function runTest(network: utxolib.Network, derivationPrefixes?: Triple<string>)
4152
keyTriple.map((k) => k.neutered()) as Triple<utxolib.BIP32Interface>,
4253
derivationPrefixes,
4354
);
44-
const utxolibAddress = getAddressUtxoLib(rootWalletKeys, chainCode, index, network);
45-
const wasmAddress = fixedScriptWallet.address(rootWalletKeys, chainCode, index, network);
55+
const utxolibAddress = getAddressUtxoLib(
56+
rootWalletKeys,
57+
chainCode,
58+
index,
59+
network,
60+
addressFormat ?? "default",
61+
);
62+
const wasmAddress = fixedScriptWallet.address(
63+
rootWalletKeys,
64+
chainCode,
65+
index,
66+
network,
67+
addressFormat,
68+
);
4669
assert.strictEqual(utxolibAddress, wasmAddress);
4770
}
4871
}
@@ -52,5 +75,11 @@ function runTest(network: utxolib.Network, derivationPrefixes?: Triple<string>)
5275

5376
utxolib.getNetworkList().forEach((network) => {
5477
runTest(network);
55-
runTest(network, ["m/1/2", "m/0/0", "m/0/0"]);
78+
runTest(network, { derivationPrefixes: ["m/1/2", "m/0/0", "m/0/0"] });
79+
if (
80+
utxolib.getMainnet(network) === utxolib.networks.bitcoincash ||
81+
utxolib.getMainnet(network) === utxolib.networks.ecash
82+
) {
83+
runTest(network, { addressFormat: "cashaddr" });
84+
}
5685
});

0 commit comments

Comments
 (0)