Skip to content

Commit 36e3018

Browse files
Merge pull request #7504 from BitGo/BTC-2720
feat: use wasm-utxo for address generation on testnets
2 parents 712e18c + 65a6c11 commit 36e3018

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

modules/abstract-utxo/src/address/fixedScript.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import * as utxolib from '@bitgo/utxo-lib';
1515
import { bitgo } from '@bitgo/utxo-lib';
1616
import { bip32 } from '@bitgo/secp256k1';
17+
import * as wasmUtxo from '@bitgo/wasm-utxo';
1718

1819
type ScriptType2Of3 = bitgo.outputScripts.ScriptType2Of3;
1920

@@ -56,6 +57,19 @@ export function generateAddressWithChainAndIndex(
5657
index: number,
5758
format: CreateAddressFormat | undefined
5859
): string {
60+
if (utxolib.isTestnet(network)) {
61+
// Convert CreateAddressFormat to AddressFormat for wasm-utxo
62+
// 'base58' -> 'default', 'cashaddr' -> 'cashaddr'
63+
const wasmFormat = format === 'base58' ? 'default' : format;
64+
return wasmUtxo.fixedScriptWallet.address(
65+
keychains.map((k) => k.pub) as [string, string, string],
66+
chain,
67+
index,
68+
network,
69+
wasmFormat
70+
);
71+
}
72+
5973
const path = '0/0/' + chain + '/' + index;
6074
const hdNodes = keychains.map(({ pub }) => bip32.fromBase58(pub));
6175
const derivedKeys = hdNodes.map((hdNode) => hdNode.derivePath(sanitizeLegacyPath(path)).publicKey);

modules/abstract-utxo/test/unit/address.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,38 @@ function run(coin: AbstractUtxoCoin) {
116116
});
117117
});
118118

119+
it('respects format parameter', function () {
120+
// Only test coins that actually support multiple address formats (BCH/BCHA)
121+
// These are the only coins where the format parameter matters
122+
const cashaddrPrefixes: Record<string, string> = {
123+
bch: 'bitcoincash:',
124+
tbch: 'bchtest:',
125+
bcha: 'ecash:',
126+
tbcha: 'ectest:',
127+
};
128+
129+
const expectedPrefix = cashaddrPrefixes[coin.getChain()];
130+
if (!expectedPrefix) {
131+
this.skip();
132+
}
133+
134+
const chain = chainCodes[0];
135+
const params = { keychains, chain };
136+
137+
// Generate with cashaddr format
138+
const addressCashaddr = generateAddress(coin.network, { ...params, format: 'cashaddr' });
139+
coin.isValidAddress(addressCashaddr).should.eql(true);
140+
addressCashaddr.should.startWith(expectedPrefix, `cashaddr should start with ${expectedPrefix}`);
141+
142+
// Generate with base58 format explicitly
143+
const addressBase58 = generateAddress(coin.network, { ...params, format: 'base58' });
144+
coin.isValidAddress(addressBase58).should.eql(true);
145+
addressBase58.should.not.match(/.*:.*/, 'base58 should not contain colon separator');
146+
147+
// Verify formats produce different strings
148+
addressCashaddr.should.not.equal(addressBase58, 'cashaddr and base58 should produce different address strings');
149+
});
150+
119151
utxoCoins.forEach((otherCoin) => {
120152
it(`has expected address compatability with ${otherCoin.getChain()}`, async function () {
121153
getParameters().forEach((p) => {

modules/abstract-utxo/test/unit/util/unspents.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as utxolib from '@bitgo/utxo-lib';
22
import { getSeed } from '@bitgo/sdk-test';
3+
import * as wasmUtxo from '@bitgo/wasm-utxo';
34

45
import { getReplayProtectionAddresses } from '../../../src';
56

@@ -31,6 +32,9 @@ export function getWalletAddress(
3132
chain = defaultChain,
3233
index = 0
3334
): string {
35+
if (utxolib.isTestnet(network)) {
36+
return wasmUtxo.fixedScriptWallet.address(walletKeys, chain, index, network);
37+
}
3438
return utxolib.address.fromOutputScript(getOutputScript(walletKeys, chain, index).scriptPubKey, network);
3539
}
3640

@@ -49,8 +53,7 @@ export function mockWalletUnspent<TNumber extends number | bigint = number>(
4953
if (chain === undefined) {
5054
throw new Error(`unspent chain must be set`);
5155
}
52-
const derived = getOutputScript(walletKeys, chain, index);
53-
const deriveAddress = utxolib.address.fromOutputScript(derived.scriptPubKey, network);
56+
const deriveAddress = getWalletAddress(network, walletKeys, chain, index);
5457
if (address) {
5558
if (address !== deriveAddress) {
5659
throw new Error(`derivedAddress mismatch: ${address} derived=${deriveAddress}`);

0 commit comments

Comments
 (0)