Swapping
Integrations
Advanced Scenarios
Cross-Chain Messaging
To EVM

CCM Swaps to EVM Chains

EVM Considerations

Besides the general implementation checklist, there are some specific considerations for EVM chains.

  • The gas limit on the destination chain (EVM) will be capped to 10 million gas.
  • The receiver contract on the destination chain must implement the cfReceive function specified in the EVM integration.
  • If the amount of gas provided is not enough to cover the gas costs of the receiver's logic on the destination chain, the transaction won't be broadcasted. An example of a gas estimation is provided below.
  • In the event of a transaction not being broadcasted due to insufficient gas, the signed payload will be available for the user to broadcast as described here.

Gas budget estimation

The user has to provide a gas budget for the destination chain that must cover the entire transaction on the destination chain, that is both the Chainflip signature verification and the execution of the user's logic. The gas limit used on the destination chain is calculated as follows:

gasLimit = gasBudgetAfterSwap / (baseFee + priorityFee)

where:

  • gasBudgetAfterSwap is the input gasBudget provided by the user after being swapped by Chainflip into the destination chain's native asset.
  • baseFee and priorityFee are the current base and priority fees on the destination chain.

The final gasLimit has to be more than the amount of gas the transaction will consume on the destination chain, otherwise the transaction won't be broadcasted. That gas limit is capped to 10M gas. There are multiple factors to take into account when estimating the gas budget:

  • The baseFee and priorityFee of the destination chain are moving targets so it's advised to use a conservative estimation.

  • That gas limit has to also cover the chainflip signature verification logic. A good approximation of that gas cost is a constant 120k gas plus the number of bytes of the message times 17. That is considering calldata costs 16 gas per byte plus a margin for additional verification overhead.

    SigVerificationGas = 120k + messageLength * 17

Therefore, the gasBudget required, assuming the user requires userLogicGas to execute the user logic, can be calculated as follows:

gasBudget = (userLogicGas + 120k + messageLength * 17) * (baseFee + priorityFee) * overestimationRatio * swapPrice 

An overestimation, overestimationRatio, is advised both due to the gas prices and the gas swap being non-deterministic and constantly changing. Currently Chainflip does not issue refunds of unspent gas but that will change in the future.

Arbitrum does not have priority fees. However, the gas consumption can vary depending on the state of the network as explained in the Arbitrum Docs (opens in a new tab).

Gas budget estimation example

  • User wants to swap 0.5 BTC to FLIP, destination chain being Ethereum.
  • User needs 100k gas to execute their logic on the destination chain.
  • The message is 100 bytes long.
  • Current base fee on the destination chain is 10 gwei and the current priority fee is 1 gwei.
  • The user overestimates the gas budget by 30% for safety.
  • BTC will be swapped to ETH for gas, let's use a 0.05 ETH to BTC conversion rate. This can be obtained by getting a quote via the Chainflip SDK.
// Total gas limit for the CCM transaction
gasLimit = (userLogicGas + 120k + messageLength * 17) * overestimationRatio = (100k + 120k + 100 * 17) * 1.3 = 288,210 gas units
 
// Destination's chain native token needed to cover for the gas
nativeTokenNeeded = gasLimit * (baseFee + priorityFee) = 288210 * (10 + 1) = 3,170,310 Gwei
 
// Required amount of input swap token to be paid as gas (gasBudget)
gasBudget = nativeTokenNeeded * swapPrice = (3,170,310 / 10^9) * 0.05 = 0.00016 BTC

Therefore, in this example, the user would specify a gasBudget of 0.00016 BTC and provide a total of 0.50016 BTC when making a swap.

BTC to USDC (Ethereum) Example

  1. A user has BTC on the Bitcoin blockchain and wants to swap it to USDC on Ethereum blockchain and then execute some logic on a smart contract.
  2. The user requests a bitcoin deposit address as described here (only when the source chain is EVM-compatible, this can be initiated via a smart contract call).
  3. The user defines, as part of requesting a deposit adddress, two additional parameters: message and gasBudget. The message can be an arbitrary HEX-encoded sequence of bytes. The gasBudget is the source asset amount that will be used to pay for gas.
  4. The user transfers an amount to swap.
  5. The Chainflip protocol swaps the gasBudget amount to the destination chain's native asset to pay for gas — ETH in this case — and the remaining swap amount (input amount - gasBudget) is swapped to the destination asset — USDC in this case. Therefore, input amount must be at least larger than gasBudget amount.
  6. After the threshold signature is completed, a transaction originating from the Vault contract transfers the destination asset to the specified receiver address, on the destination chain, and makes a call to that address with a specific interface passing the user's message. The gas limit on that call is set according to the gasBudget swap output and the current gas price.
  7. The receiver contract executes its logic, which can entail decoding the received message from the source chain and execute logic accordingly, i.e. swap USDC into <any-long-tail-asset> in a Uniswap pool.

CCM broadcast failure

While Chainflip will do it's best to broadcast and succesfully execute any swap with cross-chain messaging, there are some factors that can make the swap fail that are external to Chainflip. Here are some examples.

  • The gas budget provided is not enough to cover the gas costs of the receiver's logic on the destination chain.
  • The receiver contract not implementing the correct interface (or being an EOA).
  • The logic executed on the receiver's contract reverts.

Chainflip will use TSS to sign over a valid payload for the destination chain and try to broadcast it. If a transaction can't be broadcasted for any reason, the signed payload will be publicly accessible on the Chainflip State Chain for the user. The user can then sign over the payload and broadcast the transaction.

If the transaction reverts due to not enough gas, the user can sign that payload and broadcast it with a higher amount of gas. If it's due to the receiving logic reverting, the user can try to modify the state of the receiving contract before broadcasting it again. The payload will be valid until two key rotations have taken place.

The signed payload can be broadcasted with different gas settings but it can't modify any value in that payload (e.g. message). Therefore, always make sure to test the receiving logic and ensure it won't revert before initiating a swap.