Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {Script, console2} from "forge-std/Script.sol";
import {LibClone} from "solady/utils/LibClone.sol";
import {LibString} from "solady/utils/LibString.sol";
import {EnumerableSet} from "openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {PricingFlat} from "../src/PricingFlat.sol";
import {PricingHarberger} from "../src/PricingHarberger.sol";
import {Endpoint} from "../src/Endpoint.sol";
import {ClustersHub} from "../src/ClustersHub.sol";
import {IPricing} from "../src/interfaces/IPricing.sol";
import {IEndpoint} from "../src/interfaces/IEndpoint.sol";
import {IOAppCore} from "layerzero-oapp/contracts/oapp/interfaces/IOAppCore.sol";

contract DeployScript is Script {
using LibString for string;
using LibString for uint256;
using LibString for address;
using EnumerableSet for EnumerableSet.UintSet;

struct Deployment {
string chain;
address pricingTemplate;
address pricingProxy;
address endpointTemplate;
address endpointProxy;
address clusters;
address layerzero;
uint32 dstEid;
}

uint256 internal deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address internal deployer = vm.addr(deployerPrivateKey);
address internal constant signer = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;

EnumerableSet.UintSet internal forkIds;
mapping(uint256 forkId => Deployment) internal deployments;

uint32 internal constant LZ_EID_SEPOLIA = 40161;
uint32 internal constant LZ_EID_GOERLI = 40121;
uint32 internal constant LZ_EID_HOLESKY = 40217;

address internal constant LZ_END_SEPOLIA = 0x464570adA09869d8741132183721B4f0769a0287;
address internal constant LZ_END_GOERLI = 0x464570adA09869d8741132183721B4f0769a0287;
address internal constant LZ_END_HOLESKY = 0x464570adA09869d8741132183721B4f0769a0287;

function _addressToBytes32(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}

function setUp() public {}

function deploy(
string memory chain,
string memory rpcUrl,
bool isHarberger,
bool isHub,
uint32 dstEid,
address lzEndpoint
) internal {
// Prep fork
uint256 forkId = vm.createFork(rpcUrl);
forkIds.add(forkId);
vm.selectFork(forkId);
vm.startBroadcast(deployerPrivateKey);
// Deploy and initialize pricing
if (isHub) {
if (isHarberger) {
PricingHarberger pricing = new PricingHarberger();
deployments[forkId].pricingTemplate = address(pricing);
} else {
PricingFlat pricing = new PricingFlat();
deployments[forkId].pricingTemplate = address(pricing);
}
vm.label(deployments[forkId].pricingTemplate, chain.concat(" Pricing Template"));
deployments[forkId].pricingProxy = LibClone.deployERC1967(deployments[forkId].pricingTemplate);
vm.label(deployments[forkId].pricingProxy, chain.concat(" Pricing Proxy"));
if (isHarberger) {
PricingHarberger(deployments[forkId].pricingProxy).initialize(deployer, block.timestamp);
} else {
PricingFlat(deployments[forkId].pricingProxy).initialize(deployer);
}
}
// Deploy and initialize endpoint
deployments[forkId].endpointTemplate = address(new Endpoint());
vm.label(deployments[forkId].endpointTemplate, chain.concat(" Endpoint Template"));
deployments[forkId].endpointProxy = LibClone.deployERC1967(deployments[forkId].endpointTemplate);
vm.label(deployments[forkId].endpointProxy, chain.concat(" Endpoint Proxy"));
Endpoint(deployments[forkId].endpointProxy).initialize(deployer, signer, lzEndpoint);
if (isHub) {
deployments[forkId].clusters = address(
new ClustersHub(
deployments[forkId].pricingProxy, deployments[forkId].endpointProxy, block.timestamp + 5 minutes
)
);
vm.label(deployments[forkId].clusters, chain.concat(" Clusters Hub"));
IEndpoint(deployments[forkId].endpointProxy).setClustersAddr(deployments[forkId].clusters);
} else {
// Deploy Spoke infrastructure here
}
// Store remaining deployment information
deployments[forkId].chain = chain;
deployments[forkId].layerzero = lzEndpoint;
deployments[forkId].dstEid = dstEid;
vm.stopBroadcast();
}

function configure() internal {
uint256[] memory forks = forkIds.values();
for (uint256 i; i < forks.length; ++i) {
address endpointProxy = deployments[i].endpointProxy;
vm.selectFork(forks[i]);
vm.startBroadcast(deployerPrivateKey);
for (uint256 j; j < forks.length; ++j) {
if (i == j) continue;
IOAppCore(endpointProxy).setPeer(
deployments[forks[j]].dstEid, _addressToBytes32(deployments[forks[j]].endpointProxy)
);
}
if (i == 0) {
// Set dstEid on hub to enable replication
} else {
IEndpoint(endpointProxy).setDstEid(deployments[forks[0]].dstEid);
}
vm.stopBroadcast();
}
}

function run() public {
deploy("Sepolia", vm.envString("SEPOLIA_RPC_URL"), true, true, LZ_EID_SEPOLIA, LZ_END_SEPOLIA);
deploy("Goerli", vm.envString("GOERLI_RPC_URL"), true, false, LZ_EID_GOERLI, LZ_END_GOERLI);
deploy("Holesky", vm.envString("HOLESKY_RPC_URL"), true, false, LZ_EID_HOLESKY, LZ_END_HOLESKY);
configure();

for (uint256 i; i < forkIds.length(); ++i) {
Deployment memory deployment = deployments[forkIds.at(i)];
if (deployment.pricingTemplate != address(0)) {
console2.log(
deployment.chain.concat(" Pricing Template: ").concat(
deployment.pricingTemplate.toHexStringChecksummed()
)
);
}
if (deployment.pricingProxy != address(0)) {
console2.log(
deployment.chain.concat(" Pricing Proxy: ").concat(deployment.pricingProxy.toHexStringChecksummed())
);
}
console2.log(
deployment.chain.concat(" Endpoint Template: ").concat(
deployment.endpointTemplate.toHexStringChecksummed()
)
);
console2.log(
deployment.chain.concat(" Endpoint Proxy: ").concat(deployment.endpointProxy.toHexStringChecksummed())
);
if (deployment.clusters != address(0)) {
console2.log(
deployment.chain.concat(" Clusters: ").concat(deployment.clusters.toHexStringChecksummed())
);
}
console2.log(
deployment.chain.concat(" LayerZero Endpoint: ").concat(deployment.layerzero.toHexStringChecksummed())
);
console2.log(deployment.chain.concat(" LayerZero DstEid: ").concat(uint256(deployment.dstEid).toString()));
console2.log("");
}
}
}
34 changes: 31 additions & 3 deletions script/Testnet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.13;
import {Script, console2} from "forge-std/Script.sol";

import {LibClone} from "solady/utils/LibClone.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {PricingHarberger} from "../src/PricingHarberger.sol";
import {IPricing} from "../src/interfaces/IPricing.sol";
import {Endpoint} from "../src/Endpoint.sol";
Expand Down Expand Up @@ -48,7 +49,7 @@ contract TestnetScript is Script {
vm.label(address(sepoliaPricing), "Sepolia Pricing Template");
IPricing sepoliaPricingProxy = IPricing(LibClone.deployERC1967(address(sepoliaPricing)));
vm.label(address(sepoliaPricingProxy), "Sepolia Pricing Proxy");
PricingHarberger(address(sepoliaPricingProxy)).initialize(msg.sender, block.timestamp + 7 days);
PricingHarberger(address(sepoliaPricingProxy)).initialize(msg.sender, block.timestamp + 1 minutes);
Endpoint sepoliaEndpoint = new Endpoint();
vm.label(address(sepoliaEndpoint), "Sepolia Endpoint Template");
IEndpoint sepoliaEndpointProxy = IEndpoint(LibClone.deployERC1967(address(sepoliaEndpoint)));
Expand All @@ -67,7 +68,7 @@ contract TestnetScript is Script {
//vm.label(address(goerliPricing), "Goerli Pricing Template");
//IPricing goerliPricingProxy = IPricing(LibClone.deployERC1967(address(goerliPricing)));
//vm.label(address(goerliPricingProxy), "Goerli Pricing Proxy");
//PricingHarberger(address(goerliPricingProxy)).initialize(msg.sender, block.timestamp + 7 days);
//PricingHarberger(address(goerliPricingProxy)).initialize(msg.sender, block.timestamp + 1 minutes);
Endpoint goerliEndpoint = new Endpoint();
vm.label(address(goerliEndpoint), "Goerli Endpoint Template");
IEndpoint goerliEndpointProxy = IEndpoint(LibClone.deployERC1967(address(goerliEndpoint)));
Expand All @@ -88,7 +89,7 @@ contract TestnetScript is Script {
//vm.label(address(holeskyPricing), "Holesky Pricing Template");
//IPricing holeskyPricingProxy = IPricing(LibClone.deployERC1967(address(holeskyPricing)));
//vm.label(address(holeskyPricingProxy), "Holesky Pricing Proxy");
//PricingHarberger(address(holeskyPricingProxy)).initialize(msg.sender, block.timestamp + 7 days);
//PricingHarberger(address(holeskyPricingProxy)).initialize(msg.sender, block.timestamp + 1 minutes);
Endpoint holeskyEndpoint = new Endpoint();
vm.label(address(holeskyEndpoint), "Holesky Endpoint Template");
IEndpoint holeskyEndpointProxy = IEndpoint(LibClone.deployERC1967(address(holeskyEndpoint)));
Expand Down Expand Up @@ -120,5 +121,32 @@ contract TestnetScript is Script {
);
// No DstEid is set on Sepolia Hub as that engages replication, which is not yet fully implemented
vm.stopBroadcast();

// Check state
vm.selectFork(sepoliaFork);
console2.log("Sepolia Pricing:");
console2.log(address(sepoliaPricingProxy));
console2.log("Sepolia Endpoint:");
console2.log(address(sepoliaEndpointProxy));
console2.log("Sepolia Clusters Hub:");
console2.log(address(sepoliaClusters));
//console2.log(sepoliaEndpointProxy.dstEid());
//console2.log(Ownable(address(sepoliaEndpointProxy)).owner());
//console2.logBytes32(IOAppCore(address(sepoliaEndpointProxy)).peers(LZ_EID_GOERLI));
//console2.logBytes32(IOAppCore(address(sepoliaEndpointProxy)).peers(LZ_EID_HOLESKY));
vm.selectFork(goerliFork);
console2.log("Goerli Endpoint:");
console2.log(address(goerliEndpointProxy));
//console2.log(goerliEndpointProxy.dstEid());
//console2.log(Ownable(address(goerliEndpointProxy)).owner());
//console2.logBytes32(IOAppCore(address(goerliEndpointProxy)).peers(LZ_EID_SEPOLIA));
//console2.logBytes32(IOAppCore(address(goerliEndpointProxy)).peers(LZ_EID_HOLESKY));
vm.selectFork(holeskyFork);
console2.log("Holesky Endpoint:");
console2.log(address(holeskyEndpointProxy));
//console2.log(holeskyEndpointProxy.dstEid());
//console2.log(Ownable(address(holeskyEndpointProxy)).owner());
//console2.logBytes32(IOAppCore(address(holeskyEndpointProxy)).peers(LZ_EID_SEPOLIA));
//console2.logBytes32(IOAppCore(address(holeskyEndpointProxy)).peers(LZ_EID_GOERLI));
}
}
51 changes: 51 additions & 0 deletions script/Testpad.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Script, console2} from "forge-std/Script.sol";

import {LibClone} from "solady/utils/LibClone.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {PricingHarberger} from "../src/PricingHarberger.sol";
import {IPricing} from "../src/interfaces/IPricing.sol";
import {Endpoint} from "../src/Endpoint.sol";
import {IEndpoint} from "../src/interfaces/IEndpoint.sol";
import {IOAppCore} from "layerzero-oapp/contracts/oapp/interfaces/IOAppCore.sol";
import {ClustersHub} from "../src/ClustersHub.sol";
import {OptionsBuilder} from "layerzero-oapp/contracts/oapp/libs/OptionsBuilder.sol";
import "../lib/LayerZero-v2/protocol/contracts/EndpointV2.sol";

contract TestpadScript is Script {
using OptionsBuilder for bytes;

address internal constant HOLESKY_ENDPOINT = 0x27Ec7Bf5DdFac76f6c7A0EA7267d5b266D5Dd45C;

string internal HOLESKY_RPC_URL = vm.envString("HOLESKY_RPC_URL");
uint256 internal holeskyFork;

/// @dev Convert address to bytes32
function _addressToBytes32(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}

function setUp() public {
holeskyFork = vm.createFork(HOLESKY_RPC_URL);
}

function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);
IEndpoint endpoint = IEndpoint(HOLESKY_ENDPOINT);
IOAppCore lzEndpoint = IOAppCore(HOLESKY_ENDPOINT);

vm.selectFork(holeskyFork);
bytes memory data = abi.encodeWithSignature(
"buyName(bytes32,uint256,string)", _addressToBytes32(deployer), 0.01 ether, "zodomo"
);
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(250_000 gwei, uint128(0.01 ether));
(uint256 nativeFee,) = endpoint.quote(40161, data, options, false);
console2.log(nativeFee);
console2.log(endpoint.dstEid());
console2.log(Ownable(HOLESKY_ENDPOINT).owner());
console2.logBytes32(lzEndpoint.peers(40161));
}
}
32 changes: 18 additions & 14 deletions src/ClustersHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ contract ClustersHub is NameManagerHub {

/// @dev For payable multicall to be secure, we cannot trust msg.value params in other external methods
/// @dev Must instead do strict protocol invariant checking at the end of methods like Uniswap V2
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {
function multicall(bytes[] calldata data, bytes calldata config)
external
payable
returns (bytes[] memory results)
{
_inMulticall = true;
results = new bytes[](data.length);
bool success;
Expand All @@ -47,20 +51,20 @@ contract ClustersHub is NameManagerHub {
_checkInvariant();

bytes memory payload = abi.encodeWithSignature("multicall(bytes[])", results);
IEndpoint(endpoint).sendPayload{value: msg.value}(payload);
IEndpoint(endpoint).sendPayload{value: msg.value}(payload, config);
_inMulticall = false;
}

function add(bytes32 addr) external payable returns (bytes memory payload) {
return add(_addressToBytes32(msg.sender), addr);
function add(bytes32 addr, bytes calldata config) external payable returns (bytes memory payload) {
return add(_addressToBytes32(msg.sender), addr, config);
}

function verify(uint256 clusterId) external payable returns (bytes memory payload) {
return verify(_addressToBytes32(msg.sender), clusterId);
function verify(uint256 clusterId, bytes calldata config) external payable returns (bytes memory payload) {
return verify(_addressToBytes32(msg.sender), clusterId, config);
}

function remove(bytes32 addr) external payable returns (bytes memory payload) {
return remove(_addressToBytes32(msg.sender), addr);
function remove(bytes32 addr, bytes calldata config) external payable returns (bytes memory payload) {
return remove(_addressToBytes32(msg.sender), addr, config);
}

function getUnverifiedAddresses(uint256 clusterId) external view returns (bytes32[] memory) {
Expand All @@ -77,7 +81,7 @@ contract ClustersHub is NameManagerHub {

/// ENDPOINT FUNCTIONS ///

function add(bytes32 msgSender, bytes32 addr)
function add(bytes32 msgSender, bytes32 addr, bytes calldata config)
public
payable
onlyEndpoint(msgSender)
Expand All @@ -90,10 +94,10 @@ contract ClustersHub is NameManagerHub {

payload = abi.encodeWithSignature("add(bytes32,bytes32)", msgSender, addr);
if (_inMulticall) return payload;
else IEndpoint(endpoint).sendPayload{value: msg.value}(payload);
else IEndpoint(endpoint).sendPayload{value: msg.value}(payload, config);
}

function verify(bytes32 msgSender, uint256 clusterId)
function verify(bytes32 msgSender, uint256 clusterId, bytes calldata config)
public
payable
onlyEndpoint(msgSender)
Expand All @@ -115,10 +119,10 @@ contract ClustersHub is NameManagerHub {

payload = abi.encodeWithSignature("verify(bytes32,uint256)", msgSender, clusterId);
if (_inMulticall) return payload;
else IEndpoint(endpoint).sendPayload{value: msg.value}(payload);
else IEndpoint(endpoint).sendPayload{value: msg.value}(payload, config);
}

function remove(bytes32 msgSender, bytes32 addr)
function remove(bytes32 msgSender, bytes32 addr, bytes calldata config)
public
payable
onlyEndpoint(msgSender)
Expand All @@ -134,7 +138,7 @@ contract ClustersHub is NameManagerHub {

payload = abi.encodeWithSignature("remove(bytes32,bytes32)", msgSender, addr);
if (_inMulticall) return payload;
else IEndpoint(endpoint).sendPayload{value: msg.value}(payload);
else IEndpoint(endpoint).sendPayload{value: msg.value}(payload, config);
}

/// INTERNAL FUNCTIONS ///
Expand Down
Loading