|
| 1 | +// SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | +pragma solidity >=0.8.0; |
| 3 | + |
| 4 | +import { IERC20 } from "forge-std/interfaces/IERC20.sol"; |
| 5 | + |
| 6 | +import { OptionsBuilder } from "layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol"; |
| 7 | + |
| 8 | +import { LZBridgeTesting } from "src/testing/bridges/LZBridgeTesting.sol"; |
| 9 | +import { LZForwarder, ILayerZeroEndpointV2 } from "src/forwarders/LZForwarder.sol"; |
| 10 | +import { LZReceiver, Origin } from "src/receivers/LZReceiver.sol"; |
| 11 | +import { RecordedLogs } from "src/testing/utils/RecordedLogs.sol"; |
| 12 | + |
| 13 | +import "./IntegrationBase.t.sol"; |
| 14 | + |
| 15 | +interface ITreasury { |
| 16 | + function setLzTokenEnabled(bool _lzTokenEnabled) external; |
| 17 | + function setLzTokenFee(uint256 _lzTokenFee) external; |
| 18 | +} |
| 19 | + |
| 20 | +contract LZIntegrationTestWithLZToken is IntegrationBaseTest { |
| 21 | + |
| 22 | + using DomainHelpers for *; |
| 23 | + using LZBridgeTesting for *; |
| 24 | + using OptionsBuilder for bytes; |
| 25 | + |
| 26 | + uint32 sourceEndpointId = LZForwarder.ENDPOINT_ID_ETHEREUM; |
| 27 | + uint32 destinationEndpointId; |
| 28 | + |
| 29 | + address sourceEndpoint = LZForwarder.ENDPOINT_ETHEREUM; |
| 30 | + address destinationEndpoint; |
| 31 | + |
| 32 | + address lzToken = 0x6985884C4392D348587B19cb9eAAf157F13271cd; |
| 33 | + address lzOwner = 0xBe010A7e3686FdF65E93344ab664D065A0B02478; |
| 34 | + address treasury = 0x5ebB3f2feaA15271101a927869B3A56837e73056; |
| 35 | + |
| 36 | + Domain destination2; |
| 37 | + Bridge bridge2; |
| 38 | + |
| 39 | + function setUp() public override { |
| 40 | + super.setUp(); |
| 41 | + |
| 42 | + source.selectFork(); |
| 43 | + |
| 44 | + vm.startPrank(lzOwner); |
| 45 | + ILayerZeroEndpointV2(sourceEndpoint).setLzToken(lzToken); |
| 46 | + ITreasury(treasury).setLzTokenEnabled(true); |
| 47 | + ITreasury(treasury).setLzTokenFee(1e18); |
| 48 | + vm.stopPrank(); |
| 49 | + } |
| 50 | + |
| 51 | + function test_base() public { |
| 52 | + destinationEndpointId = LZForwarder.ENDPOINT_ID_BASE; |
| 53 | + destinationEndpoint = LZForwarder.ENDPOINT_BASE; |
| 54 | + |
| 55 | + runCrossChainTests(getChain("base").createFork()); |
| 56 | + } |
| 57 | + |
| 58 | + function test_binance() public { |
| 59 | + destinationEndpointId = LZForwarder.ENDPOINT_ID_BNB; |
| 60 | + destinationEndpoint = LZForwarder.ENDPOINT_BNB; |
| 61 | + |
| 62 | + runCrossChainTests(getChain("bnb_smart_chain").createFork()); |
| 63 | + } |
| 64 | + |
| 65 | + function initSourceReceiver() internal override returns (address) { |
| 66 | + return address(new LZReceiver( |
| 67 | + sourceEndpoint, |
| 68 | + destinationEndpointId, |
| 69 | + bytes32(uint256(uint160(destinationAuthority))), |
| 70 | + address(moSource), |
| 71 | + makeAddr("delegate"), |
| 72 | + makeAddr("owner") |
| 73 | + )); |
| 74 | + } |
| 75 | + |
| 76 | + function initDestinationReceiver() internal override returns (address) { |
| 77 | + return address(new LZReceiver( |
| 78 | + destinationEndpoint, |
| 79 | + sourceEndpointId, |
| 80 | + bytes32(uint256(uint160(sourceAuthority))), |
| 81 | + address(moDestination), |
| 82 | + makeAddr("delegate"), |
| 83 | + makeAddr("owner") |
| 84 | + )); |
| 85 | + } |
| 86 | + |
| 87 | + function initBridgeTesting() internal override returns (Bridge memory) { |
| 88 | + return LZBridgeTesting.createLZBridge(source, destination); |
| 89 | + } |
| 90 | + |
| 91 | + function queueSourceToDestination(bytes memory message) internal override { |
| 92 | + // Gas to queue message |
| 93 | + vm.deal(sourceAuthority, 1 ether); |
| 94 | + deal(lzToken, sourceAuthority, 1 ether); |
| 95 | + |
| 96 | + bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0); |
| 97 | + |
| 98 | + assertEq(IERC20(lzToken).balanceOf(address(sourceAuthority)), 1 ether); |
| 99 | + assertEq(address(sourceAuthority).balance, 1 ether); |
| 100 | + |
| 101 | + LZForwarder.sendMessage( |
| 102 | + destinationEndpointId, |
| 103 | + bytes32(uint256(uint160(destinationReceiver))), |
| 104 | + ILayerZeroEndpointV2(bridge.sourceCrossChainMessenger), |
| 105 | + message, |
| 106 | + options, |
| 107 | + sourceAuthority, |
| 108 | + true |
| 109 | + ); |
| 110 | + |
| 111 | + // LZ token and ETH spent |
| 112 | + assertLt(IERC20(lzToken).balanceOf(address(sourceAuthority)), 1 ether); |
| 113 | + assertLt(address(sourceAuthority).balance, 1 ether); |
| 114 | + } |
| 115 | + |
| 116 | + function queueDestinationToSource(bytes memory message) internal override { |
| 117 | + vm.deal(destinationAuthority, 1 ether); // Gas to queue message |
| 118 | + |
| 119 | + bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0); |
| 120 | + |
| 121 | + LZForwarder.sendMessage( |
| 122 | + sourceEndpointId, |
| 123 | + bytes32(uint256(uint160(sourceReceiver))), |
| 124 | + ILayerZeroEndpointV2(bridge.destinationCrossChainMessenger), |
| 125 | + message, |
| 126 | + options, |
| 127 | + destinationAuthority, |
| 128 | + false |
| 129 | + ); |
| 130 | + } |
| 131 | + |
| 132 | + function relaySourceToDestination() internal override { |
| 133 | + bridge.relayMessagesToDestination(true, sourceAuthority, destinationReceiver); |
| 134 | + } |
| 135 | + |
| 136 | + function relayDestinationToSource() internal override { |
| 137 | + bridge.relayMessagesToSource(true, destinationAuthority, sourceReceiver); |
| 138 | + } |
| 139 | + |
| 140 | +} |
0 commit comments