diff --git a/packages/evm/contracts/adapters/LayerZero/LayerZeroAdapter.sol b/packages/evm/contracts/adapters/LayerZero/LayerZeroAdapter.sol index e9688db8..25e9b1e6 100644 --- a/packages/evm/contracts/adapters/LayerZero/LayerZeroAdapter.sol +++ b/packages/evm/contracts/adapters/LayerZero/LayerZeroAdapter.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { ILayerZeroReceiver } from "./interfaces/ILayerZeroReceiver.sol"; import { BlockHashAdapter } from "../BlockHashAdapter.sol"; +import { ILayerZeroEndpointV2, Origin } from "./interfaces/ILayerZeroEndpointV2.sol"; -contract LayerZeroAdapter is BlockHashAdapter, Ownable, ILayerZeroReceiver { +contract LayerZeroAdapter is BlockHashAdapter, Ownable { string public constant PROVIDER = "layer-zero"; address public immutable LAYER_ZERO_ENDPOINT; - mapping(uint32 => bytes32) public enabledReportersPaths; + mapping(uint32 => bytes32) public enabledReporters; mapping(uint32 => uint256) public chainIds; error UnauthorizedLayerZeroReceive(); @@ -20,17 +20,22 @@ contract LayerZeroAdapter is BlockHashAdapter, Ownable, ILayerZeroReceiver { LAYER_ZERO_ENDPOINT = lzEndpoint; } - function lzReceive(uint16 srcEndpointId, bytes memory srcPath, uint64 /* nonce */, bytes memory payload) external { - if (msg.sender != LAYER_ZERO_ENDPOINT || enabledReportersPaths[srcEndpointId] != keccak256(srcPath)) - revert UnauthorizedLayerZeroReceive(); - uint256 sourceChainId = chainIds[srcEndpointId]; - (uint256[] memory ids, bytes32[] memory hashes) = abi.decode(payload, (uint256[], bytes32[])); - _storeHashes(sourceChainId, ids, hashes); - } - function setReporterByChain(uint256 chainId, uint16 endpointId, address reporter) external onlyOwner { - enabledReportersPaths[endpointId] = keccak256(abi.encodePacked(reporter, address(this))); + enabledReporters[endpointId] = bytes32(abi.encodePacked(reporter)); chainIds[endpointId] = chainId; emit ReporterSet(chainId, endpointId, reporter); } + + function lzReceive( + Origin calldata _origin, + bytes32 /*_guid*/, + bytes calldata _message, + address /*_executor*/, + bytes calldata /*_extraData*/ + ) external payable { + if (msg.sender != LAYER_ZERO_ENDPOINT || enabledReporters[_origin.srcEid] != _origin.sender) + revert UnauthorizedLayerZeroReceive(); + (uint256[] memory ids, bytes32[] memory hashes) = abi.decode(_message, (uint256[], bytes32[])); + _storeHashes(chainIds[_origin.srcEid], ids, hashes); + } } diff --git a/packages/evm/contracts/adapters/LayerZero/LayerZeroReporter.sol b/packages/evm/contracts/adapters/LayerZero/LayerZeroReporter.sol index fc87b8af..071e9db2 100644 --- a/packages/evm/contracts/adapters/LayerZero/LayerZeroReporter.sol +++ b/packages/evm/contracts/adapters/LayerZero/LayerZeroReporter.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { ILayerZeroEndpoint } from "./interfaces/ILayerZeroEndpoint.sol"; +import { ILayerZeroEndpointV2, MessagingParams } from "./interfaces/ILayerZeroEndpointV2.sol"; import { Reporter } from "../Reporter.sol"; contract LayerZeroReporter is Reporter, Ownable { string public constant PROVIDER = "layer-zero"; - ILayerZeroEndpoint public immutable LAYER_ZERO_ENDPOINT; + ILayerZeroEndpointV2 public immutable LAYER_ZERO_ENDPOINT; - mapping(uint256 => uint16) public endpointIds; + mapping(uint256 => uint32) public endpointIds; uint256 public fee; error EndpointIdNotAvailable(); @@ -18,7 +18,7 @@ contract LayerZeroReporter is Reporter, Ownable { event FeeSet(uint256 fee); constructor(address headerStorage, address yaho, address lzEndpoint) Reporter(headerStorage, yaho) { - LAYER_ZERO_ENDPOINT = ILayerZeroEndpoint(lzEndpoint); + LAYER_ZERO_ENDPOINT = ILayerZeroEndpointV2(lzEndpoint); } function setEndpointIdByChainId(uint256 chainId, uint16 endpointId) external onlyOwner { @@ -37,19 +37,25 @@ contract LayerZeroReporter is Reporter, Ownable { uint256[] memory ids, bytes32[] memory hashes ) internal override returns (bytes32) { - uint16 targetEndpointId = endpointIds[targetChainId]; + uint32 targetEndpointId = endpointIds[targetChainId]; if (targetEndpointId == 0) revert EndpointIdNotAvailable(); - bytes memory payload = abi.encode(ids, hashes); - bytes memory path = abi.encodePacked(adapter, address(this)); + // https://github.com/LayerZero-Labs/LayerZero-v2/blob/1fde89479fdc68b1a54cda7f19efa84483fcacc4/oapp/contracts/oapp/libs/OptionsBuilder.sol#L38 + bytes memory options = abi.encodePacked(uint16(3)); + bytes memory message = abi.encode(ids, hashes); + MessagingParams memory params = MessagingParams( + targetEndpointId, + bytes32(abi.encodePacked(adapter)), + message, + options, + false + ); // solhint-disable-next-line check-send-result LAYER_ZERO_ENDPOINT.send{ value: fee }( - targetEndpointId, - path, - payload, - payable(msg.sender), // _refundAddress: refund address - address(0), // _zroPaymentAddress: future parameter - bytes("") // _adapterParams: adapterParams (see "Advanced Features") + params, + address(0) // refundAddress ); return bytes32(0); } + + receive() external payable {} } diff --git a/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroEndpoint.sol b/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroEndpoint.sol deleted file mode 100644 index e96c0ec7..00000000 --- a/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroEndpoint.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity ^0.8.20; - -interface ILayerZeroEndpoint { - // @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; -} diff --git a/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroEndpointV2.sol b/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroEndpointV2.sol new file mode 100644 index 00000000..0bbaf8c8 --- /dev/null +++ b/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroEndpointV2.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.8.0; + +struct MessagingParams { + uint32 dstEid; + bytes32 receiver; + bytes message; + bytes options; + bool payInLzToken; +} + +struct MessagingReceipt { + bytes32 guid; + uint64 nonce; + MessagingFee fee; +} + +struct MessagingFee { + uint256 nativeFee; + uint256 lzTokenFee; +} + +struct Origin { + uint32 srcEid; + bytes32 sender; + uint64 nonce; +} + +interface ILayerZeroEndpointV2 { + function send( + MessagingParams calldata _params, + address _refundAddress + ) external payable returns (MessagingReceipt memory); +} diff --git a/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroReceiver.sol b/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroReceiver.sol deleted file mode 100644 index af1c7a87..00000000 --- a/packages/evm/contracts/adapters/LayerZero/interfaces/ILayerZeroReceiver.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity ^0.8.20; - -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; -}