Hyperlane — Building a blockchain cross-chain bridge

Jeff P
18 min readApr 6, 2024

The complete guide

I recently came across the Hyperlane bridging solution and whilst the docs are pretty good, I personally found a couple of challenges along the way with things that weren’t entirely clear to me, forcing me to go off and do research which slowed things down quite a bit. I thought I’d cover deploying a bridge from start to finish to show how I personally did it.

Setting up keys

The first thing to do is to setup some KMS keys using AWS (Amazon Web Services).

AWS Key Management Service (KMS) gives you centralized control over the cryptographic keys used to protect your data. The service is integrated with other AWS services making it easier to encrypt data you store in these services and control access to the keys that decrypt it.

If you don’t have an AWS account you’ll need to create one, but if you already have one, then login:

Creating an IAM user

If you’re not automatically taken to the IAM Dashboard, you can get there by clicking the “services” button, then going to IAM

Now head to the “Users” section of Access management:

We’ll click on the “Create user” button, and then provide a username in the format of “hyperlane-validator-[blockchain]” so in my case, I want to validate Binance Smart Chain (bsc) so I will use “hyperlane-validator-bsc” and then click “Next”

Ensure the option to add the user to the group is already selected, and click “Next” again.

Finally click “Create user” and your new user will be created

Now click on the user you just created, and open up the “Security Credentials” tab…

Scroll down to the “Access Keys” section, and click on “Create Access Key”

The option we want to select is “Application running OUTSIDE AWS” and then click “Next”

Give a description if you want to, else just click “Create access key”

Here you will see the key pair created….one is your public Access key, which is visible, and the other is your Secret (private) access key which is hidden unless you click on “Show” to view. It is extremely important that you don’t lose this information, so the best option is to click the button for “Download .csv file” to save a copy of your key pair.

Once you’ve done that, click “Done”.

Your keys are now created.

Now that the IAM User is created, the next step is to create the KMS keys themselves

Create KMS Keys

Now head back to the “services” button, and go to “Key Management Service”

First set your region to the region you operate in. In my case it’s London, so my region is eu-west-2

Now go to “Customer managed keys” and click on “Create key”

The options we want for our key are:

key type: “Asymmetric”

key usage: “Sign and verify”

key spec: “ECC_SECG_P256K1”

Click “Next”

Now we need to provide an alias, which should be “hyperlane-validator-signer-[blockchain]” so in my case it is “hyperlane-validator-signer-bsc

Click “Next”

Now we need to give the IAM user we created in the previous step the necessary admin permissions, and click “Next”.

Now do the same thing for key users, and click “Next”.

Now scroll down to the bottom and click “Finish”

Obtaining an address from an AWS KMS Key

The next thing we’ll do is obtain the address from our AWS Key. In order to do this, we’ll need to run a script.

Firstly, head to this Github repository:

Now download/clone/fork the repository and get a copy of it onto your local machine.

Navigate to the folder in your command prompt and install all the necessary dependencies with “yarn”

Also install typescript and ts-node globally with:

yarn global add typescript ts-node

We now need to set the following variables:

set ACCESS_KEY_ID=AKIAUPNQ6GGBTVSMH2HQ (replace with your IAM key)
set SECRET_ACCESS_KEY=/9143YVOErXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (replace with your secret private key)
set REGION=eu-west-2 (replace with your region)
set KEY_ID=ddb0e525-dc5c-4518-aa63-ec3217f09b5d (replace with your key id)

(Note you can get your Key ID by clicking on your newly created AMS KWS Key)

We set them all in the command prompt:

All that’s left to do then is run the command:

ts-node index.ts

We now have the address represented by our AWS KMS Key!

Deploying Contracts

Now that we have the required keys, we can deploy our contracts on the chains we want to bridge between.

To do this, we’ll first install the Hyplerlane Command Line Interface (CLI)

yarn global add @hyperlane-xyz/cli

Now check is all of the chains that you wish to connect are part of the current Hyperlane SDK with the following command:

hyperlane chains list

We can see that bsc is already part of the list, but we’ll also want to add another blockchain which isn’t on the list called “hyperblox”

In order to add this new (unsupported) chain, we’ll run the following command:

hyperlane config create chain

You then add the correct values for your chain when prompted:

This creates a file called ./config/chains.yaml

This is what the file looks like:

hyperblox:
name: hyperblox
chainId: 269
domainId: 269
protocol: ethereum
rpcUrls:
- http: https://hpbnode.com
blocks:
confirmations: 2
reorgPeriod: 2
estimateBlockTime: 6
transactionOverrides:
maxFeePerGas: 100000000000000000
maxPriorityFeePerGas: 100000000000000000

Create and configure Interchain Security Module (ISM)

The next thing we need to do is create our Interchain Security Module (ISM) and to do that we use the following command:

hyperlane config create ism

We will want to run a validator for each chain we’ll be connecting to, so in this case we’ll select both the “bsc” chain (already part of the Hyperlink SDK) and the newly-created custom chain “hyperblox”. To select the chains we simply use the arrow keys to move to the chains we want to use, and then press the space bar to select them…

next we’ll be prompted to set values for each chain. In the example screenshot below we were first prompted for values for the hyperblox chain. We set the threshold for signers to be 1 (only one validator needed) and then we set the validator address to be the address that we obtained by running the script to see what our AWS KMS address was.

Then we moved onto the bsc chain, where we selected NO for using existing validators, as we want to use our own validator here, and then once again set the threshold to 1 and the same validator address from our AWS KMS key.

This writes a new file to ./configs/ism.yaml

Here’s the contents of the ism.yaml file:

hyperblox:
threshold: 1
validators:
- "0xcc5840b100042a27d0e3bb06700f62371101a935"
bsc:
threshold: 1
validators:
- "0xcc5840b100042a27d0e3bb06700f62371101a935"

Deploying the contracts

Now that we’ve created the necessary config files, we’re ready to deploy all of the necessary contracts on both blockchains (bsc and hyperblox)

We start with the following command:

hyperlane deploy core

You’ll be prompted for a private key for an account that has funds on it for both chains….This is NOT the same as the validator address! The recommended option here is to create a new EVM wallet address, then obtain the private key for it, then fund it with enough funds (on both chains!) to cover the deployment of all the new smart contracts required. So in my case, I will fund my new wallet address with some BNB (for the bsc chain) and some HPB (for the Hyperblox chain) so that the smart contracts can be deployed.

Once that’s done, I’ll paste the private key for this funded wallet into the deploy script, and I’ll be prompted to select the chains that we’re going to deploy the smart contracts to (in my case, bsc and hyperblox)

It will ask if we want to utilize any existing smart contract addresses…..as this is our first deployment, we’ll select “no” and when prompted, we’ll select the ism.yaml file we just created.

You now need to be patient as there are a lot of smart contracts that need to be deployed, so it might take anywhere from 5–10 minutes to deploy them all.

Once complete, there should now be a new artifacts folder with an “agent-config” and “core-deployment” file in it. Let’s look at both files:

agent-config-2024–04–06–15–31–17.json

{
"chains": {
"bsc": {
"blockExplorers": [
{
"apiUrl": "https://api.bscscan.com/api",
"family": "etherscan",
"name": "BscScan",
"url": "https://bscscan.com"
}
],
"blocks": {
"confirmations": 1,
"estimateBlockTime": 3,
"reorgPeriod": 15
},
"chainId": 56,
"displayName": "Binance Smart Chain",
"displayNameShort": "Binance",
"domainId": 56,
"gasCurrencyCoinGeckoId": "binancecoin",
"gnosisSafeTransactionServiceUrl": "https://safe-transaction-bsc.safe.global/",
"name": "bsc",
"nativeToken": {
"decimals": 18,
"name": "BNB",
"symbol": "BNB"
},
"protocol": "ethereum",
"rpcUrls": [
{
"http": "https://rpc.ankr.com/bsc"
},
{
"http": "https://bsc.drpc.org"
},
{
"http": "https://bscrpc.com"
}
],
"aggregationHook": "0x402Fc106576462a892355d69ACF03D46A888ae88",
"domainRoutingIsmFactory": "0xe6Af5720d34213C805C08e2470aea979e3F72F75",
"fallbackRoutingHook": "0x237E81f87F57Badad9e09f13CC676D986cA852e7",
"interchainAccountIsm": "0xB274Bbbc1df5f1d1763216A93d473fde6f5de043",
"interchainAccountRouter": "0x4BBd67dC995572b40Dc6B3eB6CdE5185a5373868",
"interchainGasPaymaster": "0x78E25e7f84416e69b9339B0A6336EB6EFfF6b451",
"interchainSecurityModule": "0x9B81281CfE7986df6Ddb882eACCEfb5BD9fDabD2",
"mailbox": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4",
"merkleTreeHook": "0xFDb9Cd5f9daAA2E4474019405A328a88E7484f26",
"pausableHook": "0x7DBdAd1b4A922B65d37d7258a4227b6658344b7f",
"protocolFee": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367",
"proxyAdmin": "0x65993Af9D0D3a64ec77590db7ba362D6eB78eF70",
"staticAggregationHookFactory": "0xe70E86a7D1e001D419D71F960Cb6CaD59b6A3dB6",
"staticAggregationIsmFactory": "0x38B3878c4fb44d201DA924c4a04bae3EE728c065",
"staticMerkleRootMultisigIsmFactory": "0xfADBc81Ca8A957F1Bf7c78bCc575b28DBDE042b6",
"staticMessageIdMultisigIsmFactory": "0x4B1d8352E35e3BDE36dF5ED2e73C24E35c4a96b7",
"storageGasOracle": "0x91d23D603d60445411C06e6443d81395593B7940",
"testRecipient": "0x4Ef885b669D49Ea75b0BaEF37c8cBf975579277f",
"testTokenRecipient": "0x85ac1164878e017b67660a74ff1f41f3D05C02Bb",
"timelockController": "0x0000000000000000000000000000000000000000",
"validatorAnnounce": "0x7024078130D9c2100fEA474DAD009C2d1703aCcd",
"hyperblox": {
"messageIdMultisigIsm": "0xaD30611c70894ed91D6269f25A38816AAf427f61",
"merkleRootMultisigIsm": "0xfF8909986CA05E339E2CfbA3886ADC2B48621623",
"staticAggregationIsm": "0x26E906c669a0f1C929393D97f96aF197d8856aDF"
},
"domainRoutingIsm": "0x9B81281CfE7986df6Ddb882eACCEfb5BD9fDabD2",
"customHook": "0xFDb9Cd5f9daAA2E4474019405A328a88E7484f26",
"index": {
"from": 32893043
}
},
"hyperblox": {
"name": "hyperblox",
"chainId": 269,
"domainId": 269,
"protocol": "ethereum",
"rpcUrls": [
{
"http": "https://hpbnode.com"
}
],
"blocks": {
"confirmations": 2,
"reorgPeriod": 2,
"estimateBlockTime": 6
},
"staticMerkleRootMultisigIsmFactory": "0x06ba14B1bc966A5bCaE8971614407F85d59C8433",
"staticMessageIdMultisigIsmFactory": "0x906225e55fB7E8924023CE33e39fbb97d34751de",
"staticAggregationIsmFactory": "0xF0B563ace9430Bc0f7235315aa1d5808063AE835",
"staticAggregationHookFactory": "0xa70eeE19f7df3De516eCBe6E5244af28Ca025aDb",
"domainRoutingIsmFactory": "0x0A79F6F75352869F691B39989A9f3BE6FF487E84",
"interchainSecurityModule": "0x0364b76482dB2b097a968Bb3d03F73004D46e64b",
"bsc": {
"messageIdMultisigIsm": "0x725F99E6845bc6C903559855F024A279c467d683",
"merkleRootMultisigIsm": "0x59a4Fd391FC693936AE934bDF73E2C530e65f9bD",
"staticAggregationIsm": "0x61e5b585fFfD2082ddF1626CfaD13DE40Eb7e59B"
},
"domainRoutingIsm": "0x0364b76482dB2b097a968Bb3d03F73004D46e64b",
"merkleTreeHook": "0x707701e854456D447ec27406846AaC3e809443dd",
"protocolFee": "0xC604bf434c0E54C694BB34d2A2fdA62395bb1dB3",
"testRecipient": "0x7ff9fb1AfB490f74E6222CA4aFE75a07bcaA87aB",
"mailbox": "0x88493e72a7024bF7A161db31102a478DE96c8f9C",
"proxyAdmin": "0xFF23d47E244Ca06FAb5de82624ed5A948Ccf74f7",
"validatorAnnounce": "0x50eE1bB09F9A929d47bCdF7b524cEFe612e46282",
"interchainGasPaymaster": "0x0000000000000000000000000000000000000000",
"index": {
"from": 19953931
}
}
},
"defaultRpcConsensusType": "fallback"
}

core-deployment-2024–04–06–15–31–17.json

{
"hyperblox": {
"staticMerkleRootMultisigIsmFactory": "0x06ba14B1bc966A5bCaE8971614407F85d59C8433",
"staticMessageIdMultisigIsmFactory": "0x906225e55fB7E8924023CE33e39fbb97d34751de",
"staticAggregationIsmFactory": "0xF0B563ace9430Bc0f7235315aa1d5808063AE835",
"staticAggregationHookFactory": "0xa70eeE19f7df3De516eCBe6E5244af28Ca025aDb",
"domainRoutingIsmFactory": "0x0A79F6F75352869F691B39989A9f3BE6FF487E84",
"interchainSecurityModule": "0x0364b76482dB2b097a968Bb3d03F73004D46e64b",
"bsc": {
"messageIdMultisigIsm": "0x725F99E6845bc6C903559855F024A279c467d683",
"merkleRootMultisigIsm": "0x59a4Fd391FC693936AE934bDF73E2C530e65f9bD",
"staticAggregationIsm": "0x61e5b585fFfD2082ddF1626CfaD13DE40Eb7e59B"
},
"domainRoutingIsm": "0x0364b76482dB2b097a968Bb3d03F73004D46e64b",
"merkleTreeHook": "0x707701e854456D447ec27406846AaC3e809443dd",
"protocolFee": "0xC604bf434c0E54C694BB34d2A2fdA62395bb1dB3",
"testRecipient": "0x7ff9fb1AfB490f74E6222CA4aFE75a07bcaA87aB",
"mailbox": "0x88493e72a7024bF7A161db31102a478DE96c8f9C",
"proxyAdmin": "0xFF23d47E244Ca06FAb5de82624ed5A948Ccf74f7",
"validatorAnnounce": "0x50eE1bB09F9A929d47bCdF7b524cEFe612e46282"
},
"bsc": {
"staticMerkleRootMultisigIsmFactory": "0xfADBc81Ca8A957F1Bf7c78bCc575b28DBDE042b6",
"staticMessageIdMultisigIsmFactory": "0x4B1d8352E35e3BDE36dF5ED2e73C24E35c4a96b7",
"staticAggregationIsmFactory": "0x38B3878c4fb44d201DA924c4a04bae3EE728c065",
"staticAggregationHookFactory": "0xe70E86a7D1e001D419D71F960Cb6CaD59b6A3dB6",
"domainRoutingIsmFactory": "0xe6Af5720d34213C805C08e2470aea979e3F72F75",
"interchainSecurityModule": "0x9B81281CfE7986df6Ddb882eACCEfb5BD9fDabD2",
"hyperblox": {
"messageIdMultisigIsm": "0xaD30611c70894ed91D6269f25A38816AAf427f61",
"merkleRootMultisigIsm": "0xfF8909986CA05E339E2CfbA3886ADC2B48621623",
"staticAggregationIsm": "0x26E906c669a0f1C929393D97f96aF197d8856aDF"
},
"domainRoutingIsm": "0x9B81281CfE7986df6Ddb882eACCEfb5BD9fDabD2",
"merkleTreeHook": "0xFDb9Cd5f9daAA2E4474019405A328a88E7484f26",
"protocolFee": "0xA8Aa5f14a5463a78E45CC068F11c867949F3E367",
"customHook": "0xFDb9Cd5f9daAA2E4474019405A328a88E7484f26",
"testRecipient": "0x4Ef885b669D49Ea75b0BaEF37c8cBf975579277f",
"mailbox": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4",
"proxyAdmin": "0x65993Af9D0D3a64ec77590db7ba362D6eB78eF70",
"validatorAnnounce": "0x7024078130D9c2100fEA474DAD009C2d1703aCcd"
}
}

Run validators

The next step is to run some validators. We require one validator per chain, so in our case we’ll run two validators (one for bsc and one for hyperblox) — The validators will “listen” for transactions from the Hyperlane mailbox on each chain, and then validate when required.

On the Hyperlane docs this is where I personally got a bit confused, as the docs provide two options here….one to deploy validators with a cloud solution called Kurtosis, and another to deploy your own agents (either locally or via AWS services) — What I didn’t realize is that the Kurtosis option isn’t viable for a production environment as you need to paste in a private key for your validator (they don’t support AWS KMS) but they don’t currently allow for security via a secret .env file, so therefore it’s an insecure option only useful for testing between testnets.

So we’ll focus on creating our own validator agents using AWS.

First of all, switch to “EC2” in AWS services…

Set your region to the correct local region (my is eu-west-2) and then click on “Launch Instance”

We’ll give the instance a name of “hyperlane” and select ubuntu as the image type:

Leave everything else as default, then scroll down and click “Launch Instance”

You can setup a key pair for access when prompted (useful for connectivity via putty) but in my case, I’ll choose not to use a key pair for connectivity.

Next you’ll see the instance created:

Now click on “Connect to Instance”

you’ll then connect to the ubuntu command line:

Setting up an AWS S3 bucket

Before we proceed any further with our validator configuration, let’s quickly setup an AWS S3 storage bucket. To navigate to S3, go to services, “S3”

Now click “Create Bucket”

give your bucket a name such as hyperlane-validator-signatures-bsc

Uncheck “Block all public access” and check the first two options that block access via access control lists and acknowledge the bucket will be public:

Now click “Create Bucket”

Now navigate back to IAM in AWS…..

Click on the user we created earlier, and then click to copy the ARN

We’ll need this in a minute so paste it somewhere easily accessible such as into notepad:

arn:aws:iam::307998110083:user/hyperlane-validator-bsc

Now go back into S3 and click on the new bucket we just created, and go to the permissions tab and scroll down to bucket policy…

click the “Edit” button and you’ll see another ARN which is your Bucket ARN…

Now inside the policy window, we need to paste in the following policy, however, you’ll need to replace your user ARN and Bucket ARN details with your own:

(note the /* which must be present on some of the lines!)

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::hyperlane-validator-signatures-bsc",
"arn:aws:s3:::hyperlane-validator-signatures-bsc/*"
]
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::307998110083:user/hyperlane-validator-bsc"
},
"Action": [
"s3:DeleteObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::hyperlane-validator-signatures-bsc/*"
}
]
}

Configuring our validator

Going back to the command line of our AWS EC2 Ubuntu instance, we’re going to need our agent config files on our Ubuntu instance, so let’s first create the files and then copy the file information (from our local machine) onto our AWS instance.

We’ll start with the agent-config-2024–04–06–15–31–17.json file

nano agent-config-2024–04–06–15–31–17.json

We then copy/paste the file details from our local file into this….

Followed by pressing CTRL + X to exit, where we’ll be prompted to save, so you can press Y and then ENTER.

We’ll then be back at the terminal…. now let’s do the same for the core-deployment-2024–04–06–15–31–17.json file.

nano core-deployment-2024–04–06–15–31–17.json

Again, copy/paste the file, followed by CTRL + X to exit, then Y and then ENTER

You can confirm both files have been saved by using the command ls -l

ls -l

You can also confirm your current working directory with pwd

pwd

my current working directory is /home/ubuntu

The next thing we need to do is export the CONFIG_FILES environment variable to the path of the agent config file. The command for me would be:

export CONFIG_FILES=/home/ubuntu/agent-config-2024–04–06–15–31–17.json

next we’ll export and create a directory for our validator to write its signatures to…

ubuntu@ip-172-31-40-52:~$ export VALIDATOR_SIGNATURES_DIR=/tmp/hyperlane-validator-signatures
ubuntu@ip-172-31-40-52:~$ mkdir -p $VALIDATOR_SIGNATURES_DIR

Installing Docker

Next we’ll install Docker on our Ubuntu instance. We’ll do this with the following commands:

sudo apt update

sudo apt install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"

apt-cache policy docker-ce

sudo apt install docker-ce

Now check it’s running correctly:

sudo systemctl status docker

Next we need to pull the Hyperlane docker image:

sudo docker pull gcr.io/abacus-labs-dev/hyperlane-agent:3adc0e9-20240319-152359

Now we’ll create a validator directory for the chain we’re going to validate:

mkdir -p hyperlane_db_validator_bsc

All that’s left now is to fund the AMS KWS validator wallet, and then run the validator script…..

send a very small amount of BNB to the wallet address for the validator so that it can announce itself — In my case, the AWS KMS wallet address was 0xcc5840b100042a27d0e3bb06700f62371101a935 which was obtained from running the script earlier.

Next, we’ll copy the following into the command line, remembering to replace the ACCESS_KEY_ID with your key, and the SECRET_ACCESS_KEY with your secret key, and your agent-config file with the one you saved to Ubuntu.

  sudo docker run \
-it \
-e AWS_ACCESS_KEY_ID=AKIAUPNQ6GGBTVSMH2HQ \
-e AWS_SECRET_ACCESS_KEY=/9143YVOErXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
-e CONFIG_FILES=/config/agent-config.json \
--mount type=bind,source=/home/ubuntu/agent-config-2024–04–06–15–31–17.json,target=/config/agent-config.json,readonly \
--mount type=bind,source=/home/ubuntu/hyperlane_db_validator_bsc,target=/hyperlane_db \
--mount type=bind,source=/home/ubuntu/$VALIDATOR_SIGNATURES_DIR,target=/tmp/validator-signatures \
gcr.io/abacus-labs-dev/hyperlane-agent:3adc0e9-20240319-152359 \
./validator \
--db /hyperlane_db \
--originChainName bsc \
--reorgPeriod 1 \
--validator.region eu-west-2 \
--checkpointSyncer.region eu-west-2 \
--validator.type aws \
--chains.hyperblox.signer.type aws \
--chains.hyperblox.signer.region eu-west-2 \
--validator.id alias/hyperlane-validator-signer-bsc \
--chains.hyperblox.signer.id alias/hyperlane-validator-signer-bsc \
--checkpointSyncer.type s3 \
--checkpointSyncer.bucket hyperlane-validator-signatures-bsc

if all went well, you should see the following validator script running:

Our bsc validator is done….. we now need to run another validator for hyperblox

In AWS, navigate back to your EC2 instance, and click on your instance ID

Click “connect” to open up a second terminal window…

let’s create a validator director for hyperblox now

mkdir -p hyperlane_db_validator_hyperblox

We’ll also create another bucket in AWS S3

The acess settings should be the same as before…

now we’ll edit the bucket policy and add the policy script in again….

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::hyperlane-validator-signatures-hyperblox",
"arn:aws:s3:::hyperlane-validator-signatures-hyperblox/*"
]
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::307998110083:user/hyperlane-validator-bsc"
},
"Action": [
"s3:DeleteObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::hyperlane-validator-signatures-hyperblox/*"
}
]
}

(Note: we can still use the same AWS IAM User ARN for this, rather than needing to create everything from scratch)

We now need to fund the validator wallet (0xcc5840b100042a27d0e3bb06700f62371101a935) only this time with HPB

Finally, we’ll run the docker, only on this occasion, we’ll change a few of the parameters for hyperblox:

sudo docker run \
-it \
-e AWS_ACCESS_KEY_ID=AKIAUPNQ6GGBTVSMH2HQ \
-e AWS_SECRET_ACCESS_KEY=/9143YVOErXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
-e CONFIG_FILES=/config/agent-config.json \
--mount type=bind,source=/home/ubuntu/agent-config-2024–04–06–15–31–17.json,target=/config/agent-config.json,readonly \
--mount type=bind,source=/home/ubuntu/hyperlane_db_validator_hyperblox,target=/hyperlane_db \
--mount type=bind,source=/home/ubuntu/$VALIDATOR_SIGNATURES_DIR,target=/tmp/validator-signatures \
gcr.io/abacus-labs-dev/hyperlane-agent:3adc0e9-20240319-152359 \
./validator \
--db /hyperlane_db \
--originChainName hyperblox \
--reorgPeriod 1 \
--validator.region eu-west-2 \
--checkpointSyncer.region eu-west-2 \
--validator.type aws \
--chains.hyperblox.signer.type aws \
--chains.hyperblox.signer.region eu-west-2 \
--validator.id alias/hyperlane-validator-signer-bsc \
--chains.hyperblox.signer.id alias/hyperlane-validator-signer-bsc \
--checkpointSyncer.type s3 \
--checkpointSyncer.bucket hyperlane-validator-signatures-hyperblox

We now have both validators running!

Setting up a relayer

Next we need to setup a relayer. Only one relayer is required for all chains we’re connecting to.

In AWS, navigate back to your EC2 instance, and click on your instance ID

Click “connect” to open up a second terminal window…

Now we have a third command line instance to work with for our relayer.

Let’s first create a directory we can work with:

mkdir -p hyperlane_db_relayer

We then need to run the following:

sudo docker run \
-it \
-e AWS_ACCESS_KEY_ID=AKIAUPNQ6GGBTVSMH2HQ \
-e AWS_SECRET_ACCESS_KEY=/9143YVOErXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
-e CONFIG_FILES=/config/agent-config.json \
--mount type=bind,source=/home/ubuntu/agent-config-2024–04–06–15–31–17.json,target=/config/agent-config.json,readonly \
--mount type=bind,source=/home/ubuntu/hyperlane_db_relayer,target=/hyperlane_db \
--mount type=bind,source="/home/ubuntu/$VALIDATOR_SIGNATURES_DIR",target=/tmp/validator-signatures \
gcr.io/abacus-labs-dev/hyperlane-agent:3adc0e9-20240319-152359 \
./relayer \
--db /hyperlane_db \
--relayChains hyperblox,bsc \
--defaultSigner.type aws \
--defaultSigner.id alias/hyperlane-validator-signer-bsc \
--defaultSigner.region eu-west-2

It might take a while to catch up with the validators you’re running, so you’ll need to wait a while.

Testing cross chain communication

With our validators running (one for each chain we’re connecting to) and our relayer, we can now test cross-chain communication.

back on our local machine, we’ll run the following command:

hyperlane send message --key [add your deployer private key] 

in terms of the prompts, we selected yes for using core deployment artifacts, we selected the core-deployment file we created earlier, we set the origin chain as hyperblox and the destination chain as bsc.

Now let’s run the exact same text, but this time with bsc as the origin chain and hyperblox as the destination chain….

hyperlane send message --key [add your deployer private key]

So we now have cross-chain messaging from chain to chain!

Deploying a Warp Route

Warp is a Hyperlane toolkit for bridging tokens between any chains. The routes can use native currencies (like BNB), or ERC20 tokens (like USDC).

The first thing we need to do is create a Warp config…

hyperlane config create warp

It will prompt us to specify a base chain for a native token. I will select hyperblox as the base chain (HPB is the native token for Hyperblox)

We now have a new warp config file created called warp-route-deployment.yaml

Let’s take a look at it…

base:
chainName: hyperblox
type: native
address: "0x0000000000000000000000000000000000000000"
isNft: false
synthetics:
- chainName: bsc

Because Hyperlane is not aware of the Hyperblox chain metadata (It’s not a default chain in Hyperlane SDK) we’ll also have to update the chains.yaml with some extra nativeToken details

hyperblox:
name: hyperblox
chainId: 269
domainId: 269
protocol: ethereum
rpcUrls:
- http: https://hpbnode.com
blocks:
confirmations: 1
reorgPeriod: 1
estimateBlockTime: 6
nativeToken:
name: HPB
symbol: HPB
decimals: 18

We can now deploy the warp route

hyperlane deploy warp --key [your private key]

Once the contracts have been deployed, we will have two new files:

artifacts\warp-route-deployment-2024-04-06-21-27-36.json
artifacts\warp-config-2024-04-06-21-27-36.json

The warp config file will be necessary for setting up a front-end UI for the bridge, and to run a test transfer

Let’s now test sending 1 wei of HPB to BSC

hyperlane send transfer

(note: for the warp config, where the router address is held, you’ll need to specify the full path to your file)

Setting up the Front End UI

I will cover this in a separate medium posting to avoid this getting too long!

--

--

Jeff P

I tend to write about anything I find interesting. There’s not much more to it than that really :-)