Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/abstract-utxo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@bitgo/utxo-core": "^1.41.6",
"@bitgo/utxo-descriptors": "^2.2.0",
"@bitgo/utxo-ord": "^1.34.6",
"@bitgo/wasm-utxo": "^5.11.0",
"@bitgo/wasm-utxo": "^5.15.0",
"@types/lodash": "^4.14.121",
"@types/superagent": "4.1.15",
"bignumber.js": "^9.0.2",
Expand Down
11 changes: 8 additions & 3 deletions modules/abstract-utxo/src/recovery/psbt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,17 @@ function isZcash(coinName: CoinName): coinName is 'zec' | 'tzec' {

/**
* Default block heights for Zcash networks if not provided.
* These should be set to a height after the latest network upgrade.
* These are the latest network upgrade's activation heights (NU7, ZIP-259):
* zec 3543405 (mainnet, ~2026-11-05) and tzec 4465026 (testnet, 2026-10-06).
* Version 4 transactions are invalid at/after NU7 per ZIP-2003, so a v4 build at
* these heights is rejected by @bitgo/wasm-utxo at build time rather than signed
* and left unbroadcastable; recovering post-NU7 funds requires constructing a v6
* (Ironwood) transaction instead.
* TODO(BTC-2901): get the height from blockchair API instead of hardcoding.
*/
const ZCASH_DEFAULT_BLOCK_HEIGHTS: Record<'zec' | 'tzec', number> = {
zec: 3146400,
tzec: 3536500,
zec: 3543405,
tzec: 4465026,
};

/**
Expand Down
30 changes: 30 additions & 0 deletions modules/abstract-utxo/test/unit/impl/zec/psbtDecode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ describe('Zec PSBT decode (v4 + v6 Ironwood)', function () {
return psbt;
}

function buildMainnetV6Psbt(): fixedScriptWallet.ZcashIronwoodBitGoPsbt {
// NU7 mainnet activation height (ZIP-259, ~2026-11-05), carried by
// @bitgo/wasm-utxo 5.15.0.
const psbt = fixedScriptWallet.ZcashIronwoodBitGoPsbt.createEmpty('zec', walletKeys, { blockHeight: 3543405 });
psbt.addWalletInput({ txid: '55'.repeat(32), vout: 0, value: 100000n }, walletKeys, {
scriptId: { chain: 0, index: 0 },
});
psbt.addWalletOutput(walletKeys, { chain: 1, index: 0, value: 90000n });
return psbt;
}

it('decodes a v4 (Sapling-shaped) PSBT as a ZcashBitGoPsbt', function () {
const decoded = zec.decodeTransaction(Buffer.from(buildV4Psbt().serialize()));
assert.ok(decoded instanceof fixedScriptWallet.ZcashBitGoPsbt);
Expand Down Expand Up @@ -64,6 +75,25 @@ describe('Zec PSBT decode (v4 + v6 Ironwood)', function () {
assert.ok(decoded instanceof fixedScriptWallet.ZcashIronwoodBitGoPsbt);
});

it('decodes a v6 (Ironwood) mainnet PSBT at/after NU7 activation with the NU7 branch id', function () {
// From mainnet NU7 activation (3,543,405, ZIP-259) version 4 is invalid per
// ZIP-2003 and only v5/v6 transactions are valid; the NU7 consensus branch id
// 0x77190AD9 personalizes the ZIP-244 digests.
const psbt = buildMainnetV6Psbt();
assert.strictEqual(psbt.consensusBranchId, 0x77190ad9);
const decoded = zec.decodeTransaction(Buffer.from(psbt.serialize()));
assert.ok(decoded instanceof fixedScriptWallet.ZcashIronwoodBitGoPsbt);
assert.strictEqual(decoded.getVersion(), 6);
assert.strictEqual(decoded.consensusBranchId, 0x77190ad9);
});

it('rejects a v4 mainnet build at/after NU7 activation per ZIP-2003', function () {
assert.throws(
() => fixedScriptWallet.ZcashBitGoPsbt.createEmpty('zec', walletKeys, { blockHeight: 3543405 }),
/NU7/
);
});

it('throws the legacy-format error for a non-PSBT transaction', function () {
assert.throws(() => zec.decodeTransaction(Buffer.alloc(32)), /txFormat=legacy is deprecated/);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ function run(
keys: signingKeys,
recoveryDestination,
feeRateSatVB: defaultFeeRateSatB,
// Zcash: pin the historical pre-NU7 heights the recorded fixtures
// were generated with (NU6.1-era branch ids). Production defaults
// to the NU7 activation heights, at which a v4 build is rejected
// per ZIP-2003; these tests exercise v4 recovery mechanics, not
// broadcastability.
blockHeight: coin.getChain() === 'zec' ? 3146400 : coin.getChain() === 'tzec' ? 3536500 : undefined,
},
recoverUnspents
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ describe('Backup Key Recovery - Unspent Gathering', function () {
...keysFullSignedRecovery,
recoveryProvider: mockProvider,
feeRate: defaultFeeRateSatB,
// Zcash: exercise v4 recovery mechanics at a historical pre-NU7 height
// (ignored by non-Zcash coins). The production default is the NU7
// activation height, at which a v4 build is rejected per ZIP-2003.
blockHeight: 3146400,
});

// Verify recovery succeeded (transaction hex indicates unspents were gathered)
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-bin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@bitgo/unspents": "^0.51.10",
"@bitgo/utxo-core": "^1.41.6",
"@bitgo/utxo-lib": "^11.24.4",
"@bitgo/wasm-utxo": "^5.11.0",
"@bitgo/wasm-utxo": "^5.15.0",
"@noble/curves": "1.8.1",
"archy": "^1.0.0",
"bech32": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"@bitgo/secp256k1": "^1.11.1",
"@bitgo/unspents": "^0.51.10",
"@bitgo/utxo-lib": "^11.24.4",
"@bitgo/wasm-utxo": "^5.11.0",
"@bitgo/wasm-utxo": "^5.15.0",
"bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4",
"fast-sha256": "^1.3.0"
},
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-descriptors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
},
"dependencies": {
"@bitgo/utxo-core": "^1.41.6",
"@bitgo/wasm-utxo": "^5.11.0"
"@bitgo/wasm-utxo": "^5.15.0"
},
"devDependencies": {
"@stacks/bitcoin-staking": "7.6.0"
Expand Down
6 changes: 4 additions & 2 deletions modules/utxo-lib/src/bitgo/zcash/ZcashTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ export function getDefaultVersionGroupIdForVersion(version: number): number {
}

export function getDefaultConsensusBranchIdForVersion(network: ZcashNetwork, version: number): number {
// Testnet has not yet activated NU6.2 (testnet activation block 4052000), so keep
// defaulting to NU6.1 there. Mainnet activated NU6.2 at block 3364600.
// Deprecated legacy path: this utxolib backend is not height-aware and is frozen at
// NU6.1-era testnet / NU6.2-era mainnet defaults. Height-correct Zcash construction
// (NU6.2, NU6.3/Ironwood, NU7) lives in @bitgo/wasm-utxo. Testnet has long since
// activated NU6.2 (block 4052000) and NU7 (block 4465026).
if (network === networks.zcashTest) {
if (version === 4 || version === 5) {
return NU6_1_BRANCH_ID;
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-ord/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"directory": "modules/utxo-ord"
},
"dependencies": {
"@bitgo/wasm-utxo": "^5.11.0"
"@bitgo/wasm-utxo": "^5.15.0"
},
"devDependencies": {
"@bitgo/utxo-lib": "^11.24.4"
Expand Down
2 changes: 1 addition & 1 deletion modules/utxo-staking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"@bitgo/utxo-core": "^1.41.6",
"@bitgo/utxo-descriptors": "^2.2.0",
"@bitgo/utxo-lib": "^11.24.4",
"@bitgo/wasm-utxo": "^5.11.0",
"@bitgo/wasm-utxo": "^5.15.0",
"bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4",
"bip322-js": "^2.0.0",
"bitcoinjs-lib": "^6.1.7",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1076,10 +1076,10 @@
resolved "https://registry.npmjs.org/@bitgo/wasm-ton/-/wasm-ton-1.1.1.tgz"
integrity sha512-Y4x2V2ZcYWlmx42v7dlrKDtT2DuUt8smk8E98mh7RhpiifJhLk2v5RmXDwBl0A3v9TzUOU6qMOnSS/iZ8Pq52w==

"@bitgo/wasm-utxo@^5.11.0":
version "5.11.1"
resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-5.11.1.tgz#cc556b22b4746746067917c80034c69d796b7468"
integrity sha512-H7LRpyouRVefl+xBoR0ejVYJd2E6FWsZXeI1h47HBnTzqUtB+m7NcttxeyZbQugrYlSXeugDi8DpywWueepkCg==
"@bitgo/wasm-utxo@^5.15.0":
version "5.15.0"
resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-5.15.0.tgz#bd6d7e1d10e4779ff1d3432446ea704de691919d"
integrity sha512-UoNoXnFt/7VbPSr1I6i0SauSK7YQwmylORjrTmWbHCEaYEM9u2lsxGAb9latm/ctyENWQZxTIgXZzUKstnyQ7Q==

"@brandonblack/musig@^0.0.1-alpha.0":
version "0.0.1-alpha.1"
Expand Down
Loading