Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
020b722
feat: exclude singapore trust for ab1
shobhit565 Jun 5, 2026
7466534
feat: external signer callback for multisig akm wallet gen
danielpeng1 Jun 5, 2026
103baf9
feat(statics): onboard Robinhood EVM tokens
parasgarg-bitgo Jun 9, 2026
87d04a7
fix: fixes for external signer callback
github-actions[bot] Jun 5, 2026
e30261d
fix(scripts): retry yarn audit up to 3x on transient network errors
gokulhost Jun 9, 2026
49433e0
fix(scripts): use built-in retry-on-network-failure and 3s backoff
gokulhost Jun 9, 2026
5c786ef
Merge pull request #8975 from BitGo/gokuldevaraju330/wcn-865-fix-flak…
gokulhost Jun 9, 2026
326cc6e
fix(scripts): pin EricCrosson/retry to v1.4.8 with SHA256 digest
gokulhost Jun 9, 2026
5b03033
Merge pull request #8978 from BitGo/gokuldevaraju330/wcn-865-fix-flak…
gokulhost Jun 10, 2026
95e1e84
feat(sdk-coin-starknet): implement deploy account transaction support
shubham-damkondwar Jun 10, 2026
6fc31f6
fix(sdk-core): populate recipients in buildTokenEnablements for TSS w…
nvrakesh06 Jun 10, 2026
758c712
feat: onboards spaceX token
harshchawla812 Jun 10, 2026
b7ff4c7
Merge pull request #8979 from BitGo/fix/near-tss-token-enablement-mis…
nvrakesh06 Jun 10, 2026
54c9627
feat: introduce SUNSETTING coin feature for SEI
prithvishet2503 Jun 10, 2026
02f02aa
Merge pull request #8973 from BitGo/SCAAS-9660
harshchawla812 Jun 10, 2026
157895f
Merge pull request #8981 from BitGo/CECHO-1297
prithvishet2503 Jun 10, 2026
521168c
ci: fix incorrect pinned SHA for EricCrosson/retry@v1.4.8
Vignesh-285 Jun 10, 2026
27e12df
Merge pull request #8982 from BitGo/fix/vl-6482-retry-checksum
harshchawla812 Jun 10, 2026
66bfdb9
Merge pull request #8980 from BitGo/CECHO-927
shubham-damkondwar Jun 10, 2026
c6136c7
Merge pull request #8970 from BitGo/CECHO-1213
parasgarg-bitgo Jun 10, 2026
52df0da
feat(sdk-core): added canton types in tss prebuild flow
ravibitgo Jun 10, 2026
296661e
refactor(abstract-utxo): delete fetchInputs and remove redundant fee …
OttoAllmendinger May 22, 2026
7d22ff2
Merge pull request #8983 from BitGo/CHALO-573
ravibitgo Jun 10, 2026
c3a2638
Merge pull request #8916 from BitGo/otto/drop-fetchinputs
OttoAllmendinger Jun 10, 2026
40e7e91
refactor(abstract-utxo): remove createTransactionFromHex from Abstrac…
OttoAllmendinger May 22, 2026
eb3d681
refactor(abstract-utxo): pass coinName directly to BitGoPsbt.fromBytes
OttoAllmendinger May 22, 2026
03885cc
refactor(abstract-utxo): replace 3 utxolib network/script helpers wit…
OttoAllmendinger May 22, 2026
1ac21ec
refactor(abstract-utxo): migrate isValidAddress off utxolib.addressFo…
OttoAllmendinger May 22, 2026
c66a6e9
refactor(abstract-utxo): replace utxolib.bitgo helpers and drop dead …
OttoAllmendinger May 22, 2026
9a81813
refactor(abstract-utxo): remove deprecated network getter and getNetw…
OttoAllmendinger May 22, 2026
ea0b137
refactor(abstract-utxo): inline ScriptType2Of3 type definition
OttoAllmendinger May 22, 2026
0547f98
feat(sdk-core): send webauthnInfo with enterpriseId for MPC user keyc…
rajangarg047 Jun 9, 2026
5576f3a
Merge pull request #8915 from BitGo/otto/abstract-utxo-replacements
OttoAllmendinger Jun 10, 2026
ae271f7
refactor(abstract-utxo): drop utxolib RootWalletKeys from keychains.ts
OttoAllmendinger May 22, 2026
0b6356a
refactor(abstract-utxo): drop unused exports from wasmUtil
OttoAllmendinger May 22, 2026
45f0338
refactor(abstract-utxo): delete wasmUtil.ts and drop utxolib from run…
OttoAllmendinger May 22, 2026
29bfefe
Merge pull request #8987 from BitGo/otto/abstract-utxo-terminal
OttoAllmendinger Jun 10, 2026
2185f40
Merge pull request #8956 from BitGo/WCN-685/callbacks-multisig-akm
danielpeng1 Jun 10, 2026
292a83b
fix(statics): reject duplicate contract address and NFT index keys in…
nvjsr Jun 8, 2026
668adaf
Merge pull request #8974 from BitGo/rajangarg047/wcn-848-mpcv2-user-k…
rajangarg047 Jun 10, 2026
cb63106
fix(sdk-core): persist passkey for onchain generateWallet
rajangarg047 Jun 10, 2026
298cb0a
ci: flag internal-info leaks in PR review prompt
mr-neptune Jun 10, 2026
62d708b
Merge pull request #8990 from BitGo/WCN-850_catch_internal_details
mr-neptune Jun 11, 2026
4b264ac
Merge pull request #8966 from BitGo/CGD-715-fix
nvjsr Jun 11, 2026
477ffdc
fix(statics): correct FLRP P-chain explorer transaction URLs
ArunBala-Bitgo Jun 11, 2026
7ace459
feat(sdk-core): disable active operation pre-flight check in DefiVault
hitansh-madan Jun 11, 2026
dbbec42
feat(statics): rename canton fullname in test & prod env
ravibitgo Jun 11, 2026
6f72724
feat(statics): onboard polygon, avaxc, tempo
dgm003 Jun 11, 2026
933936d
Merge pull request #8992 from BitGo/CECHO-1177
ArunBala-Bitgo Jun 11, 2026
e80d7ec
chore(statics): updated coin features for bobaeth
bhavesh-prasad Jun 11, 2026
56091c8
Merge pull request #8994 from BitGo/CHALO-581
ananth99 Jun 11, 2026
5919bd3
Merge pull request #8993 from BitGo/feat/onboard-mxnd-tempo-usdt0
dgm003 Jun 11, 2026
aebe4a6
Merge pull request #8996 from BitGo/CeCHO-305-3
bhavesh-prasad Jun 11, 2026
21190c6
Merge pull request #8991 from BitGo/feat/sdk-defi-disable-preflight
kamleshmugdiya Jun 11, 2026
97ea33a
Merge pull request #8954 from BitGo/gate-ab1
shobhit565 Jun 11, 2026
467b396
chore(sdk-coin-ton): rename display name from Ton to Gram
prajwalu142 Jun 11, 2026
c8a1310
Merge pull request #8989 from BitGo/rajangarg047/wcn-870-m2-sdk-persi…
rajangarg047 Jun 11, 2026
ab43513
Merge pull request #8997 from BitGo/tonRebranding
prajwalu142 Jun 11, 2026
746e5de
Merge remote-tracking branch 'origin/master' into master-into-rel-latest
alextse-bg Jun 11, 2026
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
16 changes: 13 additions & 3 deletions .github/prompts/code-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ You are an expert code reviewer for the BitGoJS cryptocurrency wallet SDK. Pleas
- Proper validation of transaction parameters
- Safe handling of private keys and sensitive data

## Internal Information Leakage (Public Repository)
Comments and strings should describe what the code does, not the dev process. Flag in comments, JSDoc, test names, and error/log strings:
- Verification/testing metadata (dates, "dry-run confirmed", "verified/tested on", investigation notes)
- Internal team/system names or codenames (e.g. "by WP"), infra, or tooling
- Internal ticket IDs or links to internal-only docs
- Rationale on how/why a change was made rather than code behavior

For each, suggest a behavior-only rewrite.

## Code Quality & Architecture
- Adherence to BitGoJS coding standards and patterns
- TypeScript type safety and interface compliance
Expand Down Expand Up @@ -35,8 +44,9 @@ You are an expert code reviewer for the BitGoJS cryptocurrency wallet SDK. Pleas

Please provide constructive feedback focusing on:
1. Critical issues that must be addressed
2. Suggestions for improvement
3. Questions about design decisions
4. Acknowledgment of good practices
2. Internal-information leaks in comments or strings (must be removed before merge)
3. Suggestions for improvement
4. Questions about design decisions
5. Acknowledgment of good practices

Be thorough but concise, and explain the reasoning behind your suggestions.
8 changes: 6 additions & 2 deletions .github/workflows/npmjs-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,13 @@ jobs:
run: |
yarn install --frozen-lockfile

- name: Install retry
uses: BitGo/install-github-release-binary@v2
with:
targets: EricCrosson/retry@v1.4.8:sha256-d207746ff0eda67c706df25e88c02520f0cf3172279eb8eec8224fb0d3558911

- name: Run yarn audit
run: |
yarn run audit-high
run: retry --up-to 2x --every 3s -- yarn run audit-high --retry-on-network-failure

- name: Run dependency check
run: |
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ jobs:
- name: Install BitGoJS
run: sfw yarn install --with-frozen-lockfile

- name: Install retry
uses: BitGo/install-github-release-binary@v2
with:
targets: EricCrosson/retry@v1.4.8:sha256-d207746ff0eda67c706df25e88c02520f0cf3172279eb8eec8224fb0d3558911

- name: Audit Dependencies
run: yarn run improved-yarn-audit --min-severity high
run: retry --up-to 2x --every 3s -- yarn run improved-yarn-audit --min-severity high --retry-on-network-failure

- name: Set Environment Variable for Alpha
if: github.ref != 'refs/heads/master' # only publish changes if on feature branches
Expand Down
1 change: 1 addition & 0 deletions modules/abstract-utxo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
},
"devDependencies": {
"@bitgo/sdk-test": "^9.1.50",
"@bitgo/utxo-lib": "^11.24.0",
"mocha": "^10.2.0"
},
"gitHead": "18e460ddf02de2dbf13c2aa243478188fb539f0c"
Expand Down
116 changes: 34 additions & 82 deletions modules/abstract-utxo/src/abstractUtxoCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import assert from 'assert';
import { randomBytes } from 'crypto';

import _ from 'lodash';
import * as utxolib from '@bitgo/utxo-lib';
import { BIP32, fixedScriptWallet, hasPsbtMagic } from '@bitgo/wasm-utxo';
import { bitgo, getMainnet } from '@bitgo/utxo-lib';
import { address as wasmAddress, BIP32, fixedScriptWallet, hasPsbtMagic } from '@bitgo/wasm-utxo';
import {
AddressCoinSpecific,
BaseCoin,
Expand Down Expand Up @@ -62,7 +60,6 @@ import { getReplayProtectionPubkeys, isReplayProtectionUnspent } from './transac
import { supportedCrossChainRecoveries } from './config';
import {
assertValidTransactionRecipient,
DecodedTransaction,
explainTx,
fromExtendedAddressFormat,
isScriptRecipient,
Expand All @@ -77,14 +74,7 @@ import {
ErrorImplicitExternalOutputs,
} from './transaction/descriptor/verifyTransaction';
import { assertDescriptorWalletAddress, getDescriptorMapFromWallet, isDescriptorWallet } from './descriptor';
import {
getFullNameFromCoinName,
getMainnetCoinName,
getNetworkFromCoinName,
isMainnetCoin,
UtxoCoinName,
UtxoCoinNameMainnet,
} from './names';
import { getFullNameFromCoinName, getMainnetCoinName, isMainnetCoin, UtxoCoinName, UtxoCoinNameMainnet } from './names';
import { assertFixedScriptWalletAddress } from './address/fixedScript';
import { ParsedTransaction } from './transaction/types';
import { decodeDescriptorPsbt, decodePsbt, encodeTransaction, stringToBufferTryFormats } from './transaction/decode';
Expand All @@ -96,7 +86,7 @@ import { isUtxoWalletData, UtxoWallet } from './wallet';
import { isDescriptorWalletData } from './descriptor/descriptorWallet';
import type { Unspent } from './unspent';

import ScriptType2Of3 = utxolib.bitgo.outputScripts.ScriptType2Of3;
type ScriptType2Of3 = 'p2sh' | 'p2shP2wsh' | 'p2wsh' | 'p2tr' | 'p2trMusig2';

export type TxFormat =
// This is a legacy transaction format based around the bitcoinjs-lib serialization of unsigned transactions
Expand Down Expand Up @@ -142,28 +132,19 @@ type UtxoCustomSigningFunction<TNumber extends number | bigint> = {
}): Promise<SignedTransaction>;
};

const { isChainCode, scriptTypeForChain, outputScripts } = bitgo;

/**
* Check if a decoded transaction has at least one taproot key path spend (MuSig2) input.
* Works for both utxolib UtxoPsbt and wasm-utxo BitGoPsbt.
*/
function hasKeyPathSpendInput<TNumber extends number | bigint>(
tx: DecodedTransaction<TNumber>,
function hasKeyPathSpendInput(
tx: fixedScriptWallet.BitGoPsbt,
pubs: string[] | undefined,
coinName: UtxoCoinName
): boolean {
if (tx instanceof bitgo.UtxoPsbt) {
return bitgo.isTransactionWithKeyPathSpendInput(tx);
}
if (tx instanceof fixedScriptWallet.BitGoPsbt) {
assert(pubs && isTriple(pubs), 'pub triple is required to check for key path spend inputs in wasm-utxo PSBT');
const rootWalletKeys = fixedScriptWallet.RootWalletKeys.fromXpubs(pubs);
const replayProtection = { publicKeys: getReplayProtectionPubkeys(coinName) };
const parsed = tx.parseTransactionWithWalletKeys(rootWalletKeys, { replayProtection });
return parsed.inputs.some((input) => input.scriptType === 'p2trMusig2KeyPath');
}
return false;
assert(pubs && isTriple(pubs), 'pub triple is required to check for key path spend inputs in wasm-utxo PSBT');
const rootWalletKeys = fixedScriptWallet.RootWalletKeys.fromXpubs(pubs);
const replayProtection = { publicKeys: getReplayProtectionPubkeys(coinName) };
const parsed = tx.parseTransactionWithWalletKeys(rootWalletKeys, { replayProtection });
return parsed.inputs.some((input) => input.scriptType === 'p2trMusig2KeyPath');
}

/**
Expand Down Expand Up @@ -216,8 +197,6 @@ function convertValidationErrorToTxIntentMismatch(

export type { DecodedTransaction } from './transaction/types';

export type RootWalletKeys = bitgo.RootWalletKeys;

export type UtxoCoinSpecific = AddressCoinSpecific | DescriptorAddressCoinSpecific;

export interface VerifyAddressOptions<TCoinSpecific extends UtxoCoinSpecific> extends BaseVerifyAddressOptions {
Expand Down Expand Up @@ -252,8 +231,6 @@ export interface DecoratedExplainTransactionOptions<TNumber extends number | big
changeInfo?: { address: string; chain: number; index: number }[];
}

export type UtxoNetwork = utxolib.Network;

export interface TransactionPrebuild<TNumber extends number | bigint = number> extends BaseTransactionPrebuild {
txInfo?: TransactionInfo<TNumber>;
blockHeight?: number;
Expand Down Expand Up @@ -335,11 +312,6 @@ type UtxoBaseSignTransactionOptions<TNumber extends number | bigint = number> =
* When false, creates half-signed transaction with placeholder signatures.
*/
isLastSignature?: boolean;
/**
* If true, allows signing a non-segwit input with a witnessUtxo instead requiring a previous
* transaction (nonWitnessUtxo)
*/
allowNonSegwitSigningWithoutPrevTx?: boolean;
/**
* When true, the signed transaction will be converted from PSBT to legacy format before returning.
* Set automatically by presignTransaction() when the caller explicitly requested txFormat: 'legacy'.
Expand Down Expand Up @@ -432,14 +404,6 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
this.amountType = amountType;
}

/**
* @deprecated - will be removed when we drop support for utxolib
* Use `name` property instead.
*/
get network(): utxolib.Network {
return getNetworkFromCoinName(this.name);
}

getChain(): UtxoCoinName {
return this.name;
}
Expand All @@ -455,13 +419,8 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
/** Indicates whether the coin supports a block target */
supportsBlockTarget(): boolean {
// FIXME: the SDK does not seem to use this anywhere so it is unclear what the purpose of this method is
switch (getMainnet(this.network)) {
case utxolib.networks.bitcoin:
case utxolib.networks.dogecoin:
return true;
default:
return false;
}
const mainnet = getMainnetCoinName(this.name);
return mainnet === 'btc' || mainnet === 'doge';
}

sweepWithSendMany(): boolean {
Expand All @@ -470,7 +429,7 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici

/** @deprecated */
static get validAddressTypes(): ScriptType2Of3[] {
return [...outputScripts.scriptTypes2Of3];
return ['p2sh', 'p2shP2wsh', 'p2wsh', 'p2tr', 'p2trMusig2'];
}

/**
Expand Down Expand Up @@ -508,15 +467,20 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
// At the time of writing, the only additional address format is bch cashaddr.
const anyFormat = (param as { anyFormat: boolean } | undefined)?.anyFormat ?? true;
try {
// Find out if the address is valid for any format. Tries all supported formats by default.
// Throws if address cannot be decoded with any format.
const [format, script] = utxolib.addressFormat.toOutputScriptAndFormat(address, this.network);
// unless anyFormat is set, only 'default' is allowed.
if (!anyFormat && format !== 'default') {
return false;
const script = wasmAddress.toOutputScriptWithCoin(address, this.name);
// Determine which format the input address was in by round-tripping
// through each candidate and checking byte-equality. 'default' is tried
// first so canonical default-format addresses early-exit.
for (const format of ['default', 'cashaddr'] as const) {
try {
if (wasmAddress.fromOutputScriptWithCoin(script, this.name, format) === address) {
return anyFormat || format === 'default';
}
} catch {
// coin doesn't support this format; try the next one
}
}
// make sure that address is in normal representation for given format.
return address === utxolib.addressFormat.fromOutputScriptWithFormat(script, format, this.network);
return false;
} catch (e) {
return false;
}
Expand Down Expand Up @@ -596,13 +560,9 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
* @param addressDetails
*/
static inferAddressType(addressDetails: { chain: number }): ScriptType2Of3 | null {
return isChainCode(addressDetails.chain) ? scriptTypeForChain(addressDetails.chain) : null;
}

createTransactionFromHex<TNumber extends number | bigint = number>(
hex: string
): utxolib.bitgo.UtxoTransaction<TNumber> {
return utxolib.bitgo.createTransactionFromHex<TNumber>(hex, this.network, this.amountType);
return fixedScriptWallet.ChainCode.is(addressDetails.chain)
? (fixedScriptWallet.ChainCode.scriptType(addressDetails.chain) as ScriptType2Of3)
: null;
}

decodeTransaction(input: Buffer | string): fixedScriptWallet.BitGoPsbt {
Expand Down Expand Up @@ -761,7 +721,7 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
* @returns true iff coin supports spending from unspentType
*/
supportsAddressType(addressType: ScriptType2Of3): boolean {
return utxolib.bitgo.outputScripts.isSupportedScriptType(this.network, addressType);
return fixedScriptWallet.supportsScriptType(this.name, addressType);
}

/** inherited doc */
Expand All @@ -774,7 +734,10 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
* @return true iff coin supports spending from chain
*/
supportsAddressChain(chain: number): boolean {
return isChainCode(chain) && this.supportsAddressType(utxolib.bitgo.scriptTypeForChain(chain));
return (
fixedScriptWallet.ChainCode.is(chain) &&
this.supportsAddressType(fixedScriptWallet.ChainCode.scriptType(chain) as ScriptType2Of3)
);
}

keyIdsForSigning(): number[] {
Expand Down Expand Up @@ -1063,17 +1026,6 @@ export abstract class AbstractUtxoCoin extends BaseCoin implements Musig2Partici
}

const returnLegacyFormat = (params as Record<string, unknown>).txFormat === 'legacy';

// In the case that we have a 'psbt-lite' transaction format, we want to indicate in signing to not fail
const txHex = (params.txHex ?? params.txPrebuild?.txHex) as string;
if (
txHex &&
utxolib.bitgo.isPsbt(txHex as string) &&
utxolib.bitgo.isPsbtLite(utxolib.bitgo.createPsbtFromHex(txHex, this.network)) &&
params.allowNonSegwitSigningWithoutPrevTx === undefined
) {
return { ...params, allowNonSegwitSigningWithoutPrevTx: true, returnLegacyFormat };
}
return { ...params, returnLegacyFormat };
}

Expand Down
5 changes: 0 additions & 5 deletions modules/abstract-utxo/src/impl/doge/doge.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BitGoBase, HalfSignedUtxoTransaction, SignedTransaction } from '@bitgo/sdk-core';
import { bitgo } from '@bitgo/utxo-lib';

import {
AbstractUtxoCoin,
Expand Down Expand Up @@ -75,10 +74,6 @@ export class Doge extends AbstractUtxoCoin {

/* postProcessPrebuild, isBitGoTaintedUnspent, verifyCustomChangeKeySignatures do not care whether they receive number or bigint */

createTransactionFromHex<TNumber extends number | bigint = bigint>(hex: string): bitgo.UtxoTransaction<TNumber> {
return super.createTransactionFromHex<TNumber>(hex);
}

async parseTransaction<TNumber extends number | bigint = bigint>(
params: ParseTransactionOptions<TNumber>
): /*
Expand Down
7 changes: 3 additions & 4 deletions modules/abstract-utxo/src/keychains.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import assert from 'assert';

import * as t from 'io-ts';
import { bitgo } from '@bitgo/utxo-lib';
import { IRequestTracer, IWallet, KeyIndices, promiseProps, Triple } from '@bitgo/sdk-core';
import { BIP32, bip32, fixedScriptWallet } from '@bitgo/wasm-utxo';

Expand Down Expand Up @@ -48,10 +47,10 @@ export function toKeychainTriple(keychains: UtxoNamedKeychains): Triple<UtxoKeyc
}

export function toBip32Triple(
keychains: bitgo.RootWalletKeys | UtxoNamedKeychains | Triple<{ pub: string }> | string[]
keychains: fixedScriptWallet.RootWalletKeys | UtxoNamedKeychains | Triple<{ pub: string }> | string[]
): Triple<BIP32> {
if (keychains instanceof bitgo.RootWalletKeys) {
return keychains.triple.map((k) => BIP32.fromBase58(k.toBase58())) as Triple<BIP32>;
if (keychains instanceof fixedScriptWallet.RootWalletKeys) {
return [keychains.userKey(), keychains.backupKey(), keychains.bitgoKey()];
}
if (Array.isArray(keychains)) {
if (keychains.length !== 3) {
Expand Down
Loading
Loading