Skip to content

Commit b57f2c6

Browse files
Merge pull request #153 from BitGo/BTC-2650.add-address-compat-test
feat(wasm-utxo): add address compatibility tests
2 parents 0cb9979 + fcef3f0 commit b57f2c6

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import assert from "node:assert";
2+
import { address as addressNs } from "../../js/index.js";
3+
import { coinNames, type CoinName } from "../../js/coinName.js";
4+
5+
/**
6+
* For a given script, encode as an address for every coin.
7+
* Returns groups of coins that produce the same address, sorted.
8+
*/
9+
function getCompatibilityGroups(scriptHex: string): CoinName[][] {
10+
const script = Buffer.from(scriptHex, "hex");
11+
const addressToCoins = new Map<string, CoinName[]>();
12+
13+
for (const coin of coinNames) {
14+
try {
15+
const addr = addressNs.fromOutputScriptWithCoin(script, coin);
16+
const group = addressToCoins.get(addr);
17+
if (group) {
18+
group.push(coin);
19+
} else {
20+
addressToCoins.set(addr, [coin]);
21+
}
22+
} catch {
23+
// coin does not support this script type
24+
}
25+
}
26+
27+
return Array.from(addressToCoins.values())
28+
.map((g) => g.sort())
29+
.sort((a, b) => a[0].localeCompare(b[0]));
30+
}
31+
32+
// Representative scripts from test/fixtures/address/bitcoin.json
33+
const scripts = {
34+
p2sh: "a91411510d2560794b3ed7bf734bc0e030e70e4db42d87",
35+
p2shP2wsh: "a9140c4e25aa3282fa35888f5e1eedb876265328312587",
36+
p2wsh: "00208bb2ef4181b60abe68b4c9cdc44c92e73bbb17fa2611e7e5b60d794794a1c94d",
37+
p2tr: "5120c4beea12923f95c32976d3d1ca7d5490aa3ea28f96d5feacc8ecc28819925eb5",
38+
p2trMusig2: "51205f98a79a3f750b250bee5bbdca0705db0ec8621f1bda91a083536a8a8bd6b6ed",
39+
};
40+
41+
// p2sh and p2shP2wsh are both a914...87 scripts; the encoding cannot distinguish them,
42+
// so they produce the same compatibility groups.
43+
const legacyGroups: CoinName[][] = [
44+
["bch", "bcha", "bsv", "btc"],
45+
["btg"],
46+
["dash"],
47+
["doge"],
48+
["ltc"],
49+
["tbch", "tbcha", "tbsv", "tbtc", "tbtc4", "tbtcbgsig", "tbtcsig", "tbtg", "tdoge"],
50+
["tdash"],
51+
["tltc"],
52+
["tzec"],
53+
["zec"],
54+
];
55+
56+
const segwitGroups: CoinName[][] = [
57+
["btc"],
58+
["btg"],
59+
["ltc"],
60+
["tbtc", "tbtc4", "tbtcbgsig", "tbtcsig"],
61+
["tbtg"],
62+
["tltc"],
63+
];
64+
65+
const taprootGroups: CoinName[][] = [["btc"], ["tbtc", "tbtc4", "tbtcbgsig", "tbtcsig"]];
66+
67+
describe("address compatibility", function () {
68+
it("p2sh: btc/bch/bcha/bsv share mainnet format, most testnets share testnet format", function () {
69+
assert.deepStrictEqual(getCompatibilityGroups(scripts.p2sh), legacyGroups);
70+
});
71+
72+
it("p2shP2wsh: same groups as p2sh (indistinguishable script structure)", function () {
73+
assert.deepStrictEqual(getCompatibilityGroups(scripts.p2shP2wsh), legacyGroups);
74+
});
75+
76+
it("p2wsh: btc/btg/ltc each have unique bech32 HRP, testnets likewise", function () {
77+
assert.deepStrictEqual(getCompatibilityGroups(scripts.p2wsh), segwitGroups);
78+
});
79+
80+
it("p2tr: only btc family supports taproot", function () {
81+
assert.deepStrictEqual(getCompatibilityGroups(scripts.p2tr), taprootGroups);
82+
});
83+
84+
it("p2trMusig2: same groups as p2tr (same bech32m encoding)", function () {
85+
assert.deepStrictEqual(getCompatibilityGroups(scripts.p2trMusig2), taprootGroups);
86+
});
87+
});

0 commit comments

Comments
 (0)