Stack Exploder: Bridging Your Saga Chainlet Assets Across EVM Networks using Hyperlane
The Stack Exploder: Democratizing Blockchain Development using Saga’s No-Code Solutions guide delved into how you can create a chainlet using the command line based sagacli or the user-friendly Saga Web App.
But sometimes you need to collaborate with a dApp or web3 game that is on another chain, such as Ethereum or even another chainlet on Saga. Or, simply migrate assets from your game on Ethereum (or any EVM chain) to your Saga chainlet.
Crosschain functionality is becoming important in the blockchain industry because it provides seamless communication and asset transfer between disparate networks. It promotes interoperability, allowing users to access services and assets across multiple blockchains. This will unlock new opportunities for decentralized finance, gaming, and other blockchain applications.
All this is possible using Hyperlane.
Hyperlane is a permissionless interoperability layer that allows smart contract developers to send arbitrary data between blockchains.
Among its functionalities, developers can utilize Hyperlane to seamlessly transfer tokens such as ERC20 (digital tokens).
In this guide, we’ll deep-dive into leveraging Hyperlane to bridge ERC20 tokens between your Saga chainlet and Sepolia, facilitating bidirectional communication.
This guide will cover:
- Deploying Hyperlane into your Saga Chainlet
- Running Validators and Relayers (using Kurtosis)
- Testing the Bridge
- Creating and deploying a Warp Route
- Interacting with the Warp Routes
The Hyperlane protocol
Users interact with the Hyperlane protocol through mailbox smart contracts, which provide an on-chain messaging interface to send and receive interchain messages.
Hyperlane adopts a modular security paradigm, granting applications the flexibility to configure and select from a range of Interchain Security Modules (ISMs). By specifying an ISM, applications can tailor the security model to suit their integration with the Hyperlane messaging interface.
Another more simple way to see the Hyperlane protocol is:
- The Hyperlane mailbox contract is like a post office, with offices open on each chain.
- Every post office (or Hyperlane mailbox smart contract) manages both incoming and outgoing mail, ensuring that inbound correspondence is efficiently routed to individual PO boxes.
- Each application that uses Hyperlane is an owner of a unique PO box.
- The PO box owner (the app) controls the checklist (interchain security module).
- The checklist serves as a comprehensive list of criteria, encompassing security model logic and message parameters. It acts as the arbiter, determining whether a message meets the requirements for delivery to the designated PO box.
- Clerks (validators) are responsible for signing off on messages and holding PO box keys.
- Mailmen (relayer) deliver messages to destination post offices (chains).
- If message contents pass the criteria on the checklist (ISM) then the message is delivered.
In essence, the flow of Hyperlane operates as follows:
Deploy Hyperlane into your chainlet
Please note:
The wallet you use to deploy will serve as your validator and relayer. As such, it is strongly recommended to create another wallet instead of using your Genesis chainlet wallet. You will, however, have to send some chainlet tokens and SepoliaETH to the new wallet to run this tutorial.
Setup
First, install the Hyperlane CLI from NPM (Node 16 or newer is required).
npm install -g @hyperlane-xyz/cli
Next, we need to create a custom chain configurations using your Saga chainlet info.
Any chains that are already included in the Hyperlane SDK won’t require a chain config (but you can optionally create one if you want to override default settings)
Running the following command will display the default SDK chains:
hyperlane chains list
You can define the chain configuration manually using JSON or YAML (you can view my example or the example provided by Hyperlane), or create them with the following command:
hyperlane config create chain
In the end you should have chains.yaml like this:
<chianlet_name>:
chainId: <chainlet_chainId>
domainId: <chainlet_chainId>
name: <chainlet_name>
protocol: ethereum
rpcUrls:
- http: <chainlet_rpcUrl>
You should add also (it will be useful later):
isTestnet: true # If you created the chainlet on the testnet, otherwise you don't even need this line
nativeToken:
name: <your_chainlet_token_name>
symbol: <your_chainlet_token_symbol>
decimals: 18
For this tutorial it will be:
omegachain:
name: omegachain
chainId: 1712771388991266
domainId: 33333
protocol: ethereum
rpcUrls:
- http: https://omegachain-1712771388991266-1.jsonrpc.testnet.sagarpc.io
# Optional fields, not required for Hyperlane deployments but useful for later
isTestnet: true
nativeToken:
name: ome
symbol: ome
decimals: 18
⚠️ Note: You need to change domainId to another number of your choice that is not a chainlet ID. The reason for that is you will probably get an ‘Error: value out-of-bounds’ (because the chainId is too big).
Now the Hyperlane CLI is ready to interact with your Saga chainlet. However, it also needs to know how to configure your Interchain Security Module (ISM).
To create a multisig ISM config, you have to define it manually using JSON or YAML (you can view my example or the example provided by Hyperlane), or create it with the following command:
hyperlane config create ism
In the end you should have ism.yaml like this:
<chainlet_name>:
threshold: 1 # Number: Signatures required to approve a message
validators: # Array: List of validator addresses
- "<an_address_wallet>" #NOT your Genesis address wallet
For this tutorial it will be:
omegachain:
threshold: 1
validators:
- "0x4cDF9dd5d678E4274e5DBB902E91b80373899513"
In this guide, we will be using a 1/1 multisig with a threshold of 1.
However, if you want to explore advanced ISM configurations, you can find them in this GitHub example.
Deploy
Now that our ISM module is configured, it’s time to deploy Hyperlane contracts. To deploy use the command:
hyperlane deploy core \
--targets chain1,chain2,... \ # all the chains you want to bridge between
--chains $CHAIN_CONFIG_FILE \ # path to chains.yaml config e.g. ./configs/chains.yaml
--ism $MULTISIG_CONFIG_FILE \ # path to ism.yaml config e.g. ./configs/ism.yaml
--artifacts $PREDEPLOYED_ARTIFACT_FILE \ # (optional) in case you want to reuse contracts you've already predeployed
--out $OUT_DIR \ # (optional) deployment contract artifacts
--key $WALLET_PRIVATE_KEY
For this tutorial it will be:
hyperlane deploy core \
--targets sepolia,omegachain \ # We are bridging between sepolia and omegachain chains
--chains ./configs/chains.yaml \ # The chain config file
--ism ./configs/ism.yaml \ # The ISM module config file
--key 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
# This private key is from a test wallet and only for the purpose of this guide. Never share your private keys.
If the deployment went well, you should see an output similar to this in your terminal:
Hyperlane CLI
Hyperlane permissionless core deployment
----------------------------------------
Reading file configs in ./configs/chains.yaml
All chain configs in ./configs/chains.yaml are valid
Deployments can be totally new or can use some existing contract addresses.
? Do you want use some existing contract addresses? no
All multisig configs in ./configs/ism.yaml are valid
Found configs for chains: sepolia, omegachain
Deployment plan
===============
Transaction signer and owner of new contracts will be 0x4cDF9dd5d678E4274e5DBB902E91b80373899513
Deploying to sepolia, omegachain
There are several contracts required for each chain but contracts in the Hyperlane SDK will be skipped
? Is this deployment plan correct? yes
Running pre-flight checks...
Chains are valid ✅
Signer is valid ✅
Balances are sufficient ✅
All systems ready, captain! Beginning deployment...
Contract addresses will be written to artifacts/core-deployment-2024-02-28-09-12-01.json
Agent configs will be written to artifacts/agent-config-2024-02-28-09-12-01.json
Deploying ISM factory contracts
Start deploy to sepolia,omegachain
===============
# A looong list of smart contract deployments
===============
Writing agent configs
Agent configs written
Deployment is complete!
Contract address artifacts are in artifacts/core-deployment-2024-02-28-09-12-01.json
Agent configs are in artifacts/agent-config-2024-02-28-09-12-01.json
Deployment contract artifacts will be written to to the artifacts/
folder by default. The deployer will create two timestamped files:
agent-config-{timestamp}.json
which contains the data needed to run Hyperlane agents for the next step (my agent config obtained).core-deployment-{timestamp}.json
which contains the addresses of core contracts, , organized by chain (my core deployment obtained).
Run validators and relayer
Validators monitor the Mailbox contract, while relayers ensure messages reach their intended recipients successfully.
In this guide, we will use Kurtosis, which is a single-click validator and relayer deployment in the cloud, partnered with Hyperlane.
To get started, use the deploy kurtosis-agents
command to generate a link for configuring your Kurtosis deployment.
hyperlane deploy kurtosis-agents
Follow the prompts and then click on the Kurtosis Cloud link provided by the command output.
If this is your first time using Kurtosis Cloud, you’ll need to sign in with Github and Kurtosis will provision a remote cloud instance for your validator and relayer.
When you click the Kurtosis Cloud link, a prefilled configuration screen will pop up in your browser with all your relayer and validator information needed.
If you encounter issues deploying agents on Kurtosis Cloud through the CLI, you can manually input this information by:
- Signing into Kurtosis Cloud.
- Clicking
Run
on the Hyperlane Package. - Filling in the configuration modal with your
agent-config-{timestamp}.json
.
Then click Run
to deploy your relayer and validator, if everything is done correctly you’ll see a green check mark!
Congratulations! You’ve now deployed your own relayer and validator with Kurtosis!
You can access information about your relayer and validator deployment, including logs, by navigating to the Overview
tab.
Before we proceed to the next step, we recommend waiting for 15 minutes to allow the relayer to sync with Sepolia and your chainlet network.
Alternatively, you can go to Relayer > Logs and check for the synced
tag on both chains before proceeding to the next step
Testing the bridge by sending a message
Now it’s time to test if the bridge works.
To test it, we are going to send a message from our chainlet to Sepolia.
Initiate the message using the CLI. It will prompt you to select a set of core deployment artifacts. Choose the core-deployments
JSON file that you created in the Deploy section.
hyperlane send message --key $PRIVATE_KEY
The send message command will inform you when the message is dispatched. After a short wait, you’ll receive a confirmation of delivery.
If the message delivery times out, there may be an issue with the Validator or Relayer setup outlined in the previous steps.
You can see the transaction on Hyperlane Explorer. In case the transaction doesn’t appear on the Hyperlane explorer, you can check if the message arrived on the destination chain (Sepolia in this case) through the recipient address in the events logs, as shown below.
Deploy a Warp Route (Bridging ERC-20)
Warp Routes are contracts that allow any ERC-20, ERC-721 to move effortlessly between chains.
⚠️ Note: At the time of creating this blog post (Hyperlane CLI version 3.10.0), performing a warp for ERC721 tokens and consequently bridging ERC721 tokens between chains is not possible due to an error occurring when executing the command
hyperlane config create warp
However, it’s important to note that the difference in creating ERC20 and ERC721 tokens is minimal. In fact, it’s just a matter of setting theisNFT
variable to true.
If you wish to bridge an NFT between chains, please check the Hyperlane repository to see if they have released a version that properly supports NFT bridging.
Warp Routes represent Hyperlane’s permissionless token bridging module, offering a distinct approach to token bridging. Unlike conventional token wrapping protocols, Warp Routes are secured by Interchain Security Modules (ISM).
Collateral vs Synthetic chain
Before jumping into creating Warp Routes, let’s first understand the difference between Collateral vs Synthetic chains so you can understand the architecture of the Warp Route.
- Collateral chain: the origin chain where you deposit any ERC-20 or ERC-721 token to a HypCollateral contract.
- Synthetic chain: the destination chains between which HypERC-20/HypERC-721 tokens can flow. HypERC-20/HypERC-721 tokens are minted 1:1 from tokens locked as collateral.
Warp Route architecture overview
Warp Route contracts transfer value between chains by initially locking tokens as collateral on the origin chain (Collateral chain) and then minting the tokens as wrapped tokens (HypERC-20/HypERC-721 synthetics) which are transferred to the destination chain (Synthetic chain).
The locked tokens can be returned to the origin chain at any time to reclaim the initial ERC-20/ERC-721 tokens (collateral).
Warp Routes use Hyperlane Mailbox contracts which enable communication between chains.
Warp Route Token Flow
As a developer, you can transfer any ERC-20/ERC-721 contract on the Collateral chain which is wrapped by the HypERC20Collateral/HypERC721Collateral contract to mint new HypERC-20/HypERC-721 tokens.
The Mailbox contract on the collateral chain forwards the data as a message to the relayer, which then passes the message data to the Interchain Security Module (ISM) for verification.
Once verified, the ISM sends the information back to the Mailbox, which then forwards the data to the HypERC20/HypERC721 contract on the synthetic chain. This contract mints and reflects the value 1:1 of the ERC-20/ERC-721 contract on the Collateral (origin) chain.
Warp Routes require gas fees to function, which are paid as part of outbound messages. The Router estimates the gas fee for the transfer before transferring the HypERC20/HypERC721 tokens to the destination chains.
Therefore, it’s necessary to have a gas token, such as the chainlet native token (in this case, omegachain token), or any other native token (in this case, SepoliaETH), on the Collateral (origin) chain before deploying or using a Warp Route.
How to deploy Warp Route
For this guide, we will use these ERC20 tokens as examples (deployed on omegachain chainlet).
The easiest way to create a Warp Route is with the CLI’s config command. Alternatively, you can define it manually using YAML (you can see my example or the Hyperlane example)
hyperlane config create warp
Base (Collateral/Origin)
Your config must have exactly one base
entry. Here you will configure details about the token for which you are creating a Warp Route:
- chainName: Set this equal to the chain (in our case the Chainlet name) on which your token exists
- type: Set this to
TokenType.collateral
to create a Warp Route for an ERC20/ERC721 token. - address: If using
TokenType.collateral
, the address of the ERC20/ERC721 contract for which to create a route. - isNft: If using
TokenType.collateral
for an ERC721 contract, set totrue
.
Synthetics
Your config must have at least one synthetics
entry. Here you will configure details about the remote chains supported by your Warp Route.
(For the optional fields, you can check Hyperlane docs)
- chainName: Set this equal to the chain on which you want a wrapped version of your token (our case Sepolia)
In the end your should have warp-route-deployment.yaml like this:
base:
chainName: <chainlet_name>
type: collateral
address: "<contract_address_of_the_erc20/erc721>"
isNft: false # if is erc721 set to true
synthetics:
- chainName: sepolia
In this tutorial:
base:
chainName: omegachain
type: collateral
address: "0x21198920Bc56b73DBfbF547a6Ee8118A515Ce04D"
isNft: false
synthetics:
- chainName: sepolia
Deployment
Run the following command to initiate the deployment of the Warp Route:
hyperlane deploy warp
Once finished, the CLI will create two new JSON artifact files: warp-route-deployment-{timestamp}
and warp-config-{timestamp}
.
The first contains just addresses for the newly deployed Warp router contracts.
The second is a config file for the Warp UI, which you can use for the next step.
In my case warp-ui-token-config files are:
Interact with the Warp Routes
After you’ve successfully deployed a Warp Route, you can interact with your routes by forking the Hyperlane Warp UI template (I also provide my repository for better understanding, although it is very similar to the original).
With this repo you can easily “connect” your warp routes:
- Install dependencies with
yarn
- Copy all the value from the warp-config-{timestamp} file and paste them into .src/consts/tokens.yaml
3. Add your chainlet config by copying the chains.yaml file from the hyperlane config create chain
section. Additionally, include nativeToken information such as name, symbol, and decimals.
4. Lastly build the project using yarn build
and then yarn dev
Now let’s the magic happen 🪄 ✨
Here, you can see that this wallet has 2000 OmegaERC20 (OE20 for short) in the Omegachain chainlet network.
However, this token is not present in Sepolia Etherscan.
In the Hyperlane Warp UI, I bridge 1000 OmegaERC20 tokens from Omegachain to Sepolia.
You can observe that the process requires two transactions:
- The approve transaction, where you allow the HypERC20Collateral smart contract to utilize your tokens.
- The transfer transaction, where you transfer 1000 OE20 to the HypERC20Collateral after that you should know the flow 😉 .
After a few minutes, you’ll notice that 1000 OmegaERC20 tokens are in the Sepolia network.
For better understanding, I will provide a video demonstrating all of these steps:
The entire code for this guide is available in these github repos:
- Hyperlane-saga: https://github.com/chefleo/hyperlane-saga/tree/warps/omegachain
- Hyperlane Warp UI: https://github.com/chefleo/hyperlane-saga_ui_warp
Conclusion
Congratulations! You have effortlessly bridged ERC20 tokens between your Saga chainlet and the Ethereum chain. This guide is a preview into how you can evolve your chainlet to incorporate a “portal” that establishes connections with other chains. you have now unblocked a realm of boundless possibilities.
For more details around how you can Unblock your application, follow us on X, join our Discord and Telegram and subscribe to our Medium.