generated from refcell/femplate
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ab99276
commit 36c266e
Showing
2 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0; | ||
|
||
import "forge-std/Test.sol"; | ||
import "forge-std/console.sol"; | ||
|
||
struct Packet { | ||
uint64 nonce; | ||
uint32 srcEid; | ||
address sender; | ||
uint32 dstEid; | ||
bytes32 receiver; | ||
bytes32 guid; | ||
bytes message; | ||
} | ||
|
||
struct Origin { | ||
uint32 srcEid; | ||
bytes32 sender; | ||
uint64 nonce; | ||
} | ||
|
||
interface ILayerzeroV2Receiver { | ||
function lzReceive( | ||
Origin calldata _origin, | ||
bytes32 _guid, | ||
bytes calldata _message, | ||
address _executor, | ||
bytes calldata _extraData | ||
) external payable; | ||
} | ||
|
||
contract LayerZeroV2Helper is Test { | ||
bytes32 constant PACKET_SELECTOR = 0x1ab700d4ced0c005b164c0f789fd09fcbb0156d4c2041b8a3bfbcd961cd1567f; | ||
|
||
function help(address endpoint, uint256 forkId, Vm.Log[] calldata logs) external { | ||
_help(endpoint, forkId, PACKET_SELECTOR, logs); | ||
} | ||
|
||
function _help(address endpoint, uint256 forkId, bytes32 eventSelector, Vm.Log[] memory logs) internal { | ||
uint256 prevForkId = vm.activeFork(); | ||
|
||
for (uint256 i; i < logs.length; i++) { | ||
Vm.Log memory log = logs[i]; | ||
|
||
if (log.topics[0] == eventSelector) { | ||
(bytes memory payload,,) = abi.decode(log.data, (bytes, bytes, address)); | ||
Packet memory packet = this.decodePacket(payload); | ||
address receiver = address(uint160(uint256(packet.receiver))); | ||
|
||
vm.selectFork(forkId); | ||
vm.prank(endpoint); | ||
ILayerzeroV2Receiver(receiver).lzReceive( | ||
Origin(packet.srcEid, bytes32(uint256(uint160(packet.sender))), packet.nonce), | ||
packet.guid, | ||
packet.message, | ||
address(0), | ||
bytes("") | ||
); | ||
vm.selectFork(prevForkId); | ||
} | ||
} | ||
} | ||
|
||
function decodePacket(bytes calldata encodedPacket) public pure returns (Packet memory) { | ||
// Decode the packet header | ||
uint8 version = uint8(encodedPacket[0]); | ||
uint64 nonce = toUint64(encodedPacket, 1); | ||
uint32 srcEid = toUint32(encodedPacket, 9); | ||
address sender = toAddress(encodedPacket, 13); | ||
uint32 dstEid = toUint32(encodedPacket, 45); | ||
bytes32 receiver = toBytes32(encodedPacket, 49); | ||
|
||
// Decode the payload | ||
bytes32 guid = toBytes32(encodedPacket, 81); | ||
bytes memory message = encodedPacket[113:]; | ||
|
||
return Packet({ | ||
nonce: nonce, | ||
srcEid: srcEid, | ||
sender: sender, | ||
dstEid: dstEid, | ||
receiver: receiver, | ||
guid: guid, | ||
message: message | ||
}); | ||
} | ||
|
||
function toUint64(bytes calldata data, uint256 offset) internal pure returns (uint64) { | ||
require(offset + 8 <= data.length, "toUint64: out of bounds"); | ||
return uint64(bytes8(data[offset:offset + 8])); | ||
} | ||
|
||
function toUint32(bytes calldata data, uint256 offset) internal pure returns (uint32) { | ||
require(offset + 4 <= data.length, "toUint32: out of bounds"); | ||
return uint32(bytes4(data[offset:offset + 4])); | ||
} | ||
|
||
function toAddress(bytes calldata data, uint256 offset) internal pure returns (address) { | ||
require(offset + 20 <= data.length, "toAddress: out of bounds"); | ||
return address(uint160(bytes20(data[offset + 12:offset + 32]))); | ||
} | ||
|
||
function toBytes32(bytes calldata data, uint256 offset) internal pure returns (bytes32) { | ||
require(offset + 32 <= data.length, "toBytes32: out of bounds"); | ||
return bytes32(data[offset:offset + 32]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0; | ||
|
||
import "forge-std/Test.sol"; | ||
|
||
import {LayerZeroV2Helper} from "src/layerzero-v2/LayerZeroV2Helper.sol"; | ||
|
||
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 ILayerZeroV2Endpoint { | ||
function send(MessagingParams calldata _params, address _refundAddress) | ||
external | ||
payable | ||
returns (MessagingReceipt memory); | ||
|
||
function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory); | ||
} | ||
|
||
contract Target { | ||
uint256 public value; | ||
|
||
function lzReceive( | ||
Origin calldata _origin, | ||
bytes32 _guid, | ||
bytes calldata _message, | ||
address _executor, | ||
bytes calldata _extraData | ||
) external payable { | ||
value = abi.decode(_message, (uint256)); | ||
} | ||
} | ||
|
||
contract LayerZeroV2HelperTest is Test { | ||
LayerZeroV2Helper lzHelper; | ||
Target target; | ||
|
||
uint256 L1_FORK_ID; | ||
uint256 POLYGON_FORK_ID; | ||
|
||
uint32 constant L1_ID = 30101; | ||
uint32 constant POLYGON_ID = 30109; | ||
|
||
address constant lzV2Endpoint = 0x1a44076050125825900e736c501f859c50fE728c; | ||
|
||
string RPC_ETH_MAINNET = vm.envString("ETH_MAINNET_RPC_URL"); | ||
string RPC_POLYGON_MAINNET = vm.envString("POLYGON_MAINNET_RPC_URL"); | ||
|
||
function setUp() external { | ||
L1_FORK_ID = vm.createSelectFork(RPC_ETH_MAINNET, 19_730_754); | ||
lzHelper = new LayerZeroV2Helper(); | ||
|
||
POLYGON_FORK_ID = vm.createSelectFork(RPC_POLYGON_MAINNET, 56_652_576); | ||
target = new Target(); | ||
} | ||
|
||
function testSimpleLzV2() external { | ||
console.log(address(this)); | ||
vm.selectFork(L1_FORK_ID); | ||
|
||
vm.recordLogs(); | ||
_someCrossChainFunctionInYourContract(); | ||
Vm.Log[] memory logs = vm.getRecordedLogs(); | ||
lzHelper.help(lzV2Endpoint, POLYGON_FORK_ID, logs); | ||
|
||
vm.selectFork(POLYGON_FORK_ID); | ||
assertEq(target.value(), 420); | ||
} | ||
|
||
function _someCrossChainFunctionInYourContract() internal { | ||
MessagingParams memory params = MessagingParams( | ||
POLYGON_ID, | ||
bytes32(uint256(uint160(address(target)))), | ||
abi.encode(420), | ||
abi.encodePacked(uint16(1), uint256(200_000)), | ||
false | ||
); | ||
|
||
uint256 fees = ILayerZeroV2Endpoint(lzV2Endpoint).quote(params, address(this)).nativeFee; | ||
ILayerZeroV2Endpoint(lzV2Endpoint).send{value: fees}(params, address(this)); | ||
} | ||
} |