zeta-chain / node

ZetaChain’s blockchain node and an observer validator client
https://zetachain.com
MIT License
166 stars 107 forks source link

Bitcoin deposit transaction reverts with "min relay fee not met" #3024

Open 1337-ishaan opened 2 weeks ago

1337-ishaan commented 2 weeks ago

Describe the Bug I have been using Zetachain's bitcoin depositFee logic i.e depositFee = utxoData.fastestFee * 68 * 2 (using mempool api), it doesn't work as expected SOMETIMES and reverts with "min relay fee not met".

To Reproduce

  1. Setup MetaMask Flask
  2. Deposit native (test) BTC to any ZRC20 token using ZetaLink
  3. This might or might not get through with the error "min relay fee not met"

Expected Behavior Transaction goes through and user receives selected ZRC20 token on chain, I used the same logic for the transactions that went through (see links)

Links The transactions where it successfully worked as expected with the same implementation

fadeev commented 2 weeks ago

@ws4charlie can you, please, take a look? 🙏

ws4charlie commented 2 weeks ago

@1337-ishaan Thank you for posting the questions in the Github. We're here glad to help you on any issues/questions. Here are my thoughts for the issue you described above:

  1. The min relay fee not met is an error returned by Bitcoin network to reject txs that carry low fee. In your case, the broadcasted Bitcoin tx to ZetaChain TSS address didn't carry enough gas fee (Bitcoin gas fee). You would have to use a proper market fee rate to let the tx be accepted by Bitcoin network as the 1st step.

  2. Regarding the formula:depositFee = utxoData.fastestFee * 68 * 2 (using mempool api) Given a transaction T sent BTC to ZetaChain TSS address, the steps we calculate ZetaChain depositor fee are: step-1: Query transaction T by its hash from Bitcoin network and calculates the gas fee Fee by: Fee = totalInputValue - totalOutputValue, see the fee calculation step-2: Calculate transaction T FeeRate by: FeeRate = Fee / txVsize, see the fee rate calculation step-3: Calculate ZetaChain depositorFee by: depositorFee = FeeRate * 68 *2

  3. For above example tx , the depositor fee calculation will be:

    1. The Bitcoin tx Fee is 475 sats, the tx Vsize is 416 vB
    2. The tx FeeRate will be 475/416 == 1 sats/ vB
    3. The resulted depositorFee charged will be 1 * 68 * 2 == 132 sats

The key idea is that the depositorFee is based on the actual fee rate by which the transaction paid for it self in the Bitcoin network. This will allow the devs to predict the depositorFee that be charged by ZetaChain when building the transaction offline (before broadcasting to Bitcoin).

1337-ishaan commented 2 weeks ago

@ws4charlie, We are currently using mempool apis for the fees, let me try moving it to some other API

Thanks for the quick response, i'll keep everything posted

1337-ishaan commented 1 week ago

Recently created this transaction @ws4charlie,

https://mempool.space/testnet/tx/040e2be938636ff272823222dd6e481915214636da0afc6aafc2ea71b393f6ab

1337-ishaan commented 1 week ago
    const fee = await fetch(
      `${isMainnet ? MAINNET_BLOCKCYPHER_API : TESTNET_BLOCKCYPHER_API}`,
    );
    if (!fee.ok) {
      throw new Error('Failed to fetch depositFees.');
    }
    const feeData = await fee.json();
    return {
      btcFees: feeData.high_fee_per_kb,
      zetaDepositFees: feeData.high_fee_per_kb * 0.001 * 68 * 2,
    };

Blockcypher API response:

{
  "name": "BTC.test3",
  "height": 3191839,
  "hash": "00000000000e404673ed571747486762468792fb6c3cf1ed1c8bc3fe3f2c86a0",
  "time": "2024-10-28T21:31:45.67124675Z",
  "latest_url": "https://api.blockcypher.com/v1/btc/test3/blocks/00000000000e404673ed571747486762468792fb6c3cf1ed1c8bc3fe3f2c86a0",
  "previous_hash": "000000000061b2b0ac8fa87d9a71e1d1a67a539037405932bcff2ee70cc07f22",
  "previous_url": "https://api.blockcypher.com/v1/btc/test3/blocks/000000000061b2b0ac8fa87d9a71e1d1a67a539037405932bcff2ee70cc07f22",
  "peer_count": 249,
  "unconfirmed_count": 31,
  "high_fee_per_kb": 658648,
  "medium_fee_per_kb": 271731,
  "low_fee_per_kb": 137631,
  "last_fork_height": 3129966,
  "last_fork_hash": "0000000000003a2325000d9f7e2f878a2e2e212201b7bf42149df785e4e83058"
}

@ws4charlie, this is how we are structuring the current fees data, looks optimal to me, pls do share your thoughts.