import { Transaction } from '@scure/btc-signer'; import { IBitcoinProvider } from '../../providers/bitcoin.provider'; import { Wallet } from '../../wallet/wallet.dto'; import { base64 } from '@scure/base'; import { PoolErrorException, PoolErrorType } from '../../error/pool.error'; import { verifyUtxosInPsbtNotUsedAndStillOwnedByUser } from '../../util/validation'; import { checkFee } from '../../util/fee'; import { BTC_TOKEN } from '../pool.dto'; export const verifyPsbtForPayingFees = async ( signedPsbt: string, wallet: Wallet, bitcoinProvider: IBitcoinProvider, minFee: bigint, ): Promise => { const tx = Transaction.fromPSBT(base64.decode(signedPsbt)); // input should be inside the wallet. const inputs = await verifyUtxosInPsbtNotUsedAndStillOwnedByUser(signedPsbt, [ wallet, ]); const collectionUtxos = inputs.map((input) => { const utxo = wallet.utxos.find((u) => `${u.txid}:${u.vout}` === input); if (!utxo) { throw new PoolErrorException({ message: `Invalid psbt`, type: PoolErrorType.InvalidPsbt, }); } return utxo; }); try { tx.finalize(); } catch (err) { throw new PoolErrorException({ type: PoolErrorType.InvalidSignature, message: `Some of the inputs have not been signed`, }); } await checkFee(tx, collectionUtxos, bitcoinProvider); const output = tx.getOutput(0); if (!output.amount || output.amount < minFee) { throw new PoolErrorException({ type: PoolErrorType.NotEnoughFunds, message: `The psbt does not have enough funds to pay the fees.`, maxAmount: output.amount ? output.amount.toString() : '0', minAmount: minFee.toString(), token: `${BTC_TOKEN.block}:${BTC_TOKEN.tx}`, }); } return tx.id; };