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
3 changes: 1 addition & 2 deletions modules/abstract-utxo/src/abstractUtxoCoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import { getPolicyForEnv } from './descriptor/validatePolicy';
import { signTransaction } from './transaction/signTransaction';
import { isUtxoWalletData, UtxoWallet } from './wallet';
import { isDescriptorWalletData } from './descriptor/descriptorWallet';
import type { Unspent } from './unspent';

import ScriptType2Of3 = utxolib.bitgo.outputScripts.ScriptType2Of3;

Expand Down Expand Up @@ -142,8 +143,6 @@ type UtxoCustomSigningFunction<TNumber extends number | bigint> = {

const { isChainCode, scriptTypeForChain, outputScripts } = bitgo;

type Unspent<TNumber extends number | bigint = number> = bitgo.Unspent<TNumber>;

/**
* Convert ValidationError to TxIntentMismatchRecipientError with structured data
*
Expand Down
11 changes: 6 additions & 5 deletions modules/abstract-utxo/src/impl/doge/doge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@ import { UtxoCoinName } from '../../names';
import { ParsedTransaction } from '../../transaction/types';
import type { TransactionExplanation } from '../../transaction/fixedScript/explainTransaction';
import type { CrossChainRecoverySigned, CrossChainRecoveryUnsigned } from '../../recovery/crossChainRecovery';
import type { Unspent } from '../../unspent';

type UnspentJSON = bitgo.Unspent<number> & { valueString: string };
type UnspentJSON = Unspent<number> & { valueString: string };
type TransactionInfoJSON = TransactionInfo<number> & { unspents: UnspentJSON[] };
type TransactionPrebuildJSON = TransactionPrebuild<number> & { txInfo: TransactionInfoJSON };

function parseUnspents<TNumber extends number | bigint>(
unspents: UnspentJSON[] | bitgo.Unspent<TNumber>[]
): bitgo.Unspent<bigint>[] {
return unspents.map((unspent: bitgo.Unspent<TNumber> | UnspentJSON): bitgo.Unspent<bigint> => {
unspents: UnspentJSON[] | Unspent<TNumber>[]
): Unspent<bigint>[] {
return unspents.map((unspent: Unspent<TNumber> | UnspentJSON): Unspent<bigint> => {
if (typeof unspent.value === 'bigint') {
return unspent as bitgo.Unspent<bigint>;
return unspent as Unspent<bigint>;
}
if ('valueString' in unspent) {
return { ...unspent, value: BigInt(unspent.valueString) };
Expand Down
1 change: 1 addition & 0 deletions modules/abstract-utxo/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './config';
export * from './recovery';
export * from './transaction/fixedScript/replayProtection';
export * from './transaction/fixedScript/signLegacyTransaction';
export * from './unspent';

export { UtxoWallet } from './wallet';
export * as descriptor from './descriptor';
Expand Down
5 changes: 2 additions & 3 deletions modules/abstract-utxo/src/recovery/RecoveryProvider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { BlockchairApi, AddressInfo, TransactionIO } from '@bitgo/blockapis';
import { bitgo } from '@bitgo/utxo-lib';

import { ApiNotImplementedError } from './baseApi';
import type { Unspent } from '../unspent';

type Unspent<TNumber extends number | bigint = number> = bitgo.Unspent<TNumber>;
import { ApiNotImplementedError } from './baseApi';

/**
* An account with bear minimum information required for recoveries.
Expand Down
4 changes: 2 additions & 2 deletions modules/abstract-utxo/src/recovery/backupKeyRecovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { generateAddressWithChainAndIndex } from '../address';
import { encodeTransaction } from '../transaction/decode';
import { getReplayProtectionPubkeys } from '../transaction/fixedScript/replayProtection';
import { isTestnetCoin, UtxoCoinName } from '../names';
import type { WalletUnspent } from '../unspent';

import { forCoin, RecoveryProvider } from './RecoveryProvider';
import { MempoolApi } from './mempoolApi';
Expand All @@ -28,8 +29,7 @@ import { createBackupKeyRecoveryPsbt, getRecoveryAmount, PsbtBackend, toPsbtToUt
type ScriptType2Of3 = utxolib.bitgo.outputScripts.ScriptType2Of3;
type ChainCode = utxolib.bitgo.ChainCode;
type RootWalletKeys = utxolib.bitgo.RootWalletKeys;
type WalletUnspent<TNumber extends number | bigint> = utxolib.bitgo.WalletUnspent<TNumber>;
type WalletUnspentJSON = utxolib.bitgo.WalletUnspent & {
type WalletUnspentJSON = WalletUnspent & {
valueString: string;
};

Expand Down
3 changes: 1 addition & 2 deletions modules/abstract-utxo/src/recovery/crossChainRecovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getNetworkFromCoinName, isTestnetCoin, UtxoCoinName } from '../names';
import { encodeTransaction } from '../transaction/decode';
import { getReplayProtectionPubkeys } from '../transaction/fixedScript/replayProtection';
import { toTNumber } from '../tnumber';
import type { Unspent, WalletUnspent } from '../unspent';

import {
PsbtBackend,
Expand All @@ -22,8 +23,6 @@ import {

const { unspentSum } = utxolib.bitgo;
type RootWalletKeys = utxolib.bitgo.RootWalletKeys;
type Unspent<TNumber extends number | bigint = number> = utxolib.bitgo.Unspent<TNumber>;
type WalletUnspent<TNumber extends number | bigint = number> = utxolib.bitgo.WalletUnspent<TNumber>;

export interface BuildRecoveryTransactionOptions {
wallet: string;
Expand Down
2 changes: 1 addition & 1 deletion modules/abstract-utxo/src/recovery/psbt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Dimensions } from '@bitgo/unspents';
import { CoinName, fixedScriptWallet, utxolibCompat, address as wasmAddress } from '@bitgo/wasm-utxo';

import { getNetworkFromCoinName, UtxoCoinName } from '../names';
import type { WalletUnspent } from '../unspent';

type RootWalletKeys = utxolib.bitgo.RootWalletKeys;
type WalletUnspent<TNumber extends number | bigint> = utxolib.bitgo.WalletUnspent<TNumber>;

const { chainCodesP2tr, chainCodesP2trMusig2 } = utxolib.bitgo;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getDescriptorMapFromWallet, isDescriptorWallet } from '../descriptor';
import { toBip32Triple } from '../keychains';
import { getPolicyForEnv } from '../descriptor/validatePolicy';
import { UtxoCoinName } from '../names';
import type { Unspent } from '../unspent';

import { getReplayProtectionPubkeys } from './fixedScript/replayProtection';
import type {
Expand All @@ -25,7 +26,7 @@ export function explainTx<TNumber extends number | bigint>(
params: {
wallet?: IWallet;
pubs?: string[];
txInfo?: { unspents?: utxolib.bitgo.Unspent<TNumber>[] };
txInfo?: { unspents?: Unspent<TNumber>[] };
changeInfo?: fixedScript.ChangeAddressInfo[];
},
coinName: UtxoCoinName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import * as utxolib from '@bitgo/utxo-lib';
import type { Unspent } from '../../unspent';

import type { PsbtParsedScriptType } from './signPsbtUtxolib';

type Unspent<TNumber extends number | bigint = number> = utxolib.bitgo.Unspent<TNumber>;

export class InputSigningError<TNumber extends number | bigint = number> extends Error {
static expectedWalletUnspent<TNumber extends number | bigint>(
inputIndex: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as utxocore from '@bitgo/utxo-core';

import type { Bip322Message } from '../../abstractUtxoCoin';
import type { Output, FixedScriptWalletOutput } from '../types';
import type { Unspent } from '../../unspent';
import { toExtendedAddressFormat } from '../recipient';
import { getPayGoVerificationPubkey } from '../getPayGoVerificationPubkey';
import { toBip32Triple } from '../../keychains';
Expand Down Expand Up @@ -192,7 +193,7 @@ function getPsbtInputSignaturesCount(
function getTxInputSignaturesCount<TNumber extends number | bigint>(
tx: bitgo.UtxoTransaction<TNumber>,
params: {
txInfo?: { unspents?: bitgo.Unspent<TNumber>[] };
txInfo?: { unspents?: Unspent<TNumber>[] };
pubs?: bitgo.RootWalletKeys | string[];
},
coinName: UtxoCoinName
Expand Down Expand Up @@ -444,7 +445,7 @@ export function explainLegacyTx<TNumber extends number | bigint>(
tx: bitgo.UtxoTransaction<TNumber>,
params: {
pubs?: string[];
txInfo?: { unspents?: bitgo.Unspent<TNumber>[] };
txInfo?: { unspents?: Unspent<TNumber>[] };
changeInfo?: { address: string; chain: number; index: number }[];
},
coinName: UtxoCoinName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { isTriple, Triple } from '@bitgo/sdk-core';
import debugLib from 'debug';

import { UtxoCoinName } from '../../names';
import type { Unspent, WalletUnspent } from '../../unspent';

import { getReplayProtectionAddresses } from './replayProtection';
import { InputSigningError, TransactionSigningError } from './SigningError';
Expand All @@ -15,8 +16,6 @@ const debug = debugLib('bitgo:v2:utxo');

const { isWalletUnspent, signInputWithUnspent, toOutput } = utxolib.bitgo;

type Unspent<TNumber extends number | bigint = number> = utxolib.bitgo.Unspent<TNumber>;

type RootWalletKeys = utxolib.bitgo.RootWalletKeys;

/**
Expand Down Expand Up @@ -72,7 +71,7 @@ export function signAndVerifyWalletTransaction<TNumber extends number | bigint>(
return InputSigningError.expectedWalletUnspent<TNumber>(inputIndex, null, unspent);
}
try {
signInputWithUnspent<TNumber>(txBuilder, inputIndex, unspent, walletSigner);
signInputWithUnspent<TNumber>(txBuilder, inputIndex, unspent as WalletUnspent<TNumber>, walletSigner);
debug('Successfully signed input %d of %d', inputIndex + 1, unspents.length);
} catch (e) {
return new InputSigningError<TNumber>(inputIndex, null, unspent, e);
Expand All @@ -96,8 +95,10 @@ export function signAndVerifyWalletTransaction<TNumber extends number | bigint>(
if (!isWalletUnspent<TNumber>(unspent)) {
return InputSigningError.expectedWalletUnspent<TNumber>(inputIndex, null, unspent);
}
const walletUnspent = unspent as WalletUnspent<TNumber>;
try {
const publicKey = walletSigner.deriveForChainAndIndex(unspent.chain, unspent.index).signer.publicKey;
const publicKey = walletSigner.deriveForChainAndIndex(walletUnspent.chain, walletUnspent.index).signer
.publicKey;
if (
!utxolib.bitgo.verifySignatureWithPublicKey<TNumber>(signedTransaction, inputIndex, prevOutputs, publicKey)
) {
Expand All @@ -124,7 +125,7 @@ export function signLegacyTransaction<TNumber extends number | bigint>(
params: {
isLastSignature: boolean;
signingStep: 'signerNonce' | 'cosignerNonce' | 'signerSignature' | undefined;
txInfo: { unspents?: utxolib.bitgo.Unspent<TNumber>[] } | undefined;
txInfo: { unspents?: Unspent<TNumber>[] } | undefined;
pubs: string[] | undefined;
cosignerPub: string | undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as utxolib from '@bitgo/utxo-lib';
import { fixedScriptWallet } from '@bitgo/wasm-utxo';

import { UtxoCoinName } from '../../names';
import type { Unspent } from '../../unspent';

import { Musig2Participant } from './musig2';
import { signLegacyTransaction } from './signLegacyTransaction';
Expand Down Expand Up @@ -60,7 +61,7 @@ export async function signTransaction<
coinName: UtxoCoinName,
params: {
walletId: string | undefined;
txInfo: { unspents?: utxolib.bitgo.Unspent<bigint | number>[] } | undefined;
txInfo: { unspents?: Unspent<bigint | number>[] } | undefined;
isLastSignature: boolean;
signingStep: 'signerNonce' | 'cosignerNonce' | 'signerSignature' | undefined;
/** deprecated */
Expand Down
50 changes: 50 additions & 0 deletions modules/abstract-utxo/src/unspent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as utxolib from '@bitgo/utxo-lib';

/**
* Unspent transaction output (UTXO) type definition
*
* This type represents an unspent transaction output, independent from utxo-lib.
* The structure matches utxolib.bitgo.Unspent but is defined locally.
*
* @property id - Format: ${txid}:${vout}. Use `parseOutputId(id)` to parse.
* @property address - The network-specific encoded address. Use `toOutputScript(address, network)` to obtain scriptPubKey.
* @property value - The amount in satoshi.
*/
export interface Unspent<TNumber extends number | bigint = number> {
/**
* Format: ${txid}:${vout}.
* Use `parseOutputId(id)` to parse.
*/
id: string;
/**
* The network-specific encoded address.
* Use `toOutputScript(address, network)` to obtain scriptPubKey.
*/
address: string;
/**
* The amount in satoshi.
*/
value: TNumber;
}

/**
* Wallet unspent type - extends Unspent with wallet-specific fields
*
* This type includes all fields from Unspent plus:
* - chain: ChainCode (chain code for wallet derivation)
* - index: number (index for wallet derivation)
*/
export interface WalletUnspent<TNumber extends number | bigint = number> extends Unspent<TNumber> {
chain: utxolib.bitgo.ChainCode;
index: number;
}

/**
* Unspent with previous transaction data
*
* Extends Unspent with:
* - prevTx: Buffer (previous transaction data for legacy transactions)
*/
export interface UnspentWithPrevTx<TNumber extends number | bigint = number> extends Unspent<TNumber> {
prevTx: Buffer;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
FormattedOfflineVaultTxInfo,
} from '../../../src';
import { getCoinName } from '../../../src/names';
import type { Unspent, WalletUnspent } from '../../../src/unspent';
import {
defaultBitGo,
encryptKeychain,
Expand All @@ -35,7 +36,6 @@ import {
import { MockRecoveryProvider } from './mock';

const { toOutput } = utxolib.bitgo;
type WalletUnspent = utxolib.bitgo.WalletUnspent<bigint>;
type RootWalletKeys = utxolib.bitgo.RootWalletKeys;
type ScriptType2Of3 = utxolib.bitgo.outputScripts.ScriptType2Of3;

Expand Down Expand Up @@ -148,8 +148,8 @@ function run(
sinon.restore();
});

let recoverUnspents: utxolib.bitgo.Unspent<bigint>[];
let mockedApiUnspents: utxolib.bitgo.Unspent<bigint>[];
let recoverUnspents: Unspent<bigint>[];
let mockedApiUnspents: Unspent<bigint>[];

before('create recovery data', async function () {
this.timeout(10_000);
Expand Down Expand Up @@ -267,7 +267,7 @@ function run(
.map((u) => toOutput(u, coin.network))
.map((v) => ({ ...v, value: utxolib.bitgo.toTNumber(v.value, coin.amountType) }));
tx.ins.forEach((input, inputIndex) => {
const unspent = recoverUnspents[inputIndex] as WalletUnspent;
const unspent = recoverUnspents[inputIndex] as WalletUnspent<bigint>;
const { publicKey } = rootKey.derivePath(walletKeys.getDerivationPath(rootKey, unspent.chain, unspent.index));
const signatures = utxolib.bitgo
.getSignatureVerifications(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
convertLtcAddressToLegacyFormat,
} from '../../../src';
import { isMainnetCoin, isTestnetCoin } from '../../../src/names';
import type { Unspent, WalletUnspent } from '../../../src/unspent';
import {
getFixture,
keychainsBase58,
Expand All @@ -34,8 +35,6 @@ import { getDefaultWalletUnspentSigner } from '../util/keychains';

import { MockCrossChainRecoveryProvider } from './mock';

type WalletUnspent<TNumber extends number | bigint = number> = utxolib.bitgo.WalletUnspent<TNumber>;

function getKeyId(k: KeychainBase58): string {
return getSeed(k.pub).toString('hex');
}
Expand Down Expand Up @@ -116,7 +115,7 @@ function run<TNumber extends number | bigint = number>(sourceCoin: AbstractUtxoC

let depositTx: utxolib.bitgo.UtxoTransaction<TNumber>;

function getDepositUnspents(): utxolib.bitgo.Unspent<TNumber>[] {
function getDepositUnspents(): Unspent<TNumber>[] {
return [
mockUnspent<TNumber>(
sourceCoin.network,
Expand Down
5 changes: 2 additions & 3 deletions modules/abstract-utxo/test/unit/recovery/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { address as wasmAddress, AddressFormat } from '@bitgo/wasm-utxo';
import { AbstractUtxoCoin, RecoveryProvider } from '../../../src';
import { Bch } from '../../../src/impl/bch';
import { Bsv } from '../../../src/impl/bsv';

type Unspent<TNumber extends number | bigint = number> = bitgo.Unspent<TNumber>;
import type { Unspent, UnspentWithPrevTx } from '../../../src/unspent';
export class MockRecoveryProvider implements RecoveryProvider {
public unspents: Unspent<bigint>[];
private prevTxCache: Record<string, string> = {};
Expand All @@ -16,7 +15,7 @@ export class MockRecoveryProvider implements RecoveryProvider {
this.unspents.forEach((u) => {
if (utxolib.bitgo.isUnspentWithPrevTx(u)) {
const { txid } = bitgo.parseOutputId(u.id);
this.prevTxCache[txid] = u.prevTx.toString('hex');
this.prevTxCache[txid] = (u as UnspentWithPrevTx<bigint>).prevTx.toString('hex');
}
});
}
Expand Down
9 changes: 4 additions & 5 deletions modules/abstract-utxo/test/unit/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {

import { AbstractUtxoCoin, getReplayProtectionAddresses, generateAddress, getReplayProtectionPubkeys } from '../../src';
import { SdkBackend } from '../../src/transaction/types';
import type { Unspent, WalletUnspent } from '../../src/unspent';

import {
utxoCoins,
Expand All @@ -35,9 +36,6 @@ import {
defaultBitGo,
} from './util';

type Unspent<TNumber extends number | bigint = number> = bitgo.Unspent<TNumber>;
type WalletUnspent<TNumber extends number | bigint = number> = bitgo.WalletUnspent<TNumber>;

function getScriptTypes2Of3() {
return [...bitgo.outputScripts.scriptTypes2Of3, 'taprootKeyPathSpend'] as const;
}
Expand Down Expand Up @@ -486,7 +484,8 @@ function run<TNumber extends number | bigint = number>(
assert.ok(utxolib.bitgo.getPsbtInputScriptType(input), 'p2shP2pk');
return;
}
const pubkeys = walletKeys.deriveForChainAndIndex(unspent.chain, unspent.index).publicKeys;
const walletUnspent = unspent as WalletUnspent<bigint>;
const pubkeys = walletKeys.deriveForChainAndIndex(walletUnspent.chain, walletUnspent.index).publicKeys;
pubkeys.forEach((pk, pkIndex) => {
psbt.validateSignaturesOfInputCommon(index, pk).should.eql(signedBy.includes(walletKeys.triple[pkIndex]));
});
Expand Down Expand Up @@ -546,7 +545,7 @@ function run<TNumber extends number | bigint = number>(
async function testExplainTx(
stageName: string,
txHex: string,
unspents: utxolib.bitgo.Unspent<TNumber>[],
unspents: Unspent<TNumber>[],
pubs: Triple<string> | undefined
): Promise<void> {
const explanation = await coin.explainTransaction<TNumber>({
Expand Down
Loading
Loading