diff --git a/modules/abstract-utxo/src/transaction/fetchInputs.ts b/modules/abstract-utxo/src/transaction/fetchInputs.ts deleted file mode 100644 index 01459430a4..0000000000 --- a/modules/abstract-utxo/src/transaction/fetchInputs.ts +++ /dev/null @@ -1,86 +0,0 @@ -import * as utxolib from '@bitgo/utxo-lib'; -import { BitGoBase, IRequestTracer } from '@bitgo/sdk-core'; - -import { AbstractUtxoCoin, TransactionPrebuild } from '../abstractUtxoCoin'; -import { getNetworkFromCoinName, UtxoCoinName } from '../names'; - -/** - * Get the inputs for a psbt from a prebuild. - */ -export function getPsbtTxInputs( - psbtArg: string | utxolib.bitgo.UtxoPsbt, - coinName: UtxoCoinName -): { address: string; value: bigint; valueString: string }[] { - const network = getNetworkFromCoinName(coinName); - const psbt = psbtArg instanceof utxolib.bitgo.UtxoPsbt ? psbtArg : utxolib.bitgo.createPsbtFromHex(psbtArg, network); - const txInputs = psbt.txInputs; - return psbt.data.inputs.map((input, index) => { - let address: string; - let value: bigint; - if (input.witnessUtxo) { - address = utxolib.address.fromOutputScript(input.witnessUtxo.script, network); - value = input.witnessUtxo.value; - } else if (input.nonWitnessUtxo) { - const tx = utxolib.bitgo.createTransactionFromBuffer(input.nonWitnessUtxo, network, { - amountType: 'bigint', - }); - const txId = (Buffer.from(txInputs[index].hash).reverse() as Buffer).toString('hex'); - if (tx.getId() !== txId) { - throw new Error('input transaction hex does not match id'); - } - const prevTxOutputIndex = txInputs[index].index; - address = utxolib.address.fromOutputScript(tx.outs[prevTxOutputIndex].script, network); - value = tx.outs[prevTxOutputIndex].value; - } else { - throw new Error('psbt input is missing both witnessUtxo and nonWitnessUtxo'); - } - return { address, value, valueString: value.toString() }; - }); -} - -/** - * Get the inputs for a transaction from a prebuild. - */ -export async function getTxInputs(params: { - txPrebuild: TransactionPrebuild; - bitgo: BitGoBase; - coin: AbstractUtxoCoin; - disableNetworking: boolean; - reqId?: IRequestTracer; -}): Promise<{ address: string; value: TNumber; valueString: string }[]> { - const { txPrebuild, bitgo, coin, disableNetworking, reqId } = params; - if (!txPrebuild.txHex) { - throw new Error(`txPrebuild.txHex not set`); - } - const transaction = coin.createTransactionFromHex(txPrebuild.txHex); - const transactionCache = {}; - return await Promise.all( - transaction.ins.map(async (currentInput): Promise<{ address: string; value: TNumber; valueString: string }> => { - const transactionId = (Buffer.from(currentInput.hash).reverse() as Buffer).toString('hex'); - const txHex = txPrebuild.txInfo?.txHexes?.[transactionId]; - if (txHex) { - const localTx = coin.createTransactionFromHex(txHex); - if (localTx.getId() !== transactionId) { - throw new Error('input transaction hex does not match id'); - } - const currentOutput = localTx.outs[currentInput.index]; - const address = utxolib.address.fromOutputScript(currentOutput.script, coin.network); - return { - address, - value: currentOutput.value, - valueString: currentOutput.value.toString(), - }; - } else if (!transactionCache[transactionId]) { - if (disableNetworking) { - throw new Error('attempting to retrieve transaction details externally with networking disabled'); - } - if (reqId) { - bitgo.setRequestTracer(reqId); - } - transactionCache[transactionId] = await bitgo.get(coin.url(`/public/tx/${transactionId}`)).result(); - } - const transactionDetails = transactionCache[transactionId]; - return transactionDetails.outputs[currentInput.index]; - }) - ); -} diff --git a/modules/abstract-utxo/src/transaction/fixedScript/verifyTransaction.ts b/modules/abstract-utxo/src/transaction/fixedScript/verifyTransaction.ts index 26d8501a68..71996cdfd4 100644 --- a/modules/abstract-utxo/src/transaction/fixedScript/verifyTransaction.ts +++ b/modules/abstract-utxo/src/transaction/fixedScript/verifyTransaction.ts @@ -5,11 +5,9 @@ import { BitGoBase, TxIntentMismatchError, IBaseCoin } from '@bitgo/sdk-core'; import { hasPsbtMagic } from '@bitgo/wasm-utxo'; import { AbstractUtxoCoin, VerifyTransactionOptions } from '../../abstractUtxoCoin'; -import { Output, ParsedTransaction } from '../types'; -import { toTNumber } from '../../tnumber'; +import { ParsedTransaction } from '../types'; import { stringToBufferTryFormats } from '../decode'; import { verifyCustomChangeKeySignatures, verifyKeySignature, verifyUserPublicKey } from '../../verifyKey'; -import { getPsbtTxInputs, getTxInputs } from '../fetchInputs'; const debug = buildDebug('bitgo:abstract-utxo:verifyTransaction'); @@ -190,29 +188,9 @@ export async function verifyTransaction( } } - const allOutputs = parsedTransaction.outputs; if (!txPrebuild.txHex) { throw new Error(`txPrebuild.txHex not set`); } - const inputs = isPsbt - ? getPsbtTxInputs(txPrebuild.txHex, coin.name).map((v) => ({ - ...v, - value: toTNumber(v.value, coin.amountType), - })) - : await getTxInputs({ txPrebuild, bitgo, coin, disableNetworking, reqId }); - // coins (doge) that can exceed number limits (and thus will use bigint) will have the `valueString` field - const inputAmount = inputs.reduce( - (sum: bigint, i) => sum + BigInt(coin.amountType === 'bigint' ? i.valueString : i.value), - BigInt(0) - ); - const outputAmount = allOutputs.reduce((sum: bigint, o: Output) => sum + BigInt(o.amount), BigInt(0)); - const fee = inputAmount - outputAmount; - - if (fee < 0) { - throw new Error( - `attempting to spend ${outputAmount} satoshis, which exceeds the input amount (${inputAmount} satoshis) by ${-fee}` - ); - } return true; } diff --git a/modules/abstract-utxo/src/transaction/index.ts b/modules/abstract-utxo/src/transaction/index.ts index 075ef05742..d0231ff6cb 100644 --- a/modules/abstract-utxo/src/transaction/index.ts +++ b/modules/abstract-utxo/src/transaction/index.ts @@ -3,7 +3,6 @@ export * from './recipient'; export { explainTx } from './explainTransaction'; export { parseTransaction } from './parseTransaction'; export { verifyTransaction } from './verifyTransaction'; -export * from './fetchInputs'; export * as bip322 from './bip322'; export { decodePsbt } from './decode'; export * from './fixedScript';