ERC20-to-ERC20 Bridge Deployment


The following provides an example installation of an ERC20-ERC20 bridge, using the POA Sokol and Ethereum Kovan testnets. We use Docker containers to simplify TokenBridge deployment.

An additional tutorial which uses Truffle to create sample smart contracts is located here. Note: the Truffle tutorial uses previous versions of the contracts which do not include several of the current parameters.



  • Docker v18.09.1
  • NodeJS v10.15.1
  • NPM v6.4.1
  • Nifty Wallet v4.10.0



To make this example deployment more simple we use one ETH address for deployment and a second ETH address to function as the wallet for transactions. Multiple addresses will typically be used in a production setup.

  1. Prepare a temporary ETH address for deployment by creating a new wallet account. This wallet address will be used for deploying bridge contracts to both networks, as the bridge contracts management wallet, and as the validator’s wallet address. There are several ways to do this - here we use

    1. Go to, enter an easy to remember password, and click Create New Wallet
    2. Download the keystore file and access your wallet using this file
    3. Save the wallet address and private key in a text file.
    4. Repeat the process to create a second wallet - this wallet will be used for testing the bridge.
  2. Fund the test accounts.

    1. Fund the Home account using the POA Sokol Faucet
    2. Get free Kovan Coins from the gitter channel or Iracus faucet for the Foreign account.
  3. Create an empty folder for setting up your bridge. In this example we call it sokol-kovan-bridge.
    mkdir sokol-kovan-bridge && cd sokol-kovan-bridge

Smart Contracts

  1. Clone contracts repository. git clone && cd poa-bridge-contracts

  2. Copy the example deploy.env file cp deploy/.env.example deploy/.env

  3. Set deployment parameters in the new file vim deploy/.env

    1. ERC20 - ERC20
      1. Use BRIDGE_MODE=ERC_TO_ERC, comment out or delete other modes
      2. Add DEPLOYMENT_ACCOUNT_PRIVATE_KEY of wallet 1 from text file
      4. Change urls - for this example keep HOME_RPC_URL as and change FOREIGN_RPC_URL to
      5. Copy wallet 1 address from text file and add to Home and Foreign parameters:
        • VALIDATORS
      6. Change FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS to 1 (to increase speed)
      7. Add placeholder address to ERC20_TOKEN_ADDRESS. use 0x followed by 40 characters, for example: 0xcafecafecafecafecafecafecafecafecafecafe
      8. Comment out or delete BLOCK_REWARD_ADDRESS
      9. Save the file.
  4. Prepare the Docker container: docker-compose up --build

  5. Deploy a Foreign test token: ./ token
    Note: Account must be funded (see step 2).

[Foreign] deploying ERC20 token
pending txHash 0x...
[Foreign] ERC20 Token:  0x...
[Foreign] minting 100 tokens and transfer them to  0x...
pending txHash 0x....

Token deployment is completed
  1. Copy the newly created [Foreign] ERC20 Token from step 8. Paste into BlockScout (be sure Kovan network is selected from dropdown) to verify token creation.

  2. Return to the .env file and change parameters for Sokol (Home Network) deployment

    1. vim deploy/.env
    2. Change TOKEN_NAME to ‘Demo Token in Sokol’
    3. Paste in ERC20_TOKEN_ADDRESS from step 8
    4. Save
  3. Deploy the contract ./ When contracts are deployed successfully, you will see the output.

Deployment has been completed.

[   Home  ] HomeBridge: 0x... at block <block number>
[   Home  ] ERC677 Bridgeable Token: 0x....
[ Foreign ] ForeignBridge: 0x.... at block <block number>
[ Foreign ] ERC20 Token: 0x....
Contracts Deployment have been saved to `bridgeDeploymentResults.json`
    "homeBridge": {
        "address": "0x...",
        "deployedBlockNumber": <block_number>,
        "erc677": {
            "address": "0x..."
    "foreignBridge": {
        "address": "0x...",
        "deployedBlockNumber": <block number>
  1. Copy the JSON output and paste into a text file.

Token Bridge

  1. Install and run the POA Token Bridge. Go to the sokol-kovan-bridge folder and git clone && cd token-bridge

  2. Copy .env.example file cp .env.example .env

  3. Update the following variables in .env according to JSON output in step 12:

  • HOME_START_BLOCK=<block_number>
  • FOREIGN_START_BLOCK=<block_number>
  1. Use Docker to start Bridge Processes:

Initial Build & Run:
VALIDATOR_ADDRESS=<validator address> VALIDATOR_ADDRESS_PRIVATE_KEY=<validator address private key> docker-compose up -d --build

Subsequent Runs:
VALIDATOR_ADDRESS=<validator address> VALIDATOR_ADDRESS_PRIVATE_KEY=<validator address private key> docker-compose up --detach

Note: To access the output, view the Docker logs:

  • chdir to the directory where docker-compose.yml used to run the bridge instance is located
  • View the logs : docker-compose logs

Bridge UI

The Bridge UI is an optional user interface.

  1. Return to the sokol-kovan-bridge folder and git clone && cd bridge-ui

  2. Update submodules git submodule update --init --recursive

  3. Install dependencies npm install
    Note: The bridge UI configuration should be performed with an unprivileged Linux account or with the following flag npm install --unsafe-perm. More information

  4. Create a .env file from the example file cp .env.example .env

  5. Insert appropriate addresses and networks from previous installation steps. Other parameters do not need to change for this tutorial, but can be viewed in the bridge-ui repo. Save the file.

   # HomeBridge address:
   # ForeignBridge address:
   # https public RPC node for Foreign network
   # public RPC node for Home network 
  1. Build the UI npm run start. The default local interface should be deployed on http://localhost:3000/

Transfer Tokens

  1. Using a web3 wallet like Nifty Wallet, import wallet #1 and add the new token.

    • Click on Account and scroll down to Import Account
    • Type in Private Key
    • Switch to Kovan TestNet
    • Click on Tokens -> Add Tokens
    • Enter ERC20 Address from step 15
  2. Send an amount of tokens to wallet #2. You can use MEW to send these tokens. You will use this second wallet as an account to interact with the bridge - using the same wallet that is setup for validation may cause incompatibility issues.

    • Login to
    • Use private key to access the wallet
    • Connect to Kovan Network
    • Scroll down to token balances
    • Enter in ERC20 Address, Token Name, and 18 for decimal count
    • Enter in Amount of tokens to send and address for wallet #2
    • Send tokens
  3. Login to wallet #2 (login and import into Nifty wallet) to interact with the bridge. Be sure you select the correct network from the Nifty Wallet dropdown for POA Sokol and Kovan testnet.


Bridge-UI Compilation error

I removed “Example” from the title and added tag “tutorial”
Tags are now enforceable for all new posts.

@akolotov please review the tutorial



I have a question regarding step 8, because I had the following errors. Any help would be appreciated.

Deployment of token for testing environment started

[Foreign] deploying ERC20 token
TypeError: Cannot read property ‘length’ of undefined
at sendNodeRequest (/contracts/deploy/src/deploymentUtils.js:113:36)
at process._tickCallback (internal/process/next_tick.js:189:7)
Error: TypeError: Cannot read property ‘status’ of undefined
at deployContract (/contracts/deploy/src/deploymentUtils.js:49:32)
at process._tickCallback (internal/process/next_tick.js:189:7)

1 Like


@jianmliu what do you use as RPC URL? This error happens when the deployment script cannot get access to the RPC node.



Thanks and I figured out that it was due to fact that the account was not funded. It seems that account should be funded with both tokens on the two chains. Meanwhile, when I tried to set up the bridge ui, it complains

TypeError: Cannot read property ‘toWei’ of undefined



> 1 | const { toWei } = require('web3').utils

Could you help me on this issue? Thanks very much



What node version are you using? Could you share entire log of npm install? Can you try the develop branch - it includes some fixes related to web3 library.