5. Replace By Fee (RBF) with different assets

Now, we want to broadcast a transaction with fees paid in a new asset, then make a replace-by-fee (RBF) transaction to bump the fee amount using the same asset, and then try another RBF transaction, which will change the asset used to pay for transaction fees.

5.1 Create a Raw Transaction

In the previous section, we took note of the TXID of the last transaction we made. We will use the output of such a transaction as our input for a new transaction. However, if you want to use another UTXO with different vout(s), you may want to check all UTXO you can spend so that you can retrieve the transaction IDs (TXID) of all unspent assets - you can do this with .\elements-cli listunspent. This will allow you to manually collect all the information you need to create a rawtransaction.

If you want to send the transaction to a new address, run this command again:

.\elements-cli getnewaddress

This will generate what we will now call GENERATED_ADDRESS_4.

Let's also generate an address where you can receive the change:

.\elements-cli getrawchangeaddress

We can call this latest new address "CHANGE_ADDRESS".

You are now ready to create a transaction that will be replaced by another transaction with a different asset with Replace By Fee. In the command below, replace TXID_ASSET_UNSPENT with the TXID of the transaction you made above, replace VOUT_NUMBER with 1 (since we will use only that single UTXO as input of this transaction), and replace GENERATED_ADDRESS_4 with the address of the recipient of this transaction you are preparing.

Now replace AMOUNT_TO_BE_SENT and CHANGE_ADDRESS in a way that their sum plus the "fee\":0.0001 in the token ASSET is equal to the input.

For example, if the UTXO you use as input has 100.0 USDT and you use USDT to pay the fees as well, you can set AMOUNT_TO_BE_SENT = 9.999, leave the fee at 0.0001, and set REST_AMOUNT = 90.0.

Replace the CHANGE_ADDRESS with the one created with the command above. Put any amount in REST_AMOUNT (e.g. 25.0) provided that it is less than the total output of the previous transaction (the TXID_ASSET_UNSPENT). Finally, replace ASSET with the assetlabel USDT (or whichever assetlabel you set during the asset creation step for ASSET_1) or its assetid. This will create a transaction that transfers ASSET_1 and also pays transaction fees in ASSET_1.

.\elements-cli createrawtransaction "[{\"sequence\": 4294967293,\"txid\":\"<TXID_ASSET_UNSPENT>\",\"vout\":<VOUT_NUMBER>}]" "[{\"<GENERATED_ADDRESS_4>\":<AMOUNT_TO_BE_SENT>, \"asset\":\"<ASSET>\"},{\"fee\":0.0001,\"fee_asset\":\"<ASSET>\"}, {\"<CHANGE_ADDRESS>\":<REST_AMOUNT>,\"asset\":\"<ASSET>\"}]"

Note that nSequence in Bitcoin, Elements and Sequentia signals if a transaction is replaceable or not:

  • 4294967295 is Non-replaceable

  • 4294967293 is Replaceable, see BIP-125

If you run listunspent command, the output will show a series of UTXO like the one below (for illustration purposes). If you want to find the one corresponding to the transaction you made in the last section of this guide, copy and paste the output from the command prompt window to a notepad or other text editor and search for the TXID that you took note of:

{
"txid": "da837fbd39ca134e64d31b6ccf98ac791cd9321d821410dcb5b35fa27c17e718",
"vout": 1,
"address": "ert1qagjq9puh6qh360f6xn2tu6dfxdw9qaj2e0mnem",
"label": "",
"scriptPubKey": "0014ea24028797d02f1d3d3a34d4be69a9335c50764a",
"amount": 50.99999854,
"asset": "8e577a160467091d755a64276326076f04c807884acf17b294e8df18cc0f89b5",
"amountblinder": "0000000000000000000000000000000000000000000000000000000000000000",
"assetblinder": "0000000000000000000000000000000000000000000000000000000000000000",
"confirmations": 1,
"spendable": true,
"solvable": true,
"desc": "wpkh([a6dcb78c/0'/0'/5']02cb3ff840320e978957a0d651d47b1385fdb15ffc911d0ecc50fbc467ef22fe2f)#7l8p3pdy",
"safe": true
}

Based on the above example UTXO, our createrawtrasaction command could look like this:

.\elements-cli createrawtransaction "[{\"sequence\": 4294967293,\"txid\":\"da837fbd39ca134e64d31b6ccf98ac791cd9321d821410dcb5b35fa27c17e718\",\"vout\":1}]" "[{\"ert1qagjq9puh6qh360f6xn2tu6dfxdw9qaj2e0mnem\":25.99989854, \"asset\":\"8e577a160467091d755a64276326076f04c807884acf17b294e8df18cc0f89b5\"},{\"fee\":0.0001,\"fee_asset\":\"8e577a160467091d755a64276326076f04c807884acf17b294e8df18cc0f89b5\"}, {\"ert1q3ye4hhrehsw0f99pprls7ljdwtjfv3wh07yy7z\":25.0,\"asset\":\"8e577a160467091d755a64276326076f04c807884acf17b294e8df18cc0f89b5\"}]"

Note that I am using 50.99999854 as input, which is exactly = 25.99989854 + 0.0001 + 25.0, i.e. the output: amount + fee + change.

The transaction that I am preparing sends the entire sum I just sent in the previous transaction to the new address I created, except for 25.0 tokens that will be “left” in the change address. Running the createrawtransaction command I will get a hex-encoded transaction, that is, a string that appears like this:

02000000000118e7177ca25fb3b5dc1014821d32d91c79ac98cf6c1bd3644e13ca39bd7f83da0100000000fdffffff0301b5890fcc18dfe894b217cf4a8807c8046f07266327645a751d096704167a578e010000000005f5e10000160014ea24028797d02f1d3d3a34d4be69a9335c50764a01b5890fcc18dfe894b217cf4a8807c8046f07266327645a751d096704167a578e01000000009502f9000016001489335bdc79bc1cf494a108ff0f7e4d72e49645d701b5890fcc18dfe894b217cf4a8807c8046f07266327645a751d096704167a578e010000000000002710000000000000

This string is the transaction hex id (TX_HEX_ID)

Now I want to sign this transaction:

.\elements-cli signrawtransactionwithwallet <TX_HEX_ID>

The expected output will be


{
"hex": "...688 digits....",
"complete": true
}

Let’s call the “hex” value the <SIGNED_TRANSACTION_HEX>, which you are going to use below.

We now want to broadcast this transaction to all peers. After running the command below, the transaction should be in your node's mempool:

.\elements-cli sendrawtransaction <SIGNED_TRANSACTION_HEX>

Note:

  • If you get the error “bad-txns-in-ne-out, value in != value out”, then check that the value vout is exactly what appears in the UTXO of the txid you want to use (run the command .\elements-cli listunspent and check).

  • If you get the error “Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)”, then lower the fee.

  • If you get the error “non-mandatory-script-verify-flag (Witness program hash mismatch)” probably you used the TX_HEX_ID rather than the <SIGNED_TRANSACTION_HEX>

If everything went right, you will instead get as a result a string like the following which is the TXID (transaction ID):

61185a96751065556ed8cd152a9adf13609a5007de355c4aae532f2c363dc129

Now, let's run the following command to check if the transaction is indeed in the mempool:

.\elements-cli getrawmempool true

The output will be something like this with the ID of the signed transaction and all its details:

.\elements-cli getrawmempool true
{
"61185a96751065556ed8cd152a9adf13609a5007de355c4aae532f2c363dc129": {
"vsize": 257,
"weight": 1028,
"time": 1718066562,
"height": 203,
"descendantcount": 1,
"descendantsize": 257,
"ancestorcount": 1,
"ancestorsize": 257,
"wtxid": "27daae8753487b9e103c0a53f79836aba426afeee037b9f9e6f7bac482b4a8e0",
"fees": {
"base": 0.00010000,
"modified": 0.00010000,
"ancestor": 0.00010000,
"descendant": 0.00010000,
"asset": "8e577a160467091d755a64276326076f04c807884acf17b294e8df18cc0f89b5",
"value": 0.00010000
},
"depends": [
],
"spentby": [
],
"bip125-replaceable": true,
"unbroadcast": true
}
}

5.2 Bump fee using the same asset

Now, let’s use RBF to bump the fee using the same asset (replace ASSET with the asset ID you used to create the rawtransaction. Replace TXID with the 64-digit transaction ID you got during the steps above. For the moment, in place of <ASSET>, insert the asset ID of the coin we are transferring, later we will also try changing the asset

.\elements-cli bumpfee <TXID> "{\"fee_asset\":\"<ASSET>\"}"

As output, you will see the transaction, the original fee and the new fee:

"txid": "6bfe018a5961ea247e53b66329b8f42a6759ee4748fb547defc339bad04ccf6b",
"origfee": 0.00010000,
"fee": 0.00011286,
"fee_asset": "8e577a160467091d755a64276326076f04c807884acf17b294e8df18cc0f89b5",
"errors": [
]

Check if the transaction has been updated in the mempool:

.\elements-cli getrawmempool true

You will see only the new transaction that has replaced the old one.

5.3 Replace-By-Fee using a different asset

Finally, we will perform a replace-by-fee transaction that does not just bump the fee to a higher value but instead replaces the fee asset with a completely different asset altogether!

Now use bumpfee to create an RBF transaction. We need to replace the last TXID

.\elements-cli bumpfee <TXID> "{\"fee_asset\":\"<ASSET_2>\"}"

Then check again the transaction in the mempool

.\elements-cli getrawmempool true

Finally, create a block with the replaced transaction using:

.\elements-cli generatetoaddress 1 <GENERATED_ADDRESS>

Check that the RBF transaction has been received and confirmed in the blockchain:

.\elements-cli getreceivedbyaddress <GENERATED_ADDRESS_2>

Finally, check your balance

.\elements-cli getbalance

Last updated