EVM Chain Clients

THORChain supports a variety of EVM-compatible chains including Ethereum, BNB Chain, Avalanche, Arbitrum, Optimism, and Base. These clients share a common implementation that handles observation, signing, broadcasting, nonce management, and gas tracking.

Shared Architecture

All EVM clients reuse a shared implementation located at:

/bifrost/pkg/chainclients/evm/client.go

This core logic includes:

  • ABI-based decoding of inbound Router events
  • EIP-55 address formatting
  • Nonce caching and outbound coordination
  • Router interaction for ERC-20 deposits
  • Mempool scanning and reorg detection

Each EVM chain (e.g. ETH, BSC, AVAX, BASE) wraps this logic with its own chain ID, router address, gas asset, and fee tuning in its own subdirectory (e.g. ethereum/, bsc/).

Router Design

EVM chains rely on a Router contract for ERC-20 asset support. While native ETH can be sent directly to the vault, all ERC-20 token deposits must pass through the Router.

The Router enables:

  • Vaults to pull tokens using transferFrom
  • Memo inclusion via emitted Router events
  • Per-vault allowances for gas efficiency and simplicity
  • Unified logic without needing vault contracts

For examples, see Sending EVM Transactions.

Inbound Observations

Inbound transactions are detected by:

  • Watching Router contracts using eth_getLogs
  • Parsing Memo(string) and Transfer events via ABI decoding
  • Tracking native ETH deposits where to == vaultAddress

See:

Confirmation Counting

EVM transactions require delayed finality due to frequent re-orgs. THORChain uses dynamic confirmation logic.

EVM Specifics

  • Confirmation count is based on token value converted to ETH
  • Pool pricing from THORChain is used to estimate value
  • Finality is typically reached at MAXCONFIRMATIONS-ETH = 14

See Finality & Confirmation Counting.

Stuck Transaction Recovery

Unlike UTXO chains (which support CPFP), EVM chains do not allow fee bumping via future transactions. Each transaction must use a unique nonce, and replacement is only possible with the same nonce and a higher gas price.

A stuck nonce blocks all future transactions from that vault. To recover, THORChain applies an Unstuck Mechanism:

Detection

  • Runs every block
  • Flags transactions that have been unconfirmed for more than SigningTransactionPeriod - RescheduleBufferBlocks blocks

Replacement Process

  • Generates a 0-value self-to-self transaction from the vault

  • Uses the same nonce as the stuck transaction

  • Applies a higher gas price using the following logic:

    • Minimum: 110% of the original transaction's gas price
    • Target: 2× the current median network gas price
    • Final: whichever is higher between the two

Execution

  • The unstuck transaction is signed and broadcast by Bifrost
  • The nonce cache is updated to replace the old transaction
  • Any signing errors halt the process to avoid repeated failures

This unstuck logic is specific to EVM chains. UTXO chains use alternative mechanisms.

Gas Estimation

Outbound EVM gas fees are estimated based on:

  • A default gas limit (typically 200,000 units)
  • A target gas price set to ~1.5× the network median

However, THORChain generally charges users based on ~80,000 gas units to avoid overcharging.

See Gas Tracking.

Reorg Handling

EVM chains are reorg-prone. Bifrost handles this by:

  • Rescanning the last N blocks
  • Emitting an ErrataTx if a previously observed transaction is missing
  • Reverting state changes (vault balances, etc.)

See Re-orgs & Errata.

Vault Address Derivation

Vault addresses are derived from compressed ECDSA public keys using:

keccak256(pubkey)[12:]

All outbound transactions use EIP-55 checksummed formatting.