From 60e4890496cc325f7b3901efcb44b1b411e5cb36 Mon Sep 17 00:00:00 2001 From: David Kaplan Date: Mon, 7 Jul 2025 12:38:05 -0400 Subject: [PATCH] feat(sdk-coin-btc): add option to force fee from non-ordinal unspents Add option `forceFeeFromOtherUnspent` to the inscription builder that ensures fees are paid from unspents other than the one containing the ordinal. This helps prevent accidentally burning ordinals when network fees are subtracted from the ordinal-containing UTXO. Co-authored-by: llm-git BTC-0000 --- examples/ts/btc/ordinals/move-individual-ordinal.ts | 4 +++- modules/sdk-coin-btc/src/inscriptionBuilder.ts | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/ts/btc/ordinals/move-individual-ordinal.ts b/examples/ts/btc/ordinals/move-individual-ordinal.ts index 5eacfdc40b..347666bd84 100644 --- a/examples/ts/btc/ordinals/move-individual-ordinal.ts +++ b/examples/ts/btc/ordinals/move-individual-ordinal.ts @@ -41,7 +41,9 @@ async function transferIndividualOrdinal() { // Build the transaction to send the ordinal // Note that you can configure the structure of the transaction by passing in additional parameters - const buildResult = await inscriptionBuilder.prepareTransfer(satPoint, recipient, feeRateSatKb, {}); + const buildResult = await inscriptionBuilder.prepareTransfer(satPoint, recipient, feeRateSatKb, { + forceFeeFromOtherUnspent: true, + }); const sent = await inscriptionBuilder.signAndSendTransfer(walletPassphrase, buildResult); console.log('sent ' + JSON.stringify(sent, null, 2)); diff --git a/modules/sdk-coin-btc/src/inscriptionBuilder.ts b/modules/sdk-coin-btc/src/inscriptionBuilder.ts index 5b43ab4b28..2032b41df5 100644 --- a/modules/sdk-coin-btc/src/inscriptionBuilder.ts +++ b/modules/sdk-coin-btc/src/inscriptionBuilder.ts @@ -142,6 +142,7 @@ export class InscriptionBuilder implements IInscriptionBuilder { inscriptionConstraints = DefaultInscriptionConstraints, changeAddressType = 'p2wsh', txFormat = 'psbt', + forceFeeFromOtherUnspent = false, }: { signer?: utxolib.bitgo.KeyName; cosigner?: utxolib.bitgo.KeyName; @@ -152,6 +153,7 @@ export class InscriptionBuilder implements IInscriptionBuilder { }; changeAddressType?: utxolib.bitgo.outputScripts.ScriptType2Of3; txFormat?: 'psbt' | 'legacy'; + forceFeeFromOtherUnspent?: boolean; // If true, will try to use unspents other than the inscription unspent to pay for the fee } ): Promise { assert(isSatPoint(satPoint)); @@ -174,6 +176,9 @@ export class InscriptionBuilder implements IInscriptionBuilder { }; for (const supplementaryUnspentsMinValue of SUPPLEMENTARY_UNSPENTS_MIN_VALUE_SATS) { + if (forceFeeFromOtherUnspent && supplementaryUnspentsMinValue === 0) { + continue; // Skip the attempt with 0 + } try { return await this.prepareTransferWithExtraInputs( satPoint,