Skip to content

Commit

Permalink
Merge pull request #52 from catalystdao/layer-zero
Browse files Browse the repository at this point in the history
Layer Zero integration
  • Loading branch information
reednaa authored Jun 24, 2024
2 parents 5216c55 + 948ad86 commit a84050c
Show file tree
Hide file tree
Showing 36 changed files with 1,203 additions and 47 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ mumbai=
sepolia=
basesepolia=
arbitrumsepolia=
optimismsepolia=
optimismsepolia=
basttestnet=
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ out/
lcov.info

# Ignores development broadcast logs
!/broadcast
broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/

Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@
[submodule "lib/vibc-core-smart-contracts"]
path = lib/vibc-core-smart-contracts
url = https://github.com/open-ibc/vibc-core-smart-contracts
[submodule "lib/LayerZero-v2"]
path = lib/LayerZero-v2
url = https://github.com/LayerZero-Labs/LayerZero-v2
[submodule "lib/solidity-bytes-utils"]
path = lib/solidity-bytes-utils
url = https://github.com/GNSPS/solidity-bytes-utils
Binary file not shown.
1 change: 1 addition & 0 deletions lib/LayerZero-v2
Submodule LayerZero-v2 added at 3fd23f
1 change: 1 addition & 0 deletions lib/solidity-bytes-utils
Submodule solidity-bytes-utils added at e0115c
6 changes: 5 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
forge-std/=lib/forge-std/src/
openzeppelin/=lib/openzeppelin-contracts/contracts/
vibc-core-smart-contracts/=lib/vibc-core-smart-contracts/contracts/
vibc-core-smart-contracts/=lib/vibc-core-smart-contracts/contracts/
@openzeppelin/=lib/openzeppelin-contracts/
@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/protocol/

solidity-bytes-utils/=lib/solidity-bytes-utils/
27 changes: 23 additions & 4 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { BaseMultiChainDeployer} from "./BaseMultiChainDeployer.s.sol";
import { IncentivizedMockEscrow } from "../src/apps/mock/IncentivizedMockEscrow.sol";
import { IncentivizedWormholeEscrow } from "../src/apps/wormhole/IncentivizedWormholeEscrow.sol";
import { IncentivizedPolymerEscrow } from "../src/apps/polymer/vIBCEscrow.sol";
import { IncentivizedLayerZeroEscrow } from "../src/apps/layerzero/IncentivizedLayerZeroEscrow.sol";

contract DeployGeneralisedIncentives is BaseMultiChainDeployer {
using stdJson for string;
Expand All @@ -29,6 +30,7 @@ contract DeployGeneralisedIncentives is BaseMultiChainDeployer {
// define a list of AMB mappings so we can get their addresses.
mapping(string => mapping(string => address)) bridgeContract;


constructor() {
// Here we can define input salts. These are always assumed to be dependent on the secondary argument
// to an AMB. (as the first should be send lost gas to which is fixed.)
Expand Down Expand Up @@ -93,6 +95,24 @@ contract DeployGeneralisedIncentives is BaseMultiChainDeployer {
IncentivizedPolymerEscrow polymerEscrow = new IncentivizedPolymerEscrow{salt: salt}(vm.envAddress("SEND_LOST_GAS_TO"), polymerBridgeContract);

incentive = address(polymerEscrow);

} else if (versionHash == keccak256(abi.encodePacked("LayerZero"))) {
address layerZeroBridgeContract = bridgeContract[version][currentChainKey];
bytes32 salt = deploySalts[layerZeroBridgeContract];
require(layerZeroBridgeContract != address(0), "bridge cannot be address(0)");

address expectedAddress = _getAddress(
abi.encodePacked(
type(IncentivizedLayerZeroEscrow).creationCode,
abi.encode(vm.envAddress("SEND_LOST_GAS_TO"), layerZeroBridgeContract)
),
salt
);

if (expectedAddress.codehash != bytes32(0)) return expectedAddress;

IncentivizedLayerZeroEscrow layerZeroEscrow = new IncentivizedLayerZeroEscrow{salt: salt}(vm.envAddress("SEND_LOST_GAS_TO"), layerZeroBridgeContract);
incentive = address(layerZeroEscrow);
} else {
revert IncentivesVersionNotFound();
}
Expand All @@ -106,8 +126,7 @@ contract DeployGeneralisedIncentives is BaseMultiChainDeployer {
return incentive;
}

modifier load_config() {

modifier load_config() {
string memory pathRoot = vm.projectRoot();
pathToAmbConfig = string.concat(pathRoot, "/script/bridge_contracts.json");

Expand All @@ -119,11 +138,11 @@ contract DeployGeneralisedIncentives is BaseMultiChainDeployer {
// For each bridge, decode their contracts for each chain.
for (uint256 i = 0; i < availableBridges.length; ++i) {
string memory bridge = availableBridges[i];
// Get the chains this bridge support.
// Get the chains this bridge supports.
string[] memory availableBridgesChains = vm.parseJsonKeys(bridge_config, string.concat(".", bridge));
for (uint256 j = 0; j < availableBridgesChains.length; ++j) {
string memory chain = availableBridgesChains[j];
// decode the address
// Decode the address
address _bridgeContract = vm.parseJsonAddress(bridge_config, string.concat(".", bridge, ".", chain, ".bridge"));
bridgeContract[bridge][chain] = _bridgeContract;
}
Expand Down
50 changes: 50 additions & 0 deletions script/SimpleApplication.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import { ICrossChainReceiver } from "../src/interfaces/ICrossChainReceiver.sol";
import { IIncentivizedMessageEscrow } from "../src/interfaces/IIncentivizedMessageEscrow.sol";

/**
* @title Example application contract
*/
contract SimpleApplication is ICrossChainReceiver {

event Event(bytes message);

IIncentivizedMessageEscrow immutable MESSAGE_ESCROW;

constructor(address messageEscrow_) {
MESSAGE_ESCROW = IIncentivizedMessageEscrow(messageEscrow_);
}

function submitMessage(
bytes32 destinationIdentifier,
bytes calldata destinationAddress,
bytes calldata message,
IIncentivizedMessageEscrow.IncentiveDescription calldata incentive,
uint64 deadline
) external payable returns(uint256 gasRefund, bytes32 messageIdentifier) {
(gasRefund, messageIdentifier) = MESSAGE_ESCROW.submitMessage{value: msg.value}(
destinationIdentifier,
destinationAddress,
message,
incentive,
deadline
);
}

function setRemoteImplementation(bytes32 destinationIdentifier, bytes calldata implementation) external {
MESSAGE_ESCROW.setRemoteImplementation(destinationIdentifier, implementation);
}

function receiveAck(bytes32 /* destinationIdentifier */, bytes32 /* messageIdentifier */, bytes calldata acknowledgement) external {
emit Event(acknowledgement);
}

function receiveMessage(bytes32 /* sourceIdentifierbytes */, bytes32 /* messageIdentifier */, bytes calldata /* fromApplication */, bytes calldata message) external returns(bytes calldata acknowledgement) {
emit Event(message);
return message;
}

receive() external payable {}
}
45 changes: 45 additions & 0 deletions script/SubmitMessage.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

import { BaseMultiChainDeployer} from "./BaseMultiChainDeployer.s.sol";

// Import all the Apps for deployment here.
import { IMessageEscrowStructs } from "../src/interfaces/IMessageEscrowStructs.sol";
import { IIncentivizedMessageEscrow } from "../src/interfaces/IIncentivizedMessageEscrow.sol";

import { SimpleApplication } from "./SimpleApplication.sol";

contract SubmitMessage is BaseMultiChainDeployer {
function submitMessage(address app, bytes32 destinationIdentifier, bytes memory destinationAddress, string memory message, address refundGasTo) external broadcast {
IMessageEscrowStructs.IncentiveDescription memory incentive = IMessageEscrowStructs.IncentiveDescription({
maxGasDelivery: 200000,
maxGasAck: 200000,
refundGasTo: refundGasTo,
priceOfDeliveryGas: 1 gwei,
priceOfAckGas: 1 gwei,
targetDelta: 0
});

uint256 incentiveValue = 200000 * 1 gwei * 2;

SimpleApplication(payable(app)).submitMessage{value: 2807712706467 + incentiveValue}(
destinationIdentifier,
destinationAddress,
abi.encodePacked(message),
incentive,
0
);
}

function setRemoteImplementation(address app, bytes32 destinationIdentifier, bytes calldata implementation) broadcast external {
SimpleApplication(payable(app)).setRemoteImplementation(destinationIdentifier, implementation);
}

function deploySimpleApplication(string[] memory chains, address escrow) iter_chains_string(chains) broadcast external returns(address app) {
app = address(new SimpleApplication{salt: bytes32(0)}(escrow));
}
}

10 changes: 10 additions & 0 deletions script/bridge_contracts.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,15 @@
"bridge": "0xE2029629f51ab994210d671Dc08b7Ec94899b278",
"escrow": "0x87AE7bC6B565E545bDD51788C43BF9E5cbB72EBD"
}
},
"LayerZero": {
"basesepolia": {
"bridge": "0x6EDCE65403992e310A62460808c4b910D972f10f",
"escrow": "0xDb93559e30F5A3845438DDcf7Ca8A2D6D9005d30"
},
"optimismsepolia": {
"bridge": "0x6EDCE65403992e310A62460808c4b910D972f10f",
"escrow": "0xDb93559e30F5A3845438DDcf7Ca8A2D6D9005d30"
}
}
}
126 changes: 126 additions & 0 deletions script/layerzero/InitConfig.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

import { BaseMultiChainDeployer} from "../BaseMultiChainDeployer.s.sol";

import { IncentivizedLayerZeroEscrow } from "../../src/apps/layerzero/IncentivizedLayerZeroEscrow.sol";

import { ILayerZeroEndpointV2 } from "LayerZero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol";

contract InitConfigLayerZero is BaseMultiChainDeployer {
using stdJson for string;

error IncentivesNotFound();

string bridge_config;

bytes32 constant KECCACK_OF_NOTHING = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;

// define a list of AMB mappings so we can get their addresses.
mapping(string => address) escrow;
mapping(string => uint32 eid) chainEid;

function _setInitConfig(string[] memory counterPartyChains) internal {
IncentivizedLayerZeroEscrow lzescrow = IncentivizedLayerZeroEscrow(payable(escrow[currentChainKey]));
ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(lzescrow.ENDPOINT());
endpoint.eid();

// Get all eids.
uint32[] memory remoteEids = getEids(counterPartyChains);

// Get 1 example of the send library.
address sendLibrary = endpoint.getSendLibrary(address(lzescrow), remoteEids[0]);

lzescrow.initConfig(sendLibrary, remoteEids);
}

function _initConfig(string[] memory chains, string[] memory counterPartyChains) iter_chains_string(chains) broadcast internal {
_setInitConfig(counterPartyChains);
}

function _loadEids(string[] memory chains) iter_chains_string(chains) internal {
IncentivizedLayerZeroEscrow lzescrow = IncentivizedLayerZeroEscrow(payable(escrow[currentChainKey]));
ILayerZeroEndpointV2 endpoint = ILayerZeroEndpointV2(lzescrow.ENDPOINT());
chainEid[currentChainKey] = endpoint.eid();
}

function _loadAllEids(string[] memory chains, string[] memory counterPartyChains) internal {
_loadEids(combineString(chains, counterPartyChains));
}

function initConfig(string[] memory chains, string[] memory counterPartyChains) load_config external {
_loadAllEids(chains, counterPartyChains);
_initConfig(chains, counterPartyChains);
}

//-- Helpers --//
function getEids(string[] memory chains) public view returns(uint32[] memory eids) {
eids = new uint32[](chains.length);
for (uint256 i = 0; i < chains.length; ++i) {
eids[i] = chainEid[chains[i]];
}
}

function combineString(string[] memory a, string[] memory b) public pure returns (string[] memory all_chains) {
all_chains = new string[](a.length + b.length);
uint256 i = 0;
for (i = 0; i < a.length; ++i) {
all_chains[i] = a[i];
}
uint256 j = 0;
for (uint256 p = 0; p < b.length; ++p) {
string memory selected = b[p];
bool found = false;
for (uint256 q = 0; q < a.length; ++q) {
if (keccak256(abi.encode(a[q])) == keccak256(abi.encode(selected))) {
found = true;
break;
}
}
if (!found) {
all_chains[i+j] = selected;
++j;
}
}
string[] memory all_chains_copy = all_chains;
all_chains = new string[](i+j);
for (i = 0; i < all_chains.length; ++i) {
all_chains[i] = all_chains_copy[i];
}
}

function filter(string[] memory a, string memory val) public pure returns(string[] memory filtered) {
filtered = new string[](a.length - 1);
uint256 j = 0;
for (uint256 i = 0; i < a.length; ++i) {
string memory currentElement = a[i];
if (keccak256(abi.encodePacked(val)) == keccak256(abi.encodePacked(currentElement))) continue;
filtered[j] = currentElement;
++j;
}
require(j == a.length - 1, "Invalid Index"); // May be because val is replicated in a.
}

modifier load_config() {
string memory pathRoot = vm.projectRoot();
string memory pathToAmbConfig = string.concat(pathRoot, "/script/bridge_contracts.json");

bridge_config = vm.readFile(pathToAmbConfig);

string memory bridge = "LayerZero";
// Get the chains this bridge supports.
string[] memory availableBridgesChains = vm.parseJsonKeys(bridge_config, string.concat(".", bridge));
for (uint256 j = 0; j < availableBridgesChains.length; ++j) {
string memory chain = availableBridgesChains[j];
// Decode the address
address escrowContract = vm.parseJsonAddress(bridge_config, string.concat(".", bridge, ".", chain, ".escrow"));
escrow[chain] = escrowContract;
}

_;
}
}

20 changes: 20 additions & 0 deletions script/layerzero/LzTryExecute.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;

import "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";

import { BaseMultiChainDeployer} from "../BaseMultiChainDeployer.s.sol";

import { IncentivizedLayerZeroEscrow } from "../../src/apps/layerzero/IncentivizedLayerZeroEscrow.sol";

contract LZProcessMessage is BaseMultiChainDeployer {
function processMessage(
address escrow,
bytes calldata rawMessage,
bytes32 feeRecipient
) external broadcast {
IncentivizedLayerZeroEscrow(payable(escrow)).processPacket{value: 2806592784579}(hex"", rawMessage, feeRecipient);
}
}

Loading

0 comments on commit a84050c

Please sign in to comment.