diff --git a/modules/abstract-utxo/package.json b/modules/abstract-utxo/package.json index 800aa800f5..4207799a65 100644 --- a/modules/abstract-utxo/package.json +++ b/modules/abstract-utxo/package.json @@ -67,7 +67,7 @@ "@bitgo/utxo-descriptors": "^1.3.4", "@bitgo/utxo-lib": "^11.24.1", "@bitgo/utxo-ord": "^1.32.4", - "@bitgo/wasm-utxo": "^4.21.1", + "@bitgo/wasm-utxo": "^4.27.0", "@types/lodash": "^4.14.121", "@types/superagent": "4.1.15", "bignumber.js": "^9.0.2", diff --git a/modules/abstract-utxo/src/impl/index.ts b/modules/abstract-utxo/src/impl/index.ts index 37d2099f35..c0dd274673 100644 --- a/modules/abstract-utxo/src/impl/index.ts +++ b/modules/abstract-utxo/src/impl/index.ts @@ -6,4 +6,5 @@ export * as btg from './btg'; export * as ltc from './ltc'; export * as dash from './dash'; export * as doge from './doge'; +export * as pearl from './pearl'; export * as zec from './zec'; diff --git a/modules/abstract-utxo/src/impl/pearl/index.ts b/modules/abstract-utxo/src/impl/pearl/index.ts new file mode 100644 index 0000000000..53d3ecfca4 --- /dev/null +++ b/modules/abstract-utxo/src/impl/pearl/index.ts @@ -0,0 +1,2 @@ +export * from './pearl'; +export * from './tpearl'; diff --git a/modules/abstract-utxo/src/impl/pearl/pearl.ts b/modules/abstract-utxo/src/impl/pearl/pearl.ts new file mode 100644 index 0000000000..9695ed5f7d --- /dev/null +++ b/modules/abstract-utxo/src/impl/pearl/pearl.ts @@ -0,0 +1,21 @@ +import { BitGoBase } from '@bitgo/sdk-core'; + +import { AbstractUtxoCoin } from '../../abstractUtxoCoin'; +import { UtxoCoinName } from '../../names'; + +/** + * Pearl (Duplex) is a taproot-only UTXO chain, a btcd fork using BIP-340 Schnorr + * signatures and BIP-341 script-path spending with a NUMS internal key. + * + * Unlike the other utxo coins, Pearl has no `@bitgo/utxo-lib` network registration - + * it is served entirely through `@bitgo/wasm-utxo`. No script type override is needed + * here: `supportsAddressType` delegates to `fixedScriptWallet.supportsScriptType`, + * which already reports only p2tr and p2trMusig2 for this coin. + */ +export class Pearl extends AbstractUtxoCoin { + readonly name: UtxoCoinName = 'pearl'; + + static createInstance(bitgo: BitGoBase): Pearl { + return new Pearl(bitgo); + } +} diff --git a/modules/abstract-utxo/src/impl/pearl/tpearl.ts b/modules/abstract-utxo/src/impl/pearl/tpearl.ts new file mode 100644 index 0000000000..c569b40629 --- /dev/null +++ b/modules/abstract-utxo/src/impl/pearl/tpearl.ts @@ -0,0 +1,13 @@ +import { BitGoBase } from '@bitgo/sdk-core'; + +import { UtxoCoinName } from '../../names'; + +import { Pearl } from './pearl'; + +export class Tpearl extends Pearl { + readonly name: UtxoCoinName = 'tpearl'; + + static createInstance(bitgo: BitGoBase): Tpearl { + return new Tpearl(bitgo); + } +} diff --git a/modules/abstract-utxo/src/index.ts b/modules/abstract-utxo/src/index.ts index 1118441b2a..4fd1f3c206 100644 --- a/modules/abstract-utxo/src/index.ts +++ b/modules/abstract-utxo/src/index.ts @@ -21,4 +21,5 @@ export * from './impl/btg'; export * from './impl/ltc'; export * from './impl/dash'; export * from './impl/doge'; +export * from './impl/pearl'; export * from './impl/zec'; diff --git a/modules/abstract-utxo/src/names.ts b/modules/abstract-utxo/src/names.ts index 9e1a5c74c2..71f37f1318 100644 --- a/modules/abstract-utxo/src/names.ts +++ b/modules/abstract-utxo/src/names.ts @@ -1,4 +1,4 @@ -export const utxoCoinsMainnet = ['btc', 'bch', 'bcha', 'bsv', 'btg', 'dash', 'doge', 'ltc', 'zec'] as const; +export const utxoCoinsMainnet = ['btc', 'bch', 'bcha', 'bsv', 'btg', 'dash', 'doge', 'ltc', 'pearl', 'zec'] as const; export const utxoCoinsTestnet = [ 'tbtc', 'tbtc4', @@ -11,6 +11,7 @@ export const utxoCoinsTestnet = [ 'tdash', 'tdoge', 'tltc', + 'tpearl', 'tzec', ] as const; @@ -62,6 +63,8 @@ function getBaseNameFromMainnet(coinName: UtxoCoinNameMainnet): string { return 'Dogecoin'; case 'ltc': return 'Litecoin'; + case 'pearl': + return 'Pearl'; case 'zec': return 'ZCash'; } diff --git a/modules/abstract-utxo/test/unit/impl/pearl/unit/index.ts b/modules/abstract-utxo/test/unit/impl/pearl/unit/index.ts new file mode 100644 index 0000000000..63d38b0d13 --- /dev/null +++ b/modules/abstract-utxo/test/unit/impl/pearl/unit/index.ts @@ -0,0 +1,85 @@ +import assert from 'node:assert/strict'; + +import { BitGoAPI } from '@bitgo/sdk-api'; +import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test'; +import * as utxolib from '@bitgo/utxo-lib'; + +import { AbstractUtxoCoin } from '../../../../../src/abstractUtxoCoin'; +import { Pearl, Tpearl } from '../../../../../src/impl/pearl'; + +describe('Pearl', function () { + let bitgo: TestBitGoAPI; + + /** `bitgo.coin()` is typed as BaseCoin; these are registered as AbstractUtxoCoin */ + function getCoin(coinName: 'pearl' | 'tpearl'): AbstractUtxoCoin { + return bitgo.coin(coinName) as unknown as AbstractUtxoCoin; + } + + before(function () { + bitgo = TestBitGo.decorate(BitGoAPI, { + env: 'mock', + }); + bitgo.initializeTestVars(); + bitgo.safeRegister('pearl', Pearl.createInstance); + bitgo.safeRegister('tpearl', Tpearl.createInstance); + }); + + it('should instantiate the coin', function () { + assert.ok(bitgo.coin('pearl') instanceof Pearl); + assert.ok(bitgo.coin('tpearl') instanceof Tpearl); + }); + + it('should return the chain', function () { + assert.strictEqual(bitgo.coin('pearl').getChain(), 'pearl'); + assert.strictEqual(bitgo.coin('tpearl').getChain(), 'tpearl'); + }); + + it('should return full name', function () { + assert.strictEqual(bitgo.coin('pearl').getFullName(), 'Pearl'); + assert.strictEqual(bitgo.coin('tpearl').getFullName(), 'Testnet Pearl'); + }); + + it('should have tpearl as the testnet variant of pearl', function () { + assert.ok(bitgo.coin('tpearl') instanceof Pearl); + }); + + /** + * Pearl is taproot-only. This is not enforced by an override here - it comes from + * `supportsAddressType` delegating to wasm-utxo, which reports only the taproot + * script types for this coin. Pinned so a regression in either layer is caught. + */ + it('should support only the taproot script types', function () { + for (const coinName of ['pearl', 'tpearl'] as const) { + const coin = getCoin(coinName); + assert.strictEqual(coin.supportsAddressType('p2tr'), true); + assert.strictEqual(coin.supportsAddressType('p2trMusig2'), true); + assert.strictEqual(coin.supportsAddressType('p2sh'), false); + assert.strictEqual(coin.supportsAddressType('p2shP2wsh'), false); + assert.strictEqual(coin.supportsAddressType('p2wsh'), false); + } + }); + + it('should support only the taproot address chains', function () { + for (const coinName of ['pearl', 'tpearl'] as const) { + const coin = getCoin(coinName); + // 30/31 = p2tr, 40/41 = p2trMusig2 + for (const chain of [30, 31, 40, 41]) { + assert.strictEqual(coin.supportsAddressChain(chain), true, `chain ${chain} should be supported`); + } + // 0/1 = p2sh, 10/11 = p2shP2wsh, 20/21 = p2wsh + for (const chain of [0, 1, 10, 11, 20, 21]) { + assert.strictEqual(coin.supportsAddressChain(chain), false, `chain ${chain} should not be supported`); + } + } + }); + + /** + * Pearl is served through @bitgo/wasm-utxo and is deliberately absent from + * @bitgo/utxo-lib. No other checked-in coin has this profile, so it cannot be + * inferred from an existing coin - assert it explicitly. + */ + it('should have no utxo-lib network registration', function () { + assert.ok(!('pearl' in utxolib.networks)); + assert.ok(!('tpearl' in utxolib.networks)); + }); +}); diff --git a/modules/sdk-coin-pearl/.eslintignore b/modules/sdk-coin-pearl/.eslintignore new file mode 100644 index 0000000000..190f83e0df --- /dev/null +++ b/modules/sdk-coin-pearl/.eslintignore @@ -0,0 +1,5 @@ +node_modules +.idea +public +dist + diff --git a/modules/sdk-coin-pearl/.gitignore b/modules/sdk-coin-pearl/.gitignore new file mode 100644 index 0000000000..67ccce4c64 --- /dev/null +++ b/modules/sdk-coin-pearl/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.idea/ +dist/ diff --git a/modules/sdk-coin-pearl/.mocharc.yml b/modules/sdk-coin-pearl/.mocharc.yml new file mode 100644 index 0000000000..f499ec0a83 --- /dev/null +++ b/modules/sdk-coin-pearl/.mocharc.yml @@ -0,0 +1,8 @@ +require: 'tsx' +timeout: '60000' +reporter: 'min' +reporter-option: + - 'cdn=true' + - 'json=false' +exit: true +spec: ['test/unit/**/*.ts'] diff --git a/modules/sdk-coin-pearl/.npmignore b/modules/sdk-coin-pearl/.npmignore new file mode 100644 index 0000000000..d5fb3a098c --- /dev/null +++ b/modules/sdk-coin-pearl/.npmignore @@ -0,0 +1,14 @@ +!dist/ +dist/test/ +dist/tsconfig.tsbuildinfo +.idea/ +.prettierrc.yml +tsconfig.json +src/ +test/ +scripts/ +.nyc_output +CODEOWNERS +node_modules/ +.prettierignore +.mocharc.js diff --git a/modules/sdk-coin-pearl/.prettierignore b/modules/sdk-coin-pearl/.prettierignore new file mode 100644 index 0000000000..3a11d6af29 --- /dev/null +++ b/modules/sdk-coin-pearl/.prettierignore @@ -0,0 +1,2 @@ +.nyc_output/ +dist/ diff --git a/modules/sdk-coin-pearl/.prettierrc.yml b/modules/sdk-coin-pearl/.prettierrc.yml new file mode 100644 index 0000000000..7c3d8dd32a --- /dev/null +++ b/modules/sdk-coin-pearl/.prettierrc.yml @@ -0,0 +1,3 @@ +printWidth: 120 +singleQuote: true +trailingComma: 'es5' diff --git a/modules/sdk-coin-pearl/README.md b/modules/sdk-coin-pearl/README.md new file mode 100644 index 0000000000..8cf2024289 --- /dev/null +++ b/modules/sdk-coin-pearl/README.md @@ -0,0 +1,32 @@ +# BitGo sdk-coin-pearl + +SDK coins provide a modular approach to a monolithic architecture. This and all BitGoJS SDK coins allow developers to use only the coins needed for a given project. + +Pearl (Duplex) is a taproot-only UTXO chain — a btcd fork using BIP-340 Schnorr signatures and BIP-341 script-path spending. It is served through `@bitgo/wasm-utxo` and, unlike the other UTXO coins, has no `@bitgo/utxo-lib` network registration. + +## Installation + +All coins are loaded traditionally through the `bitgo` package. If you are using coins individually, you will be accessing the coin via the `@bitgo/sdk-api` package. + +In your project install both `@bitgo/sdk-api` and `@bitgo/sdk-coin-pearl`. + +```shell +npm i @bitgo/sdk-api @bitgo/sdk-coin-pearl +``` + +Next, you will be able to initialize an instance of "bitgo" through `@bitgo/sdk-api` instead of `bitgo`. + +```javascript +import { BitGoAPI } from '@bitgo/sdk-api'; +import { Pearl } from '@bitgo/sdk-coin-pearl'; + +const sdk = new BitGoAPI(); + +sdk.register('pearl', Pearl.createInstance); +``` + +## Development + +Most of the coin implementations are derived from `@bitgo/sdk-core`, `@bitgo/statics`, and coin specific packages. These implementations are used to interact with the BitGo API and BitGo platform services. + +The `Pearl` and `Tpearl` classes live in `@bitgo/abstract-utxo` and are re-exported here; this package is a registration shim only. diff --git a/modules/sdk-coin-pearl/package.json b/modules/sdk-coin-pearl/package.json new file mode 100644 index 0000000000..f5b23a5ed6 --- /dev/null +++ b/modules/sdk-coin-pearl/package.json @@ -0,0 +1,64 @@ +{ + "name": "@bitgo/sdk-coin-pearl", + "version": "1.0.0", + "description": "BitGo SDK coin library for Pearl", + "main": "./dist/cjs/src/index.js", + "module": "./dist/esm/index.js", + "browser": "./dist/esm/index.js", + "types": "./dist/cjs/src/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/cjs/src/index.d.ts", + "default": "./dist/cjs/src/index.js" + } + } + }, + "scripts": { + "build": "npm run build:cjs && npm run build:esm", + "build:cjs": "yarn tsc --build --incremental --verbose .", + "build:esm": "yarn tsc --project tsconfig.esm.json", + "fmt": "prettier --write .", + "check-fmt": "prettier --check '**/*.{ts,js,json}'", + "clean": "rm -rf ./dist", + "lint": "eslint --quiet .", + "prepare": "npm run build", + "unit-test": "echo 'test in abstract-utxo'" + }, + "author": "BitGo SDK Team ", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "repository": { + "type": "git", + "url": "https://github.com/BitGo/BitGoJS.git", + "directory": "modules/sdk-coin-pearl" + }, + "lint-staged": { + "*.{js,ts}": [ + "yarn prettier --write", + "yarn eslint --fix" + ] + }, + "publishConfig": { + "access": "public" + }, + "nyc": { + "extension": [ + ".ts" + ] + }, + "dependencies": { + "@bitgo/abstract-utxo": "^12.0.5", + "@bitgo/sdk-core": "^38.4.0" + }, + "files": [ + "dist/cjs", + "dist/esm" + ] +} diff --git a/modules/sdk-coin-pearl/src/index.ts b/modules/sdk-coin-pearl/src/index.ts new file mode 100644 index 0000000000..54a48d530f --- /dev/null +++ b/modules/sdk-coin-pearl/src/index.ts @@ -0,0 +1,10 @@ +import { BitGoBase } from '@bitgo/sdk-core'; +import { Pearl, Tpearl } from '@bitgo/abstract-utxo'; + +export { Pearl } from '@bitgo/abstract-utxo'; +export { Tpearl } from '@bitgo/abstract-utxo'; + +export const register = (sdk: BitGoBase): void => { + sdk.register('pearl', Pearl.createInstance); + sdk.register('tpearl', Tpearl.createInstance); +}; diff --git a/modules/sdk-coin-pearl/tsconfig.esm.json b/modules/sdk-coin-pearl/tsconfig.esm.json new file mode 100644 index 0000000000..17f39ab0f3 --- /dev/null +++ b/modules/sdk-coin-pearl/tsconfig.esm.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/esm", + "rootDir": "./src", + "module": "ES2020", + "target": "ES2020", + "moduleResolution": "bundler", + "lib": ["ES2020", "DOM"], + "declaration": true, + "declarationMap": true, + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "test", "dist"], + "references": [] +} diff --git a/modules/sdk-coin-pearl/tsconfig.json b/modules/sdk-coin-pearl/tsconfig.json new file mode 100644 index 0000000000..b9a213a387 --- /dev/null +++ b/modules/sdk-coin-pearl/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist/cjs", + "rootDir": "./", + "strictPropertyInitialization": false, + "esModuleInterop": true, + "typeRoots": ["../../types", "./node_modules/@types", "../../node_modules/@types"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules"], + "references": [ + { + "path": "../abstract-utxo" + }, + { + "path": "../sdk-api" + }, + { + "path": "../sdk-core" + } + ] +} diff --git a/modules/sdk-core/src/bitgo/utils/abstractUtxoCoinUtil.ts b/modules/sdk-core/src/bitgo/utils/abstractUtxoCoinUtil.ts index 1846a3a26a..060d830d71 100644 --- a/modules/sdk-core/src/bitgo/utils/abstractUtxoCoinUtil.ts +++ b/modules/sdk-core/src/bitgo/utils/abstractUtxoCoinUtil.ts @@ -11,13 +11,37 @@ export function inferAddressType(addressDetails: { chain: number }): ScriptType2 : null; } +/** + * Resolve the utxo-lib network for a statics utxo coin. + * + * Not every utxo coin has one: wasm-only coins (e.g. pearl) are served through + * `@bitgo/wasm-utxo` and are deliberately absent from the utxo-lib network registry, + * so `utxolibName` carries a wasm `CoinName` that does not resolve here. Those coins + * must have their script types resolved through wasm-utxo instead - see + * `AbstractUtxoCoin.supportsAddressType`, which delegates to + * `fixedScriptWallet.supportsScriptType`. + * + * @deprecated - will be removed when we drop support for utxolib + */ +function getUtxolibNetwork(coinName: string, coin: UtxoCoin): utxolib.Network { + const network = utxolib.networks[coin.network.utxolibName as utxolib.NetworkName]; + assert( + network, + `coin ${coinName} has no utxo-lib network (utxolibName=${coin.network.utxolibName}). ` + + `Script types for wasm-only coins must be resolved through @bitgo/wasm-utxo.` + ); + return network; +} + /** * Get the supported 2 of 3 script types for a given utxo coin + * + * @throws if the coin has no utxo-lib network - see `getUtxolibNetwork` */ export function getUtxoCoinScriptTypes2Of3(coinName: string): utxolib.bitgo.outputScripts.ScriptType2Of3[] { const coin = coins.get(coinName); assert(coin instanceof UtxoCoin, `coin ${coinName} is not a utxo coin`); - const network = utxolib.networks[coin.network.utxolibName as utxolib.NetworkName]; + const network = getUtxolibNetwork(coinName, coin); return utxolib.bitgo.outputScripts.scriptTypes2Of3.filter((v) => utxolib.bitgo.outputScripts.isSupportedScriptType(network, v) ); @@ -52,7 +76,7 @@ export function getUtxoCoinScriptTypesForWalletType( const coin = coins.get(coinName); assert(coin instanceof UtxoCoin, `coin ${coinName} is not a utxo coin`); - const network = utxolib.networks[coin.network.utxolibName as utxolib.NetworkName]; + const network = getUtxolibNetwork(coinName, coin); return scriptTypes.filter((scriptType) => isEnabledAddressType(network, walletType, scriptType as ScriptType2Of3)); } diff --git a/modules/sdk-core/test/unit/bitgo/utils/abstractUtxoCoinUtil.ts b/modules/sdk-core/test/unit/bitgo/utils/abstractUtxoCoinUtil.ts index 2a03cbddd2..f51790867a 100644 --- a/modules/sdk-core/test/unit/bitgo/utils/abstractUtxoCoinUtil.ts +++ b/modules/sdk-core/test/unit/bitgo/utils/abstractUtxoCoinUtil.ts @@ -14,6 +14,18 @@ describe('getUtxoCoinScriptTypes', function () { assert.ok(fn('doge', ['p2sh'])); }); + it('fail with an actionable message for wasm-only coins', function () { + // pearl is served through @bitgo/wasm-utxo and has no utxo-lib network, so its + // utxolibName does not resolve here. Assert the guidance rather than letting it + // fall through to a bare `TypeError: invalid network`. + for (const coinName of ['pearl', 'tpearl']) { + assert.throws( + () => getUtxoCoinScriptTypes2Of3(coinName), + (e: any) => /has no utxo-lib network/.test(e.message) && /@bitgo\/wasm-utxo/.test(e.message) + ); + } + }); + it('fail for invalid coin name', function () { assert.throws( () => getUtxoCoinScriptTypes2Of3('dummy'), diff --git a/modules/utxo-bin/package.json b/modules/utxo-bin/package.json index c922d9f377..4911d7f8d3 100644 --- a/modules/utxo-bin/package.json +++ b/modules/utxo-bin/package.json @@ -31,7 +31,7 @@ "@bitgo/unspents": "^0.51.7", "@bitgo/utxo-core": "^1.39.4", "@bitgo/utxo-lib": "^11.24.1", - "@bitgo/wasm-utxo": "^4.21.1", + "@bitgo/wasm-utxo": "^4.27.0", "@noble/curves": "1.8.1", "archy": "^1.0.0", "bech32": "^2.0.0", diff --git a/modules/utxo-core/package.json b/modules/utxo-core/package.json index 3e235baf71..fc1c1b39dc 100644 --- a/modules/utxo-core/package.json +++ b/modules/utxo-core/package.json @@ -81,7 +81,7 @@ "@bitgo/secp256k1": "^1.11.0", "@bitgo/unspents": "^0.51.7", "@bitgo/utxo-lib": "^11.24.1", - "@bitgo/wasm-utxo": "^4.21.1", + "@bitgo/wasm-utxo": "^4.27.0", "bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4", "fast-sha256": "^1.3.0" }, diff --git a/modules/utxo-descriptors/package.json b/modules/utxo-descriptors/package.json index 540674c7d5..61d96b220d 100644 --- a/modules/utxo-descriptors/package.json +++ b/modules/utxo-descriptors/package.json @@ -60,6 +60,6 @@ }, "dependencies": { "@bitgo/utxo-core": "^1.39.4", - "@bitgo/wasm-utxo": "^4.21.1" + "@bitgo/wasm-utxo": "^4.27.0" } } diff --git a/modules/utxo-ord/package.json b/modules/utxo-ord/package.json index 53a733a519..d3bca80b99 100644 --- a/modules/utxo-ord/package.json +++ b/modules/utxo-ord/package.json @@ -45,7 +45,7 @@ "directory": "modules/utxo-ord" }, "dependencies": { - "@bitgo/wasm-utxo": "^4.21.1" + "@bitgo/wasm-utxo": "^4.27.0" }, "devDependencies": { "@bitgo/utxo-lib": "^11.24.1" diff --git a/modules/utxo-staking/package.json b/modules/utxo-staking/package.json index 519ccd0fbb..d888f34c30 100644 --- a/modules/utxo-staking/package.json +++ b/modules/utxo-staking/package.json @@ -63,7 +63,7 @@ "@bitgo/babylonlabs-io-btc-staking-ts": "^3.5.1", "@bitgo/utxo-core": "^1.39.4", "@bitgo/utxo-lib": "^11.24.1", - "@bitgo/wasm-utxo": "^4.21.1", + "@bitgo/wasm-utxo": "^4.27.0", "bip174": "npm:@bitgo-forks/bip174@3.1.0-master.4", "bip322-js": "^2.0.0", "bitcoinjs-lib": "^6.1.7", diff --git a/tsconfig.packages.json b/tsconfig.packages.json index 8145df7655..96777c7767 100644 --- a/tsconfig.packages.json +++ b/tsconfig.packages.json @@ -196,6 +196,9 @@ { "path": "./modules/sdk-coin-osmo" }, + { + "path": "./modules/sdk-coin-pearl" + }, { "path": "./modules/sdk-coin-polygon" }, diff --git a/yarn.lock b/yarn.lock index 3008abfbcc..ab53ed1214 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1063,10 +1063,10 @@ resolved "https://registry.npmjs.org/@bitgo/wasm-ton/-/wasm-ton-1.1.1.tgz" integrity sha512-Y4x2V2ZcYWlmx42v7dlrKDtT2DuUt8smk8E98mh7RhpiifJhLk2v5RmXDwBl0A3v9TzUOU6qMOnSS/iZ8Pq52w== -"@bitgo/wasm-utxo@^4.21.1": - version "4.21.1" - resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-4.21.1.tgz#8763e2505cab0772af35565f355ad1f48552a916" - integrity sha512-GqBNp6FnzK4y6hPSRUn45LYg2tQIl80kNpJ5ivEdYBAg9BXtmvsNwSyr2GuDt3g3MGTZ9/4M1GlbB0OMMUKjAA== +"@bitgo/wasm-utxo@^4.27.0": + version "4.27.0" + resolved "https://registry.npmjs.org/@bitgo/wasm-utxo/-/wasm-utxo-4.27.0.tgz#35e613b7022787e357dab43b71a662d05155ae4e" + integrity sha512-If9zQ3bLO9Xn61h5zWgto3sR9CR+OGD7KoBYJQ8Vp9jBMNKeIe7ZYCc+6xJARwAx90woVl/ivkjPoaYJtmsiYw== "@brandonblack/musig@^0.0.1-alpha.0": version "0.0.1-alpha.1"