Deplying Hyperlane Warp Routes for ERC20 Token Bridging

A. Objective

In this guide, we will show how to bridge WETH10 from L1 (Sepolia) to L2 (Rollup Testnet) using Hyperlane Warp Routes.

These steps apply to all other ERC-20 tokens on any AltLayer Rollup

B. Contract Deployment

For this tutorial, we will use the following addresses

Deployer: 0xC6391bAb6AfCc5dBDcbafA57C3340BbF9C800d33

Validator: 0x7C19F05dB313D89dea09781DF2c076EC1132C423

Relayer: 0x5d3C6567683d9467B2c317A02ddA5B97E20F6029

You will need to generate your own addresses for the following role. Please ensure they are funded with gas tokens

To begin, clone the hyperlane repo https://github.com/hyperlane-xyz/hyperlane-deploy and run

yarn install

Modify config/chains.ts with your chain configuration

The following is a sample configuration with L1 being Sepolia and L2 being AltLayer Testnet.

import { ChainMap, ChainMetadata } from '@hyperlane-xyz/sdk';

export const chains: ChainMap<ChainMetadata> = {
  sepolia: {
    name: 'sepolia',
    chainId: 11155111,
    nativeToken: {
      name: 'ether',
      symbol: 'ETH',
      decimals: 18,
    },
    publicRpcUrls: [
      {
        http: 'https://eth-sepolia.g.alchemy.com/v2/api-key',
      },
    ],
  },
  testnet: {
    name: 'testnet',
    chainId: 9997,
    nativeToken: {
      name: 'ALT',
      symbol: 'ALT',
      decimals: 18,
    },
    publicRpcUrls: [
      {
        http: 'https://testnet-rollup-api.altlayer.io',
      },
    ],
  },
};

Modify config/multisig_ism.ts. In this example, we will set it to 1. In the production environment, a higher threshold should be set.

import { ChainMap, MultisigIsmConfig } from '@hyperlane-xyz/sdk';

export const multisigIsmConfig: ChainMap<MultisigIsmConfig> = {
  // ----------- Your chains here -----------------
  sepolia: {
    threshold: 1,
    validators: [
      '0x7C19F05dB313D89dea09781DF2c076EC1132C423', // validator address
    ],
  },
  testnet: {
    threshold: 1,
    validators: [
      '0x7C19F05dB313D89dea09781DF2c076EC1132C423', // validator address
    ],
  },
};

Run the following command using the deployer private key to deploy the contracts on L1 (Sepolia)

yarn ts-node scripts/deploy-hyperlane.ts --local testnet \
  --remotes sepolia \
  --key <deployer private key>

Run the following command using the deployer private key to deploy the contracts on L2

yarn ts-node scripts/deploy-hyperlane.ts --local sepolia \
  --remotes testnet \
  --key <deployer private key>

After running the command, some artifacts will be produced. Here's a sample

  1. artifacts/addresses.json

{
  "testnet": {
    "multisigIsm": "0x63aC18CFB9207ba750393DaB7509F1aAE4F35B97",
    "proxyAdmin": "0x6aa797913c88b03718044924DDC16A3Ee0f37A3F",
    "mailbox": "0x190c91b92c95DEDf09a954aC538CC926945d81Fb",
    "validatorAnnounce": "0xFc9D5Cf9bdd090182968aF7D478Ee9dfF06dD909",
    "testRecipient": "0xD08D64aF4ed573845861Abcd89860ae8889ed12D",
    "storageGasOracle": "0xAd2310dBcB8aae371082831dA587e96BB1E51daD",
    "interchainGasPaymaster": "0xe7A1f91B9049cC4D1a82C271aF4D6CCA9AFeB20e",
    "defaultIsmInterchainGasPaymaster": "0xd51A3FBAC4424a2a0C330686020341FD70ADc9c5"
  },
  "sepolia": {
    "multisigIsm": "0x63aC18CFB9207ba750393DaB7509F1aAE4F35B97",
    "testRecipient": "0x6aa797913c88b03718044924DDC16A3Ee0f37A3F",
    "proxyAdmin": "0x5324d2355c2cB034cE5dCBCB3Fbb868DBa8C982a",
    "storageGasOracle": "0x190c91b92c95DEDf09a954aC538CC926945d81Fb",
    "interchainGasPaymaster": "0x65Ff5C940Dd9f11BE608e44602370B347f581B2b",
    "defaultIsmInterchainGasPaymaster": "0x34407596169673017849399F332819aa5ef0e565",
    "mailbox": "0xd51A3FBAC4424a2a0C330686020341FD70ADc9c5",
    "validatorAnnounce": "0x2c29105f892e6A7F8E0547A9423861734c6352D0"
  }
}
  1. artifacts/agent_config.json

{
  "chains": {
    "sepolia": {
      "name": "sepolia",
      "domain": 11155111,
      "addresses": {
        "mailbox": "0xd51A3FBAC4424a2a0C330686020341FD70ADc9c5",
        "interchainGasPaymaster": "0x65Ff5C940Dd9f11BE608e44602370B347f581B2b",
        "validatorAnnounce": "0x2c29105f892e6A7F8E0547A9423861734c6352D0"
      },
      "protocol": "ethereum",
      "finalityBlocks": 1,
      "connection": {
        "type": "http"
      },
      "index": {
        "from": 3728779
      }
    },
    "testnet": {
      "name": "testnet",
      "domain": 9997,
      "addresses": {
        "mailbox": "0x190c91b92c95DEDf09a954aC538CC926945d81Fb",
        "interchainGasPaymaster": "0xe7A1f91B9049cC4D1a82C271aF4D6CCA9AFeB20e",
        "validatorAnnounce": "0xFc9D5Cf9bdd090182968aF7D478Ee9dfF06dD909"
      },
      "protocol": "ethereum",
      "finalityBlocks": 1,
      "connection": {
        "type": "http"
      },
      "index": {}
    }
  }
}

Modify config/warp_tokens.ts using values from artifacts/addresses.json. In this configuration, we filled the contract addresses of WETH10, the token we would like to bridge from L1 to L2.

import { TokenType } from '@hyperlane-xyz/hyperlane-token';

import type { WarpRouteConfig } from '../src/warp/config';

// A config for deploying Warp Routes to a set of chains
// Not required for Hyperlane core deployments
export const warpRouteConfig: WarpRouteConfig = {
  base: {
    // Chain name must be in the Hyperlane SDK or in the chains.ts config
    chainName: 'sepolia',
    type: TokenType.collateral, //  TokenType.native or TokenType.collateral
    // If type is collateral, a token address is required:
    address: '0xe67abda0d43f7ac8f37876bbf00d1dfadbb93aaa', // WETH10
    mailbox: '0xd51A3FBAC4424a2a0C330686020341FD70ADc9c5',
    interchainGasPaymaster: '0x65Ff5C940Dd9f11BE608e44602370B347f581B2b',

    // Optionally, specify owner, mailbox, and interchainGasPaymaster addresses
    // If not specified, the Permissionless Deployment artifacts or the SDK's defaults will be used
  },
  synthetics: [
    {
      chainName: 'testnet',
      mailbox: '0x190c91b92c95DEDf09a954aC538CC926945d81Fb',
      interchainGasPaymaster: '0xe7A1f91B9049cC4D1a82C271aF4D6CCA9AFeB20e',

      // Optionally specify a name, symbol, and totalSupply
      // If not specified, the base token's properties will be used

      // Optionally, specify owner, mailbox, and interchainGasPaymaster addresses
      // If not specified, the Permissionless Deployment artifacts or the SDK's defaults will be used
    },
  ],
};

Run this command using the deployer private key to deploy the wrap contracts. This will deploy the HypERC20 contracts to L2. In this example, the HypERC20 contract will be WETH10 on L2.

yarn ts-node scripts/deploy-warp-routes.ts --key <deployer private key>

After running the command, artifacts will be produced

  1. artifacts/warp-token-addresses.json

{
  "sepolia": {
    "router": "0xffA5f94329f41b9353F4ccA74Ba59D3Faed75AAe",
    "tokenType": "collateral"
  },
  "testnet": {
    "router": "0xffA5f94329f41b9353F4ccA74Ba59D3Faed75AAe",
    "tokenType": "synthetic"
  }
}
  1. artifacts/warp-ui-token-list.json

[
  {
    "chainId": 11155111,
    "name": "Wrapped Ether v10",
    "symbol": "WETH10",
    "decimals": 18,
    "type": "collateral",
    "address": "0xe67abda0d43f7ac8f37876bbf00d1dfadbb93aaa",
    "hypCollateralAddress": "0xffA5f94329f41b9353F4ccA74Ba59D3Faed75AAe"
  }
]

Last updated

#191:

Change request updated