Liquidity Layer API
Attach value with your Hyperlane messages using the Liquidity Layer API.
Hyperlane's Liquidity layer will wrap around several token bridges to allow developers to send tokens alongside their message.
- Circle
- Token: USDC
- Chains: Goerli and Fuji
- Portal
- Token: USDC, ETH
- Chains: Goerli, Fuji, Mumbai, BSC Testnet, Alfajores
Developers can send interchain messages very similarly to the Messaging API by calling the
LiquidityLayerRouter.dispatchWithTokens
endpoint. At the moment, dispatched messages must be received by a contract with the handleWithTokens()
function. You will learn more about this in the Receive section up next, but for now let's cover the message sending interface.interface ILiquidityLayerRouter {
function dispatchWithTokens(
uint32 _destinationDomain,
bytes32 _recipientAddress,
bytes calldata _messageBody,
address _token,
uint256 _amount,
string calldata _bridge
) external returns (bytes32);
}
The address of the
LiquidityLayerRouter
is 0x2abe0860D81FB4242C748132bD69D125D88eaE26
on every chain._destinationDomain
is the chain you're sending to, it is not the chainID, rather it is a unique ID assigned by the protocol to each chain. Domain ID's can be found here._recipientAddress
is the receiving contract, it needs to be a contract with the handleWithTokens()
function, you can read about it in the Receive section._messageBody
is the message you're passing. _token
is the address of the token on the origin chain you are trying to transfer_amount
is the amount of _token
you want to transfer_bridge
is a string identifier for the value bridge you want to use, "Circle"
or "Portal"
are currently supportedinterface ILiquidityLayerMessageRecipient {
function handleWithTokens(
uint32 _origin,
bytes32 _sender,
bytes calldata _message,
address _token,
uint256 _amount
) external;
}
_sender
the address of the message sender on the source chain_messageBody
the message being passed._address
is the address of the token that was transferred to the recipient_amount
is the amount of the token that was transferred
The same points about access control and encoding from the Messaging API apply to the LiquidityLayer API as well, so be sure to check it out. However, rather than requiring access control such that the Mailbox can only call the
handle
function, the LiquidityLayerRouter on the local chain must be the only address that can call the handleWithTokens
function.Just like all Hyperlane messages that wish to have their messages delivered by a relayer, users must pay for interchain gas.
The
dispatchWithTokens
function in the Liquidity Layer API returns the message ID as a bytes32
. This message ID can then be used by the caller to pay for interchain gas.Because the Liquidity Layer uses the default ISM for security, the DefaultIsmInterchainGasPaymaster IGP should be used. When specifying the amount of gas, the caller must pay for a gas amount high enough to cover:
- 1."Overhead" gas used by the Liquidity Layer contract on the destination chain. This is about 280,000 gas. This is because the actual cost of bridging the tokens via the underlying Circle or Portal bridge can be fairly high.
- 2.The gas used by the recipient's
handleWithTokens
function on the destination chain.
function dispatchWithTokensAndPayGas() external payable {
// First, dispatch with tokens
bytes32 messageId = liquidityLayer.dispatchWithTokens(/* ... */);
// Then, pay for gas
// The mainnet DefaultIsmInterchainGasPaymaster
IInterchainGasPaymaster igp = IInterchainGasPaymaster(
0x56f52c0A1ddcD557285f7CBc782D3d83096CE1Cc
);
// Pay with the msg.value
igp.payForGas{ value: msg.value }(
// The ID of the message
messageId,
// Destination domain
destinationDomain,
// The total gas amount. This should be the
// overhead gas amount (280,000 gas) + gas used by the call being made.
// For example, if the handleWithTokens function uses 120,000 gas,
// we pay for 400k gas.
400000,
// Refund the msg.sender
msg.sender
);
}
Last modified 2d ago