EVM-Substrate Transfers

Developer Resource

Cross-EVM/Substrate Token Transfers

Handling cross-system token transfers between Substrate and EVM can be complex. Address mappings play a crucial role in facilitating these transfers. While we provide


  1. Alice only has an account on Tangle EVM using the Metamask wallet.
  2. Bob has an account on Tangle using the Polkadot.js wallet, and another account on Tangle EVM using the Metamask wallet.
  3. Charlie only has an account on Tangle using the Polkadot.js wallet.

Assigned values:

  • Alice's account: 0xa5fAA47a324754354CB0A305941C8cCc6b5de296
  • Bob's accounts: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty and 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990
  • Charlie's account: 5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y

Address Mapping Explanation

Address mappings between Substrate and EVM are one-way transformations that facilitate token transfers between the two systems.

  • Substrate to EVM: When a Substrate address is converted to an EVM address, the resulting EVM address can be used to receive tokens on the EVM side. The conversion involves extracting and hashing a part of the Substrate address, providing a unique EVM address corresponding to the original Substrate address.
  • EVM to Substrate: Once tokens are sent to the EVM address, the recipient can interact with the Substrate network by calling the evm.withdraw function. This allows the recipient to withdraw tokens from the EVM environment back to the Substrate environment.

Key Points:

  • The conversion is a one-way mapping from Substrate to EVM.
  • The resulting EVM address is a hash of part of the Substrate address.
  • Tokens can be received on the EVM side using the EVM address.
  • The evm.withdraw function facilitates the transfer of tokens back to the Substrate side.

Convert Substrate Address to EVM

To convert a Substrate address to an EVM address, the following script can be used:

import { decodeAddress } from "";
import { u8aToHex } from "";
const input = Deno.args[0];
if (!input) {
  console.error("usage: deno run substrateToEvm.ts <SUBSTRATE_ADDRESS_HERE>");
const accountId = decodeAddress(input);
const res = accountId.subarray(0, 20);
const output = u8aToHex(res);
console.log({ input, output });
// run using:
// $ deno run substrateToEvm.ts <SUBSTRATE_ADDRESS_HERE>

The script takes a Substrate address as input, decodes it, and then extracts the first 20 bytes of the account ID. These 20 bytes are then converted into a hexadecimal string, resulting in an EVM-compatible address.

Convert EVM Address to Substrate

Here is an example using the Deno Runtime and @polkadot/util to convert an address from EVM to Substrate:

You can also use this convenient tool:

EVM to Tangle Address Converter

Enter an EVM address to convert it to the prefixed form unique to Tangle Network. To convert an SS58 address to a public key or other networks, you can use

Please note that the conversion from an EVM address to a Tangle address using the provided tool is a one-way operation, and you cannot derive the original EVM address from a Tangle address.
Learn more about Addresses on Tangle.
import {
} from "";
import {
} from "";
const input = Deno.args[0];
if (!input) {
  console.error("usage: deno run evmToSubstrate.ts <ETH_ADDRESS_HERE>");
const addr = hexToU8a(input);
const data = stringToU8a("evm:");
const res = blake2AsU8a(u8aConcat(data, addr));
const output = encodeAddress(res, 42);
console.log({ input, output });
// run using:
// $ deno run evmToSubstrate.ts <ETH_ADDRESS_HERE>
Note The conversion from an EVM address to a Substrate address is a one-way operation. Due to the hashing process, it is not possible to reverse the process and obtain the original EVM address from the resulting Substrate address.

Case 1: Sending from Substrate to EVM

Bob wants to send 100 TNT to Alice, but he does not have the 100 TNT on his EVM account in Metamask. Therefore, he uses his Tangle account in the Polkadot.js wallet.

  1. Alice's address is 0xa5fAA47a324754354CB0A305941C8cCc6b5de296.
  2. Bob converts Alice's address to a substrate address using the evmToSubstrate function:
// => 5C9ysBsWKpw3D8MFaEauFgdtMPqboS64YNYHyu1rCynLyKMZ
  1. Bob sends the 100 TNT to 5C9ysBsWKpw3D8MFaEauFgdtMPqboS64YNYHyu1rCynLyKMZ.
  2. Alice receives the 100 TNT in her Metamask wallet.

Case 2: Sending from EVM to Substrate

Alice wants to send 50 TNT to Charlie. However, Charlie only has a Substrate account that he controls in his Polkadot.js wallet.

  1. Charlie's address is 5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y.
  2. Alice converts Charlie's address to an EVM address using the substrateToEvm function.
// => 0x90b5ab205c6974c9ea841be688864633dc9ca8a3
  1. Alice uses her Metamask and sends 50 TNT to 0x90b5ab205c6974c9ea841be688864633dc9ca8a3.
  2. Charlie's balance on Substrate remains the same!

    Because: Charlie needs to withdraw the balance from his EVM account.

  3. Charlie goes to Polkadot.js and calls: evm.withdraw("0x90b5ab205c6974c9ea841be688864633dc9ca8a3", 50 TNT).
  4. Charlie sees that he has now received 50 TNT in his account.