Skip to content

EVM Balances

The "EVM" module in Substrate provides support for executing Ethereum contracts on a substrate chain. To perform any gas or balance-related actions on the EVM, the calling account must have a EVM balance.

Balance Conversion

To use Ethereum contracts on a Substrate chain, the chain must have a protocol that support thes following requirements:

  1. A (32-byte) Substrate address must have a corresponding (20-byte) Ethereum address.
  2. Each (20-byte) Ethereum address must have its balance maintained.

Step 1

The EVM pallet satisfies step 1 by cutting the source Substrate address into an Ethereum address, taking the first 20 bytes.


Step 2

To maintain the balances of the cut-down EVM addresses, the SwapDEX utilizes the Substrate balances pallet. The balances pallet converts a corresponding 20-byte address into an substrate address (32-byte).

Note that these reconverted 32-byte addresses have no inherent relationship to the original truncated Substrate address.



  • Consider the following 32-byte substrate address: 0x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF
  • Truncate the address to build an EVM Pallet representation: 0x1234567890ABCDEF1234567890ABCDEF12345678
  • The balance of 0x1234567890ABCDEF1234567890ABCDEF12345678 comes from the balances pallet
  • The balances pallet manages uses a 32-byte representation of 0x1234567890ABCDEF1234567890ABCDEF12345678
  • This representation is generated by hashing 0x1234567890ABCDEF1234567890ABCDEF12345678 with a specific EVM prefix
  • The prefix is: (0x65766D3A)
  • The balances module performs: HASH(0x65766D3A0x1234567890ABCDEF1234567890ABCDEF12345678) end gets =
  • 32-byte EVM representation of truncated address: 0xAF8536395A1EEC8EDA6FB9CF36739ECF75BECF6FEA04CEEC108BBB6AA15B7CB3
  • The balance of 0xAF8536395A1EEC8EDA6FB9CF36739ECF75BECF6FEA04CEEC108BBB6AA15B7CB3 in the balances pallet is used for EVM-related operations.


Note that these actions are not reversible: we cannot convert from an EVM address back to its Ethereum address, nor can we convert from an Ethereum address back to its "source" Substrate address.

Managing Ethereum Balances on Substrate

Two operations are possible:

  • We can "deposit" funds from a Substrate account into its corresponding Ethereum account and
  • We can "withdraw" funds from an Ethereum account back into the source Substrate account.


Since the EVM address that represents an Ethereum address is computed deterministically by hashing, as shown above, we can perform a standard balance transfer from our source Substrate account to the EVM address to seed the Ethereum account with funds.

This can be performed by calling balances::transfer(prefixAndHash(truncate(account)).signAndSend(account), where account is the source substrate account. truncate() takes the substrate source address (32-bytes) and produces the 20-byte Ethereum address. Finally, prefixAndHash() applies the evm: prefix and performs the hash to convert the Ethereum address back into a 32-byte Substrate address.


Since the EVM address is computed deterministically, via hashing, we do not have a private key for it, so we cannot perform a balance transfer from it via normal means. As a result, the EVM module provides a unique function withdraw to transfer funds back from an Ethereum account to the source Substrate account.

This can be performed by calling evm::withdraw(truncate(account), value).signAndSend(account) where account is the source Substrate account, and truncate takes the first 20 bytes as the Ethereum address.

Ethereum Balances

An EVM address can be given a balance at genesis, or by sending balance directly to the "substrate-ethereum address equivalent" as you would normally do between accounts.

SwapDEX handles Ethereum balances as if they were running on the Ethereum blockchain. That includes that gas is subtracted from the balance (you can access the quantity of gas used from the transaction receipt returned by the EVM module through web3 or truffle), and transfers work as expected.

The balance of the 20-byte Ethereum address and the 32-byte EVM address should be identical, when compared: web3.eth.getBalance(ethAddress) should equal system::balances(prefixAndHash(ethAddress)).freeBalance, where ethAddress is the 20-byte Ethereum address, and prefixAndHash applies the evm: prefix and takes the hash, as explained above.


Each EVM address is deterministically mapped to another substrate address which maintains its balance within the balances pallet, and which can be used to sent funds directly via a basic transfer. This substrate address is equivalent to the 20-byte EVM address for all intents and purposes, and is a deterministic computation from the original substrate address — it can be used in other pallets freely as a "proxy" for the EVM address. However, it does not have a private key, so it cannot sign.

Funds must be withdrawn from an EVM account (20-byte address) via the pallet_evm::withdraw function, as the "substrate-ethereum equivalent" does not have a known private key from which to send transactions.

Written by Masterdubs & Petar

Back to top