Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scripts for deployment #3

Closed
wants to merge 6 commits into from
Closed
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
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

47 changes: 33 additions & 14 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
test = 'test'
cache_path = 'cache'
fs_permissions = [
{ access = "read-write", path = "./deployments" },
{ access = "read", path = "./" },
]
optimizer = true
optimizer-runs = 200
evm_version = "cancun"
solc_version = "0.8.24"
prompt_timeout = 120
src = "src"
out = "out"
libs = ["lib"]
test = 'test'
cache_path = 'cache'
fs_permissions = [
{ access = "read-write", path = "./deployments" },
{ access = "read", path = "./" },
]
optimizer = true
optimizer-runs = 200
evm_version = "cancun"
solc_version = "0.8.24"
prompt_timeout = 120

[rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"
arbitrum = "${ARBITRUM_RPC_URL}"
optimism = "${OPTIMISM_RPC_URL}"
base = "${BASE_RPC_URL}"
fraxtal = "${FRAXTAL_RPC_URL}"
holesky = "${HOLESKY_RPC_URL}"
fraxtal_testnet = "${FRAXTAL_TESTNET_RPC_URL}"

[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
arbitrum = { key = "${ARBISCAN_API_KEY}" }
optimism = { key = "${OPTIMISTIC_ETHERSCAN_API_KEY}" }
base = { key = "${BASESCAN_API_KEY}", url = "https://api.basescan.org/api/" }
holesky = { key = "${ETHERSCAN_API_KEY}" }
fraxtal = { key = "${FRAXSCAN_API_KEY}", url = "https://api.fraxscan.io/api/" }
fraxtal_testnet = { key = "${FRAXSCAN_API_KEY}", url = "https://api-holesky.fraxscan.io/api/" }

1 change: 0 additions & 1 deletion lib/solmate
Submodule solmate deleted from 97bdb2
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"dependencies": {
"@layerzerolabs/lz-evm-v1-0.7": "^2.3.40",
"hardhat-deploy": "^0.12.4",
"lint-staged": "^15.2.10"
"lint-staged": "^15.2.10",
"solmate": "^6.2.0"
}
}
4 changes: 2 additions & 2 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ forge-std/=node_modules/forge-std/src/
@layerzerolabs/lz-evm-v1-0.7/=node_modules/@layerzerolabs/lz-evm-v1-0.7/
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/
@solmate/=lib/solmate/src/
@adapters/=src/
@solmate/=node_modules/solmate/src/
@/=src/
@factory/=src/factory/
@interfaces/=src/interfaces/
solidity-bytes-utils/=node_modules/solidity-bytes-utils/
Expand Down
85 changes: 85 additions & 0 deletions script/BaseData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: MIt
pragma solidity ^0.8.24;

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

contract BaseData is Script {
struct Actors {
address OFT_DELEGATE;
address TOKEN_ADMIN;
address PROXY_ADMIN;
}

struct ChainAddresses {
address lzEndpoint;
}

struct ChainIds {
uint256 mainnet;
uint256 base;
uint256 optimism;
uint256 arbitrum;
uint256 fraxtal;
uint256 holeksy;
uint256 fraxtalTestnet;
}

mapping(uint256 => Actors) public actors;
mapping(uint256 => ChainAddresses) public addresses;

ChainIds public chainIds = ChainIds({
mainnet: 1,
base: 8453,
optimism: 10,
arbitrum: 42161,
fraxtal: 252,
holeksy: 17000,
fraxtalTestnet: 2522
});

function setUp() public virtual {
addresses[chainIds.mainnet] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c});
actors[chainIds.mainnet] = Actors({
OFT_DELEGATE: 0xfcad670592a3b24869C0b51a6c6FDED4F95D6975, // yn security council
TOKEN_ADMIN: 0xfcad670592a3b24869C0b51a6c6FDED4F95D6975,
PROXY_ADMIN: 0xfcad670592a3b24869C0b51a6c6FDED4F95D6975
});

addresses[chainIds.fraxtal] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c});
actors[chainIds.fraxtal] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)});

addresses[chainIds.optimism] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c});
actors[chainIds.optimism] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)});

addresses[chainIds.arbitrum] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c});
actors[chainIds.arbitrum] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)});

addresses[chainIds.base] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c});
actors[chainIds.base] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)});

addresses[chainIds.holeksy] = ChainAddresses({lzEndpoint: 0x6EDCE65403992e310A62460808c4b910D972f10f});
actors[chainIds.holeksy] = Actors({
OFT_DELEGATE: 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913, // yn security council
TOKEN_ADMIN: 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913,
PROXY_ADMIN: 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913
});

addresses[chainIds.fraxtalTestnet] = ChainAddresses({lzEndpoint: 0x6EDCE65403992e310A62460808c4b910D972f10f});
actors[chainIds.fraxtalTestnet] =
Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)});
}

function getActors(uint256 chainId) external view returns (Actors memory) {
return actors[chainId];
}

function getChainAddresses(uint256 chainId) external view returns (ChainAddresses memory) {
return addresses[chainId];
}

function isSupportedChainId(uint256 chainId) external view returns (bool) {
return chainId == chainIds.mainnet || chainId == chainIds.base || chainId == chainIds.fraxtal
|| chainId == chainIds.optimism || chainId == chainIds.arbitrum || chainId == chainIds.holeksy
|| chainId == chainIds.fraxtalTestnet;
}
}
20 changes: 20 additions & 0 deletions script/BaseScript.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

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

import {BaseData} from "script/BaseData.sol";

abstract contract BaseScript is BaseData {
using stdJson for string;

function setUp() public virtual override {
super.setUp();
console.log("BaseScript.setUp");

// TODO: parse token address from json or as input from user
// TODO: setup forks based on if testnet or mainnet deployment as per json
// TODO: setup saving of deployment data in deployments json file
}
}
141 changes: 77 additions & 64 deletions src/factory/ImmutableMultiChainDeployer.sol
Original file line number Diff line number Diff line change
@@ -1,66 +1,62 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {CREATE3} from "solmate/utils/CREATE3.sol";
import {CREATE3} from "@solmate/utils/CREATE3.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol";
import {IImmutableMultiChainDeployer} from "@interfaces/IImmutableMultiChainDeployer.sol";
import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol";
import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol";
import "forge-std/console.sol";
import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol";
import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol";

contract ImmutableMultiChainDeployer is IImmutableMultiChainDeployer {
event ContractCreated(address deployedAddress);
/// @notice Emitted when a new contract is deployed
/// @param _deployedAddress The address of the newly deployed contract
event ContractCreated(address indexed _deployedAddress);

// mapping to track the already deployed addresses
mapping(address => bool) private _deployed;
/// @notice Mapping to track deployed addresses
mapping(address => bool) private _deployedContracts;

/// @dev Custom errors
error InvalidSalt();
error AlreadyDeployed();
error IncorrectDeploymentAddress();

/// @dev Modifier to ensure that the first 20 bytes of a submitted salt match
/// those of the calling account. This provides protection against the salt
/// being stolen by frontrunners or other attackers. The protection can also be
/// bypassed if desired by setting each of the first 20 bytes to zero.
/// @param salt bytes32 The salt value to check against the calling address.
modifier containsCaller(bytes32 salt) {
// prevent contract submissions from being stolen from tx.pool by requiring
// that the first 20 bytes of the submitted salt match msg.sender.
require(
(address(bytes20(salt)) == msg.sender) || (bytes20(salt) == bytes20(0)),
"Invalid salt - first 20 bytes of the salt must match calling address."
);
/// those of the calling account, providing protection against salt misuse.
/// @param _salt The salt value to check against the calling address.
modifier containsCaller(bytes32 _salt) {
if (address(bytes20(_salt)) != msg.sender && bytes20(_salt) != bytes20(0)) {
revert InvalidSalt();
}
_;
}

/// @inheritdoc IImmutableMultiChainDeployer
function deploy(bytes32 salt, bytes memory initCode)
/// @inheritdoc IImmutableMultiChainDeployer
function deploy(bytes32 _salt, bytes memory _initCode)
public
payable
override
containsCaller(salt)
returns (address _deployedContract)
containsCaller(_salt)
returns (address deployedContract)
{
// get target deployment
address targetDeploymentAddress = CREATE3.getDeployed(salt);

require(
!_deployed[targetDeploymentAddress],
"Invalid deployment. a contract has already been deployed at this address"
);
address _targetDeploymentAddress = CREATE3.getDeployed(_salt);

// use create 3 to deploy contract
_deployedContract = CREATE3.deploy(salt, initCode, msg.value);
if (_deployedContracts[_targetDeploymentAddress]) {
revert AlreadyDeployed();
}

// check address against target to make sure deployment was successful
require(targetDeploymentAddress == _deployedContract, "failed to deploy to correct address");
deployedContract = CREATE3.deploy(_salt, _initCode, msg.value);

// record the deployment of the contract to prevent redeploys.
_deployed[_deployedContract] = true;
if (_targetDeploymentAddress != deployedContract) {
revert IncorrectDeploymentAddress();
}

// emit event
emit ContractCreated(_deployedContract);
_deployedContracts[deployedContract] = true;
emit ContractCreated(deployedContract);
}

/// @inheritdoc IImmutableMultiChainDeployer
/// @inheritdoc IImmutableMultiChainDeployer
function deployL2YnOFTAdapter(
bytes32 _implSalt,
bytes32 _proxySalt,
Expand All @@ -70,45 +66,62 @@ contract ImmutableMultiChainDeployer is IImmutableMultiChainDeployer {
RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs,
address _proxyController,
bytes memory _l2YnOFTAdapterBytecode
) public returns (address _deployedContract) {
bytes memory constructorParams = abi.encode(_token, _lzEndpoint);
bytes memory contractCode = abi.encodePacked(_l2YnOFTAdapterBytecode, constructorParams);

address adapterImpl = deploy(_implSalt, contractCode);
_deployedContract = deployProxy(_proxySalt, adapterImpl, _proxyController);
L2YnOFTAdapterUpgradeable(_deployedContract).initialize(_owner, _rateLimitConfigs);
) public override returns (address deployedContract) {
bytes memory _constructorParams = abi.encode(_token, _lzEndpoint);
bytes memory _contractCode = abi.encodePacked(_l2YnOFTAdapterBytecode, _constructorParams);
bytes memory _initializeArgs =
abi.encodeWithSelector(L2YnOFTAdapterUpgradeable.initialize.selector, _owner, _rateLimitConfigs);
deployedContract =
deployContractAndProxy(_implSalt, _proxySalt, _proxyController, _contractCode, _initializeArgs);
}

/// @inheritdoc IImmutableMultiChainDeployer
/// @inheritdoc IImmutableMultiChainDeployer
function deployL2YnERC20(
bytes32 _implSalt,
bytes32 _proxySalt,
string memory _name,
string memory _symbol,
string calldata _name,
string calldata _symbol,
address _owner,
address _proxyController,
bytes memory _l2YnERC20UpgradeableByteCode
) public returns (address _deployedContract) {
address adapterImpl = deploy(_implSalt, _l2YnERC20UpgradeableByteCode);
_deployedContract = deployProxy(_proxySalt, adapterImpl, _proxyController);
L2YnERC20Upgradeable(_deployedContract).initialize(_name, _symbol, _owner);
) public override returns (address deployedContract) {
bytes memory _initializeArgs =
abi.encodeWithSelector(L2YnERC20Upgradeable.initialize.selector, _name, _symbol, _owner);
deployedContract = deployContractAndProxy(
_implSalt, _proxySalt, _proxyController, _l2YnERC20UpgradeableByteCode, _initializeArgs
);
}

/// @inheritdoc IImmutableMultiChainDeployer
function getDeployed(bytes32 salt) public view override returns (address deployed) {
// hash salt with the deployer address to give each deployer its own namespace
return CREATE3.getDeployed(salt);
/// @inheritdoc IImmutableMultiChainDeployer
function getDeployed(bytes32 _salt) external view override returns (address deployed) {
return CREATE3.getDeployed(_salt);
}

function hasBeenDeployed(address deploymentAddress) external view returns (bool) {
// determine if a contract has been deployed to the provided address.
return _deployed[deploymentAddress];
/// @inheritdoc IImmutableMultiChainDeployer
function hasBeenDeployed(address _deploymentAddress) external view override returns (bool beenDeployed) {
beenDeployed = _deployedContracts[_deploymentAddress];
}

function deployProxy(bytes32 salt, address implementation, address controller) internal returns (address proxy) {
bytes memory bytecode = type(TransparentUpgradeableProxy).creationCode;
bytes memory constructorParams = abi.encode(implementation, controller, "");
bytes memory contractCode = abi.encodePacked(bytecode, constructorParams);
proxy = deploy(salt, contractCode);
/// @inheritdoc IImmutableMultiChainDeployer
function deployProxy(bytes32 _salt, address _implementation, address _controller, bytes memory _initializeArgs)
public
returns (address proxy)
{
bytes memory _constructorParams = abi.encode(_implementation, _controller, _initializeArgs);
bytes memory _contractCode =
abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, _constructorParams);
proxy = deploy(_salt, _contractCode);
}

/// @inheritdoc IImmutableMultiChainDeployer
function deployContractAndProxy(
bytes32 _implSalt,
bytes32 _proxySalt,
address _controller,
bytes memory _bytecode,
bytes memory _initializeArgs
) public returns (address addr) {
address _implAddr = deploy(_implSalt, _bytecode);
return deployProxy(_proxySalt, _implAddr, _controller, _initializeArgs);
}
}
Loading
Loading