Overview

When users engage in digital currency transactions on blockchain networks, they are required to pay transaction fees. These fees are paid to the network’s miners, who confirm and validate the transactions and add them to the blockchain ledger. The calculation methods for transaction fees vary across different networks.

Gas is the fee required to successfully conduct a transaction or execute a contract on the Ethereum network. These fees are denominated in minute fractions of the cryptocurrency ether (ETH), known as gwei. On the Bitcoin network, the fee rate is calculated in satoshis (the smallest unit of the Bitcoin cryptocurrency) per unit of data that your transaction will consume, abbreviated as sats/vByte.

Calculation Methods

On the Ethereum network, gas fees are calculated by multiplying the gas price by the gas limit. Keep in mind that gas prices are influenced by the supply and demand for transactions. In times of network congestion, gas prices may surge, requiring clients to pay a higher fee for expedited transaction completion.

For the Bitcoin network, transaction fees are calculated by multiplying the transaction size by the fee rate (satoshi per byte). Fee rates on the Bitcoin network also fluctuate in response to changing network conditions. Clients can adjust rates based on the urgency of their transactions.

Estimating Transaction Fees API

Before initiating a transaction, clients need to estimate the transaction fees by calling the estimate_fee endpoint. They need to pass in all required parameters, such as coin code, amount, address, gas price and gas limit.

The endpoint returns gas fees based on the parameters specified by the user, indicating the success or failure status. The response also includes different gas fees for transactions at slow, average, and fast speeds.

After obtaining the transaction fees, clients must reserve both the transaction amount and the estimated fee amount in the wallet address from which the transaction will be initiated. Failure to do so may result in a transaction failure.

If the wallet address lacks sufficient balance to cover both the transaction amount and transaction fees, clients must promptly top up the required coin balance for paying transaction fees or reduce the transaction amount.

For more information on the endpoint, please click here.

Calling the API for Estimating Transaction Fees

Note that different types of coins and wallets require different input parameters. For account-based models, clients should provide the gas price and gas limit. In UTXO-based models, clients must specify transaction fees and inputs (the UTXOs being spent). Web3 wallets require additional parameters, including calldata. Please ensure that the correct parameters are passed in based on your specific use cases.

from cobo_custody.client.mpc_client import MPCClient
from cobo_custody.config import DEVELOP_ENV
from cobo_custody.signer.local_signer import LocalSigner

api_secret = "your_api_secret"  # your wallet api secret

# init cobo client
mpc_client = MPCClient(signer=LocalSigner(api_secret), env=DEVELOP_ENV, debug=False)

# Params example
coin = "ETH"
amount = 1
address = "0x0c4554ab637e8682155aca0923ed0ea2a469e1e7"
replace_cobo_id = "20231206165108000159686000005421"
from_address = None
to_address_details = None
fee = None
gas_price = None
gas_limit = None
extra_parameters = '{"calldata": "0x23b872dd0000000000000000000000000c4554ab637e8682155aca0923ed0ea2a469e1e7000000000000000000000000cd0ef2cf9dff3b23d28eda1f49a245347a71ab9d000000000000000000000000000000000000000000000000000000000047b32d"}'

response = mpc_client.estimate_fee(
   coin=coin,
   address=address,
   amount=amount,
   replace_cobo_id=replace_cobo_id,
   from_address=from_address,
   to_address_details=to_address_details,
   fee=fee,
   gas_price=gas_price,
   gas_limit=gas_limit,
   extra_parameters=extra_parameters
)
print(f"estimate_fee: {response.result}")

API Responses

The response contains a success status and specific result attributes. There are two possible success statuses: success or failure. The specific results come in three types: slow, average, and fast.

  • Slow: Submitted transaction fees are lower than the current average on the network, leading to a longer confirmation time and potential failure to confirm.
  • Average: Submitted transaction fees are roughly equal to the current average on the network.
  • Fast: Submitted transaction fees exceed the current average on the network, resulting in a faster confirmation time.

For example:

  • For BTC, the transaction fee obtained from the network serves as the recommended average transaction fee. The fast transaction fee is set at 10 times the average, and the slow transaction fee is set at 0.1 times the average.
  • For ETH, the transaction fee obtained from the network serves as the recommended average transaction fee. The fast transaction fee is set at 2 times the average, and the slow transaction fee is set at 1 time the average.
estimate_fee: {
	'fee_coin': 'ETH',
	'fee_decimal': 18,
	'slow': {
		'fee_per_byte': 0,
		'fee_amount': 0,
		'gas_price': 48779970845,
		'gas_limit': 21000
	},
	'average': {
		'fee_per_byte': 0,
		'fee_amount': 0,
		'gas_price': 48779970845,
		'gas_limit': 21000
	},
	'fast': {
		'fee_per_byte': 0,
		'fee_amount': 0,
		'gas_price': 97559941690,
		'gas_limit': 21000
	}

Best Practices for Optimizing Transaction Fees

  1. Interact on-chain during periods of lower gas prices
  2. Interact with smart contracts that entail lower gas consumption.
  3. Adopt best practices for optimizing transactions fees
    • Minimize on-chain data (use events, IPFS, stateless contracts, Merkle proofs)
      • Use events to record information instead of storing it in contract state.
      • Use distributed file storage systems like IPFS to store large amounts of data.
      • Employ stateless contracts and Merkle proofs to reduce on-chain storage requirements.
    • Minimize on-chain operations (strings, return stored values, loops, local storage, batching)
      • Avoid unnecessary string operations and complex computations.
      • Return stored values directly instead of calculating them on-chain.
      • Reduce loop usage and optimize algorithm efficiency.
    • Optimize local storage by minimizing read and write operations on state variables.
      • Batch operations to reduce the number of individual transactions.
    • Memory location (calldata, stack, memory, storage)
      • Use calldata, stack, memory, and storage efficiently to reduce gas consumption.
      • Manage data memory locations carefully.
    • Variable order
      • Arrange variables in order based on access frequency and gas fees.
    • Data types
      • Choose appropriate data types to reduce gas consumption.
    • Libraries (embedded libraries, independently deployed library contracts)
      • Use embedded libraries to reduce duplicate code.
      • Independently deploy library contracts to share logic and reduce gas consumption.
    • Minimal Proxy
      • Use the minimal proxy pattern to reduce the gas fees of deploying and executing proxy contracts.
    • Functions
      • Optimize functions to minimize gas consumption.
    • Contract size (messages, modifiers, functions)
      • Streamline messages, modifiers, and functions to reduce contract size.
    • Solidity compiler optimizer
      • Make effective use of Solidity compiler optimizer settings to strike a balance between compilation optimization and gas fees.