Skip to main content

Bridge on Hyperliquid with Chainlink CCIP

Updated on
Sep 30, 2025

38 min read

Overview

Hyperliquid pairs two layers under one unified state: HyperCore, an ultra-low-latency order-book engine accessed via signed actions, and HyperEVM, a fully EVM-compatible network for standard Solidity development.

Chainlink CCIP enables bridging assets between chains using a burn-and-mint mechanism. Within Hyperliquid, conversions between HyperCore (HIP-1) assets and their HyperEVM representations are handled by native protocol flows.

In this guide, you’ll use Foundry to wrap a HyperEVM token that corresponds to a HIP-1 asset and bridge that token between HyperEVM and BNB Smart Chain (BSC) using CCIP.

What You Will Do


  • Create a wrapper contract for a HyperEVM token linked to a HIP-1 asset
  • Deploy and configure CCIP token pools on HyperEVM and BSC
  • Verify our deployed token and pool contracts on-chain
  • Execute CCIP transfers between HyperEVM and BSC with Foundry scripts

What You Will Need


Disclaimer

We are using the MAINNETS of each chain in this guide. This is due to Chainlink CCIP not being available on HyperEVM Testnet at the time of writing. Please exercise caution and only use funds you can afford to lose.

Setting up the Development Environment

We will use Foundry to compile, deploy, and interact with our smart contracts. If you haven't installed Foundry yet, you can do so by running the following command in your terminal:

curl -L https://foundry.paradigm.xyz | bash

Follow the on-screen instructions and afterwards, you will be able to use the foundryup command to install Foundry. Ensure you execute this command in a new terminal session which accounts for the changes to your PATH variable.

foundryup

We will need a new folder locally where our project for this guide will live. We will name ours hyperevm_ccip, but you can call it anything you like. Run these commands in your terminal to create the folder and navigate into it with your code editor. In this guide, we will be using VS Code.

forge init hyperevm_ccip
cd hyperevm_ccip
code .

At this point, your setup should look something like this:

Great! Our Foundry project structure is now setup. Next create an .env file in the root of your project folder. This is where we will store our environment variables, such as our private key and RPC URLs. Here is what the format of the .env file should look like:

HYPEREVM_RPC="your_hyperevm_rpc_url"
BSC_RPC="your_bsc_rpc_url"
PRIVATE_KEY="your_private_key"
ETHERSCAN_API_KEY="your_etherscan_api_key"

We will discuss what each of these variables are shortly and how to obtain them. The next step is to delete the default src/Counter.sol contract and script/Counter.s.sol script that Foundry generates for us. We will not be using these in this guide. Alternatively, you can run the following commands in your terminal to remove these files:

rm src/Counter.sol
rm script/Counter.s.sol

You will also need to configure the foundry.toml file in the root of your project folder to include important settings for the Solidity compiler and remappings for the import statements we will be using. Here is what your foundry.toml file should look like:

[profile.default]
src = "src"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 200

remappings = [
'@chainlink/contracts-ccip/=node_modules/@chainlink/contracts-ccip/',
'@chainlink/contracts/=node_modules/@chainlink/contracts/',
]

fs_permissions = [{ access = "read-write", path = "./" }]

In this file, we added optimizer settings to optimize our smart contracts for deployment. The fs_permissions entry allows Foundry to read and write files in the project directory. The remappings entries are the paths of the Chainlink contracts packages that we will be using in this guide. We will install these packages next.

Installing Dependencies

We will be using two Chainlink contracts packages in this guide: @chainlink/contracts-ccip and @chainlink/contracts. The first package contains the core CCIP contracts that we will be interacting with and the CCIP token pool contracts that we will be deploying. The second package contains the tailored ERC20 contracts that comply with Chainlink's Cross Chain Transfer requirements.

We will also be installing the @layerzerolabs/hyperliquid-composer package, which will be used to increase the gas limit for our transactions on HyperEVM. HyperEVM has a multi-block architecture that consists of smaller blocks with gas limits of 2 million gas units and larger blocks with gas limits of 30 million gas units. Smaller blocks have 1-second block times, while larger blocks have 1-minute block times. By default, an account on HyperEVM is limited to sending transactions that comply with the smaller block gas limit. This package will allow us to enable our account to send transactions with higher gas limits to fit within the larger blocks.

To install these packages, enter the following commands using your preferred package manager:

npm install @chainlink/contracts-ccip @chainlink/contracts @layerzerolabs/hyperliquid-composer

Great! You have successfully installed the dependencies we will be using in this guide. Next, we will discuss the environment variables we need to populate in our .env file.

Environment Variables

QuickNode Endpoints

Firstly, we need to obtain the appropriate RPC Endpoints for HyperEVM and BSC. You can get these from QuickNode. Simply sign up for a free trial, create a new multi-chain endpoint, and copy the HTTPS URLs for each chain. Paste the corresponding URLs into the HYPEREVM_RPC and BSC_RPC variables in your .env file.

Etherscan API

Next, go to your profile on Etherscan and navigate to the API KEYS tab. If you do not have an account, create one here. Here you will create an API key that will help you verify your smart contracts on-chain. Copy the API key and paste it into the ETHERSCAN_API_KEY variable in your .env file.

Etherscan API v2
Etherscan has upgraded their API to v2. When you create an API key on Etherscan, it can also be used for multiple chains that Etherscan supports, including HyperEVM and BSC. So you do not need to create a separate API keys for each chain.

Private Key

Lastly, go into your MetaMask and copy the private key of one of your accounts. To learn how to access your private key, check out this short guide. Paste this private key into the PRIVATE_KEY variable in your .env file.

With that, all the environment variables in your .env file should now be populated. The final step in this setup process is to add the appropriate networks to our MetaMask wallet.

Adding Networks to MetaMask

We will be adding the HyperEVM Mainnet and Binance Smart Chain Mainnet networks to our MetaMask wallet. The easiest way to add these networks is to go to hyperevmscan.io and bscscan.com and click on the Add button on the bottom left of the page. This will add the networks to your MetaMask wallet:

Congratulations! You have successfully set up your development environment for this guide. Our next step is to bridge an HIP-1 asset from HyperCore to HyperEVM.

Bridging from HyperCore to HyperEVM

You will now bridge an HIP-1 asset from HyperCore to HyperEVM. This process involves converting the HIP-1 asset to its corresponding HyperEVM token representation. For this guide, we will be using Hyperliquid's native ecosystem coin: HYPE. Head over to the Hyperliquid trading interface and login with MetaMask to get started.

If you do not already have HYPE coins, you can acquire some by depositing USDC from Arbitrum Mainnet into Hyperliquid and then trading it for HYPE on Spot on the trading interface:

Hyperliquid Trading Interface

REMINDER
We are using the Mainnets of each chain in this guide. This is due to Chainlink CCIP not being available on HyperEVM testnet at the time of writing. Please exercise caution and only use funds you can afford to lose.

Once you have some HYPE, you can proceed to bridge it to HyperEVM. To do this click on the Transfer to/from EVM button on the bottom of the page below the chart. Simply enter the amount of HYPE you want to bridge and click Confirm.

Bridging HYPE to HyperEVM

Bridging HYPE to HyperEVM

Great! You have successfully bridged HYPE from HyperCore to HyperEVM. You should now be able to see your HYPE balance in MetaMask on the HyperEVM network. We will now move on to creating a wrapper contract for HYPE that complies with Chainlink's Cross Chain Transfer requirements.

Creating a Wrapper Contract for HYPE

To bridge HYPE between HyperEVM and BSC using Chainlink CCIP, we need to create a wrapper contract that adheres to Chainlink's Cross Chain Transfer requirements. This involves creating a new ERC20 token contract that wraps the existing HYPE asset on HyperEVM and a corresponding ERC20 token contract on BSC.

We will create a QuickNode Wrapped Hype token with the symbol qWHYPE. Enter the following command to create a new Solidity file in the src folder of your project directory and paste the code below into it.

touch src/qWHYPE.sol

Understanding the Wrapper Contract

Let's break down the code in the qWHYPE.sol contract. The contract imports the BurnMintERC20 contract from the @chainlink/contracts package, which provides the necessary functionality for minting and burning tokens. When users deposit HYPE into the contract, it mints an equivalent amount of qWHYPE tokens to their address. Conversely, when users withdraw qWHYPE tokens, the contract burns the tokens and transfers the corresponding amount of HYPE back to the user's address.

This specific contract will be deployed on the HyperEVM network. On BSC, we will be deploying the base BurnMintERC20 contract directly, as it does not require any additional functionality. We will be deploying both contracts using scripts in the next section.

Writing Foundry Scripts

We will be writing several Foundry scripts to deploy and interact with our smart contracts. This section will be divided into several parts to cover each script in detail. We will be creating the following scripts and executing them in this order:

Script NameDescription
DeployTokens.s.solDeploys the qWHYPE contract on HyperEVM and the base BurnMintERC20 contract on BSC
DeployPools.s.solDeploys the CCIP token pool contracts on both HyperEVM and BSC
SetupAdmin.s.solRegister and configure admin roles on the CCIP contracts for each chain
ConfigurePools.s.solConfigures our CCIP token pools for cross-chain transfers between each other
DepositAndTransferTokens.s.solDeposits a small amount of HYPE on the qWHYPE contract to mint qWHYPE tokens and then execute a cross-chain transfer to BSC
TransferTokens.s.solExecute a cross-chain transfer of qWHYPE tokens from either direction

Prerequisites

Before we write the scripts we will need a way to track our deployed contract addresses and a file to store common constants we will use throughout our scripts.

Execute the following commands to create the appropriate files:

touch script/Constants.s.sol
mkdir -p script/output
touch script/output/deployments.json

We will be using the deployments.json file to track the deployed contract addresses on each chain.

Here is what the Constants.s.sol file should look like:

Click to Expand Code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {Script} from "forge-std/Script.sol";

contract Constants is Script {

struct CCIPConstants {
uint64 chainSelector;
address router;
address rmnProxy;
address tokenAdminRegistry;
address registryModuleOwnerCustom;
string nativeCurrencySymbol;
}

function getCCIPConstants(uint256 chainId) public pure returns (CCIPConstants memory) {
if(chainId == 999) {
return CCIPConstants({
chainSelector: 2442541497099098535,
router: 0x13b3332b66389B1467CA6eBd6fa79775CCeF65ec,
rmnProxy: 0x07f15e9813FBd007d38CF534133C0838f449ecFA,
tokenAdminRegistry: 0xcE44363496ABc3a9e53B3F404a740F992D977bDF,
registryModuleOwnerCustom: 0xbAb3aBB5F29275065F2814F1f4B10Ffc1284fFEf,
nativeCurrencySymbol: "HYPE"
});
} else if (chainId == 56) {
return CCIPConstants({
chainSelector: 11344663589394136015,
router: 0x34B03Cb9086d7D758AC55af71584F81A598759FE,
rmnProxy: 0x9e09697842194f77d315E0907F1Bda77922e8f84,
tokenAdminRegistry: 0x736Fd8660c443547a85e4Eaf70A49C1b7Bb008fc,
registryModuleOwnerCustom: 0x47Db76c9c97F4bcFd54D8872FDb848Cab696092d,
nativeCurrencySymbol: "BNB"
});
}
revert("Chain not supported");
}
}

Script Menu

This script will deploy the qWHYPE contract on HyperEVM and the base BurnMintERC20 contract on BSC. Create a new file in the script folder of your project directory named DeployTokens.s.sol and paste the code below into it.

Click to Expand Code

Create the file:

touch script/DeployTokens.s.sol

Paste the code below into the file:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {Script, console} from "forge-std/Script.sol";
import {qWHYPE} from "../src/qWHYPE.sol";
import {BurnMintERC20} from "@chainlink/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol";

contract DeployTokens is Script {
string internal constant OUTPUT_PATH = "script/output/deployments.json";

/// forge script script/DeployTokens.s.sol:DeployTokens
function run() external {
// Load env vars
bytes memory hyperevm = bytes(vm.envString("HYPEREVM_RPC"));
bytes memory bsc = bytes(vm.envString("BSC_RPC"));
uint256 pk = vm.envUint("PRIVATE_KEY");

// Check if env vars are set
require(hyperevm.length != 0, "HYPEREVM_RPC not set");
require(bsc.length != 0, "BSC_RPC not set");

// print deployer address
address deployer = vm.addr(pk);
console.log("Deployer address:", deployer);

// Deploy on both chains
address hyperAddr = deployOn(hyperevm, deployer, pk);
address bscAddr = deployOn(bsc, deployer, pk);

// Write deployed addresses to JSON file
string memory obj = vm.serializeString("deployments", "qWHYPE_hyperevm", vm.toString(hyperAddr));
obj = vm.serializeString("deployments", "qWHYPE_bsc", vm.toString(bscAddr));
vm.writeJson(obj, OUTPUT_PATH);
}

function deployOn(bytes memory rpc, address deployer, uint256 pk) internal returns (address) {
vm.selectFork(vm.createFork(string(rpc)));
vm.startBroadcast(pk);
string memory chainName = getChainName(block.chainid);
address tokenAddr = address(block.chainid == 999 ? new qWHYPE() : new BurnMintERC20("QuickNode Wrapped HYPE", "qWHYPE", 18, 0, 0));
console.log("\nDeployed qWHYPE to:", tokenAddr, "on", chainName);
BurnMintERC20(tokenAddr).grantMintAndBurnRoles(deployer);
console.log("Granted minter and burner roles on", chainName, "qWHYPE to:", deployer);
vm.stopBroadcast();
return tokenAddr;
}

function getChainName(uint256 chainId) internal pure returns (string memory) {
if (chainId == 56) return "\x1b[36mBSC Mainnet\x1b[0m";
else if (chainId == 999) return "\x1b[32mHyperEVM Mainnet\x1b[0m";
else revert("Unsupported chain ID");
}
}

Understanding the DeployTokens Script

In this script, we first load the environment variables for the RPC URLs and private key. We then define a deployOn function that takes an RPC URL, deployer address, and private key as parameters. This function creates a fork of the specified chain, starts broadcasting transactions using the provided private key, and deploys either the qWHYPE contract (on HyperEVM) or the base BurnMintERC20 contract (on BSC). After deployment, it grants the deployer address minting and burning roles on the deployed token contract.

Running the Scripts

Now that we have written all the necessary scripts, we can execute them in sequence to deploy and configure our CCIP token pools and perform a cross-chain transfer of qWHYPE tokens.

Earlier, we discussed the multi-block architecture of Hyperliquid, smaller blocks use a maximum of 2M gas while larger blocks can use up to 30M gas. Our contract deployment transactions will most definitely exceed the 2M gas limit so we need to first enable our account to use larger blocks. To do this execute the following command in your terminal:

source .env
npx @layerzerolabs/hyperliquid-composer set-block --size big --network mainnet --private-key $PRIVATE_KEY
info

We suggest not passing your private key directly in the command line as it may be stored in your shell history. Always use environment variables or secure methods to handle sensitive information!


warning

If your wallet isn't registered on HyperCore, this command may fail with User or API Wallet does not exist. Ensure you've made a deposit or trade on Hyperliquid to register your wallet. If you followed the steps in Bridging from HyperCore to HyperEVM correctly, your wallet is already registered!

Great! Our account can now use larger blocks. We will now deploy our tokens using the DeployTokens.s.sol script:

forge script script/DeployTokens.s.sol:DeployTokens --broadcast --verify --verifier etherscan

This command will deploy our tokens to both the HyperEVM and BSC networks. You will see the deployment progress in your terminal and the transaction hashes once the transactions are confirmed. The --broadcast flag indicates that we want to send the transactions to the network, while the --verify and --verifier etherscan flags will automatically verify our contracts on hyperevmscan.io and bscscan.com after deployment. You will also notice that your deployments.json file has been populated with the deployed contract addresses. Your terminal output should look something like this:

Deployment Output

Next, we will deploy our CCIP token pools using the DeployPools.s.sol script:

forge script script/DeployPools.s.sol:DeployPools --broadcast --verify --verifier etherscan

This command will deploy our token pools to both the HyperEVM and BSC networks. Similar to the previous step, you will see the deployment progress in your terminal and the transaction hashes once the transactions are confirmed. The deployments.json file will be updated with the deployed pool addresses. Your terminal output should look something like this:

Pool Deployment Output

Next, we will set up the admin for our tokens using the SetupAdmin.s.sol script and configure our pools using the ConfigurePools.s.sol script. We can execute both scripts in sequence using the following commands:

forge script script/SetupAdmin.s.sol:SetupAdmin --broadcast
forge script script/ConfigurePools.s.sol:ConfigurePools --broadcast

Like the previous step, you will see a similar terminal output with the transaction hashes once the transactions are confirmed.

Our First Cross-Chain Transfer

Finally, we will perform a cross-chain transfer of qWHYPE tokens from HyperEVM to BSC using the DepositAndTransferTokens.s.sol script:

forge script script/DepositAndTransferTokens.s.sol:DepositAndTransferTokens --broadcast

This command will deposit HYPE to mint qWHYPE on HyperEVM and then transfer the qWHYPE tokens to BSC. You will see the transfer progress in your terminal and the transaction hash once the transaction is confirmed. You will also see the CCIP message ID of the transfer, which you can use to track the status of the transfer on the Chainlink CCIP Explorer. Your terminal will output the message ID as shown below:

Transfer Output Terminal output showing the CCIP message ID

Let's verify if the qWHYPE tokens have been received on BSC. Open your MetaMask Wallet, switch to the BSC network, and import the qWHYPE token using the address found in your deployments.json file with the key qWHYPE_bsc. If you need help importing a token, follow MetaMask’s guide here. You should see a balance of 0.01 qWHYPE tokens in your wallet, confirming that the cross-chain transfer was successful!


MetaMask Balance

Transferring In Any Direction

The TransferTokens.s.sol script can be used to transfer qWHYPE tokens in either direction between HyperEVM and BSC. You can specify the direction of the transfer by passing either to-bsc or to-hyperevm as an argument when running the script. For example, to transfer qWHYPE tokens from BSC to HyperEVM, you would run the following command:

forge script script/TransferTokens.s.sol:TransferTokens --broadcast --sig 'run(string)' 'to-hyperevm'

The output will be similar to our first cross-chain transfer, showing the transaction hash and CCIP message ID. Pasting the message ID into the Chainlink CCIP Explorer will now show the transfer in the opposite direction:

CCIP Explorer Reverse

Conclusion

Congratulations! You have successfully learned how to bridge tokens on Hyperliquid using Chainlink CCIP. You have deployed your own ERC-20 tokens, set up CCIP token pools, and performed cross-chain transfers of qWHYPE tokens between HyperEVM and BSC.

Next Steps

Now that you have a working cross-chain bridge, you can further improve and customize your setup. Here are some ideas:


  • Hyperliquid Bridge UI: Build a user-friendly interface for your bridge using frameworks like React or Vue.js. This will allow users to easily interact with your bridge without needing to use command-line tools.
  • Rate Limiting: Implement rate limiting on your token pools to prevent abuse and ensure fair usage. You can configure rate limits in the ConfigurePools.s.sol script.
  • Implement Additional Chains: Extend your bridge to support additional chains supported by Chainlink CCIP. You can follow the same steps outlined in this guide to deploy and configure token pools on other chains. Check the lanes and supported chains on the CCIP Directory.
  • Wrap Additional HIP-1 Assets: You can create and deploy additional wrapped tokens for other HIP-1 assets on Hyperliquid, following a similar process as we did for HYPE. The only difference would be that a wrapper ERC-20 contract would need to be created for each asset. This will allow users to bridge a wider range of assets between HyperEVM and other chains.

Further Resources


If you are stuck or have questions, drop them in our Discord. Stay up to date with the latest by following us on X (@QuickNode) or our Telegram announcement channel.

We ❤️ Feedback!

If you have any feedback or questions about this documentation, let us know. We'd love to hear from you!

Share this guide