Adding LayerZeroRouter

pull/2243/head
pxgnome 2 years ago
parent f6ad1e9a95
commit 943b0162fa
  1. 137
      solidity/contracts/interfaces/middleware/layerzero/ILayerZeroEndpoint.sol
  2. 17
      solidity/contracts/interfaces/middleware/layerzero/ILayerZeroReceiver.sol
  3. 31
      solidity/contracts/interfaces/middleware/layerzero/ILayerZeroUserApplicationConfig.sol
  4. 350
      solidity/contracts/middleware/layerzero/LayerZeroRouter.sol
  5. 161
      solidity/contracts/middleware/layerzero/MockLayerZeroRouter.sol
  6. 195
      solidity/test/middleware/layerzero/LayerZeroRouter.t.sol

@ -0,0 +1,137 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
// @notice send a LayerZero message to the specified address at a LayerZero endpoint.
// @param _dstChainId - the destination chain identifier
// @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
// @param _payload - a custom bytes payload to send to the destination contract
// @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
// @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
// @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
function send(
uint16 _dstChainId,
bytes calldata _destination,
bytes calldata _payload,
address payable _refundAddress,
address _zroPaymentAddress,
bytes calldata _adapterParams
) external payable;
// @notice used by the messaging library to publish verified payload
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source contract (as bytes) at the source chain
// @param _dstAddress - the address on destination chain
// @param _nonce - the unbound message ordering nonce
// @param _gasLimit - the gas limit for external contract execution
// @param _payload - verified payload to send to the destination contract
function receivePayload(
uint16 _srcChainId,
bytes calldata _srcAddress,
address _dstAddress,
uint64 _nonce,
uint256 _gasLimit,
bytes calldata _payload
) external;
// @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress)
external
view
returns (uint64);
// @notice get the outboundNonce from this source chain which, consequently, is always an EVM
// @param _srcAddress - the source chain contract address
function getOutboundNonce(uint16 _dstChainId, address _srcAddress)
external
view
returns (uint64);
// @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
// @param _dstChainId - the destination chain identifier
// @param _userApplication - the user app address on this EVM chain
// @param _payload - the custom message to send over LayerZero
// @param _payInZRO - if false, user app pays the protocol fee in native token
// @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
function estimateFees(
uint16 _dstChainId,
address _userApplication,
bytes calldata _payload,
bool _payInZRO,
bytes calldata _adapterParam
) external view returns (uint256 nativeFee, uint256 zroFee);
// @notice get this Endpoint's immutable source identifier
function getChainId() external view returns (uint16);
// @notice the interface to retry failed message on this Endpoint destination
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
// @param _payload - the payload to be retried
function retryPayload(
uint16 _srcChainId,
bytes calldata _srcAddress,
bytes calldata _payload
) external;
// @notice query if any STORED payload (message blocking) at the endpoint.
// @param _srcChainId - the source chain identifier
// @param _srcAddress - the source chain contract address
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress)
external
view
returns (bool);
// @notice query if the _libraryAddress is valid for sending msgs.
// @param _userApplication - the user app address on this EVM chain
function getSendLibraryAddress(address _userApplication)
external
view
returns (address);
// @notice query if the _libraryAddress is valid for receiving msgs.
// @param _userApplication - the user app address on this EVM chain
function getReceiveLibraryAddress(address _userApplication)
external
view
returns (address);
// @notice query if the non-reentrancy guard for send() is on
// @return true if the guard is on. false otherwise
function isSendingPayload() external view returns (bool);
// @notice query if the non-reentrancy guard for receive() is on
// @return true if the guard is on. false otherwise
function isReceivingPayload() external view returns (bool);
// @notice get the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _userApplication - the contract address of the user application
// @param _configType - type of configuration. every messaging library has its own convention.
function getConfig(
uint16 _version,
uint16 _chainId,
address _userApplication,
uint256 _configType
) external view returns (bytes memory);
// @notice get the send() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getSendVersion(address _userApplication)
external
view
returns (uint16);
// @notice get the lzReceive() LayerZero messaging library version
// @param _userApplication - the contract address of the user application
function getReceiveVersion(address _userApplication)
external
view
returns (uint16);
}

@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
interface ILayerZeroReceiver {
// @notice LayerZero endpoint will invoke this function to deliver the message on the destination
// @param _srcChainId - the source endpoint identifier
// @param _srcAddress - the source sending contract address from the source chain
// @param _nonce - the ordered message nonce
// @param _payload - the signed payload is the UA bytes has encoded to be sent
function lzReceive(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint64 _nonce,
bytes calldata _payload
) external;
}

@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
interface ILayerZeroUserApplicationConfig {
// @notice set the configuration of the LayerZero messaging library of the specified version
// @param _version - messaging library version
// @param _chainId - the chainId for the pending config change
// @param _configType - type of configuration. every messaging library has its own convention.
// @param _config - configuration in the bytes. can encode arbitrary content.
function setConfig(
uint16 _version,
uint16 _chainId,
uint256 _configType,
bytes calldata _config
) external;
// @notice set the send() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setSendVersion(uint16 _version) external;
// @notice set the lzReceive() LayerZero messaging library version to _version
// @param _version - new messaging library version
function setReceiveVersion(uint16 _version) external;
// @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
// @param _srcChainId - the chainId of the source chain
// @param _srcAddress - the contract address of the source contract at the source chain
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress)
external;
}

@ -0,0 +1,350 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.13;
import {Router} from "../../Router.sol";
import {TypeCasts} from "../../libs/TypeCasts.sol";
import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol";
import {ILayerZeroEndpoint} from "../../interfaces/middleware/layerzero/ILayerZeroEndpoint.sol";
import {ILayerZeroReceiver} from "../../interfaces/middleware/layerzero/ILayerZeroReceiver.sol";
/**
* @title LayerZeroRouter
* @notice Example of middleware to use hyperlane in a layerzero app on layerZero
* @dev Implemented send() and a virtual lzReceive().
* @dev Please make sure to edit lzReceive() and setEstGasAmount() to match gas usage of lzReceive() in your app
* @dev Run `forge test --match-contract LayerZeroRouterTest` to see tests
*/
abstract contract LayerZeroRouter is Router, ILayerZeroEndpoint {
mapping(uint16 => uint32) layerZeroToHyperlaneDomain;
mapping(uint32 => uint16) hyperlaneToLayerZeroDomain;
ILayerZeroReceiver public layerZeroReceiver;
error LayerZeroDomainNotMapped(uint16);
error HyperlaneDomainNotMapped(uint32);
uint256 estGasAmount;
function initialize(address _owner, address _mailbox) public initializer {
_transferOwnership(_owner);
__Router_initialize(_mailbox);
}
function initialize(
address _owner,
address _mailbox,
address _interchainGasPaymaster
) public initializer {
_transferOwnership(_owner);
__Router_initialize(_mailbox, _interchainGasPaymaster);
}
function initialize(
address _owner,
address _mailbox,
address _interchainGasPaymaster,
address _interchainSecurityModule
) public initializer {
_transferOwnership(_owner);
__Router_initialize(
_mailbox,
_interchainGasPaymaster,
_interchainSecurityModule
);
}
/**
* @notice Adds a domain ID mapping from layerZeroDomain/hyperlaneDomain domain IDs and vice versa
* @param _layerZeroDomains An array of layerZeroDomain domain IDs
* @param _hyperlaneDomains An array of hyperlaneDomain domain IDs
*/
function mapDomains(
uint16[] calldata _layerZeroDomains,
uint32[] calldata _hyperlaneDomains
) external onlyOwner {
for (uint256 i = 0; i < _layerZeroDomains.length; i += 1) {
layerZeroToHyperlaneDomain[
_layerZeroDomains[i]
] = _hyperlaneDomains[i];
hyperlaneToLayerZeroDomain[
_hyperlaneDomains[i]
] = _layerZeroDomains[i];
}
}
/**
* @notice Gets layerZero domain ID from hyperlane domain ID
* @param _hyperlaneDomain The hyperlane domain ID
*/
function getLayerZeroDomain(uint32 _hyperlaneDomain)
public
view
returns (uint16 layerZeroDomain)
{
layerZeroDomain = hyperlaneToLayerZeroDomain[_hyperlaneDomain];
if (layerZeroDomain == 0) {
revert HyperlaneDomainNotMapped(_hyperlaneDomain);
}
}
/**
* @notice Gets hyperlane domain ID from layerZero domain ID
* @param _layerZeroDomain The layerZero domain ID
*/
function getHyperlaneDomain(uint16 _layerZeroDomain)
public
view
returns (uint32 hyperlaneDomain)
{
hyperlaneDomain = layerZeroToHyperlaneDomain[_layerZeroDomain];
if (hyperlaneDomain == 0) {
revert LayerZeroDomainNotMapped(_layerZeroDomain);
}
}
/**
* @notice handles the version Adapter Parameters for LayerZero
* @param _adapterParams The adapter params used in LayerZero sends
*/
function _interpretAdapterParamsV1(bytes memory _adapterParams)
internal
pure
returns (uint256 gasAmount)
{
uint16 version;
require(_adapterParams.length == 34, "Please check your adapterparams");
(version, gasAmount) = abi.decode(_adapterParams, (uint16, uint256));
}
/**
* @notice handles the version Adapter Parameters for LayerZero
* @param _adapterParams The adapter params used in LayerZero sends
*/
function _interpretAdapterParamsV2(bytes memory _adapterParams)
internal
pure
returns (
uint256 gasAmount,
uint256 nativeForDst,
address addressOnDst
)
{
require(_adapterParams.length == 86, "Please check your adapterparams");
uint16 version;
(version, gasAmount, nativeForDst, addressOnDst) = abi.decode(
_adapterParams,
(uint16, uint256, uint256, address)
);
}
function splitAddress(bytes memory hexString)
public
pure
returns (address, address)
{
// bytes memory byteArray = bytes(hexString);
require(
hexString.length == 40,
"Input string must be 40 characters long"
);
bytes20 firstAddress;
bytes20 secondAddress;
assembly {
firstAddress := mload(add(hexString, 0x20))
secondAddress := mload(add(hexString, 0x30))
}
return (address(firstAddress), address(secondAddress));
}
/**
* @notice Sends a hyperlane message using LayerZero endpoint interface
* @dev NOTE: Layerzero's documentation is inconsistent in github vs docs. Following: https://layerzero.gitbook.io/docs/evm-guides/master/how-to-send-a-message
* @param _dstChainId - the destination chain identifier
* @param _remoteAndLocalAddresses - remote address concated with local address packed into 40 bytes
* @param _payload - the payload to be sent to the destination chain
* @param _refundAddress - the address to refund the gas fees to
* @param _zroPaymentAddress - not used (only for LayerZero)
* @param _adapterParams - the adapter params used in LayerZero sends
*/
function send(
uint16 _dstChainId,
bytes memory _remoteAndLocalAddresses,
bytes calldata _payload,
address payable _refundAddress,
address _zroPaymentAddress,
bytes memory _adapterParams
) external payable override {
uint32 dstChainId32 = layerZeroToHyperlaneDomain[_dstChainId];
_mustHaveRemoteRouter(dstChainId32);
address remoteAddr;
address localAddr;
if (_remoteAndLocalAddresses.length == 40) {
(remoteAddr, localAddr) = splitAddress(_remoteAndLocalAddresses);
} else if (_remoteAndLocalAddresses.length == 32) {
remoteAddr = abi.decode(_remoteAndLocalAddresses, (address));
} else {
revert("Invalid remote and local addresses");
}
bytes memory adapterParams;
uint256 gasFees;
if (_adapterParams.length > 0) {
if (_adapterParams.length == 33) {
gasFees = _interpretAdapterParamsV1(_adapterParams);
} else if (_adapterParams.length == 86) {
uint256 nativeForDst;
address addressOnDst;
(
gasFees,
nativeForDst,
addressOnDst
) = _interpretAdapterParamsV2(_adapterParams);
} else {
revert("Invalid adapter params");
}
} else {
(gasFees, ) = estimateFees(
_dstChainId,
msg.sender,
_payload,
_zroPaymentAddress != address(0x0),
adapterParams
);
}
require(msg.value >= gasFees, "Not enough fee for gas");
bytes32 _messageId = mailbox.dispatch(
dstChainId32,
TypeCasts.addressToBytes32(remoteAddr),
_payload
);
interchainGasPaymaster.payForGas{value: msg.value}(
_messageId,
dstChainId32,
gasFees,
_refundAddress
);
}
/**
* @notice The internal Router `handle` function which extracts the true recipient of the message and passes the translated hyperlane domain ID to lzReceive
* @param _originHyperlaneDomain the origin domain as specified by Hyperlane
* @param _sender The sender address
* @param _message The wrapped message to include sender and recipient
*/
function handle(
uint32 _originHyperlaneDomain,
bytes32 _sender,
bytes calldata _message
)
public
override
onlyMailbox
onlyRemoteRouter(_originHyperlaneDomain, _sender)
{
_handle(_originHyperlaneDomain, _sender, _message);
}
function _handle(
uint32 _originHyperlaneDomain,
bytes32 _sender,
bytes calldata _message
) internal override {
uint16 srcChainId = getLayerZeroDomain(_originHyperlaneDomain);
lzReceive(srcChainId, _sender, 0, _message); //Note nonce does not exist in hyperlane on the destination chain
}
/**
* @notice Originally LayerZero endpoint which will be evoked by this contract's handle function
* @dev override from ILayerZeroEndpoint.sol
* @param _srcChainId - the source endpoint identifier
* @param _srcAddress - the source sending contract address from the source chain
* @param _nonce - the ordered message nonce (not used in Hyperlane)
* @param _payload - the signed payload is the UA bytes has encoded to be sent
*/
function lzReceive(
uint16 _srcChainId,
bytes32 _srcAddress,
uint64 _nonce,
bytes memory _payload
) public virtual {}
/**
* @notice Gets a quote in source native gas, for the amount that send() requires to pay for message delivery
* @dev override from ILayerZeroEndpoint.sol
* @param _dstChainId - the destination chain identifier
* @param _userApplication - the user app address on this EVM chain
* @param _payload - the custom message to send over LayerZero
* @param _payInZRO - if false, user app pays the protocol fee in native token
* @param _adapterParams - parameters for the adapter service, e.g. send some dust native token to dstChain
*/
function estimateFees(
uint16 _dstChainId,
address _userApplication,
bytes memory _payload,
bool _payInZRO,
bytes memory _adapterParams
) public view override returns (uint256 nativeFee, uint256 zroFee) {
require(estGasAmount > 0, "Please set gas amount");
return (
interchainGasPaymaster.quoteGasPayment(
layerZeroToHyperlaneDomain[_dstChainId],
estGasAmount
),
0
);
}
/**
* @notice Sets the gas amount for the estimateFees function since this will depend upon gas your lzreceive() uses
* @dev Used for showcase and testing suggest editing getGasAmount
* @param _gas The amount of gas to set
*/
function setEstGasAmount(uint256 _gas) external onlyOwner {
estGasAmount = _gas;
}
/**
* @notice Gets the gas amount for the estimateFees function
* @dev Please override this to however you wish to calculate your gas usage on destiniation chain
* @param _payload The payload to be sent to the destination chain
*/
function getEstGasAmount(bytes memory _payload)
public
view
returns (uint256)
{
return estGasAmount;
}
/**
* @notice Gets the chain ID of the current chain
* @dev override from ILayerZeroEndpoint.sol -- NOTE OVERFLOW RISK
*/
function getChainId() external view override returns (uint16) {
return hyperlaneToLayerZeroDomain[mailbox.localDomain()];
}
/**
* @notice Gets the mailbox count this source chain since hyperlane does not have nonce
* @dev override from ILayerZeroEndpoint.sol
* @param _dstChainId - the destination chain identifier
* @param _srcAddress - the source chain contract address
*
*/
function getOutboundNonce(uint16 _dstChainId, address _srcAddress)
external
view
returns (uint64)
{
return uint64(mailbox.count());
}
}

@ -0,0 +1,161 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.13;
import {Router} from "../../Router.sol";
import {TypeCasts} from "../../libs/TypeCasts.sol";
import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol";
import {ILayerZeroEndpoint} from "../../interfaces/middleware/layerzero/ILayerZeroEndpoint.sol";
import {ILayerZeroReceiver} from "../../interfaces/middleware/layerzero/ILayerZeroReceiver.sol";
import {LayerZeroRouter} from "./LayerZeroRouter.sol";
/**
* @title MockLayerZeroRouter
* @dev Used for testing LayerZeroRouter
*/
contract MockLayerZeroRouter is LayerZeroRouter {
/**
* @notice Originally LayerZero endpoint which will be evoked by this contract's handle function
* @dev override from ILayerZeroEndpoint.sol -- NEED UPDATING
* @param _srcChainId - the source endpoint identifier
* @param _srcAddress - the source sending contract address from the source chain
* @param _nonce - the ordered message nonce (not used in Hyperlane)
* @param _payload - the signed payload is the UA bytes has encoded to be sent
*/
function lzReceive(
uint16 _srcChainId,
bytes32 _srcAddress,
uint64 _nonce,
bytes memory _payload
) public override {}
/**
* @dev Below are the functions that are not supported in the interface "ILayerZeroEndpoint" due to way hyperlane is structured
*/
function receivePayload(
uint16 _srcChainId,
bytes calldata _srcAddress,
address _dstAddress,
uint64 _nonce,
uint256 _gasLimit,
bytes calldata _payload
) external override {
//Not supported
}
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress)
external
view
override
returns (uint64)
{
//Not supported
return 0;
}
function retryPayload(
uint16 _srcChainId,
bytes calldata _srcAddress,
bytes calldata _payload
) external override {
//Not supported
}
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress)
external
view
override
returns (bool)
{
//Not supported
return false;
}
function getSendLibraryAddress(address _userApplication)
external
view
override
returns (address)
{
//Not supported
return address(0);
}
function getReceiveLibraryAddress(address _userApplication)
external
view
override
returns (address)
{
//Not supported
return address(0);
}
function isSendingPayload() external view override returns (bool) {
//Not supported
return false;
}
function isReceivingPayload() external view override returns (bool) {
//Not supported
return false;
}
function getConfig(
uint16 _version,
uint16 _chainId,
address _userApplication,
uint256 _configType
) external view returns (bytes memory) {
//Not supported
return "";
}
function getSendVersion(address _userApplication)
external
view
override
returns (uint16)
{
//Not supported
return 0;
}
function getReceiveVersion(address _userApplication)
external
view
override
returns (uint16)
{
//Not supported
return 0;
}
/**
* @dev Below are the functions that are not supported in the interface "ILayerZeroUserApplicationConfig" due to way hyperlane is structured
*/
function setConfig(
uint16 _version,
uint16 _chainId,
uint256 _configType,
bytes calldata _config
) external override {
//Not supported
}
function setSendVersion(uint16 _version) external override {
//Not supported
}
function setReceiveVersion(uint16 _version) external override {
//Not supported
}
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress)
external
override
{
//Not supported
}
}

@ -0,0 +1,195 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../../../contracts/test/TestRecipient.sol";
import {MockLayerZeroRouter} from "../../../contracts/middleware/layerzero/MockLayerZeroRouter.sol";
import {MockHyperlaneEnvironment, MockMailbox} from "../../../contracts/mock/MockHyperlaneEnvironment.sol";
import {TypeCasts} from "../../../contracts/libs/TypeCasts.sol";
contract LayerZeroRouterTest is Test {
MockHyperlaneEnvironment testEnvironment;
MockLayerZeroRouter originRouter;
MockLayerZeroRouter destinationRouter;
TestRecipient recipient;
uint16 lzOriginDomain = 123;
uint16 lzDestinationDomain = 321;
uint32 hlOriginDomain = 456;
uint32 hlDestinationDomain = 654;
address owner = vm.addr(123);
function setUp() public {
console.log("Owner Address: %s", owner);
originRouter = new MockLayerZeroRouter();
destinationRouter = new MockLayerZeroRouter();
testEnvironment = new MockHyperlaneEnvironment(
hlOriginDomain,
hlDestinationDomain
);
console.log("Origin Router Address: %s", address(originRouter));
console.log(
"Origin Mailbox: %s",
address(testEnvironment.mailboxes(hlOriginDomain))
);
console.log(
"Destination Router Address: %s",
address(destinationRouter)
);
console.log(
"Destination Mailbox: %s",
address(testEnvironment.mailboxes(hlDestinationDomain))
);
originRouter.initialize(
owner,
address(testEnvironment.mailboxes(hlOriginDomain)),
address(testEnvironment.igps(hlOriginDomain)),
address(testEnvironment.isms(hlOriginDomain))
);
destinationRouter.initialize(
owner,
address(testEnvironment.mailboxes(hlDestinationDomain)),
address(testEnvironment.igps(hlDestinationDomain)),
address(testEnvironment.isms(hlDestinationDomain))
);
uint16[] memory lzDomains = new uint16[](2);
lzDomains[0] = lzOriginDomain;
lzDomains[1] = lzDestinationDomain;
uint32[] memory hlDomains = new uint32[](2);
hlDomains[0] = hlOriginDomain;
hlDomains[1] = hlDestinationDomain;
originRouter.mapDomains(lzDomains, hlDomains);
destinationRouter.mapDomains(lzDomains, hlDomains);
originRouter.enrollRemoteRouter(
hlDestinationDomain,
TypeCasts.addressToBytes32(address(destinationRouter))
);
destinationRouter.enrollRemoteRouter(
hlOriginDomain,
TypeCasts.addressToBytes32(address(originRouter))
);
recipient = new TestRecipient();
//Set expected gas usage
uint256 gasEstimate = 0.01 ether;
originRouter.setEstGasAmount(gasEstimate);
destinationRouter.setEstGasAmount(gasEstimate);
}
function testCanSendMessage(bytes calldata _messageBody) public {
uint256 gasPrice = 100000000000000000000; //Need fix here
address a = address(recipient);
address b = msg.sender;
bytes memory destination = abi.encodePacked(a, b);
console.log("Recipient: %s", a);
console.log("Sender: %s", b);
bytes memory payload = abi.encode("abc");
originRouter.send{value: gasPrice}(
lzDestinationDomain,
destination,
payload,
payable(address(0)),
address(0),
""
);
bytes32 senderAsBytes32 = TypeCasts.addressToBytes32(
address(originRouter)
);
vm.expectCall(
address(recipient),
abi.encodeWithSelector(
recipient.handle.selector,
hlOriginDomain,
senderAsBytes32,
payload
)
);
testEnvironment.processNextPendingMessage();
assertEq(recipient.lastData(), payload);
assertEq(recipient.lastSender(), senderAsBytes32);
bytes memory destinationAs32 = abi.encode(address(recipient));
originRouter.send{value: gasPrice}(
lzDestinationDomain,
destinationAs32,
payload,
payable(address(0)),
address(0),
""
);
vm.expectCall(
address(recipient),
abi.encodeWithSelector(
recipient.handle.selector,
hlOriginDomain,
senderAsBytes32,
payload
)
);
testEnvironment.processNextPendingMessage();
assertEq(recipient.lastData(), payload);
assertEq(recipient.lastSender(), senderAsBytes32);
}
function testCanReceiveMessage(bytes calldata _messageBody) public {
uint256 gasPrice = 100000000000000000000; //Need fix here
address a = address(destinationRouter);
address b = msg.sender;
bytes memory destination = abi.encodePacked(a, b);
console.log("Recipient: %s", a);
console.log("Sender: %s", b);
bytes memory payload = abi.encode("abc");
originRouter.send{value: gasPrice}(
lzDestinationDomain,
destination,
payload,
payable(address(0)),
address(0),
""
);
bytes32 senderAsBytes32 = TypeCasts.addressToBytes32(
address(originRouter)
);
vm.expectCall(
address(destinationRouter),
abi.encodeWithSelector(
destinationRouter.handle.selector,
hlOriginDomain,
senderAsBytes32,
payload
)
);
testEnvironment.processNextPendingMessage();
}
}
Loading…
Cancel
Save