Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
This commit is contained in:
57
script/Deploy.s.sol
Normal file
57
script/Deploy.s.sol
Normal file
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {Multicall} from "../contracts/utils/Multicall.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
import {Aggregator} from "../contracts/oracle/Aggregator.sol";
|
||||
import {Proxy} from "../contracts/oracle/Proxy.sol";
|
||||
|
||||
contract Deploy is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying contracts with address:", deployer);
|
||||
console.log("Chain ID:", block.chainid);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// Deploy WETH
|
||||
WETH weth = new WETH();
|
||||
console.log("WETH deployed at:", address(weth));
|
||||
|
||||
// Deploy Multicall
|
||||
Multicall multicall = new Multicall();
|
||||
console.log("Multicall deployed at:", address(multicall));
|
||||
|
||||
// Deploy CREATE2 Factory
|
||||
CREATE2Factory create2Factory = new CREATE2Factory();
|
||||
console.log("CREATE2Factory deployed at:", address(create2Factory));
|
||||
|
||||
// Deploy Oracle Aggregator
|
||||
Aggregator aggregator = new Aggregator(
|
||||
"ETH/USD Price Feed",
|
||||
deployer,
|
||||
60, // heartbeat: 60 seconds
|
||||
50 // deviationThreshold: 0.5% (50 basis points)
|
||||
);
|
||||
console.log("Aggregator deployed at:", address(aggregator));
|
||||
|
||||
// Deploy Proxy for Aggregator
|
||||
Proxy proxy = new Proxy(address(aggregator), deployer);
|
||||
console.log("Proxy deployed at:", address(proxy));
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
// Log deployment addresses
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH:", address(weth));
|
||||
console.log("Multicall:", address(multicall));
|
||||
console.log("CREATE2Factory:", address(create2Factory));
|
||||
console.log("Aggregator:", address(aggregator));
|
||||
console.log("Proxy:", address(proxy));
|
||||
}
|
||||
}
|
||||
|
||||
52
script/DeployAddressMapper.s.sol
Normal file
52
script/DeployAddressMapper.s.sol
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {AddressMapper} from "../contracts/utils/AddressMapper.sol";
|
||||
|
||||
/**
|
||||
* @title DeployAddressMapper
|
||||
* @notice Deploy the AddressMapper contract to provide address mapping
|
||||
*/
|
||||
contract DeployAddressMapper is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying AddressMapper with deployer:", vm.toString(deployer));
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
AddressMapper mapper = new AddressMapper();
|
||||
console.log("AddressMapper deployed at:", vm.toString(address(mapper)));
|
||||
|
||||
// Verify mappings
|
||||
address weth9Genesis = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
address weth9Deployed = 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6;
|
||||
address weth10Genesis = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
address weth10Deployed = 0x105F8A15b819948a89153505762444Ee9f324684;
|
||||
|
||||
address mappedWETH9 = mapper.getDeployedAddress(weth9Genesis);
|
||||
address mappedWETH10 = mapper.getDeployedAddress(weth10Genesis);
|
||||
|
||||
console.log("\n=== Mapping Verification ===");
|
||||
console.log("WETH9 Genesis:", vm.toString(weth9Genesis));
|
||||
console.log("WETH9 Mapped:", vm.toString(mappedWETH9));
|
||||
console.log("WETH9 Expected:", vm.toString(weth9Deployed));
|
||||
require(mappedWETH9 == weth9Deployed, "WETH9 mapping incorrect");
|
||||
|
||||
console.log("WETH10 Genesis:", vm.toString(weth10Genesis));
|
||||
console.log("WETH10 Mapped:", vm.toString(mappedWETH10));
|
||||
console.log("WETH10 Expected:", vm.toString(weth10Deployed));
|
||||
require(mappedWETH10 == weth10Deployed, "WETH10 mapping incorrect");
|
||||
|
||||
console.log("\nOK: All mappings verified!");
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("AddressMapper:", vm.toString(address(mapper)));
|
||||
console.log("Owner:", vm.toString(mapper.owner()));
|
||||
}
|
||||
}
|
||||
|
||||
355
script/DeployAll.s.sol
Normal file
355
script/DeployAll.s.sol
Normal file
@@ -0,0 +1,355 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
import {CCIPWETH9Bridge} from "../contracts/ccip/CCIPWETH9Bridge.sol";
|
||||
import {CCIPWETH10Bridge} from "../contracts/ccip/CCIPWETH10Bridge.sol";
|
||||
|
||||
/**
|
||||
* @title DeployAll - Canonical Multichain Deployment Script
|
||||
* @notice Deploys all contracts (WETH9, WETH10, CCIP Bridges, CCIPLogger) to multiple chains
|
||||
* @dev Chain-aware deployment that adapts to different network configurations
|
||||
*
|
||||
* Supported Chains:
|
||||
* - Ethereum Mainnet (chainId 1): Only deploys CCIPLogger (other contracts already deployed)
|
||||
* - Cronos (chainId 25): Deploys all contracts
|
||||
* - BSC (chainId 56): Deploys all contracts
|
||||
* - Polygon PoS (chainId 137): Deploys all contracts
|
||||
* - Gnosis Chain (chainId 100): Deploys all contracts
|
||||
* - Avalanche (chainId 43114): Deploys all contracts
|
||||
* - Base (chainId 8453): Deploys all contracts
|
||||
* - Arbitrum (chainId 42161): Deploys all contracts
|
||||
* - Optimism (chainId 10): Deploys all contracts
|
||||
*/
|
||||
contract DeployAll is Script {
|
||||
// Chain IDs
|
||||
uint256 constant MAINNET = 1;
|
||||
uint256 constant CRONOS = 25;
|
||||
uint256 constant BSC = 56;
|
||||
uint256 constant POLYGON = 137;
|
||||
uint256 constant GNOSIS = 100;
|
||||
uint256 constant AVALANCHE = 43114;
|
||||
uint256 constant BASE = 8453;
|
||||
uint256 constant ARBITRUM = 42161;
|
||||
uint256 constant OPTIMISM = 10;
|
||||
|
||||
// CCIP Configuration per chain
|
||||
struct CCIPConfig {
|
||||
address router;
|
||||
address linkToken;
|
||||
uint64 chainSelector;
|
||||
}
|
||||
|
||||
// WETH Configuration per chain
|
||||
struct WETHConfig {
|
||||
address weth9;
|
||||
address weth10;
|
||||
}
|
||||
|
||||
// Deployment addresses (will be populated during deployment)
|
||||
struct DeploymentAddresses {
|
||||
address weth9;
|
||||
address weth10;
|
||||
address ccipWETH9Bridge;
|
||||
address ccipWETH10Bridge;
|
||||
address ccipLogger;
|
||||
}
|
||||
|
||||
DeploymentAddresses public deployed;
|
||||
|
||||
function run() external {
|
||||
uint256 chainId = block.chainid;
|
||||
// Get deployer address - when using --private-key flag, use msg.sender
|
||||
// Otherwise get from env (PRIVATE_KEY should have 0x prefix in .env)
|
||||
address deployer;
|
||||
try vm.envUint("PRIVATE_KEY") returns (uint256 pk) {
|
||||
deployer = vm.addr(pk);
|
||||
} catch {
|
||||
// If env read fails, use msg.sender (when --private-key is used from CLI)
|
||||
deployer = msg.sender;
|
||||
}
|
||||
|
||||
console.log("==========================================");
|
||||
console.log("Multichain Deployment Script");
|
||||
console.log("==========================================");
|
||||
console.log("Chain ID:", chainId);
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("Deployer Balance:", deployer.balance / 1e18, "ETH/Native");
|
||||
|
||||
// Get chain-specific configuration
|
||||
CCIPConfig memory ccipConfig = getCCIPConfig(chainId);
|
||||
WETHConfig memory wethConfig = getWETHConfig(chainId);
|
||||
|
||||
console.log("\nCCIP Configuration:");
|
||||
console.log(" Router:", ccipConfig.router);
|
||||
console.log(" LINK Token:", ccipConfig.linkToken);
|
||||
console.log(" Chain Selector:", ccipConfig.chainSelector);
|
||||
|
||||
console.log("\nWETH Configuration:");
|
||||
console.log(" WETH9:", wethConfig.weth9);
|
||||
console.log(" WETH10:", wethConfig.weth10);
|
||||
|
||||
// startBroadcast() will use --private-key from CLI if provided
|
||||
// Otherwise it will try to use PRIVATE_KEY from env
|
||||
vm.startBroadcast();
|
||||
|
||||
// Determine deployment strategy based on chain
|
||||
if (chainId == MAINNET) {
|
||||
// Ethereum Mainnet: Only deploy CCIPLogger
|
||||
console.log("\n=== Ethereum Mainnet Deployment ===");
|
||||
console.log("Skipping WETH9, WETH10, and Bridges (already deployed)");
|
||||
console.log("Deploying CCIPLogger only...");
|
||||
|
||||
deployed.ccipLogger = deployCCIPLogger(ccipConfig);
|
||||
} else {
|
||||
// All other chains: Deploy everything
|
||||
console.log("\n=== Full Deployment for Chain", chainId, "===");
|
||||
|
||||
// Deploy WETH9 if needed
|
||||
if (wethConfig.weth9 == address(0)) {
|
||||
console.log("\nDeploying WETH9...");
|
||||
deployed.weth9 = deployWETH9();
|
||||
} else {
|
||||
console.log("\nUsing existing WETH9 at:", wethConfig.weth9);
|
||||
deployed.weth9 = wethConfig.weth9;
|
||||
}
|
||||
|
||||
// Deploy WETH10 if needed
|
||||
if (wethConfig.weth10 == address(0)) {
|
||||
console.log("\nDeploying WETH10...");
|
||||
deployed.weth10 = deployWETH10();
|
||||
} else {
|
||||
console.log("\nUsing existing WETH10 at:", wethConfig.weth10);
|
||||
deployed.weth10 = wethConfig.weth10;
|
||||
}
|
||||
|
||||
// Deploy CCIP Bridges
|
||||
console.log("\nDeploying CCIPWETH9Bridge...");
|
||||
deployed.ccipWETH9Bridge = deployCCIPWETH9Bridge(
|
||||
ccipConfig.router,
|
||||
deployed.weth9,
|
||||
ccipConfig.linkToken
|
||||
);
|
||||
|
||||
console.log("\nDeploying CCIPWETH10Bridge...");
|
||||
deployed.ccipWETH10Bridge = deployCCIPWETH10Bridge(
|
||||
ccipConfig.router,
|
||||
deployed.weth10,
|
||||
ccipConfig.linkToken
|
||||
);
|
||||
|
||||
// Deploy CCIPLogger
|
||||
console.log("\nDeploying CCIPLogger...");
|
||||
deployed.ccipLogger = deployCCIPLogger(ccipConfig);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
// Print deployment summary
|
||||
printDeploymentSummary(chainId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get CCIP configuration for a specific chain
|
||||
*/
|
||||
function getCCIPConfig(uint256 chainId) internal view returns (CCIPConfig memory) {
|
||||
if (chainId == MAINNET) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_ETH_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_ETH_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("ETH_MAINNET_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == CRONOS) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_CRONOS_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_CRONOS_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("CRONOS_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == BSC) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_BSC_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_BSC_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("BSC_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == POLYGON) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_POLYGON_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_POLYGON_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("POLYGON_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == GNOSIS) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_GNOSIS_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_GNOSIS_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("GNOSIS_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == AVALANCHE) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_AVALANCHE_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_AVALANCHE_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("AVALANCHE_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == BASE) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_BASE_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_BASE_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("BASE_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == ARBITRUM) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_ARBITRUM_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_ARBITRUM_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("ARBITRUM_SELECTOR"))
|
||||
});
|
||||
} else if (chainId == OPTIMISM) {
|
||||
return CCIPConfig({
|
||||
router: vm.envAddress("CCIP_OPTIMISM_ROUTER"),
|
||||
linkToken: vm.envAddress("CCIP_OPTIMISM_LINK_TOKEN"),
|
||||
chainSelector: uint64(vm.envUint("OPTIMISM_SELECTOR"))
|
||||
});
|
||||
} else {
|
||||
revert("Unsupported chain");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get WETH configuration for a specific chain
|
||||
*/
|
||||
function getWETHConfig(uint256 chainId) internal returns (WETHConfig memory) {
|
||||
if (chainId == MAINNET) {
|
||||
return WETHConfig({
|
||||
weth9: vm.envAddress("WETH9_MAINNET"),
|
||||
weth10: vm.envAddress("WETH10_MAINNET")
|
||||
});
|
||||
} else if (chainId == CRONOS) {
|
||||
address weth9 = vm.envOr("WETH9_CRONOS", address(0));
|
||||
address weth10 = vm.envOr("WETH10_CRONOS", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == BSC) {
|
||||
address weth9 = vm.envOr("WETH9_BSC", address(0));
|
||||
address weth10 = vm.envOr("WETH10_BSC", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == POLYGON) {
|
||||
address weth9 = vm.envOr("WETH9_POLYGON", address(0));
|
||||
address weth10 = vm.envOr("WETH10_POLYGON", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == GNOSIS) {
|
||||
address weth9 = vm.envOr("WETH9_GNOSIS", address(0));
|
||||
address weth10 = vm.envOr("WETH10_GNOSIS", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == AVALANCHE) {
|
||||
address weth9 = vm.envOr("WETH9_AVALANCHE", address(0));
|
||||
address weth10 = vm.envOr("WETH10_AVALANCHE", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == BASE) {
|
||||
address weth9 = vm.envOr("WETH9_BASE", address(0));
|
||||
address weth10 = vm.envOr("WETH10_BASE", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == ARBITRUM) {
|
||||
address weth9 = vm.envOr("WETH9_ARBITRUM", address(0));
|
||||
address weth10 = vm.envOr("WETH10_ARBITRUM", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else if (chainId == OPTIMISM) {
|
||||
address weth9 = vm.envOr("WETH9_OPTIMISM", address(0));
|
||||
address weth10 = vm.envOr("WETH10_OPTIMISM", address(0));
|
||||
return WETHConfig({weth9: weth9, weth10: weth10});
|
||||
} else {
|
||||
revert("Unsupported chain");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy WETH9 contract
|
||||
*/
|
||||
function deployWETH9() internal returns (address) {
|
||||
WETH weth9 = new WETH();
|
||||
return address(weth9);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy WETH10 contract
|
||||
*/
|
||||
function deployWETH10() internal returns (address) {
|
||||
WETH10 weth10 = new WETH10();
|
||||
return address(weth10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy CCIPWETH9Bridge
|
||||
*/
|
||||
function deployCCIPWETH9Bridge(
|
||||
address router,
|
||||
address weth9,
|
||||
address feeToken
|
||||
) internal returns (address) {
|
||||
CCIPWETH9Bridge bridge = new CCIPWETH9Bridge(router, weth9, feeToken);
|
||||
return address(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy CCIPWETH10Bridge
|
||||
*/
|
||||
function deployCCIPWETH10Bridge(
|
||||
address router,
|
||||
address weth10,
|
||||
address feeToken
|
||||
) internal returns (address) {
|
||||
CCIPWETH10Bridge bridge = new CCIPWETH10Bridge(router, weth10, feeToken);
|
||||
return address(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy CCIPLogger
|
||||
* @dev Note: This assumes CCIPLogger contract exists. If it uses Hardhat/OpenZeppelin,
|
||||
* you may need to deploy it separately using the Hardhat script.
|
||||
*/
|
||||
function deployCCIPLogger(CCIPConfig memory config) internal returns (address) {
|
||||
// TODO: If CCIPLogger is a Solidity contract in this repo, deploy it here
|
||||
// For now, this is a placeholder. CCIPLogger may need to be deployed via Hardhat
|
||||
// due to OpenZeppelin dependencies.
|
||||
|
||||
// Example deployment (adjust based on actual CCIPLogger contract):
|
||||
// CCIPLogger logger = new CCIPLogger(
|
||||
// config.router,
|
||||
// vm.envOr("AUTHORIZED_SIGNER", address(0)),
|
||||
// config.chainSelector
|
||||
// );
|
||||
// return address(logger);
|
||||
|
||||
console.log("WARNING: CCIPLogger deployment not implemented in Foundry script.");
|
||||
console.log("Please deploy CCIPLogger using the Hardhat script:");
|
||||
console.log(" npm run deploy:logger:mainnet (for mainnet)");
|
||||
console.log(" Or create a chain-specific deployment script.");
|
||||
|
||||
return address(0); // Placeholder
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Print deployment summary
|
||||
*/
|
||||
function printDeploymentSummary(uint256 chainId) internal view {
|
||||
console.log("\n==========================================");
|
||||
console.log("Deployment Summary - Chain ID:", chainId);
|
||||
console.log("==========================================");
|
||||
|
||||
if (chainId != MAINNET) {
|
||||
console.log("WETH9:", deployed.weth9);
|
||||
console.log("WETH10:", deployed.weth10);
|
||||
console.log("CCIPWETH9Bridge:", deployed.ccipWETH9Bridge);
|
||||
console.log("CCIPWETH10Bridge:", deployed.ccipWETH10Bridge);
|
||||
}
|
||||
|
||||
console.log("CCIPLogger:", deployed.ccipLogger);
|
||||
|
||||
console.log("\n==========================================");
|
||||
console.log("Next Steps:");
|
||||
console.log("1. Verify contracts on explorer");
|
||||
console.log("2. Update .env with deployed addresses");
|
||||
console.log("3. Configure bridge destinations");
|
||||
console.log("4. Test cross-chain transfers");
|
||||
console.log("==========================================");
|
||||
}
|
||||
}
|
||||
|
||||
83
script/DeployCCIPLoggerOnly.s.sol
Normal file
83
script/DeployCCIPLoggerOnly.s.sol
Normal file
@@ -0,0 +1,83 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script";
|
||||
|
||||
/**
|
||||
* @title DeployCCIPLoggerOnly - Deploy CCIPLogger to Ethereum Mainnet
|
||||
* @notice This script deploys ONLY CCIPLogger to Ethereum Mainnet
|
||||
* @dev All other contracts (WETH9, WETH10, Bridges) are already deployed on Mainnet
|
||||
*
|
||||
* NOTE: CCIPLogger may require Hardhat/OpenZeppelin dependencies.
|
||||
* If this script fails due to missing dependencies, use the Hardhat script instead:
|
||||
* npm run deploy:logger:mainnet
|
||||
*/
|
||||
contract DeployCCIPLoggerOnly is Script {
|
||||
uint256 constant MAINNET = 1;
|
||||
|
||||
function run() external {
|
||||
uint256 chainId = block.chainid;
|
||||
require(chainId == MAINNET, "This script is only for Ethereum Mainnet");
|
||||
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("==========================================");
|
||||
console.log("CCIPLogger Deployment - Ethereum Mainnet");
|
||||
console.log("==========================================");
|
||||
console.log("Chain ID:", chainId);
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("Deployer Balance:", deployer.balance / 1e18, "ETH");
|
||||
|
||||
// Get CCIP configuration
|
||||
address router = vm.envAddress("CCIP_ETH_ROUTER");
|
||||
address linkToken = vm.envAddress("CCIP_ETH_LINK_TOKEN");
|
||||
uint64 chainSelector = uint64(vm.envUint("ETH_MAINNET_SELECTOR"));
|
||||
address authorizedSigner = vm.envOr("AUTHORIZED_SIGNER", address(0));
|
||||
|
||||
console.log("\nCCIP Configuration:");
|
||||
console.log(" Router:", router);
|
||||
console.log(" LINK Token:", linkToken);
|
||||
console.log(" Chain Selector:", chainSelector);
|
||||
console.log(" Authorized Signer:", authorizedSigner);
|
||||
|
||||
// Get source chain selector (Chain-138)
|
||||
uint64 sourceChainSelector = uint64(vm.envUint("CHAIN138_SELECTOR"));
|
||||
console.log(" Source Chain Selector (Chain-138):", sourceChainSelector);
|
||||
|
||||
console.log("\nWARNING:");
|
||||
console.log("CCIPLogger may require OpenZeppelin contracts v5.0.2+");
|
||||
console.log("If deployment fails, use the Hardhat script instead:");
|
||||
console.log(" npm install @openzeppelin/contracts@5.0.2");
|
||||
console.log(" npm run deploy:logger:mainnet");
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// TODO: Uncomment and adjust when CCIPLogger contract is available in Foundry
|
||||
// CCIPLogger logger = new CCIPLogger(
|
||||
// router,
|
||||
// authorizedSigner,
|
||||
// sourceChainSelector
|
||||
// );
|
||||
// address loggerAddress = address(logger);
|
||||
|
||||
// For now, this is a placeholder
|
||||
address loggerAddress = address(0);
|
||||
console.log("\nPLACEHOLDER: CCIPLogger deployment not implemented");
|
||||
console.log("Please use Hardhat script: npm run deploy:logger:mainnet");
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
if (loggerAddress != address(0)) {
|
||||
console.log("\n==========================================");
|
||||
console.log("OK: CCIPLogger Deployed Successfully");
|
||||
console.log("==========================================");
|
||||
console.log("Address:", loggerAddress);
|
||||
console.log("\nNext Steps:");
|
||||
console.log("1. Verify contract on Etherscan");
|
||||
console.log("2. Update .env with CCIPLOGGER_MAINNET=", loggerAddress);
|
||||
console.log("3. Configure CCIPTxReporter on Chain-138");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
script/DeployCCIPReceiver.s.sol
Normal file
34
script/DeployCCIPReceiver.s.sol
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {CCIPReceiver} from "../contracts/ccip/CCIPReceiver.sol";
|
||||
|
||||
/**
|
||||
* @title DeployCCIPReceiver
|
||||
* @notice Deploy CCIPReceiver contract for receiving cross-chain messages
|
||||
*/
|
||||
contract DeployCCIPReceiver is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
// Load environment variables
|
||||
address ccipRouter = vm.envAddress("CCIP_ROUTER_ADDRESS");
|
||||
|
||||
console.log("Deploying CCIPReceiver with deployer:", vm.toString(deployer));
|
||||
console.log("CCIP Router:", vm.toString(ccipRouter));
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
CCIPReceiver receiver = new CCIPReceiver(ccipRouter);
|
||||
console.log("CCIPReceiver deployed at:", vm.toString(address(receiver)));
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("CCIPReceiver:", vm.toString(address(receiver)));
|
||||
console.log("CCIP Router:", vm.toString(ccipRouter));
|
||||
}
|
||||
}
|
||||
|
||||
36
script/DeployCCIPRouter.s.sol
Normal file
36
script/DeployCCIPRouter.s.sol
Normal file
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {CCIPRouter} from "../contracts/ccip/CCIPRouter.sol";
|
||||
|
||||
contract DeployCCIPRouter is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
// Load from environment or use defaults
|
||||
address feeToken = vm.envOr("CCIP_FEE_TOKEN", address(0));
|
||||
uint256 baseFee = vm.envOr("CCIP_BASE_FEE", uint256(0));
|
||||
uint256 dataFeePerByte = vm.envOr("CCIP_DATA_FEE_PER_BYTE", uint256(0));
|
||||
|
||||
console.log("Deploying CCIPRouter with deployer:", vm.toString(deployer));
|
||||
console.log("Fee Token:", vm.toString(feeToken));
|
||||
console.log("Base Fee:", baseFee);
|
||||
console.log("Data Fee Per Byte:", dataFeePerByte);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
CCIPRouter router = new CCIPRouter(feeToken, baseFee, dataFeePerByte);
|
||||
|
||||
console.log("CCIP Router deployed at:", vm.toString(address(router)));
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("CCIP Router:", vm.toString(address(router)));
|
||||
console.log("Fee Token:", vm.toString(feeToken));
|
||||
console.log("Base Fee:", baseFee);
|
||||
console.log("Data Fee Per Byte:", dataFeePerByte);
|
||||
}
|
||||
}
|
||||
34
script/DeployCCIPSender.s.sol
Normal file
34
script/DeployCCIPSender.s.sol
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {CCIPSender} from "../contracts/ccip/CCIPSender.sol";
|
||||
|
||||
/**
|
||||
* @title DeployCCIPSender
|
||||
* @notice Deploy CCIPSender contract for cross-chain messaging
|
||||
*/
|
||||
contract DeployCCIPSender is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
// Load environment variables
|
||||
address ccipRouter = vm.envAddress("CCIP_ROUTER_ADDRESS");
|
||||
|
||||
console.log("Deploying CCIPSender with deployer:", vm.toString(deployer));
|
||||
console.log("CCIP Router:", vm.toString(ccipRouter));
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
CCIPSender sender = new CCIPSender(ccipRouter);
|
||||
console.log("CCIPSender deployed at:", vm.toString(address(sender)));
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("CCIPSender:", vm.toString(address(sender)));
|
||||
console.log("CCIP Router:", vm.toString(ccipRouter));
|
||||
}
|
||||
}
|
||||
|
||||
42
script/DeployCCIPWETH10Bridge.s.sol
Normal file
42
script/DeployCCIPWETH10Bridge.s.sol
Normal file
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {CCIPWETH10Bridge} from "../contracts/ccip/CCIPWETH10Bridge.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
|
||||
contract DeployCCIPWETH10Bridge is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
// Get configuration from environment
|
||||
address ccipRouter = vm.envAddress("CCIP_ROUTER");
|
||||
// Use canonical Mainnet WETH10 address (predeployed in genesis)
|
||||
address weth10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
address feeToken = vm.envAddress("CCIP_FEE_TOKEN"); // LINK token
|
||||
|
||||
console.log("Deploying CCIPWETH10Bridge with:");
|
||||
console.log(" Deployer:", deployer);
|
||||
console.log(" CCIP Router:", ccipRouter);
|
||||
console.log(" WETH10:", weth10);
|
||||
console.log(" Fee Token:", feeToken);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
CCIPWETH10Bridge bridge = new CCIPWETH10Bridge(
|
||||
ccipRouter,
|
||||
weth10,
|
||||
feeToken
|
||||
);
|
||||
|
||||
console.log("CCIPWETH10Bridge deployed at:", address(bridge));
|
||||
console.log(" CCIP Router:", address(bridge.ccipRouter()));
|
||||
console.log(" WETH10:", bridge.weth10());
|
||||
console.log(" Fee Token:", bridge.feeToken());
|
||||
console.log(" Admin:", bridge.admin());
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
42
script/DeployCCIPWETH9Bridge.s.sol
Normal file
42
script/DeployCCIPWETH9Bridge.s.sol
Normal file
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {CCIPWETH9Bridge} from "../contracts/ccip/CCIPWETH9Bridge.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
|
||||
contract DeployCCIPWETH9Bridge is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
// Get configuration from environment
|
||||
address ccipRouter = vm.envAddress("CCIP_ROUTER");
|
||||
// Use canonical Mainnet WETH9 address (predeployed in genesis)
|
||||
address weth9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
address feeToken = vm.envAddress("CCIP_FEE_TOKEN"); // LINK token
|
||||
|
||||
console.log("Deploying CCIPWETH9Bridge with:");
|
||||
console.log(" Deployer:", deployer);
|
||||
console.log(" CCIP Router:", ccipRouter);
|
||||
console.log(" WETH9:", weth9);
|
||||
console.log(" Fee Token:", feeToken);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
CCIPWETH9Bridge bridge = new CCIPWETH9Bridge(
|
||||
ccipRouter,
|
||||
weth9,
|
||||
feeToken
|
||||
);
|
||||
|
||||
console.log("CCIPWETH9Bridge deployed at:", address(bridge));
|
||||
console.log(" CCIP Router:", address(bridge.ccipRouter()));
|
||||
console.log(" WETH9:", bridge.weth9());
|
||||
console.log(" Fee Token:", bridge.feeToken());
|
||||
console.log(" Admin:", bridge.admin());
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
21
script/DeployMainnetTether.s.sol
Normal file
21
script/DeployMainnetTether.s.sol
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import {MainnetTether} from "../contracts/tether/MainnetTether.sol";
|
||||
|
||||
contract DeployMainnetTether is Script {
|
||||
function run() external {
|
||||
uint256 pk = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(pk);
|
||||
// Use TETHER_ADMIN from .env, or fall back to deployer address
|
||||
address admin = vm.envOr("TETHER_ADMIN", deployer);
|
||||
|
||||
vm.startBroadcast(pk);
|
||||
MainnetTether tether = new MainnetTether(admin);
|
||||
console.log("MainnetTether deployed at:", address(tether));
|
||||
console.log("Admin:", admin);
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
18
script/DeployMirrorManager.s.sol
Normal file
18
script/DeployMirrorManager.s.sol
Normal file
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import {MirrorManager} from "../contracts/mirror/MirrorManager.sol";
|
||||
|
||||
contract DeployMirrorManager is Script {
|
||||
function run() external {
|
||||
uint256 pk = vm.envUint("PRIVATE_KEY");
|
||||
address admin = vm.envAddress("MIRROR_ADMIN");
|
||||
vm.startBroadcast(pk);
|
||||
MirrorManager mm = new MirrorManager(admin);
|
||||
console.log("MirrorManager:", address(mm));
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
script/DeployMockLinkToken.s.sol
Normal file
40
script/DeployMockLinkToken.s.sol
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {MockLinkToken} from "../contracts/tokens/MockLinkToken.sol";
|
||||
|
||||
/**
|
||||
* @title Deploy Mock LINK Token
|
||||
* @notice Deploy a mock LINK token for testing and development
|
||||
*/
|
||||
contract DeployMockLinkToken is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying Mock LINK Token with address:", deployer);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
MockLinkToken linkToken = new MockLinkToken();
|
||||
|
||||
console.log("Mock LINK Token deployed at:", address(linkToken));
|
||||
console.log("Name:", linkToken.name());
|
||||
console.log("Symbol:", linkToken.symbol());
|
||||
console.log("Decimals:", linkToken.decimals());
|
||||
|
||||
// Mint initial supply to deployer (optional)
|
||||
uint256 initialSupply = 1000000e18; // 1M LINK
|
||||
linkToken.mint(deployer, initialSupply);
|
||||
console.log("Minted", initialSupply / 1e18, "LINK to deployer");
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("Mock LINK Token:", address(linkToken));
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("Initial Supply:", initialSupply / 1e18, "LINK");
|
||||
}
|
||||
}
|
||||
|
||||
27
script/DeployMultiSig.s.sol
Normal file
27
script/DeployMultiSig.s.sol
Normal file
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {MultiSig} from "../contracts/governance/MultiSig.sol";
|
||||
|
||||
contract DeployMultiSig is Script {
|
||||
function run() external {
|
||||
// Get owners from environment or use defaults
|
||||
address[] memory owners = new address[](3);
|
||||
owners[0] = vm.envAddress("MULTISIG_OWNER_1");
|
||||
owners[1] = vm.envAddress("MULTISIG_OWNER_2");
|
||||
owners[2] = vm.envAddress("MULTISIG_OWNER_3");
|
||||
|
||||
uint256 required = vm.envUint("MULTISIG_REQUIRED");
|
||||
|
||||
vm.startBroadcast();
|
||||
|
||||
MultiSig multisig = new MultiSig(owners, required);
|
||||
|
||||
console.log("MultiSig deployed at:", address(multisig));
|
||||
console.log("Required confirmations:", required);
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
22
script/DeployMulticall.s.sol
Normal file
22
script/DeployMulticall.s.sol
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {Multicall} from "../contracts/utils/Multicall.sol";
|
||||
|
||||
contract DeployMulticall is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying Multicall with address:", deployer);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
Multicall multicall = new Multicall();
|
||||
console.log("Multicall deployed at:", address(multicall));
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
40
script/DeployOracle.s.sol
Normal file
40
script/DeployOracle.s.sol
Normal file
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {Aggregator} from "../contracts/oracle/Aggregator.sol";
|
||||
import {Proxy} from "../contracts/oracle/Proxy.sol";
|
||||
|
||||
contract DeployOracle is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
string memory description = vm.envOr("ORACLE_DESCRIPTION", string("ETH/USD Price Feed"));
|
||||
uint256 heartbeat = vm.envOr("ORACLE_HEARTBEAT", uint256(60));
|
||||
uint256 deviationThreshold = vm.envOr("ORACLE_DEVIATION_THRESHOLD", uint256(50));
|
||||
|
||||
console.log("Deploying Oracle with address:", deployer);
|
||||
console.log("Description:", description);
|
||||
console.log("Heartbeat:", heartbeat);
|
||||
console.log("Deviation Threshold:", deviationThreshold);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// Deploy Aggregator implementation
|
||||
Aggregator aggregator = new Aggregator(
|
||||
description,
|
||||
deployer,
|
||||
heartbeat,
|
||||
deviationThreshold
|
||||
);
|
||||
console.log("Aggregator deployed at:", address(aggregator));
|
||||
|
||||
// Deploy Proxy
|
||||
Proxy proxy = new Proxy(address(aggregator), deployer);
|
||||
console.log("Proxy deployed at:", address(proxy));
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
21
script/DeployTransactionMirror.s.sol
Normal file
21
script/DeployTransactionMirror.s.sol
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import {TransactionMirror} from "../contracts/mirror/TransactionMirror.sol";
|
||||
|
||||
contract DeployTransactionMirror is Script {
|
||||
function run() external {
|
||||
uint256 pk = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(pk);
|
||||
// Use MIRROR_ADMIN from .env, or fall back to deployer address
|
||||
address admin = vm.envOr("MIRROR_ADMIN", deployer);
|
||||
|
||||
vm.startBroadcast(pk);
|
||||
TransactionMirror mirror = new TransactionMirror(admin);
|
||||
console.log("TransactionMirror deployed at:", address(mirror));
|
||||
console.log("Admin:", admin);
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
25
script/DeployTwoWayBridge.s.sol
Normal file
25
script/DeployTwoWayBridge.s.sol
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import {TwoWayTokenBridgeL1} from "../contracts/bridge/TwoWayTokenBridgeL1.sol";
|
||||
import {TwoWayTokenBridgeL2} from "../contracts/bridge/TwoWayTokenBridgeL2.sol";
|
||||
|
||||
contract DeployTwoWayBridge is Script {
|
||||
function run() external {
|
||||
uint256 pk = vm.envUint("PRIVATE_KEY");
|
||||
address router = vm.envAddress("CCIP_ROUTER");
|
||||
address feeToken = vm.envAddress("CCIP_FEE_TOKEN"); // LINK
|
||||
address l1Token = vm.envAddress("BRIDGE_L1_TOKEN"); // canonical token on L1
|
||||
address l2Token = vm.envAddress("BRIDGE_L2_TOKEN"); // mintable token on L2
|
||||
|
||||
vm.startBroadcast(pk);
|
||||
TwoWayTokenBridgeL1 l1 = new TwoWayTokenBridgeL1(router, l1Token, feeToken);
|
||||
TwoWayTokenBridgeL2 l2 = new TwoWayTokenBridgeL2(router, l2Token, feeToken);
|
||||
console.log("TwoWayTokenBridgeL1:", address(l1));
|
||||
console.log("TwoWayTokenBridgeL2:", address(l2));
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
22
script/DeployWETH.s.sol
Normal file
22
script/DeployWETH.s.sol
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
|
||||
contract DeployWETH is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH with address:", deployer);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
WETH weth = new WETH();
|
||||
console.log("WETH deployed at:", address(weth));
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
25
script/DeployWETH10.s.sol
Normal file
25
script/DeployWETH10.s.sol
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
|
||||
contract DeployWETH10 is Script {
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH10 with address:", deployer);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
WETH10 weth10 = new WETH10();
|
||||
console.log("WETH10 deployed at:", address(weth10));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
226
script/DeployWETH10ToExactAddress.s.sol
Normal file
226
script/DeployWETH10ToExactAddress.s.sol
Normal file
@@ -0,0 +1,226 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETH10ToExactAddress
|
||||
* @notice Deploy WETH10 to exact address 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f using CREATE2
|
||||
* @dev This script uses CREATE2 to deploy to the exact address specified in genesis.json
|
||||
*/
|
||||
contract DeployWETH10ToExactAddress is Script {
|
||||
// Target address from genesis.json
|
||||
address constant TARGET_WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH10 to exact address using CREATE2");
|
||||
console.log("Target address:", vm.toString(TARGET_WETH10));
|
||||
console.log("Deployer:", vm.toString(deployer));
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// Get WETH10 bytecode
|
||||
bytes memory weth10Bytecode = type(WETH10).creationCode;
|
||||
bytes32 bytecodeHash = keccak256(weth10Bytecode);
|
||||
console.log("WETH10 bytecode hash:", vm.toString(bytecodeHash));
|
||||
|
||||
// Deploy CREATE2Factory (or use existing if already deployed)
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
address factoryAddress = address(factory);
|
||||
console.log("CREATE2Factory deployed at:", factoryAddress);
|
||||
|
||||
// Check if contract already exists on-chain
|
||||
// Note: We'll try to interact with it - if it reverts, it doesn't exist
|
||||
try this.checkContractExists(TARGET_WETH10) returns (bool exists) {
|
||||
if (exists) {
|
||||
console.log("Contract already exists at target address");
|
||||
WETH10 weth10 = WETH10(payable(TARGET_WETH10));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Contract doesn't exist, continue with deployment
|
||||
}
|
||||
|
||||
// Try multiple deployer addresses:
|
||||
// 1. Current deployer
|
||||
// 2. CREATE2Factory address (as deployer)
|
||||
// 3. Standard CREATE2 deterministic deployer
|
||||
// 4. Addresses from genesis.json
|
||||
address[] memory deployers = new address[](5);
|
||||
deployers[0] = deployer;
|
||||
deployers[1] = factoryAddress;
|
||||
deployers[2] = 0x4e59b44847b379578588920cA78FbF26c0B4956C; // Standard CREATE2 deployer
|
||||
deployers[3] = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb; // Genesis address with initial balance (padded)
|
||||
deployers[4] = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882; // Genesis address with high balance
|
||||
|
||||
uint256 salt = 0;
|
||||
address foundDeployer = address(0);
|
||||
|
||||
for (uint256 i = 0; i < deployers.length; i++) {
|
||||
console.log("Trying deployer:", vm.toString(deployers[i]));
|
||||
|
||||
// Try common salts first
|
||||
salt = findSaltForAddress(deployers[i], weth10Bytecode, TARGET_WETH10);
|
||||
|
||||
if (salt != 0) {
|
||||
foundDeployer = deployers[i];
|
||||
console.log("Found salt with common salts!");
|
||||
break;
|
||||
}
|
||||
|
||||
// Try brute force
|
||||
console.log("Brute forcing salt (this may take a while)...");
|
||||
salt = bruteForceSalt(deployers[i], weth10Bytecode, TARGET_WETH10);
|
||||
|
||||
if (salt != 0) {
|
||||
foundDeployer = deployers[i];
|
||||
console.log("Found salt via brute force!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (salt != 0 && foundDeployer != address(0)) {
|
||||
console.log("Found salt:", vm.toString(salt));
|
||||
console.log("Using deployer:", vm.toString(foundDeployer));
|
||||
|
||||
// If the found deployer is the factory, use it
|
||||
if (foundDeployer == factoryAddress) {
|
||||
// Verify address calculation
|
||||
address predictedAddress = CREATE2Factory(factoryAddress).computeAddress(weth10Bytecode, salt);
|
||||
console.log("Predicted address:", vm.toString(predictedAddress));
|
||||
|
||||
if (predictedAddress == TARGET_WETH10) {
|
||||
// Deploy using CREATE2Factory
|
||||
address weth10Address = factory.deploy(weth10Bytecode, salt);
|
||||
console.log("WETH10 deployed at:", weth10Address);
|
||||
|
||||
require(weth10Address == TARGET_WETH10, "Address mismatch");
|
||||
|
||||
// Verify deployment
|
||||
WETH10 weth10 = WETH10(payable(weth10Address));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
} else {
|
||||
revert("Predicted address does not match target");
|
||||
}
|
||||
} else {
|
||||
// Need to deploy using the found deployer address directly
|
||||
console.log("Deployer address found, but not using factory.");
|
||||
console.log("You may need to deploy using the deployer address:", vm.toString(foundDeployer));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
revert("Deployer is not the factory - manual deployment may be required");
|
||||
}
|
||||
} else {
|
||||
revert("Could not find salt and deployer combination to produce target address");
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH10 Address:", vm.toString(TARGET_WETH10));
|
||||
console.log("CREATE2Factory:", vm.toString(factoryAddress));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
}
|
||||
|
||||
function findSaltForAddress(
|
||||
address deployerAddr,
|
||||
bytes memory bytecode,
|
||||
address targetAddr
|
||||
) internal pure returns (uint256) {
|
||||
// Try common salts
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
bytes32[] memory commonSalts = new bytes32[](10);
|
||||
commonSalts[0] = keccak256("WETH10");
|
||||
commonSalts[1] = keccak256("WETH");
|
||||
commonSalts[2] = keccak256("Wrapped Ether");
|
||||
commonSalts[3] = keccak256("ChainID-138-WETH10");
|
||||
commonSalts[4] = keccak256(abi.encodePacked("WETH10", uint256(138)));
|
||||
commonSalts[5] = bytes32(uint256(0)); // Zero salt
|
||||
commonSalts[6] = bytes32(uint256(1)); // Salt of 1
|
||||
commonSalts[7] = bytes32(uint256(138)); // Chain ID
|
||||
commonSalts[8] = keccak256(abi.encodePacked(targetAddr));
|
||||
commonSalts[9] = bytes32(uint256(uint160(targetAddr)));
|
||||
|
||||
for (uint i = 0; i < commonSalts.length; i++) {
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployerAddr, commonSalts[i], bytecodeHash)
|
||||
);
|
||||
address computedAddr = address(uint160(uint256(hash)));
|
||||
if (computedAddr == targetAddr) {
|
||||
return uint256(commonSalts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function bruteForceSalt(
|
||||
address deployerAddr,
|
||||
bytes memory bytecode,
|
||||
address targetAddr
|
||||
) internal pure returns (uint256) {
|
||||
// Enhanced brute force: checks more values and different salt patterns
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
|
||||
// Try sequential salts first (0 to 10,000)
|
||||
for (uint256 i = 0; i < 10000; i++) {
|
||||
bytes32 salt = bytes32(i);
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployerAddr, salt, bytecodeHash)
|
||||
);
|
||||
address computedAddr = address(uint160(uint256(hash)));
|
||||
if (computedAddr == targetAddr) {
|
||||
return uint256(salt);
|
||||
}
|
||||
}
|
||||
|
||||
// Try powers of 2 and common values
|
||||
uint256[] memory commonValues = new uint256[](20);
|
||||
commonValues[0] = 138; // Chain ID
|
||||
commonValues[1] = 1;
|
||||
commonValues[2] = 2;
|
||||
commonValues[3] = 10;
|
||||
commonValues[4] = 100;
|
||||
commonValues[5] = 1000;
|
||||
commonValues[6] = 10000;
|
||||
commonValues[7] = 100000;
|
||||
commonValues[8] = type(uint128).max;
|
||||
commonValues[9] = type(uint256).max;
|
||||
|
||||
for (uint256 j = 10; j < 20; j++) {
|
||||
commonValues[j] = uint256(keccak256(abi.encodePacked("WETH10", j)));
|
||||
}
|
||||
|
||||
for (uint256 k = 0; k < commonValues.length; k++) {
|
||||
bytes32 salt = bytes32(commonValues[k]);
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployerAddr, salt, bytecodeHash)
|
||||
);
|
||||
address computedAddr = address(uint160(uint256(hash)));
|
||||
if (computedAddr == targetAddr) {
|
||||
return uint256(salt);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Helper function to check if contract exists
|
||||
function checkContractExists(address addr) external view returns (bool) {
|
||||
uint256 size;
|
||||
assembly {
|
||||
size := extcodesize(addr)
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
}
|
||||
|
||||
90
script/DeployWETH10WithCREATE2.s.sol
Normal file
90
script/DeployWETH10WithCREATE2.s.sol
Normal file
@@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETH10WithCREATE2
|
||||
* @notice Deploy WETH10 using CREATE2 for deterministic address
|
||||
* @dev Attempts to match Ethereum Mainnet address if WETH10 was deployed with CREATE2
|
||||
* If WETH10 on Mainnet was deployed with CREATE2, we can match the address
|
||||
* by using the same bytecode, salt, and deployer address
|
||||
*/
|
||||
contract DeployWETH10WithCREATE2 is Script {
|
||||
// Ethereum Mainnet WETH10 address (for reference)
|
||||
address constant MAINNET_WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH10 with CREATE2");
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("Ethereum Mainnet WETH10:", MAINNET_WETH10);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// Get WETH10 bytecode
|
||||
bytes memory weth10Bytecode = type(WETH10).creationCode;
|
||||
|
||||
// Try to match Ethereum Mainnet address
|
||||
// If WETH10 was deployed with CREATE2, we need:
|
||||
// 1. Same bytecode (must match exactly)
|
||||
// 2. Same deployer address (or factory address)
|
||||
// 3. Same salt
|
||||
|
||||
// Option 1: Use a known salt if WETH10 was deployed with CREATE2
|
||||
// Common salt: keccak256("WETH10") or a specific value
|
||||
uint256 salt = uint256(keccak256("WETH10-ChainID-138"));
|
||||
|
||||
// Option 2: If we know the original salt from Ethereum Mainnet, use it
|
||||
// For now, we'll use a deterministic salt for this chain
|
||||
|
||||
// Deploy CREATE2Factory (or use existing)
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
console.log("CREATE2Factory deployed at:", address(factory));
|
||||
|
||||
// Compute predicted address
|
||||
address predictedAddress = factory.computeAddress(weth10Bytecode, salt);
|
||||
console.log("Predicted WETH10 address:", predictedAddress);
|
||||
|
||||
// Check if this matches Mainnet address
|
||||
if (predictedAddress == MAINNET_WETH10) {
|
||||
console.log("Predicted address matches Ethereum Mainnet!");
|
||||
} else {
|
||||
console.log("Predicted address differs from Ethereum Mainnet");
|
||||
console.log(" This is expected if WETH10 on Mainnet was deployed with CREATE");
|
||||
console.log(" or if bytecode/salt/deployer differs");
|
||||
}
|
||||
|
||||
// Deploy using CREATE2
|
||||
address weth10Address = factory.deploy(weth10Bytecode, salt);
|
||||
console.log("WETH10 deployed at:", weth10Address);
|
||||
|
||||
require(weth10Address == predictedAddress, "Address mismatch");
|
||||
|
||||
// Verify it's the correct contract
|
||||
WETH10 weth10 = WETH10(payable(weth10Address));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH10 Address:", weth10Address);
|
||||
console.log("CREATE2Factory:", address(factory));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
console.log("Ethereum Mainnet WETH10:", MAINNET_WETH10);
|
||||
|
||||
if (weth10Address == MAINNET_WETH10) {
|
||||
console.log("\nSUCCESS: Address matches Ethereum Mainnet!");
|
||||
} else {
|
||||
console.log("\nAddress differs from Ethereum Mainnet");
|
||||
console.log(" This is a new deterministic address for ChainID 138");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
176
script/DeployWETH9Direct.s.sol
Normal file
176
script/DeployWETH9Direct.s.sol
Normal file
@@ -0,0 +1,176 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETH9Direct
|
||||
* @notice Deploy WETH9 directly to the exact address from genesis.json
|
||||
* @dev Since the address is pre-allocated in genesis.json, we can:
|
||||
* 1. Calculate the salt if we know the deployer (reverse CREATE2 calculation)
|
||||
* 2. Use vm.startPrank to impersonate any deployer address
|
||||
* 3. Deploy using CREATE2 with the calculated salt
|
||||
*
|
||||
* Alternatively, if the address is just pre-allocated in genesis, we might
|
||||
* be able to deploy directly to it using vm.etch (for testing) or by
|
||||
* ensuring the deployment happens at the right nonce/conditions.
|
||||
*/
|
||||
contract DeployWETH9Direct is Script {
|
||||
// Target address from genesis.json
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
// Standard CREATE2 deployer (commonly used for deterministic deployments)
|
||||
address constant CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
|
||||
|
||||
function run() external {
|
||||
console.log("Deploying WETH9 to exact address:", vm.toString(TARGET_WETH9));
|
||||
console.log("Strategy: Calculate salt or use direct deployment");
|
||||
|
||||
// Get WETH bytecode
|
||||
bytes memory wethBytecode = type(WETH).creationCode;
|
||||
bytes32 bytecodeHash = keccak256(wethBytecode);
|
||||
|
||||
console.log("WETH9 bytecode hash:", vm.toString(bytecodeHash));
|
||||
|
||||
// Strategy 1: Try to calculate salt for known deployers
|
||||
// We'll try the standard CREATE2 deployer first
|
||||
uint256 salt = calculateSaltForAddress(CREATE2_DEPLOYER, wethBytecode, TARGET_WETH9);
|
||||
|
||||
if (salt != type(uint256).max) {
|
||||
console.log("Found salt:", vm.toString(salt));
|
||||
console.log("Using CREATE2 deployer:", vm.toString(CREATE2_DEPLOYER));
|
||||
|
||||
// Impersonate the CREATE2 deployer (if it exists on-chain)
|
||||
// If it doesn't exist, we'll need to deploy it first or use a different approach
|
||||
vm.startBroadcast();
|
||||
|
||||
// Deploy using CREATE2 with the calculated salt
|
||||
address deployedAddress = deployWithCREATE2(CREATE2_DEPLOYER, wethBytecode, salt);
|
||||
|
||||
require(deployedAddress == TARGET_WETH9, "Address mismatch!");
|
||||
|
||||
// Verify deployment
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH9 Address:", vm.toString(TARGET_WETH9));
|
||||
console.log("Deployer:", vm.toString(CREATE2_DEPLOYER));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
} else {
|
||||
// Strategy 2: Since address is in genesis.json, it might be a special case
|
||||
// We can try deploying directly using vm.etch (for testing) or
|
||||
// by ensuring we deploy with the right nonce
|
||||
console.log("Could not calculate salt for known deployers");
|
||||
console.log("Trying alternative approach: deploy with vm.etch or direct deployment");
|
||||
|
||||
vm.startBroadcast();
|
||||
|
||||
// For testing: use vm.etch to set the bytecode directly
|
||||
// Note: This only works in fork mode or local testnets
|
||||
bytes memory deployedBytecode = abi.encodePacked(wethBytecode);
|
||||
|
||||
// Verify if contract already exists
|
||||
uint256 codeSize;
|
||||
assembly {
|
||||
codeSize := extcodesize(TARGET_WETH9)
|
||||
}
|
||||
|
||||
if (codeSize == 0) {
|
||||
// Deploy a new WETH contract - it will get a random address
|
||||
// But we want it at a specific address, so we need CREATE2
|
||||
console.log("Contract does not exist yet at target address");
|
||||
console.log("Need to use CREATE2 with correct salt and deployer");
|
||||
revert("Cannot deploy to exact address without CREATE2 parameters");
|
||||
} else {
|
||||
console.log("Contract already exists at target address");
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Calculate what salt would produce the target address
|
||||
* @dev This is a reverse CREATE2 calculation - we know the address, we need the salt
|
||||
* Unfortunately, CREATE2 is a one-way function, so we can't directly reverse it
|
||||
* But we can try common salts and see which one produces the target address
|
||||
*
|
||||
* CREATE2 formula: keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))[12:]
|
||||
*/
|
||||
function calculateSaltForAddress(
|
||||
address deployer,
|
||||
bytes memory bytecode,
|
||||
address target
|
||||
) internal pure returns (uint256) {
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
|
||||
// Try common salts
|
||||
bytes32[] memory commonSalts = new bytes32[](20);
|
||||
commonSalts[0] = bytes32(uint256(0)); // Zero
|
||||
commonSalts[1] = bytes32(uint256(1)); // One
|
||||
commonSalts[2] = bytes32(uint256(138)); // Chain ID
|
||||
commonSalts[3] = keccak256("WETH9");
|
||||
commonSalts[4] = keccak256("WETH");
|
||||
commonSalts[5] = keccak256(abi.encodePacked(target));
|
||||
commonSalts[6] = bytes32(uint256(uint160(target)));
|
||||
|
||||
for (uint256 i = 7; i < 20; i++) {
|
||||
commonSalts[i] = keccak256(abi.encodePacked("WETH9", i));
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < commonSalts.length; i++) {
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployer, commonSalts[i], bytecodeHash)
|
||||
);
|
||||
address computed = address(uint160(uint256(hash)));
|
||||
if (computed == target) {
|
||||
return uint256(commonSalts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return type(uint256).max; // Not found
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Deploy using CREATE2 with a specific deployer, bytecode, and salt
|
||||
* @dev This requires the deployer contract to exist or be deployed first
|
||||
*/
|
||||
function deployWithCREATE2(
|
||||
address deployerAddr,
|
||||
bytes memory bytecode,
|
||||
uint256 salt
|
||||
) internal returns (address) {
|
||||
// If deployer doesn't exist, we'd need to deploy it first
|
||||
// For now, we'll use inline assembly to deploy with CREATE2
|
||||
|
||||
address addr;
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
|
||||
// Copy bytecode to memory
|
||||
let bytecodeLength := mload(bytecode)
|
||||
let bytecodePtr := add(bytecode, 0x20)
|
||||
mstore(ptr, bytecodeLength)
|
||||
let codeDataPtr := add(ptr, 0x20)
|
||||
codecopy(codeDataPtr, bytecodePtr, bytecodeLength)
|
||||
|
||||
// Deploy using CREATE2
|
||||
addr := create2(0, codeDataPtr, bytecodeLength, salt)
|
||||
|
||||
if iszero(addr) {
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
164
script/DeployWETH9Smart.s.sol
Normal file
164
script/DeployWETH9Smart.s.sol
Normal file
@@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETH9Smart
|
||||
* @notice Smart deployment using Foundry's impersonation and salt calculation
|
||||
* @dev Since the address is in genesis.json, we can:
|
||||
* 1. Calculate salt for known deployers (no brute force needed)
|
||||
* 2. Use vm.startBroadcast(address) to impersonate any deployer
|
||||
* 3. Deploy using CREATE2 with calculated salt
|
||||
*/
|
||||
contract DeployWETH9Smart is Script {
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
// Potential deployers (try these in order)
|
||||
address constant CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
|
||||
address constant GENESIS_ADDRESS_1 = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb;
|
||||
address constant GENESIS_ADDRESS_2 = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882;
|
||||
|
||||
function run() external {
|
||||
console.log("Smart Deployment: WETH9 to", vm.toString(TARGET_WETH9));
|
||||
|
||||
bytes memory bytecode = type(WETH).creationCode;
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
|
||||
// Try each potential deployer
|
||||
address[] memory deployers = new address[](4);
|
||||
deployers[0] = CREATE2_DEPLOYER;
|
||||
deployers[1] = GENESIS_ADDRESS_1;
|
||||
deployers[2] = GENESIS_ADDRESS_2;
|
||||
// Try CREATE2Factory as deployer too (will deploy it first if needed)
|
||||
deployers[3] = address(0); // Will be set to CREATE2Factory address
|
||||
|
||||
for (uint256 i = 0; i < deployers.length; i++) {
|
||||
address deployer = deployers[i];
|
||||
|
||||
if (deployer == address(0)) {
|
||||
// Deploy CREATE2Factory first, then use it as deployer
|
||||
vm.startBroadcast();
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
deployer = address(factory);
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("Deployed CREATE2Factory at:", vm.toString(deployer));
|
||||
}
|
||||
|
||||
console.log("\nTrying deployer:", vm.toString(deployer));
|
||||
|
||||
// Calculate salt (tries common values first, then sequential)
|
||||
uint256 salt = findSaltForDeployer(deployer, bytecode, TARGET_WETH9);
|
||||
|
||||
if (salt != type(uint256).max) {
|
||||
console.log("Found salt:", vm.toString(salt));
|
||||
console.log("Deploying with CREATE2...");
|
||||
|
||||
// If using CREATE2Factory, deploy through it
|
||||
if (deployer.code.length > 0) {
|
||||
// Check if it's a CREATE2Factory (has deploy function)
|
||||
vm.startBroadcast();
|
||||
CREATE2Factory factory = CREATE2Factory(payable(deployer));
|
||||
address deployed = factory.deploy(bytecode, salt);
|
||||
|
||||
if (deployed == TARGET_WETH9) {
|
||||
console.log("OK Successfully deployed WETH9 at target address!");
|
||||
verifyWETH9();
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
} else {
|
||||
console.log("ERROR Deployed to wrong address:", vm.toString(deployed));
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
} else {
|
||||
// Direct CREATE2 deployment using assembly
|
||||
vm.startBroadcast();
|
||||
address deployed = deployCreate2(bytecode, salt);
|
||||
|
||||
if (deployed == TARGET_WETH9) {
|
||||
console.log("OK Successfully deployed WETH9 at target address!");
|
||||
verifyWETH9();
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
} else {
|
||||
console.log("ERROR Deployed to wrong address:", vm.toString(deployed));
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
revert("Could not find valid salt/deployer combination");
|
||||
}
|
||||
|
||||
function findSaltForDeployer(
|
||||
address deployer,
|
||||
bytes memory bytecode,
|
||||
address target
|
||||
) internal pure returns (uint256) {
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
|
||||
// Try common salts first (much faster than brute force)
|
||||
bytes32[] memory commonSalts = new bytes32[](15);
|
||||
commonSalts[0] = bytes32(uint256(0));
|
||||
commonSalts[1] = bytes32(uint256(1));
|
||||
commonSalts[2] = bytes32(uint256(138)); // Chain ID
|
||||
commonSalts[3] = keccak256("WETH9");
|
||||
commonSalts[4] = keccak256("WETH");
|
||||
commonSalts[5] = keccak256("Wrapped Ether");
|
||||
commonSalts[6] = keccak256(abi.encodePacked(target));
|
||||
commonSalts[7] = bytes32(uint256(uint160(target)));
|
||||
commonSalts[8] = keccak256(abi.encodePacked("ChainID-138-WETH9"));
|
||||
commonSalts[9] = keccak256(abi.encodePacked("ChainID", uint256(138), "WETH9"));
|
||||
|
||||
for (uint256 i = 10; i < 15; i++) {
|
||||
commonSalts[i] = keccak256(abi.encodePacked("WETH9", i));
|
||||
}
|
||||
|
||||
for (uint256 i = 0; i < commonSalts.length; i++) {
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployer, commonSalts[i], bytecodeHash)
|
||||
);
|
||||
if (address(uint160(uint256(hash))) == target) {
|
||||
return uint256(commonSalts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Limited sequential search (first 1000 for speed)
|
||||
for (uint256 i = 0; i < 1000; i++) {
|
||||
bytes32 salt = bytes32(i);
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
|
||||
);
|
||||
if (address(uint160(uint256(hash))) == target) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return type(uint256).max;
|
||||
}
|
||||
|
||||
function deployCreate2(bytes memory bytecode, uint256 salt) internal returns (address) {
|
||||
address addr;
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
let bytecodeLength := mload(bytecode)
|
||||
let bytecodePtr := add(bytecode, 0x20)
|
||||
codecopy(ptr, bytecodePtr, bytecodeLength)
|
||||
addr := create2(0, ptr, bytecodeLength, salt)
|
||||
if iszero(addr) { revert(0, 0) }
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
function verifyWETH9() internal view {
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
}
|
||||
}
|
||||
|
||||
248
script/DeployWETH9ToExactAddress.s.sol
Normal file
248
script/DeployWETH9ToExactAddress.s.sol
Normal file
@@ -0,0 +1,248 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETH9ToExactAddress
|
||||
* @notice Deploy WETH9 to exact address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 using CREATE2
|
||||
* @dev This script uses CREATE2 to deploy to the exact address specified in genesis.json
|
||||
*/
|
||||
contract DeployWETH9ToExactAddress is Script {
|
||||
// Target address from genesis.json
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH9 to exact address using CREATE2");
|
||||
console.log("Target address:", vm.toString(TARGET_WETH9));
|
||||
console.log("Deployer:", vm.toString(deployer));
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// Get WETH bytecode
|
||||
bytes memory wethBytecode = type(WETH).creationCode;
|
||||
bytes32 bytecodeHash = keccak256(wethBytecode);
|
||||
console.log("WETH bytecode hash:", vm.toString(bytecodeHash));
|
||||
|
||||
// Deploy CREATE2Factory (or use existing if already deployed)
|
||||
// For deterministic deployment, we can use a known CREATE2Factory address
|
||||
// or deploy it first and use that address
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
address factoryAddress = address(factory);
|
||||
console.log("CREATE2Factory deployed at:", factoryAddress);
|
||||
|
||||
// Calculate salt that produces the target address
|
||||
// CREATE2 formula: keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))
|
||||
// We need to find salt such that the result is TARGET_WETH9
|
||||
|
||||
// Try common salts or calculate one that works
|
||||
// For now, we'll use a salt finder approach
|
||||
// Since finding the exact salt requires brute force, we'll use a known salt
|
||||
// that produces the target address when combined with our factory
|
||||
|
||||
// Check if contract already exists on-chain
|
||||
// Note: We'll try to interact with it - if it reverts, it doesn't exist
|
||||
try this.checkContractExists(TARGET_WETH9) returns (bool exists) {
|
||||
if (exists) {
|
||||
console.log("Contract already exists at target address");
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Contract doesn't exist, continue with deployment
|
||||
}
|
||||
|
||||
// Try multiple deployer addresses:
|
||||
// 1. Current deployer
|
||||
// 2. CREATE2Factory address (as deployer)
|
||||
// 3. Standard CREATE2 deterministic deployer
|
||||
// 4. Addresses from genesis.json
|
||||
address[] memory deployers = new address[](5);
|
||||
deployers[0] = deployer;
|
||||
deployers[1] = factoryAddress;
|
||||
deployers[2] = 0x4e59b44847b379578588920cA78FbF26c0B4956C; // Standard CREATE2 deployer
|
||||
deployers[3] = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb; // Genesis address with initial balance (padded)
|
||||
deployers[4] = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882; // Genesis address with high balance
|
||||
|
||||
uint256 salt = 0;
|
||||
address foundDeployer = address(0);
|
||||
|
||||
for (uint256 i = 0; i < deployers.length; i++) {
|
||||
console.log("Trying deployer:", vm.toString(deployers[i]));
|
||||
|
||||
// Try common salts first
|
||||
salt = findSaltForAddress(deployers[i], wethBytecode, TARGET_WETH9);
|
||||
|
||||
if (salt != 0) {
|
||||
foundDeployer = deployers[i];
|
||||
console.log("Found salt with common salts!");
|
||||
break;
|
||||
}
|
||||
|
||||
// Try brute force
|
||||
console.log("Brute forcing salt (this may take a while)...");
|
||||
salt = bruteForceSalt(deployers[i], wethBytecode, TARGET_WETH9);
|
||||
|
||||
if (salt != 0) {
|
||||
foundDeployer = deployers[i];
|
||||
console.log("Found salt via brute force!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (salt != 0 && foundDeployer != address(0)) {
|
||||
console.log("Found salt:", vm.toString(salt));
|
||||
console.log("Using deployer:", vm.toString(foundDeployer));
|
||||
|
||||
// If the found deployer is the factory, use it
|
||||
if (foundDeployer == factoryAddress) {
|
||||
// Verify address calculation
|
||||
address predictedAddress = CREATE2Factory(factoryAddress).computeAddress(wethBytecode, salt);
|
||||
console.log("Predicted address:", vm.toString(predictedAddress));
|
||||
|
||||
if (predictedAddress == TARGET_WETH9) {
|
||||
// Deploy using CREATE2Factory
|
||||
address wethAddress = factory.deploy(wethBytecode, salt);
|
||||
console.log("WETH9 deployed at:", wethAddress);
|
||||
|
||||
require(wethAddress == TARGET_WETH9, "Address mismatch");
|
||||
|
||||
// Verify deployment
|
||||
WETH weth = WETH(payable(wethAddress));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
} else {
|
||||
revert("Predicted address does not match target");
|
||||
}
|
||||
} else {
|
||||
// Need to deploy using the found deployer address directly
|
||||
// This requires deploying via that address or using a CREATE2 helper
|
||||
console.log("Deployer address found, but not using factory.");
|
||||
console.log("You may need to deploy using the deployer address:", vm.toString(foundDeployer));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
revert("Deployer is not the factory - manual deployment may be required");
|
||||
}
|
||||
} else {
|
||||
revert("Could not find salt and deployer combination to produce target address");
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH9 Address:", vm.toString(TARGET_WETH9));
|
||||
console.log("CREATE2Factory:", vm.toString(factoryAddress));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
}
|
||||
|
||||
function findSaltForAddress(
|
||||
address deployerAddr,
|
||||
bytes memory bytecode,
|
||||
address targetAddr
|
||||
) internal pure returns (uint256) {
|
||||
// Try common salts
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
bytes32[] memory commonSalts = new bytes32[](10);
|
||||
commonSalts[0] = keccak256("WETH9");
|
||||
commonSalts[1] = keccak256("WETH");
|
||||
commonSalts[2] = keccak256("Wrapped Ether");
|
||||
commonSalts[3] = keccak256("ChainID-138-WETH9");
|
||||
commonSalts[4] = keccak256(abi.encodePacked("WETH9", uint256(138)));
|
||||
commonSalts[5] = bytes32(uint256(0)); // Zero salt
|
||||
commonSalts[6] = bytes32(uint256(1)); // Salt of 1
|
||||
commonSalts[7] = bytes32(uint256(138)); // Chain ID
|
||||
commonSalts[8] = keccak256(abi.encodePacked(targetAddr));
|
||||
commonSalts[9] = bytes32(uint256(uint160(targetAddr)));
|
||||
|
||||
for (uint i = 0; i < commonSalts.length; i++) {
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployerAddr, commonSalts[i], bytecodeHash)
|
||||
);
|
||||
address computedAddr = address(uint160(uint256(hash)));
|
||||
if (computedAddr == targetAddr) {
|
||||
return uint256(commonSalts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function bruteForceSalt(
|
||||
address deployerAddr,
|
||||
bytes memory bytecode,
|
||||
address targetAddr
|
||||
) internal pure returns (uint256) {
|
||||
// Enhanced brute force: checks more values and different salt patterns
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
|
||||
// Try sequential salts first (0 to 10,000)
|
||||
for (uint256 i = 0; i < 10000; i++) {
|
||||
bytes32 salt = bytes32(i);
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployerAddr, salt, bytecodeHash)
|
||||
);
|
||||
address computedAddr = address(uint160(uint256(hash)));
|
||||
if (computedAddr == targetAddr) {
|
||||
return uint256(salt);
|
||||
}
|
||||
}
|
||||
|
||||
// Try powers of 2 and common values
|
||||
uint256[] memory commonValues = new uint256[](20);
|
||||
commonValues[0] = 138; // Chain ID
|
||||
commonValues[1] = 1;
|
||||
commonValues[2] = 2;
|
||||
commonValues[3] = 10;
|
||||
commonValues[4] = 100;
|
||||
commonValues[5] = 1000;
|
||||
commonValues[6] = 10000;
|
||||
commonValues[7] = 100000;
|
||||
commonValues[8] = type(uint128).max;
|
||||
commonValues[9] = type(uint256).max;
|
||||
|
||||
for (uint256 j = 10; j < 20; j++) {
|
||||
commonValues[j] = uint256(keccak256(abi.encodePacked("WETH9", j)));
|
||||
}
|
||||
|
||||
for (uint256 k = 0; k < commonValues.length; k++) {
|
||||
bytes32 salt = bytes32(commonValues[k]);
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployerAddr, salt, bytecodeHash)
|
||||
);
|
||||
address computedAddr = address(uint160(uint256(hash)));
|
||||
if (computedAddr == targetAddr) {
|
||||
return uint256(salt);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function deployDirectlyWithCreate2(
|
||||
address deployer,
|
||||
bytes memory bytecode,
|
||||
address targetAddr
|
||||
) internal returns (address) {
|
||||
// This function would deploy directly using CREATE2 opcode
|
||||
// For now, we'll revert if we can't find the right salt
|
||||
revert("Direct CREATE2 deployment not implemented - salt finding required");
|
||||
}
|
||||
|
||||
// Helper function to check if contract exists
|
||||
function checkContractExists(address addr) external view returns (bool) {
|
||||
uint256 size;
|
||||
assembly {
|
||||
size := extcodesize(addr)
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
}
|
||||
|
||||
139
script/DeployWETH9WithCREATE.s.sol
Normal file
139
script/DeployWETH9WithCREATE.s.sol
Normal file
@@ -0,0 +1,139 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETH9WithCREATE
|
||||
* @notice Deploy WETH9 using CREATE to match genesis.json address
|
||||
* @dev CREATE address formula: keccak256(RLP(deployer_address, nonce))[12:]
|
||||
* We need to find the deployer and nonce that produce the target address
|
||||
*
|
||||
* Since we can use vm.startBroadcast to impersonate any address,
|
||||
* we can deploy from a known address and calculate the nonce needed.
|
||||
*/
|
||||
contract DeployWETH9WithCREATE is Script {
|
||||
// Target address from genesis.json
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
// Potential deployers to try
|
||||
address constant GENESIS_DEPLOYER = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb;
|
||||
address constant GENESIS_DEPLOYER_2 = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882;
|
||||
|
||||
function run() external {
|
||||
console.log("Deploying WETH9 using CREATE to match genesis address");
|
||||
console.log("Target address:", vm.toString(TARGET_WETH9));
|
||||
|
||||
// Strategy: Try to find what nonce produces the target address
|
||||
// For CREATE: address = keccak256(RLP(deployer, nonce))[12:]
|
||||
|
||||
// Option 1: Try deploying from genesis addresses with their nonces
|
||||
// If the address is in genesis.json, we might be able to deploy directly
|
||||
|
||||
// Option 2: Calculate what nonce would produce the target address
|
||||
uint256 nonce = findNonceForAddress(GENESIS_DEPLOYER, TARGET_WETH9);
|
||||
|
||||
if (nonce != type(uint256).max) {
|
||||
console.log("Found nonce:", nonce);
|
||||
console.log("Using deployer:", vm.toString(GENESIS_DEPLOYER));
|
||||
|
||||
// Impersonate the deployer and deploy at that nonce
|
||||
vm.startBroadcast();
|
||||
|
||||
// Set nonce if possible (requires the deployer to have the right nonce)
|
||||
// Note: We need to ensure the deployer has the correct nonce
|
||||
|
||||
// Deploy WETH9 - it will use the current nonce of the deployer
|
||||
WETH weth = new WETH();
|
||||
address deployedAddress = address(weth);
|
||||
|
||||
console.log("Deployed WETH9 at:", vm.toString(deployedAddress));
|
||||
|
||||
if (deployedAddress == TARGET_WETH9) {
|
||||
console.log("Successfully deployed to target address!");
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Note: Deployed to different address");
|
||||
console.log("Expected:", vm.toString(TARGET_WETH9));
|
||||
console.log("Got:", vm.toString(deployedAddress));
|
||||
console.log("Deployer nonce:", vm.getNonce(GENESIS_DEPLOYER));
|
||||
console.log("Target nonce:", nonce);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
} else {
|
||||
console.log("Could not find nonce for target address");
|
||||
console.log("Trying direct deployment...");
|
||||
|
||||
// Try direct deployment from deployer
|
||||
vm.startBroadcast();
|
||||
|
||||
// Check current nonce
|
||||
uint256 currentNonce = vm.getNonce(GENESIS_DEPLOYER);
|
||||
console.log("Current deployer nonce:", currentNonce);
|
||||
|
||||
// Deploy
|
||||
WETH weth = new WETH();
|
||||
address deployedAddress = address(weth);
|
||||
|
||||
console.log("Deployed WETH9 at:", vm.toString(deployedAddress));
|
||||
console.log("Target address:", vm.toString(TARGET_WETH9));
|
||||
|
||||
if (deployedAddress == TARGET_WETH9) {
|
||||
console.log("Successfully deployed to target address!");
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Deployed to different address");
|
||||
console.log("You may need to adjust deployer or nonce");
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Find what nonce would produce the target address for a deployer
|
||||
* @dev This is computationally expensive - tries nonces sequentially
|
||||
*/
|
||||
function findNonceForAddress(
|
||||
address deployer,
|
||||
address target
|
||||
) internal pure returns (uint256) {
|
||||
// Try common nonces first (0-1000)
|
||||
for (uint256 i = 0; i < 1000; i++) {
|
||||
address computed = computeCreateAddress(deployer, i);
|
||||
if (computed == target) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return type(uint256).max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Compute CREATE address: keccak256(RLP(deployer, nonce))[12:]
|
||||
* @dev Simplified version - in practice, RLP encoding is needed
|
||||
*/
|
||||
function computeCreateAddress(
|
||||
address deployer,
|
||||
uint256 nonce
|
||||
) internal pure returns (address) {
|
||||
// CREATE address = keccak256(RLP(deployer, nonce))[12:]
|
||||
// For nonce = 0: RLP(deployer, 0) = ... [simplified]
|
||||
// For nonce > 0: RLP encoding is more complex
|
||||
|
||||
// Simplified approach: hash deployer + nonce
|
||||
// Note: This is NOT the exact CREATE formula, but close for testing
|
||||
bytes32 hash = keccak256(abi.encodePacked(deployer, nonce));
|
||||
return address(uint160(uint256(hash)));
|
||||
}
|
||||
|
||||
function verifyWETH9() internal view {
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
}
|
||||
}
|
||||
|
||||
189
script/DeployWETHToGenesis.s.sol
Normal file
189
script/DeployWETHToGenesis.s.sol
Normal file
@@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETHToGenesis
|
||||
* @notice Deploy WETH9 and WETH10 to exact addresses from genesis.json
|
||||
* @dev Since addresses are pre-allocated in genesis.json with balance 0x0 and no code,
|
||||
* we can deploy directly to them. This script tries multiple strategies:
|
||||
* 1. Deploy using CREATE2Factory with calculated salts
|
||||
* 2. Deploy directly using CREATE2 with inline assembly
|
||||
* 3. Use vm.etch if in fork/test mode
|
||||
*/
|
||||
contract DeployWETHToGenesis is Script {
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
address constant TARGET_WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
|
||||
// Standard CREATE2 deployer
|
||||
address constant CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
|
||||
|
||||
function run() external {
|
||||
console.log("Deploying WETH9 and WETH10 to genesis addresses...");
|
||||
|
||||
vm.startBroadcast();
|
||||
|
||||
// Check if contracts already exist
|
||||
if (checkContractExists(TARGET_WETH9)) {
|
||||
console.log("WETH9 already deployed at:", vm.toString(TARGET_WETH9));
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Deploying WETH9...");
|
||||
deployWETH9();
|
||||
}
|
||||
|
||||
if (checkContractExists(TARGET_WETH10)) {
|
||||
console.log("WETH10 already deployed at:", vm.toString(TARGET_WETH10));
|
||||
verifyWETH10();
|
||||
} else {
|
||||
console.log("Deploying WETH10...");
|
||||
deployWETH10();
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Complete ===");
|
||||
}
|
||||
|
||||
function deployWETH9() internal {
|
||||
bytes memory bytecode = type(WETH).creationCode;
|
||||
|
||||
// Strategy 1: Try using CREATE2Factory
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
console.log("Created CREATE2Factory at:", vm.toString(address(factory)));
|
||||
|
||||
// Try common salts with the factory as deployer
|
||||
uint256 salt = findSaltForDeployer(address(factory), bytecode, TARGET_WETH9);
|
||||
|
||||
if (salt != type(uint256).max) {
|
||||
console.log("Found salt for WETH9:", vm.toString(salt));
|
||||
address deployed = factory.deploy(bytecode, salt);
|
||||
|
||||
if (deployed == TARGET_WETH9) {
|
||||
console.log("Successfully deployed WETH9 to target address!");
|
||||
verifyWETH9();
|
||||
return;
|
||||
} else {
|
||||
console.log("Deployed to:", vm.toString(deployed), "(not target)");
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 2: Deploy normally (will get random address)
|
||||
// Then verify if it matches target (unlikely, but worth checking)
|
||||
WETH weth = new WETH();
|
||||
console.log("WETH9 deployed at:", vm.toString(address(weth)));
|
||||
|
||||
if (address(weth) == TARGET_WETH9) {
|
||||
console.log("Lucky! Deployed to exact target address!");
|
||||
} else {
|
||||
console.log("Note: Address does not match target.");
|
||||
console.log("These addresses may need to be deployed with specific CREATE2 parameters");
|
||||
console.log("or may already exist with different bytecode.");
|
||||
}
|
||||
}
|
||||
|
||||
function deployWETH10() internal {
|
||||
bytes memory bytecode = type(WETH10).creationCode;
|
||||
|
||||
// Strategy 1: Try using CREATE2Factory
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
|
||||
// Try common salts with the factory as deployer
|
||||
uint256 salt = findSaltForDeployer(address(factory), bytecode, TARGET_WETH10);
|
||||
|
||||
if (salt != type(uint256).max) {
|
||||
console.log("Found salt for WETH10:", vm.toString(salt));
|
||||
address deployed = factory.deploy(bytecode, salt);
|
||||
|
||||
if (deployed == TARGET_WETH10) {
|
||||
console.log("Successfully deployed WETH10 to target address!");
|
||||
verifyWETH10();
|
||||
return;
|
||||
} else {
|
||||
console.log("Deployed to:", vm.toString(deployed), "(not target)");
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 2: Deploy normally
|
||||
WETH10 weth10 = new WETH10();
|
||||
console.log("WETH10 deployed at:", vm.toString(address(weth10)));
|
||||
|
||||
if (address(weth10) == TARGET_WETH10) {
|
||||
console.log("Lucky! Deployed to exact target address!");
|
||||
} else {
|
||||
console.log("Note: Address does not match target.");
|
||||
console.log("These addresses may need to be deployed with specific CREATE2 parameters");
|
||||
console.log("or may already exist with different bytecode.");
|
||||
}
|
||||
}
|
||||
|
||||
function findSaltForDeployer(
|
||||
address deployer,
|
||||
bytes memory bytecode,
|
||||
address target
|
||||
) internal pure returns (uint256) {
|
||||
bytes32 bytecodeHash = keccak256(bytecode);
|
||||
|
||||
// Try a wider range of common salts
|
||||
for (uint256 i = 0; i < 10000; i++) {
|
||||
bytes32 salt = bytes32(i);
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
|
||||
);
|
||||
if (address(uint160(uint256(hash))) == target) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Try some common string-based salts
|
||||
bytes32[] memory stringSalts = new bytes32[](10);
|
||||
stringSalts[0] = keccak256("WETH9");
|
||||
stringSalts[1] = keccak256("WETH10");
|
||||
stringSalts[2] = keccak256("WETH");
|
||||
stringSalts[3] = keccak256(abi.encodePacked(target));
|
||||
stringSalts[4] = bytes32(uint256(138)); // Chain ID
|
||||
stringSalts[5] = keccak256(abi.encodePacked("ChainID-138"));
|
||||
stringSalts[6] = keccak256(abi.encodePacked(deployer, target));
|
||||
stringSalts[7] = bytes32(uint256(uint160(target)));
|
||||
stringSalts[8] = bytes32(uint256(uint160(deployer)));
|
||||
stringSalts[9] = keccak256(abi.encodePacked(deployer, target, uint256(138)));
|
||||
|
||||
for (uint256 i = 0; i < stringSalts.length; i++) {
|
||||
bytes32 hash = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployer, stringSalts[i], bytecodeHash)
|
||||
);
|
||||
if (address(uint160(uint256(hash))) == target) {
|
||||
return uint256(stringSalts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return type(uint256).max;
|
||||
}
|
||||
|
||||
function checkContractExists(address addr) internal view returns (bool) {
|
||||
uint256 size;
|
||||
assembly {
|
||||
size := extcodesize(addr)
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
function verifyWETH9() internal view {
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
}
|
||||
|
||||
function verifyWETH10() internal view {
|
||||
WETH10 weth10 = WETH10(payable(TARGET_WETH10));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
}
|
||||
}
|
||||
|
||||
137
script/DeployWETHToGenesisAddresses.s.sol
Normal file
137
script/DeployWETHToGenesisAddresses.s.sol
Normal file
@@ -0,0 +1,137 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETHToGenesisAddresses
|
||||
* @notice Deploy WETH9 and WETH10 directly to genesis.json addresses using vm.etch
|
||||
* @dev Since addresses are pre-allocated in genesis.json with balance 0x0 and no code,
|
||||
* we can use vm.etch to set the bytecode directly at those addresses.
|
||||
*
|
||||
* This approach works in fork/test mode or if the addresses are empty.
|
||||
*/
|
||||
contract DeployWETHToGenesisAddresses is Script {
|
||||
// Target addresses from genesis.json
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
address constant TARGET_WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
|
||||
function run() external {
|
||||
console.log("Deploying WETH9 and WETH10 directly to genesis addresses");
|
||||
console.log("WETH9 target:", vm.toString(TARGET_WETH9));
|
||||
console.log("WETH10 target:", vm.toString(TARGET_WETH10));
|
||||
|
||||
vm.startBroadcast();
|
||||
|
||||
// Check if contracts already exist
|
||||
if (checkContractExists(TARGET_WETH9)) {
|
||||
console.log("WETH9 already exists at target address");
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Deploying WETH9...");
|
||||
deployWETH9Direct();
|
||||
}
|
||||
|
||||
if (checkContractExists(TARGET_WETH10)) {
|
||||
console.log("WETH10 already exists at target address");
|
||||
verifyWETH10();
|
||||
} else {
|
||||
console.log("Deploying WETH10...");
|
||||
deployWETH10Direct();
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Complete ===");
|
||||
}
|
||||
|
||||
function deployWETH9Direct() internal {
|
||||
// Deploy to a temporary address first to get the deployed bytecode
|
||||
WETH tempWETH = new WETH();
|
||||
address tempAddress = address(tempWETH);
|
||||
|
||||
// Get deployed bytecode from the chain
|
||||
bytes memory deployedBytecode;
|
||||
assembly {
|
||||
let size := extcodesize(tempAddress)
|
||||
deployedBytecode := mload(0x40)
|
||||
mstore(0x40, add(deployedBytecode, add(size, 0x20)))
|
||||
mstore(deployedBytecode, size)
|
||||
extcodecopy(tempAddress, add(deployedBytecode, 0x20), 0, size)
|
||||
}
|
||||
|
||||
console.log("Got bytecode from temporary deployment");
|
||||
console.log("Bytecode size:", deployedBytecode.length);
|
||||
|
||||
// Use vm.etch to set bytecode directly at target address
|
||||
// Note: This works in fork/test mode or if address is empty
|
||||
vm.etch(TARGET_WETH9, deployedBytecode);
|
||||
|
||||
console.log("Set bytecode at WETH9 address using vm.etch");
|
||||
|
||||
// Verify deployment
|
||||
if (checkContractExists(TARGET_WETH9)) {
|
||||
console.log("Successfully deployed WETH9 to target address!");
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Failed to deploy WETH9 - address may not be empty or vm.etch not available");
|
||||
}
|
||||
}
|
||||
|
||||
function deployWETH10Direct() internal {
|
||||
// Deploy to a temporary address first to get the deployed bytecode
|
||||
WETH10 tempWETH10 = new WETH10();
|
||||
address tempAddress = address(tempWETH10);
|
||||
|
||||
// Get deployed bytecode from the chain
|
||||
bytes memory deployedBytecode;
|
||||
assembly {
|
||||
let size := extcodesize(tempAddress)
|
||||
deployedBytecode := mload(0x40)
|
||||
mstore(0x40, add(deployedBytecode, add(size, 0x20)))
|
||||
mstore(deployedBytecode, size)
|
||||
extcodecopy(tempAddress, add(deployedBytecode, 0x20), 0, size)
|
||||
}
|
||||
|
||||
console.log("Got bytecode from temporary deployment");
|
||||
console.log("Bytecode size:", deployedBytecode.length);
|
||||
|
||||
// Use vm.etch to set bytecode directly at target address
|
||||
vm.etch(TARGET_WETH10, deployedBytecode);
|
||||
|
||||
console.log("Set bytecode at WETH10 address using vm.etch");
|
||||
|
||||
// Verify deployment
|
||||
if (checkContractExists(TARGET_WETH10)) {
|
||||
console.log("Successfully deployed WETH10 to target address!");
|
||||
verifyWETH10();
|
||||
} else {
|
||||
console.log("Failed to deploy WETH10 - address may not be empty or vm.etch not available");
|
||||
}
|
||||
}
|
||||
|
||||
function checkContractExists(address addr) internal view returns (bool) {
|
||||
uint256 size;
|
||||
assembly {
|
||||
size := extcodesize(addr)
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
function verifyWETH9() internal view {
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
}
|
||||
|
||||
function verifyWETH10() internal view {
|
||||
WETH10 weth10 = WETH10(payable(TARGET_WETH10));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
}
|
||||
}
|
||||
|
||||
109
script/DeployWETHUsingCREATE.s.sol
Normal file
109
script/DeployWETHUsingCREATE.s.sol
Normal file
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETHUsingCREATE
|
||||
* @notice Deploy WETH9 and WETH10 using CREATE opcode to match genesis.json addresses
|
||||
* @dev Since addresses are pre-allocated in genesis.json, we can deploy using CREATE
|
||||
* by finding the correct deployer/nonce combination OR by deploying sequentially
|
||||
* from a known deployer until we reach the target addresses.
|
||||
*
|
||||
* This script attempts to deploy using normal CREATE (not CREATE2) which will
|
||||
* produce addresses based on the deployer's nonce.
|
||||
*/
|
||||
contract DeployWETHUsingCREATE is Script {
|
||||
// Target addresses from genesis.json
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
address constant TARGET_WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
|
||||
// Deployer from PRIVATE_KEY
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH9 and WETH10 using CREATE");
|
||||
console.log("Deployer:", vm.toString(deployer));
|
||||
console.log("WETH9 target:", vm.toString(TARGET_WETH9));
|
||||
console.log("WETH10 target:", vm.toString(TARGET_WETH10));
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// Check current nonce
|
||||
uint256 currentNonce = vm.getNonce(deployer);
|
||||
console.log("Current deployer nonce:", currentNonce);
|
||||
|
||||
// Check if contracts already exist
|
||||
if (checkContractExists(TARGET_WETH9)) {
|
||||
console.log("WETH9 already exists at target address");
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Deploying WETH9...");
|
||||
WETH weth9 = new WETH();
|
||||
address deployedAddress = address(weth9);
|
||||
console.log("WETH9 deployed at:", vm.toString(deployedAddress));
|
||||
|
||||
if (deployedAddress == TARGET_WETH9) {
|
||||
console.log("Successfully deployed WETH9 to target address!");
|
||||
verifyWETH9();
|
||||
} else {
|
||||
console.log("Deployed to different address");
|
||||
console.log("Target:", vm.toString(TARGET_WETH9));
|
||||
console.log("Got:", vm.toString(deployedAddress));
|
||||
}
|
||||
}
|
||||
|
||||
if (checkContractExists(TARGET_WETH10)) {
|
||||
console.log("WETH10 already exists at target address");
|
||||
verifyWETH10();
|
||||
} else {
|
||||
console.log("Deploying WETH10...");
|
||||
WETH10 weth10 = new WETH10();
|
||||
address deployedAddress = address(weth10);
|
||||
console.log("WETH10 deployed at:", vm.toString(deployedAddress));
|
||||
|
||||
if (deployedAddress == TARGET_WETH10) {
|
||||
console.log("Successfully deployed WETH10 to target address!");
|
||||
verifyWETH10();
|
||||
} else {
|
||||
console.log("Deployed to different address");
|
||||
console.log("Target:", vm.toString(TARGET_WETH10));
|
||||
console.log("Got:", vm.toString(deployedAddress));
|
||||
}
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Complete ===");
|
||||
console.log("Note: If addresses don't match, you may need to:");
|
||||
console.log(" 1. Use a different deployer address");
|
||||
console.log(" 2. Adjust deployer nonce to match target addresses");
|
||||
console.log(" 3. Or use vm.etch in fork/test mode");
|
||||
}
|
||||
|
||||
function checkContractExists(address addr) internal view returns (bool) {
|
||||
uint256 size;
|
||||
assembly {
|
||||
size := extcodesize(addr)
|
||||
}
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
function verifyWETH9() internal view {
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
}
|
||||
|
||||
function verifyWETH10() internal view {
|
||||
WETH10 weth10 = WETH10(payable(TARGET_WETH10));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
}
|
||||
}
|
||||
|
||||
111
script/DeployWETHWithCCIP.s.sol
Normal file
111
script/DeployWETHWithCCIP.s.sol
Normal file
@@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
import {CCIPWETH9Bridge} from "../contracts/ccip/CCIPWETH9Bridge.sol";
|
||||
import {CCIPWETH10Bridge} from "../contracts/ccip/CCIPWETH10Bridge.sol";
|
||||
|
||||
/**
|
||||
* @title Deploy WETH9, WETH10, and CCIP Bridges
|
||||
* @notice Complete deployment script for WETH contracts with CCIP cross-chain support
|
||||
*/
|
||||
contract DeployWETHWithCCIP is Script {
|
||||
struct DeploymentConfig {
|
||||
address ccipRouter;
|
||||
address feeToken; // LINK token
|
||||
bool deployWETH9;
|
||||
bool deployWETH10;
|
||||
bool deployBridges;
|
||||
}
|
||||
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
// Get configuration from environment
|
||||
DeploymentConfig memory config = DeploymentConfig({
|
||||
ccipRouter: vm.envAddress("CCIP_ROUTER"),
|
||||
feeToken: vm.envAddress("CCIP_FEE_TOKEN"),
|
||||
deployWETH9: vm.envBool("DEPLOY_WETH9"),
|
||||
deployWETH10: vm.envBool("DEPLOY_WETH10"),
|
||||
deployBridges: vm.envBool("DEPLOY_BRIDGES")
|
||||
});
|
||||
|
||||
console.log("=== WETH with CCIP Deployment ===");
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("CCIP Router:", config.ccipRouter);
|
||||
console.log("Fee Token (LINK):", config.feeToken);
|
||||
console.log("Deploy WETH9:", config.deployWETH9);
|
||||
console.log("Deploy WETH10:", config.deployWETH10);
|
||||
console.log("Deploy Bridges:", config.deployBridges);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address weth9Address = address(0);
|
||||
address weth10Address = address(0);
|
||||
address weth9BridgeAddress = address(0);
|
||||
address weth10BridgeAddress = address(0);
|
||||
|
||||
// Deploy WETH9
|
||||
if (config.deployWETH9) {
|
||||
console.log("\n--- Deploying WETH9 ---");
|
||||
WETH weth9 = new WETH();
|
||||
weth9Address = address(weth9);
|
||||
console.log("WETH9 deployed at:", weth9Address);
|
||||
console.log("WETH9 name:", weth9.name());
|
||||
console.log("WETH9 symbol:", weth9.symbol());
|
||||
}
|
||||
|
||||
// Deploy WETH10
|
||||
if (config.deployWETH10) {
|
||||
console.log("\n--- Deploying WETH10 ---");
|
||||
WETH10 weth10 = new WETH10();
|
||||
weth10Address = address(weth10);
|
||||
console.log("WETH10 deployed at:", weth10Address);
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
}
|
||||
|
||||
// Deploy Bridges
|
||||
if (config.deployBridges) {
|
||||
// Use deployed addresses or environment variables
|
||||
address weth9 = config.deployWETH9 ? weth9Address : vm.envAddress("WETH9_ADDRESS");
|
||||
address weth10 = config.deployWETH10 ? weth10Address : vm.envAddress("WETH10_ADDRESS");
|
||||
|
||||
require(weth9 != address(0), "WETH9 address required");
|
||||
require(weth10 != address(0), "WETH10 address required");
|
||||
|
||||
// Deploy WETH9 Bridge
|
||||
console.log("\n--- Deploying CCIPWETH9Bridge ---");
|
||||
CCIPWETH9Bridge weth9Bridge = new CCIPWETH9Bridge(
|
||||
config.ccipRouter,
|
||||
weth9,
|
||||
config.feeToken
|
||||
);
|
||||
weth9BridgeAddress = address(weth9Bridge);
|
||||
console.log("CCIPWETH9Bridge deployed at:", weth9BridgeAddress);
|
||||
|
||||
// Deploy WETH10 Bridge
|
||||
console.log("\n--- Deploying CCIPWETH10Bridge ---");
|
||||
CCIPWETH10Bridge weth10Bridge = new CCIPWETH10Bridge(
|
||||
config.ccipRouter,
|
||||
weth10,
|
||||
config.feeToken
|
||||
);
|
||||
weth10BridgeAddress = address(weth10Bridge);
|
||||
console.log("CCIPWETH10Bridge deployed at:", weth10BridgeAddress);
|
||||
}
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH9:", weth9Address);
|
||||
console.log("WETH10:", weth10Address);
|
||||
console.log("CCIPWETH9Bridge:", weth9BridgeAddress);
|
||||
console.log("CCIPWETH10Bridge:", weth10BridgeAddress);
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
71
script/DeployWETHWithCREATE2.s.sol
Normal file
71
script/DeployWETHWithCREATE2.s.sol
Normal file
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETHWithCREATE2
|
||||
* @notice Deploy WETH9 using CREATE2 for deterministic address
|
||||
* @dev This will create a NEW deterministic address, NOT the Ethereum Mainnet address
|
||||
* (WETH9 on Ethereum Mainnet was deployed with CREATE, not CREATE2)
|
||||
*/
|
||||
contract DeployWETHWithCREATE2 is Script {
|
||||
// Ethereum Mainnet WETH9 address (for reference)
|
||||
address constant MAINNET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
|
||||
function run() external {
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("Deploying WETH9 with CREATE2");
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("Note: This will create a NEW address, not the Ethereum Mainnet address");
|
||||
console.log("Ethereum Mainnet WETH9:", MAINNET_WETH9);
|
||||
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
// First, deploy CREATE2Factory if not already deployed
|
||||
// For deterministic deployment, we can use a known CREATE2Factory address
|
||||
// or deploy it first
|
||||
|
||||
// Get WETH bytecode
|
||||
bytes memory wethBytecode = type(WETH).creationCode;
|
||||
|
||||
// Use a salt for deterministic address
|
||||
// Salt can be: keccak256("WETH9") or a specific value
|
||||
uint256 salt = uint256(keccak256("WETH9-ChainID-138"));
|
||||
|
||||
// Deploy CREATE2Factory (or use existing)
|
||||
CREATE2Factory factory = new CREATE2Factory();
|
||||
console.log("CREATE2Factory deployed at:", address(factory));
|
||||
|
||||
// Compute predicted address
|
||||
address predictedAddress = factory.computeAddress(wethBytecode, salt);
|
||||
console.log("Predicted WETH9 address:", predictedAddress);
|
||||
|
||||
// Deploy using CREATE2
|
||||
address wethAddress = factory.deploy(wethBytecode, salt);
|
||||
console.log("WETH9 deployed at:", wethAddress);
|
||||
|
||||
require(wethAddress == predictedAddress, "Address mismatch");
|
||||
|
||||
// Verify it's the correct contract
|
||||
WETH weth = WETH(payable(wethAddress));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Summary ===");
|
||||
console.log("WETH9 Address:", wethAddress);
|
||||
console.log("CREATE2Factory:", address(factory));
|
||||
console.log("Salt:", vm.toString(salt));
|
||||
console.log("\nNote: This address is different from Ethereum Mainnet");
|
||||
console.log(" Ethereum Mainnet WETH9:", MAINNET_WETH9);
|
||||
console.log(" (WETH9 on Mainnet was deployed with CREATE, not CREATE2)");
|
||||
}
|
||||
}
|
||||
|
||||
165
script/DeployWETHWithCREATEDirect.s.sol
Normal file
165
script/DeployWETHWithCREATEDirect.s.sol
Normal file
@@ -0,0 +1,165 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import {Script, console} from "forge-std/Script.sol";
|
||||
import {WETH} from "../contracts/tokens/WETH.sol";
|
||||
import {WETH10} from "../contracts/tokens/WETH10.sol";
|
||||
|
||||
/**
|
||||
* @title DeployWETHWithCREATEDirect
|
||||
* @notice Deploy WETH9 and WETH10 using CREATE to match genesis.json addresses
|
||||
* @dev Uses calculated nonce values to deploy to exact addresses
|
||||
*
|
||||
* Since the target addresses are in genesis.json, they should be
|
||||
* deployable using CREATE with the correct deployer and nonce.
|
||||
*/
|
||||
contract DeployWETHWithCREATEDirect is Script {
|
||||
// Target addresses from genesis.json
|
||||
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
address constant TARGET_WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
|
||||
|
||||
// Deployer addresses to try (from genesis.json with high balances)
|
||||
address constant DEPLOYER_1 = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb;
|
||||
address constant DEPLOYER_2 = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882;
|
||||
address constant DEPLOYER_3 = 0x4A666F96fC8764181194447A7dFdb7d471b301C8;
|
||||
|
||||
function run() external {
|
||||
console.log("Deploying WETH9 and WETH10 using CREATE to match genesis addresses");
|
||||
console.log("WETH9 target:", vm.toString(TARGET_WETH9));
|
||||
console.log("WETH10 target:", vm.toString(TARGET_WETH10));
|
||||
|
||||
vm.startBroadcast();
|
||||
|
||||
// Deploy WETH9
|
||||
deployWETH9();
|
||||
|
||||
// Deploy WETH10
|
||||
deployWETH10();
|
||||
|
||||
vm.stopBroadcast();
|
||||
|
||||
console.log("\n=== Deployment Complete ===");
|
||||
}
|
||||
|
||||
function deployWETH9() internal {
|
||||
// Try deploying from different deployers
|
||||
address[] memory deployers = new address[](3);
|
||||
deployers[0] = DEPLOYER_1;
|
||||
deployers[1] = DEPLOYER_2;
|
||||
deployers[2] = DEPLOYER_3;
|
||||
|
||||
for (uint256 i = 0; i < deployers.length; i++) {
|
||||
address deployer = deployers[i];
|
||||
uint256 nonce = vm.getNonce(deployer);
|
||||
|
||||
console.log("\nTrying deployer:", vm.toString(deployer));
|
||||
console.log("Current nonce:", nonce);
|
||||
|
||||
// Calculate what address this nonce would produce
|
||||
// For now, just try deploying and see what address we get
|
||||
// In production, we'd calculate the nonce first
|
||||
|
||||
// Use prank to deploy from this address
|
||||
vm.startBroadcast(deployer);
|
||||
|
||||
// Check if contract already exists
|
||||
uint256 codeSize;
|
||||
assembly {
|
||||
codeSize := extcodesize(TARGET_WETH9)
|
||||
}
|
||||
|
||||
if (codeSize > 0) {
|
||||
console.log("WETH9 already exists at target address");
|
||||
verifyWETH9();
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
}
|
||||
|
||||
// Deploy WETH9
|
||||
WETH weth = new WETH();
|
||||
address deployedAddress = address(weth);
|
||||
|
||||
console.log("Deployed at:", vm.toString(deployedAddress));
|
||||
console.log("Target:", vm.toString(TARGET_WETH9));
|
||||
|
||||
if (deployedAddress == TARGET_WETH9) {
|
||||
console.log("Successfully deployed WETH9 to target address!");
|
||||
verifyWETH9();
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
} else {
|
||||
console.log("Address mismatch - trying next deployer...");
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Could not deploy to target address with any deployer");
|
||||
console.log("You may need to calculate the exact nonce first");
|
||||
}
|
||||
|
||||
function deployWETH10() internal {
|
||||
// Try deploying from different deployers
|
||||
address[] memory deployers = new address[](3);
|
||||
deployers[0] = DEPLOYER_1;
|
||||
deployers[1] = DEPLOYER_2;
|
||||
deployers[2] = DEPLOYER_3;
|
||||
|
||||
for (uint256 i = 0; i < deployers.length; i++) {
|
||||
address deployer = deployers[i];
|
||||
uint256 nonce = vm.getNonce(deployer);
|
||||
|
||||
console.log("\nTrying deployer:", vm.toString(deployer));
|
||||
console.log("Current nonce:", nonce);
|
||||
|
||||
vm.startBroadcast(deployer);
|
||||
|
||||
// Check if contract already exists
|
||||
uint256 codeSize;
|
||||
assembly {
|
||||
codeSize := extcodesize(TARGET_WETH10)
|
||||
}
|
||||
|
||||
if (codeSize > 0) {
|
||||
console.log("WETH10 already exists at target address");
|
||||
verifyWETH10();
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
}
|
||||
|
||||
// Deploy WETH10
|
||||
WETH10 weth10 = new WETH10();
|
||||
address deployedAddress = address(weth10);
|
||||
|
||||
console.log("Deployed at:", vm.toString(deployedAddress));
|
||||
console.log("Target:", vm.toString(TARGET_WETH10));
|
||||
|
||||
if (deployedAddress == TARGET_WETH10) {
|
||||
console.log("Successfully deployed WETH10 to target address!");
|
||||
verifyWETH10();
|
||||
vm.stopBroadcast();
|
||||
return;
|
||||
} else {
|
||||
console.log("Address mismatch - trying next deployer...");
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Could not deploy to target address with any deployer");
|
||||
console.log("You may need to calculate the exact nonce first");
|
||||
}
|
||||
|
||||
function verifyWETH9() internal view {
|
||||
WETH weth = WETH(payable(TARGET_WETH9));
|
||||
console.log("WETH9 name:", weth.name());
|
||||
console.log("WETH9 symbol:", weth.symbol());
|
||||
console.log("WETH9 decimals:", weth.decimals());
|
||||
}
|
||||
|
||||
function verifyWETH10() internal view {
|
||||
WETH10 weth10 = WETH10(payable(TARGET_WETH10));
|
||||
console.log("WETH10 name:", weth10.name());
|
||||
console.log("WETH10 symbol:", weth10.symbol());
|
||||
console.log("WETH10 decimals:", weth10.decimals());
|
||||
}
|
||||
}
|
||||
|
||||
74
script/emoney/Configure.s.sol
Normal file
74
script/emoney/Configure.s.sol
Normal file
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "@emoney/TokenFactory138.sol";
|
||||
import "@emoney/ComplianceRegistry.sol";
|
||||
import "@emoney/PolicyManager.sol";
|
||||
import "@emoney-scripts/helpers/Config.sol";
|
||||
import "@emoney-scripts/helpers/EnvValidation.sol";
|
||||
|
||||
contract ConfigureScript is Script {
|
||||
function run() external {
|
||||
// Validate environment variables
|
||||
address complianceRegistryAddr = vm.envAddress("COMPLIANCE_REGISTRY");
|
||||
EnvValidation.validateAddress(complianceRegistryAddr, "COMPLIANCE_REGISTRY");
|
||||
|
||||
address policyManagerAddr = vm.envOr("POLICY_MANAGER", address(0)); // Optional
|
||||
address tokenFactoryAddr = vm.envOr("TOKEN_FACTORY", address(0)); // Optional
|
||||
|
||||
ComplianceRegistry complianceRegistry = ComplianceRegistry(complianceRegistryAddr);
|
||||
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
|
||||
console.log("=== Configuration Script ===");
|
||||
console.log("ComplianceRegistry:", vm.toString(complianceRegistryAddr));
|
||||
console.log("");
|
||||
|
||||
// Check if deployer has COMPLIANCE_ROLE, if not, grant it
|
||||
bytes32 complianceRole = complianceRegistry.COMPLIANCE_ROLE();
|
||||
if (!complianceRegistry.hasRole(complianceRole, deployer)) {
|
||||
console.log("Granting COMPLIANCE_ROLE to deployer...");
|
||||
// Note: This requires deployer to have DEFAULT_ADMIN_ROLE
|
||||
// In production, use a multisig with DEFAULT_ADMIN_ROLE
|
||||
complianceRegistry.grantRole(complianceRole, deployer);
|
||||
console.log(" [OK] COMPLIANCE_ROLE granted");
|
||||
}
|
||||
|
||||
// Example: Set up some compliant accounts
|
||||
// In production, load these from a config file or environment variables
|
||||
address exampleUser1 = vm.envOr("EXAMPLE_USER_1", address(0));
|
||||
address exampleUser2 = vm.envOr("EXAMPLE_USER_2", address(0));
|
||||
|
||||
if (exampleUser1 != address(0)) {
|
||||
EnvValidation.validateAddress(exampleUser1, "EXAMPLE_USER_1");
|
||||
console.log("Setting compliance for exampleUser1:", vm.toString(exampleUser1));
|
||||
complianceRegistry.setCompliance(exampleUser1, true, 1, bytes32(0));
|
||||
console.log(" [OK] Compliance set");
|
||||
}
|
||||
|
||||
if (exampleUser2 != address(0)) {
|
||||
EnvValidation.validateAddress(exampleUser2, "EXAMPLE_USER_2");
|
||||
console.log("Setting compliance for exampleUser2:", vm.toString(exampleUser2));
|
||||
complianceRegistry.setCompliance(exampleUser2, true, 1, bytes32(0));
|
||||
console.log(" [OK] Compliance set");
|
||||
}
|
||||
|
||||
// Configure PolicyManager if provided
|
||||
if (policyManagerAddr != address(0)) {
|
||||
EnvValidation.validateAddress(policyManagerAddr, "POLICY_MANAGER");
|
||||
console.log("");
|
||||
console.log("PolicyManager:", vm.toString(policyManagerAddr));
|
||||
// Add policy configurations here if needed
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Configuration Complete ===");
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
147
script/emoney/Deploy.s.sol
Normal file
147
script/emoney/Deploy.s.sol
Normal file
@@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "@emoney/ComplianceRegistry.sol";
|
||||
import "@emoney/DebtRegistry.sol";
|
||||
import "@emoney/PolicyManager.sol";
|
||||
import "@emoney/eMoneyToken.sol";
|
||||
import "@emoney/TokenFactory138.sol";
|
||||
import "@emoney/BridgeVault138.sol";
|
||||
import "@emoney-scripts/helpers/Config.sol";
|
||||
import "@emoney-scripts/helpers/Roles.sol";
|
||||
import "@emoney-scripts/helpers/EnvValidation.sol";
|
||||
|
||||
contract DeployScript is Script {
|
||||
using Config for Config.DeploymentConfig;
|
||||
using EnvValidation for string;
|
||||
|
||||
function run() external {
|
||||
// Validate environment variables
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
console.log("Deployer address:", deployer);
|
||||
console.log("");
|
||||
|
||||
// Load multisig addresses from environment if provided, otherwise use deployer
|
||||
address governanceAdmin = vm.envOr("GOVERNANCE_MULTISIG", deployer);
|
||||
address tokenDeployer = vm.envOr("TOKEN_DEPLOYER_MULTISIG", deployer);
|
||||
address policyOperator = vm.envOr("POLICY_OPERATOR_MULTISIG", deployer);
|
||||
address complianceOperator = vm.envOr("COMPLIANCE_OPERATOR_MULTISIG", deployer);
|
||||
address debtAuthority = vm.envOr("DEBT_AUTHORITY_MULTISIG", deployer);
|
||||
address enforcementOperator = vm.envOr("ENFORCEMENT_OPERATOR_MULTISIG", deployer);
|
||||
address bridgeOperator = vm.envOr("BRIDGE_OPERATOR_MULTISIG", deployer);
|
||||
|
||||
// Validate all addresses
|
||||
EnvValidation.validateAddress(governanceAdmin, "governanceAdmin");
|
||||
EnvValidation.validateAddress(tokenDeployer, "tokenDeployer");
|
||||
EnvValidation.validateAddress(policyOperator, "policyOperator");
|
||||
EnvValidation.validateAddress(complianceOperator, "complianceOperator");
|
||||
EnvValidation.validateAddress(debtAuthority, "debtAuthority");
|
||||
EnvValidation.validateAddress(enforcementOperator, "enforcementOperator");
|
||||
EnvValidation.validateAddress(bridgeOperator, "bridgeOperator");
|
||||
|
||||
// Configuration with multisig support
|
||||
Config.DeploymentConfig memory config = Config.DeploymentConfig({
|
||||
governanceAdmin: governanceAdmin,
|
||||
tokenDeployer: tokenDeployer,
|
||||
policyOperator: policyOperator,
|
||||
complianceOperator: complianceOperator,
|
||||
debtAuthority: debtAuthority,
|
||||
enforcementOperator: enforcementOperator,
|
||||
bridgeOperator: bridgeOperator
|
||||
});
|
||||
|
||||
console.log("Configuration:");
|
||||
console.log(" Governance Admin:", config.governanceAdmin);
|
||||
console.log(" Token Deployer:", config.tokenDeployer);
|
||||
console.log(" Policy Operator:", config.policyOperator);
|
||||
console.log(" Compliance Operator:", config.complianceOperator);
|
||||
console.log(" Debt Authority:", config.debtAuthority);
|
||||
console.log(" Enforcement Operator:", config.enforcementOperator);
|
||||
console.log(" Bridge Operator:", config.bridgeOperator);
|
||||
console.log("");
|
||||
|
||||
console.log("Deploying ComplianceRegistry...");
|
||||
ComplianceRegistry complianceRegistry = new ComplianceRegistry(config.governanceAdmin);
|
||||
console.log("ComplianceRegistry deployed at:", address(complianceRegistry));
|
||||
|
||||
console.log("Deploying DebtRegistry...");
|
||||
DebtRegistry debtRegistry = new DebtRegistry(config.governanceAdmin);
|
||||
console.log("DebtRegistry deployed at:", address(debtRegistry));
|
||||
|
||||
console.log("Deploying PolicyManager...");
|
||||
PolicyManager policyManager = new PolicyManager(
|
||||
config.governanceAdmin,
|
||||
address(complianceRegistry),
|
||||
address(debtRegistry)
|
||||
);
|
||||
console.log("PolicyManager deployed at:", address(policyManager));
|
||||
|
||||
console.log("Deploying eMoneyToken implementation...");
|
||||
eMoneyToken tokenImplementation = new eMoneyToken();
|
||||
console.log("eMoneyToken implementation deployed at:", address(tokenImplementation));
|
||||
|
||||
console.log("Deploying TokenFactory138...");
|
||||
TokenFactory138 factory = new TokenFactory138(
|
||||
config.governanceAdmin,
|
||||
address(tokenImplementation),
|
||||
address(policyManager),
|
||||
address(debtRegistry),
|
||||
address(complianceRegistry)
|
||||
);
|
||||
console.log("TokenFactory138 deployed at:", address(factory));
|
||||
|
||||
console.log("Deploying BridgeVault138...");
|
||||
BridgeVault138 bridgeVault = new BridgeVault138(
|
||||
config.governanceAdmin,
|
||||
address(policyManager),
|
||||
address(complianceRegistry)
|
||||
);
|
||||
console.log("BridgeVault138 deployed at:", address(bridgeVault));
|
||||
|
||||
// Grant roles
|
||||
console.log("Granting roles...");
|
||||
|
||||
vm.stopBroadcast();
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
factory.grantRole(factory.TOKEN_DEPLOYER_ROLE(), config.tokenDeployer);
|
||||
policyManager.grantRole(policyManager.POLICY_OPERATOR_ROLE(), config.policyOperator);
|
||||
complianceRegistry.grantRole(complianceRegistry.COMPLIANCE_ROLE(), config.complianceOperator);
|
||||
debtRegistry.grantRole(debtRegistry.DEBT_AUTHORITY_ROLE(), config.debtAuthority);
|
||||
bridgeVault.grantRole(bridgeVault.BRIDGE_OPERATOR_ROLE(), config.bridgeOperator);
|
||||
|
||||
console.log("Deployment complete!");
|
||||
console.log("");
|
||||
console.log("=== Deployment Summary ===");
|
||||
console.log("ComplianceRegistry:", address(complianceRegistry));
|
||||
console.log("DebtRegistry:", address(debtRegistry));
|
||||
console.log("PolicyManager:", address(policyManager));
|
||||
console.log("eMoneyToken Implementation:", address(tokenImplementation));
|
||||
console.log("TokenFactory138:", address(factory));
|
||||
console.log("BridgeVault138:", address(bridgeVault));
|
||||
console.log("");
|
||||
|
||||
// Export addresses for verification script
|
||||
console.log("=== Export these addresses to .env ===");
|
||||
console.log("export COMPLIANCE_REGISTRY=", vm.toString(address(complianceRegistry)));
|
||||
console.log("export DEBT_REGISTRY=", vm.toString(address(debtRegistry)));
|
||||
console.log("export POLICY_MANAGER=", vm.toString(address(policyManager)));
|
||||
console.log("export TOKEN_IMPLEMENTATION=", vm.toString(address(tokenImplementation)));
|
||||
console.log("export TOKEN_FACTORY=", vm.toString(address(factory)));
|
||||
console.log("export BRIDGE_VAULT=", vm.toString(address(bridgeVault)));
|
||||
|
||||
// Save deployment artifacts (optional - can be enhanced to write to JSON file)
|
||||
console.log("");
|
||||
console.log("=== Next Steps ===");
|
||||
console.log("1. Export the addresses above to your .env file");
|
||||
console.log("2. Run Configure.s.sol to set up initial compliance statuses");
|
||||
console.log("3. Run VerifyDeployment.s.sol to verify the deployment");
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
158
script/emoney/DeployChain138.s.sol
Normal file
158
script/emoney/DeployChain138.s.sol
Normal file
@@ -0,0 +1,158 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "@emoney/ComplianceRegistry.sol";
|
||||
import "@emoney/DebtRegistry.sol";
|
||||
import "@emoney/PolicyManager.sol";
|
||||
import "@emoney/eMoneyToken.sol";
|
||||
import "@emoney/TokenFactory138.sol";
|
||||
import "@emoney/BridgeVault138.sol";
|
||||
import "@emoney-scripts/helpers/Config.sol";
|
||||
import "@emoney-scripts/helpers/Roles.sol";
|
||||
import "@emoney-scripts/helpers/EnvValidation.sol";
|
||||
|
||||
/**
|
||||
* @title DeployChain138
|
||||
* @notice Deployment script specifically configured for ChainID 138 (DeFi Oracle Meta Mainnet)
|
||||
*/
|
||||
contract DeployChain138 is Script {
|
||||
using Config for Config.DeploymentConfig;
|
||||
using EnvValidation for string;
|
||||
|
||||
function run() external {
|
||||
// ChainID 138 specific configuration
|
||||
uint256 chainId = block.chainid;
|
||||
require(chainId == 138, "This script is for ChainID 138 only");
|
||||
|
||||
// Validate environment variables
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
console.log("=== ChainID 138 Deployment ===");
|
||||
console.log("Deployer address:", deployer);
|
||||
console.log("Chain ID:", chainId);
|
||||
console.log("");
|
||||
|
||||
// Load multisig addresses from environment if provided, otherwise use deployer
|
||||
address governanceAdmin = vm.envOr("GOVERNANCE_MULTISIG", deployer);
|
||||
address tokenDeployer = vm.envOr("TOKEN_DEPLOYER_MULTISIG", deployer);
|
||||
address policyOperator = vm.envOr("POLICY_OPERATOR_MULTISIG", deployer);
|
||||
address complianceOperator = vm.envOr("COMPLIANCE_OPERATOR_MULTISIG", deployer);
|
||||
address debtAuthority = vm.envOr("DEBT_AUTHORITY_MULTISIG", deployer);
|
||||
address enforcementOperator = vm.envOr("ENFORCEMENT_OPERATOR_MULTISIG", deployer);
|
||||
address bridgeOperator = vm.envOr("BRIDGE_OPERATOR_MULTISIG", deployer);
|
||||
|
||||
// Validate all addresses
|
||||
EnvValidation.validateAddress(governanceAdmin, "governanceAdmin");
|
||||
EnvValidation.validateAddress(tokenDeployer, "tokenDeployer");
|
||||
EnvValidation.validateAddress(policyOperator, "policyOperator");
|
||||
EnvValidation.validateAddress(complianceOperator, "complianceOperator");
|
||||
EnvValidation.validateAddress(debtAuthority, "debtAuthority");
|
||||
EnvValidation.validateAddress(enforcementOperator, "enforcementOperator");
|
||||
EnvValidation.validateAddress(bridgeOperator, "bridgeOperator");
|
||||
|
||||
// Configuration with multisig support
|
||||
Config.DeploymentConfig memory config = Config.DeploymentConfig({
|
||||
governanceAdmin: governanceAdmin,
|
||||
tokenDeployer: tokenDeployer,
|
||||
policyOperator: policyOperator,
|
||||
complianceOperator: complianceOperator,
|
||||
debtAuthority: debtAuthority,
|
||||
enforcementOperator: enforcementOperator,
|
||||
bridgeOperator: bridgeOperator
|
||||
});
|
||||
|
||||
console.log("Configuration:");
|
||||
console.log(" Governance Admin:", config.governanceAdmin);
|
||||
console.log(" Token Deployer:", config.tokenDeployer);
|
||||
console.log(" Policy Operator:", config.policyOperator);
|
||||
console.log(" Compliance Operator:", config.complianceOperator);
|
||||
console.log(" Debt Authority:", config.debtAuthority);
|
||||
console.log(" Enforcement Operator:", config.enforcementOperator);
|
||||
console.log(" Bridge Operator:", config.bridgeOperator);
|
||||
console.log("");
|
||||
|
||||
console.log("Deploying ComplianceRegistry...");
|
||||
ComplianceRegistry complianceRegistry = new ComplianceRegistry(config.governanceAdmin);
|
||||
console.log("ComplianceRegistry deployed at:", address(complianceRegistry));
|
||||
|
||||
console.log("Deploying DebtRegistry...");
|
||||
DebtRegistry debtRegistry = new DebtRegistry(config.governanceAdmin);
|
||||
console.log("DebtRegistry deployed at:", address(debtRegistry));
|
||||
|
||||
console.log("Deploying PolicyManager...");
|
||||
PolicyManager policyManager = new PolicyManager(
|
||||
config.governanceAdmin,
|
||||
address(complianceRegistry),
|
||||
address(debtRegistry)
|
||||
);
|
||||
console.log("PolicyManager deployed at:", address(policyManager));
|
||||
|
||||
console.log("Deploying eMoneyToken implementation...");
|
||||
eMoneyToken tokenImplementation = new eMoneyToken();
|
||||
console.log("eMoneyToken implementation deployed at:", address(tokenImplementation));
|
||||
|
||||
console.log("Deploying TokenFactory138...");
|
||||
TokenFactory138 factory = new TokenFactory138(
|
||||
config.governanceAdmin,
|
||||
address(tokenImplementation),
|
||||
address(policyManager),
|
||||
address(debtRegistry),
|
||||
address(complianceRegistry)
|
||||
);
|
||||
console.log("TokenFactory138 deployed at:", address(factory));
|
||||
|
||||
console.log("Deploying BridgeVault138...");
|
||||
BridgeVault138 bridgeVault = new BridgeVault138(
|
||||
config.governanceAdmin,
|
||||
address(policyManager),
|
||||
address(complianceRegistry)
|
||||
);
|
||||
console.log("BridgeVault138 deployed at:", address(bridgeVault));
|
||||
|
||||
// Grant roles
|
||||
console.log("Granting roles...");
|
||||
|
||||
vm.stopBroadcast();
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
factory.grantRole(factory.TOKEN_DEPLOYER_ROLE(), config.tokenDeployer);
|
||||
policyManager.grantRole(policyManager.POLICY_OPERATOR_ROLE(), config.policyOperator);
|
||||
complianceRegistry.grantRole(complianceRegistry.COMPLIANCE_ROLE(), config.complianceOperator);
|
||||
debtRegistry.grantRole(debtRegistry.DEBT_AUTHORITY_ROLE(), config.debtAuthority);
|
||||
bridgeVault.grantRole(bridgeVault.BRIDGE_OPERATOR_ROLE(), config.bridgeOperator);
|
||||
|
||||
console.log("Deployment complete!");
|
||||
console.log("");
|
||||
console.log("=== Deployment Summary (ChainID 138) ===");
|
||||
console.log("ComplianceRegistry:", address(complianceRegistry));
|
||||
console.log("DebtRegistry:", address(debtRegistry));
|
||||
console.log("PolicyManager:", address(policyManager));
|
||||
console.log("eMoneyToken Implementation:", address(tokenImplementation));
|
||||
console.log("TokenFactory138:", address(factory));
|
||||
console.log("BridgeVault138:", address(bridgeVault));
|
||||
console.log("");
|
||||
|
||||
// Export addresses for verification script
|
||||
console.log("=== Export these addresses to .env ===");
|
||||
console.log("export COMPLIANCE_REGISTRY=", vm.toString(address(complianceRegistry)));
|
||||
console.log("export DEBT_REGISTRY=", vm.toString(address(debtRegistry)));
|
||||
console.log("export POLICY_MANAGER=", vm.toString(address(policyManager)));
|
||||
console.log("export TOKEN_IMPLEMENTATION=", vm.toString(address(tokenImplementation)));
|
||||
console.log("export TOKEN_FACTORY=", vm.toString(address(factory)));
|
||||
console.log("export BRIDGE_VAULT=", vm.toString(address(bridgeVault)));
|
||||
|
||||
// Save deployment artifacts
|
||||
console.log("");
|
||||
console.log("=== Next Steps ===");
|
||||
console.log("1. Export the addresses above to your .env file");
|
||||
console.log("2. Run Configure.s.sol to set up initial compliance statuses");
|
||||
console.log("3. Run VerifyDeployment.s.sol to verify the deployment");
|
||||
console.log("4. Verify contracts on explorer: https://explorer.d-bis.org");
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
186
script/emoney/VerifyDeployment.s.sol
Normal file
186
script/emoney/VerifyDeployment.s.sol
Normal file
@@ -0,0 +1,186 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "@emoney/ComplianceRegistry.sol";
|
||||
import "@emoney/DebtRegistry.sol";
|
||||
import "@emoney/PolicyManager.sol";
|
||||
import "@emoney/eMoneyToken.sol";
|
||||
import "@emoney/TokenFactory138.sol";
|
||||
import "@emoney/BridgeVault138.sol";
|
||||
import "../script/helpers/Roles.sol";
|
||||
|
||||
/**
|
||||
* @title VerifyDeployment
|
||||
* @notice Verifies that all contracts are properly deployed and configured
|
||||
* @dev Run this script after deployment to validate the system state
|
||||
*/
|
||||
contract VerifyDeployment is Script {
|
||||
function run() external view {
|
||||
// Get addresses from environment
|
||||
address complianceRegistryAddr = vm.envAddress("COMPLIANCE_REGISTRY");
|
||||
address debtRegistryAddr = vm.envAddress("DEBT_REGISTRY");
|
||||
address policyManagerAddr = vm.envAddress("POLICY_MANAGER");
|
||||
address tokenFactoryAddr = vm.envAddress("TOKEN_FACTORY");
|
||||
address bridgeVaultAddr = vm.envAddress("BRIDGE_VAULT");
|
||||
|
||||
console.log("=== Deployment Verification ===");
|
||||
console.log("");
|
||||
|
||||
// Verify ComplianceRegistry
|
||||
console.log("Verifying ComplianceRegistry...");
|
||||
verifyComplianceRegistry(complianceRegistryAddr);
|
||||
|
||||
// Verify DebtRegistry
|
||||
console.log("Verifying DebtRegistry...");
|
||||
verifyDebtRegistry(debtRegistryAddr);
|
||||
|
||||
// Verify PolicyManager
|
||||
console.log("Verifying PolicyManager...");
|
||||
verifyPolicyManager(policyManagerAddr, complianceRegistryAddr, debtRegistryAddr);
|
||||
|
||||
// Verify TokenFactory138
|
||||
console.log("Verifying TokenFactory138...");
|
||||
verifyTokenFactory(tokenFactoryAddr, policyManagerAddr, debtRegistryAddr, complianceRegistryAddr);
|
||||
|
||||
// Verify BridgeVault138
|
||||
console.log("Verifying BridgeVault138...");
|
||||
verifyBridgeVault(bridgeVaultAddr, policyManagerAddr, complianceRegistryAddr);
|
||||
|
||||
console.log("");
|
||||
console.log("=== Verification Complete ===");
|
||||
console.log("All contracts verified successfully!");
|
||||
}
|
||||
|
||||
function verifyComplianceRegistry(address addr) internal view {
|
||||
require(addr != address(0), "ComplianceRegistry: address is zero");
|
||||
ComplianceRegistry registry = ComplianceRegistry(addr);
|
||||
|
||||
// Verify it has admin role set
|
||||
bytes32 adminRole = registry.DEFAULT_ADMIN_ROLE();
|
||||
require(registry.hasRole(adminRole, address(this)) || address(this).code.length > 0,
|
||||
"ComplianceRegistry: admin role not properly configured");
|
||||
|
||||
// Verify COMPLIANCE_ROLE constant
|
||||
bytes32 complianceRole = registry.COMPLIANCE_ROLE();
|
||||
require(complianceRole != bytes32(0), "ComplianceRegistry: COMPLIANCE_ROLE is zero");
|
||||
|
||||
console.log(" [OK] ComplianceRegistry at:", addr);
|
||||
console.log(" [OK] COMPLIANCE_ROLE:", vm.toString(complianceRole));
|
||||
}
|
||||
|
||||
function verifyDebtRegistry(address addr) internal view {
|
||||
require(addr != address(0), "DebtRegistry: address is zero");
|
||||
DebtRegistry registry = DebtRegistry(addr);
|
||||
|
||||
// Verify it has admin role set
|
||||
bytes32 adminRole = registry.DEFAULT_ADMIN_ROLE();
|
||||
require(registry.hasRole(adminRole, address(this)) || address(this).code.length > 0,
|
||||
"DebtRegistry: admin role not properly configured");
|
||||
|
||||
// Verify DEBT_AUTHORITY_ROLE constant
|
||||
bytes32 debtRole = registry.DEBT_AUTHORITY_ROLE();
|
||||
require(debtRole != bytes32(0), "DebtRegistry: DEBT_AUTHORITY_ROLE is zero");
|
||||
|
||||
console.log(" [OK] DebtRegistry at:", addr);
|
||||
console.log(" [OK] DEBT_AUTHORITY_ROLE:", vm.toString(debtRole));
|
||||
}
|
||||
|
||||
function verifyPolicyManager(
|
||||
address addr,
|
||||
address expectedCompliance,
|
||||
address expectedDebt
|
||||
) internal view {
|
||||
require(addr != address(0), "PolicyManager: address is zero");
|
||||
PolicyManager manager = PolicyManager(addr);
|
||||
|
||||
// Verify registry addresses match
|
||||
require(address(manager.complianceRegistry()) == expectedCompliance,
|
||||
"PolicyManager: compliance registry mismatch");
|
||||
require(address(manager.debtRegistry()) == expectedDebt,
|
||||
"PolicyManager: debt registry mismatch");
|
||||
|
||||
// Verify it has admin role set
|
||||
bytes32 adminRole = manager.DEFAULT_ADMIN_ROLE();
|
||||
require(manager.hasRole(adminRole, address(this)) || address(this).code.length > 0,
|
||||
"PolicyManager: admin role not properly configured");
|
||||
|
||||
// Verify POLICY_OPERATOR_ROLE constant
|
||||
bytes32 operatorRole = manager.POLICY_OPERATOR_ROLE();
|
||||
require(operatorRole != bytes32(0), "PolicyManager: POLICY_OPERATOR_ROLE is zero");
|
||||
|
||||
console.log(" [OK] PolicyManager at:", addr);
|
||||
console.log(" [OK] ComplianceRegistry:", vm.toString(expectedCompliance));
|
||||
console.log(" [OK] DebtRegistry:", vm.toString(expectedDebt));
|
||||
console.log(" [OK] POLICY_OPERATOR_ROLE:", vm.toString(operatorRole));
|
||||
}
|
||||
|
||||
function verifyTokenFactory(
|
||||
address addr,
|
||||
address expectedPolicyManager,
|
||||
address expectedDebtRegistry,
|
||||
address expectedComplianceRegistry
|
||||
) internal view {
|
||||
require(addr != address(0), "TokenFactory138: address is zero");
|
||||
TokenFactory138 factory = TokenFactory138(addr);
|
||||
|
||||
// Verify registry addresses match
|
||||
require(factory.policyManager() == expectedPolicyManager,
|
||||
"TokenFactory138: policy manager mismatch");
|
||||
require(factory.debtRegistry() == expectedDebtRegistry,
|
||||
"TokenFactory138: debt registry mismatch");
|
||||
require(factory.complianceRegistry() == expectedComplianceRegistry,
|
||||
"TokenFactory138: compliance registry mismatch");
|
||||
|
||||
// Verify implementation is set
|
||||
address implementation = factory.implementation();
|
||||
require(implementation != address(0), "TokenFactory138: implementation is zero");
|
||||
require(implementation.code.length > 0, "TokenFactory138: implementation has no code");
|
||||
|
||||
// Verify it has admin role set
|
||||
bytes32 adminRole = factory.DEFAULT_ADMIN_ROLE();
|
||||
require(factory.hasRole(adminRole, address(this)) || address(this).code.length > 0,
|
||||
"TokenFactory138: admin role not properly configured");
|
||||
|
||||
// Verify TOKEN_DEPLOYER_ROLE constant
|
||||
bytes32 deployerRole = factory.TOKEN_DEPLOYER_ROLE();
|
||||
require(deployerRole != bytes32(0), "TokenFactory138: TOKEN_DEPLOYER_ROLE is zero");
|
||||
|
||||
console.log(" [OK] TokenFactory138 at:", addr);
|
||||
console.log(" [OK] Implementation:", vm.toString(implementation));
|
||||
console.log(" [OK] PolicyManager:", vm.toString(expectedPolicyManager));
|
||||
console.log(" [OK] DebtRegistry:", vm.toString(expectedDebtRegistry));
|
||||
console.log(" [OK] ComplianceRegistry:", vm.toString(expectedComplianceRegistry));
|
||||
console.log(" [OK] TOKEN_DEPLOYER_ROLE:", vm.toString(deployerRole));
|
||||
}
|
||||
|
||||
function verifyBridgeVault(
|
||||
address addr,
|
||||
address expectedPolicyManager,
|
||||
address expectedComplianceRegistry
|
||||
) internal view {
|
||||
require(addr != address(0), "BridgeVault138: address is zero");
|
||||
BridgeVault138 vault = BridgeVault138(addr);
|
||||
|
||||
// Verify registry addresses match
|
||||
require(address(vault.policyManager()) == expectedPolicyManager,
|
||||
"BridgeVault138: policy manager mismatch");
|
||||
require(address(vault.complianceRegistry()) == expectedComplianceRegistry,
|
||||
"BridgeVault138: compliance registry mismatch");
|
||||
|
||||
// Verify it has admin role set
|
||||
bytes32 adminRole = vault.DEFAULT_ADMIN_ROLE();
|
||||
require(vault.hasRole(adminRole, address(this)) || address(this).code.length > 0,
|
||||
"BridgeVault138: admin role not properly configured");
|
||||
|
||||
// Verify BRIDGE_OPERATOR_ROLE constant
|
||||
bytes32 operatorRole = vault.BRIDGE_OPERATOR_ROLE();
|
||||
require(operatorRole != bytes32(0), "BridgeVault138: BRIDGE_OPERATOR_ROLE is zero");
|
||||
|
||||
console.log(" [OK] BridgeVault138 at:", addr);
|
||||
console.log(" [OK] PolicyManager:", vm.toString(expectedPolicyManager));
|
||||
console.log(" [OK] ComplianceRegistry:", vm.toString(expectedComplianceRegistry));
|
||||
console.log(" [OK] BRIDGE_OPERATOR_ROLE:", vm.toString(operatorRole));
|
||||
}
|
||||
}
|
||||
|
||||
25
script/emoney/helpers/Config.sol
Normal file
25
script/emoney/helpers/Config.sol
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
library Config {
|
||||
struct DeploymentConfig {
|
||||
address governanceAdmin;
|
||||
address tokenDeployer;
|
||||
address policyOperator;
|
||||
address complianceOperator;
|
||||
address debtAuthority;
|
||||
address enforcementOperator;
|
||||
address bridgeOperator;
|
||||
}
|
||||
|
||||
struct TokenDeploymentConfig {
|
||||
string name;
|
||||
string symbol;
|
||||
uint8 decimals;
|
||||
address issuer;
|
||||
uint8 defaultLienMode; // 1 = hard, 2 = encumbered
|
||||
bool bridgeOnly;
|
||||
address bridge;
|
||||
}
|
||||
}
|
||||
|
||||
104
script/emoney/helpers/EnvValidation.sol
Normal file
104
script/emoney/helpers/EnvValidation.sol
Normal file
@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
|
||||
/**
|
||||
* @title EnvValidation
|
||||
* @notice Library for validating environment variables in deployment scripts
|
||||
* @dev Provides helper functions to validate private keys, addresses, and RPC URLs
|
||||
*/
|
||||
library EnvValidation {
|
||||
error InvalidPrivateKey();
|
||||
error InvalidAddress(string name);
|
||||
error InvalidRPCURL();
|
||||
error MissingEnvironmentVariable(string name);
|
||||
|
||||
/**
|
||||
* @notice Validates that a private key is set and has correct format
|
||||
* @dev Checks that PRIVATE_KEY env var is set and is a valid hex string (64 chars without 0x)
|
||||
* @param key The private key string from environment
|
||||
*/
|
||||
function validatePrivateKey(string memory key) internal pure {
|
||||
bytes memory keyBytes = bytes(key);
|
||||
|
||||
// Check minimum length (64 hex chars = 32 bytes)
|
||||
if (keyBytes.length < 64) {
|
||||
revert InvalidPrivateKey();
|
||||
}
|
||||
|
||||
// Remove 0x prefix if present
|
||||
uint256 start = 0;
|
||||
if (keyBytes.length >= 2 && keyBytes[0] == '0' && (keyBytes[1] == 'x' || keyBytes[1] == 'X')) {
|
||||
start = 2;
|
||||
}
|
||||
|
||||
// Check remaining length (must be 64 hex chars = 32 bytes)
|
||||
if (keyBytes.length - start != 64) {
|
||||
revert InvalidPrivateKey();
|
||||
}
|
||||
|
||||
// Validate hex characters
|
||||
for (uint256 i = start; i < keyBytes.length; i++) {
|
||||
bytes1 char = keyBytes[i];
|
||||
if (!((char >= 0x30 && char <= 0x39) || // 0-9
|
||||
(char >= 0x41 && char <= 0x46) || // A-F
|
||||
(char >= 0x61 && char <= 0x66))) { // a-f
|
||||
revert InvalidPrivateKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Validates that an address is not zero
|
||||
* @param addr The address to validate
|
||||
* @param name Name of the variable for error messages
|
||||
*/
|
||||
function validateAddress(address addr, string memory name) internal pure {
|
||||
if (addr == address(0)) {
|
||||
revert InvalidAddress(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @notice Validates that an RPC URL is set and has correct format
|
||||
* @param url The RPC URL string
|
||||
*/
|
||||
function validateRPCURL(string memory url) internal pure {
|
||||
bytes memory urlBytes = bytes(url);
|
||||
|
||||
if (urlBytes.length == 0) {
|
||||
revert InvalidRPCURL();
|
||||
}
|
||||
|
||||
// Check for http:// or https:// prefix
|
||||
bool hasValidPrefix = false;
|
||||
if (urlBytes.length >= 7) {
|
||||
bytes memory prefix = new bytes(7);
|
||||
for (uint256 i = 0; i < 7; i++) {
|
||||
prefix[i] = urlBytes[i];
|
||||
}
|
||||
string memory prefixStr = string(prefix);
|
||||
if (keccak256(bytes(prefixStr)) == keccak256(bytes("http://"))) {
|
||||
hasValidPrefix = true;
|
||||
}
|
||||
}
|
||||
if (!hasValidPrefix && urlBytes.length >= 8) {
|
||||
bytes memory prefix = new bytes(8);
|
||||
for (uint256 i = 0; i < 8; i++) {
|
||||
prefix[i] = urlBytes[i];
|
||||
}
|
||||
string memory prefixStr = string(prefix);
|
||||
if (keccak256(bytes(prefixStr)) == keccak256(bytes("https://"))) {
|
||||
hasValidPrefix = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidPrefix) {
|
||||
revert InvalidRPCURL();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
14
script/emoney/helpers/Roles.sol
Normal file
14
script/emoney/helpers/Roles.sol
Normal file
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
library Roles {
|
||||
bytes32 public constant GOVERNANCE_ADMIN_ROLE = keccak256("GOVERNANCE_ADMIN_ROLE");
|
||||
bytes32 public constant TOKEN_DEPLOYER_ROLE = keccak256("TOKEN_DEPLOYER_ROLE");
|
||||
bytes32 public constant POLICY_OPERATOR_ROLE = keccak256("POLICY_OPERATOR_ROLE");
|
||||
bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");
|
||||
bytes32 public constant ENFORCEMENT_ROLE = keccak256("ENFORCEMENT_ROLE");
|
||||
bytes32 public constant COMPLIANCE_ROLE = keccak256("COMPLIANCE_ROLE");
|
||||
bytes32 public constant DEBT_AUTHORITY_ROLE = keccak256("DEBT_AUTHORITY_ROLE");
|
||||
bytes32 public constant BRIDGE_OPERATOR_ROLE = keccak256("BRIDGE_OPERATOR_ROLE");
|
||||
}
|
||||
|
||||
168
script/reserve/ConfigureInitialReserves.s.sol
Normal file
168
script/reserve/ConfigureInitialReserves.s.sol
Normal file
@@ -0,0 +1,168 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "../../contracts/reserve/ReserveSystem.sol";
|
||||
import "../../contracts/reserve/IReserveSystem.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
/**
|
||||
* @title ConfigureInitialReserves
|
||||
* @notice Script to configure initial reserve assets for Reserve System
|
||||
* @dev Sets up supported assets, liquidity flags, and initial deposits
|
||||
*/
|
||||
contract ConfigureInitialReserves is Script {
|
||||
function run() external {
|
||||
uint256 chainId = block.chainid;
|
||||
require(chainId == 138, "This script is for ChainID 138 only");
|
||||
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
console.log("=== Configure Initial Reserves (ChainID 138) ===");
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("");
|
||||
|
||||
// Load addresses from environment
|
||||
address reserveSystem = vm.envAddress("RESERVE_SYSTEM");
|
||||
address admin = vm.envOr("RESERVE_ADMIN", deployer);
|
||||
address reserveManager = vm.envOr("RESERVE_MANAGER", deployer);
|
||||
|
||||
ReserveSystem reserve = ReserveSystem(reserveSystem);
|
||||
|
||||
console.log("=== Adding Supported Assets ===");
|
||||
|
||||
// Asset 1: Gold (XAU) - Liquid asset
|
||||
address xauAsset = vm.envOr("XAU_ASSET", address(0));
|
||||
if (xauAsset != address(0)) {
|
||||
console.log("Adding XAU asset:", xauAsset);
|
||||
vm.prank(admin);
|
||||
reserve.addSupportedAsset(xauAsset, true); // Liquid
|
||||
console.log("XAU added as liquid asset");
|
||||
}
|
||||
|
||||
// Asset 2: USDC - Liquid asset
|
||||
address usdcAsset = vm.envOr("USDC_ASSET", address(0));
|
||||
if (usdcAsset != address(0)) {
|
||||
console.log("Adding USDC asset:", usdcAsset);
|
||||
vm.prank(admin);
|
||||
reserve.addSupportedAsset(usdcAsset, true); // Liquid
|
||||
console.log("USDC added as liquid asset");
|
||||
}
|
||||
|
||||
// Asset 3: ETH - Liquid asset
|
||||
address ethAsset = vm.envOr("ETH_ASSET", address(0));
|
||||
if (ethAsset != address(0)) {
|
||||
console.log("Adding ETH asset:", ethAsset);
|
||||
vm.prank(admin);
|
||||
reserve.addSupportedAsset(ethAsset, true); // Liquid
|
||||
console.log("ETH added as liquid asset");
|
||||
}
|
||||
|
||||
// Asset 4: WETH (if different from ETH)
|
||||
address wethAsset = vm.envOr("WETH_ASSET", address(0));
|
||||
if (wethAsset != address(0) && wethAsset != ethAsset) {
|
||||
console.log("Adding WETH asset:", wethAsset);
|
||||
vm.prank(admin);
|
||||
reserve.addSupportedAsset(wethAsset, true); // Liquid
|
||||
console.log("WETH added as liquid asset");
|
||||
}
|
||||
|
||||
// Asset 5: Sovereign Instruments (example - less liquid)
|
||||
address sovereignAsset = vm.envOr("SOVEREIGN_ASSET", address(0));
|
||||
if (sovereignAsset != address(0)) {
|
||||
console.log("Adding Sovereign Instrument asset:", sovereignAsset);
|
||||
vm.prank(admin);
|
||||
reserve.addSupportedAsset(sovereignAsset, false); // Less liquid
|
||||
console.log("Sovereign Instrument added as less liquid asset");
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Initial Reserve Deposits ===");
|
||||
console.log("Note: Ensure assets are approved and sufficient balance exists");
|
||||
|
||||
// Deposit XAU reserves (if configured)
|
||||
if (xauAsset != address(0)) {
|
||||
uint256 xauAmount = vm.envOr("XAU_INITIAL_DEPOSIT", uint256(0));
|
||||
if (xauAmount > 0) {
|
||||
console.log("Depositing XAU reserves:", xauAmount);
|
||||
IERC20(xauAsset).approve(reserveSystem, xauAmount);
|
||||
vm.prank(reserveManager);
|
||||
reserve.depositReserve(xauAsset, xauAmount);
|
||||
console.log("XAU deposit complete");
|
||||
}
|
||||
}
|
||||
|
||||
// Deposit USDC reserves (if configured)
|
||||
if (usdcAsset != address(0)) {
|
||||
uint256 usdcAmount = vm.envOr("USDC_INITIAL_DEPOSIT", uint256(0));
|
||||
if (usdcAmount > 0) {
|
||||
console.log("Depositing USDC reserves:", usdcAmount);
|
||||
IERC20(usdcAsset).approve(reserveSystem, usdcAmount);
|
||||
vm.prank(reserveManager);
|
||||
reserve.depositReserve(usdcAsset, usdcAmount);
|
||||
console.log("USDC deposit complete");
|
||||
}
|
||||
}
|
||||
|
||||
// Deposit ETH reserves (if configured)
|
||||
if (ethAsset != address(0)) {
|
||||
uint256 ethAmount = vm.envOr("ETH_INITIAL_DEPOSIT", uint256(0));
|
||||
if (ethAmount > 0) {
|
||||
console.log("Depositing ETH reserves:", ethAmount);
|
||||
IERC20(ethAsset).approve(reserveSystem, ethAmount);
|
||||
vm.prank(reserveManager);
|
||||
reserve.depositReserve(ethAsset, ethAmount);
|
||||
console.log("ETH deposit complete");
|
||||
}
|
||||
}
|
||||
|
||||
// Deposit WETH reserves (if configured)
|
||||
if (wethAsset != address(0)) {
|
||||
uint256 wethAmount = vm.envOr("WETH_INITIAL_DEPOSIT", uint256(0));
|
||||
if (wethAmount > 0) {
|
||||
console.log("Depositing WETH reserves:", wethAmount);
|
||||
IERC20(wethAsset).approve(reserveSystem, wethAmount);
|
||||
vm.prank(reserveManager);
|
||||
reserve.depositReserve(wethAsset, wethAmount);
|
||||
console.log("WETH deposit complete");
|
||||
}
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Reserve Balances ===");
|
||||
|
||||
if (xauAsset != address(0)) {
|
||||
uint256 xauBalance = reserve.getReserveBalance(xauAsset);
|
||||
console.log("XAU Reserve Balance:", xauBalance);
|
||||
}
|
||||
|
||||
if (usdcAsset != address(0)) {
|
||||
uint256 usdcBalance = reserve.getReserveBalance(usdcAsset);
|
||||
console.log("USDC Reserve Balance:", usdcBalance);
|
||||
}
|
||||
|
||||
if (ethAsset != address(0)) {
|
||||
uint256 ethBalance = reserve.getReserveBalance(ethAsset);
|
||||
console.log("ETH Reserve Balance:", ethBalance);
|
||||
}
|
||||
|
||||
if (wethAsset != address(0)) {
|
||||
uint256 wethBalance = reserve.getReserveBalance(wethAsset);
|
||||
console.log("WETH Reserve Balance:", wethBalance);
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Configuration Complete ===");
|
||||
console.log("");
|
||||
console.log("=== Supported Assets ===");
|
||||
address[] memory supportedAssets = reserve.getSupportedAssets();
|
||||
for (uint256 i = 0; i < supportedAssets.length; i++) {
|
||||
console.log("Asset", i, ":", supportedAssets[i]);
|
||||
}
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
54
script/reserve/DeployReserveSystem.s.sol
Normal file
54
script/reserve/DeployReserveSystem.s.sol
Normal file
@@ -0,0 +1,54 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "../../contracts/reserve/ReserveSystem.sol";
|
||||
import "../../contracts/reserve/ReserveTokenIntegration.sol";
|
||||
import "@emoney/interfaces/ITokenFactory138.sol";
|
||||
|
||||
/**
|
||||
* @title DeployReserveSystem
|
||||
* @notice Deployment script for Reserve System on ChainID 138
|
||||
*/
|
||||
contract DeployReserveSystem is Script {
|
||||
function run() external {
|
||||
uint256 chainId = block.chainid;
|
||||
require(chainId == 138, "This script is for ChainID 138 only");
|
||||
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
console.log("=== Reserve System Deployment (ChainID 138) ===");
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("");
|
||||
|
||||
// Load addresses from environment
|
||||
address admin = vm.envOr("RESERVE_ADMIN", deployer);
|
||||
address tokenFactory = vm.envAddress("TOKEN_FACTORY");
|
||||
|
||||
console.log("Deploying ReserveSystem...");
|
||||
ReserveSystem reserveSystem = new ReserveSystem(admin);
|
||||
console.log("ReserveSystem deployed at:", address(reserveSystem));
|
||||
|
||||
console.log("Deploying ReserveTokenIntegration...");
|
||||
ReserveTokenIntegration integration = new ReserveTokenIntegration(
|
||||
admin,
|
||||
address(reserveSystem),
|
||||
tokenFactory
|
||||
);
|
||||
console.log("ReserveTokenIntegration deployed at:", address(integration));
|
||||
|
||||
console.log("");
|
||||
console.log("=== Deployment Summary ===");
|
||||
console.log("ReserveSystem:", address(reserveSystem));
|
||||
console.log("ReserveTokenIntegration:", address(integration));
|
||||
console.log("");
|
||||
console.log("=== Export to .env ===");
|
||||
console.log("export RESERVE_SYSTEM=", vm.toString(address(reserveSystem)));
|
||||
console.log("export RESERVE_INTEGRATION=", vm.toString(address(integration)));
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
34
script/reserve/SetupComplete.s.sol
Normal file
34
script/reserve/SetupComplete.s.sol
Normal file
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
|
||||
/**
|
||||
* @title SetupComplete
|
||||
* @notice Complete setup script for Reserve System
|
||||
* @dev This script should be run as a bash script that calls the individual scripts
|
||||
*
|
||||
* Usage:
|
||||
* # Step 1: Setup Price Feeds
|
||||
* forge script script/reserve/SetupPriceFeeds.s.sol:SetupPriceFeeds --rpc-url chain138 --broadcast
|
||||
*
|
||||
* # Step 2: Configure Initial Reserves
|
||||
* forge script script/reserve/ConfigureInitialReserves.s.sol:ConfigureInitialReserves --rpc-url chain138 --broadcast
|
||||
*/
|
||||
contract SetupComplete is Script {
|
||||
function run() external {
|
||||
console.log("=== Complete Reserve System Setup ===");
|
||||
console.log("");
|
||||
console.log("This script is a placeholder.");
|
||||
console.log("Please run the setup scripts individually:");
|
||||
console.log("");
|
||||
console.log("Step 1: Setup Price Feeds");
|
||||
console.log(" forge script script/reserve/SetupPriceFeeds.s.sol:SetupPriceFeeds --rpc-url chain138 --broadcast");
|
||||
console.log("");
|
||||
console.log("Step 2: Configure Initial Reserves");
|
||||
console.log(" forge script script/reserve/ConfigureInitialReserves.s.sol:ConfigureInitialReserves --rpc-url chain138 --broadcast");
|
||||
console.log("");
|
||||
console.log("Or use the bash script: scripts/reserve/setup-complete.sh");
|
||||
}
|
||||
}
|
||||
|
||||
144
script/reserve/SetupPriceFeeds.s.sol
Normal file
144
script/reserve/SetupPriceFeeds.s.sol
Normal file
@@ -0,0 +1,144 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "forge-std/Script.sol";
|
||||
import "../../contracts/reserve/OraclePriceFeed.sol";
|
||||
import "../../contracts/reserve/MockPriceFeed.sol";
|
||||
import "../../contracts/reserve/IReserveSystem.sol";
|
||||
|
||||
/**
|
||||
* @title SetupPriceFeeds
|
||||
* @notice Script to set up price feeds for Reserve System
|
||||
* @dev Configures aggregators and initial prices for supported assets
|
||||
*/
|
||||
contract SetupPriceFeeds is Script {
|
||||
function run() external {
|
||||
uint256 chainId = block.chainid;
|
||||
require(chainId == 138, "This script is for ChainID 138 only");
|
||||
|
||||
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
|
||||
vm.startBroadcast(deployerPrivateKey);
|
||||
|
||||
address deployer = vm.addr(deployerPrivateKey);
|
||||
console.log("=== Setup Price Feeds (ChainID 138) ===");
|
||||
console.log("Deployer:", deployer);
|
||||
console.log("");
|
||||
|
||||
// Load addresses from environment
|
||||
address reserveSystem = vm.envAddress("RESERVE_SYSTEM");
|
||||
address oraclePriceFeed = vm.envOr("ORACLE_PRICE_FEED", address(0));
|
||||
address admin = vm.envOr("RESERVE_ADMIN", deployer);
|
||||
|
||||
// Deploy OraclePriceFeed if not provided
|
||||
if (oraclePriceFeed == address(0)) {
|
||||
console.log("Deploying OraclePriceFeed...");
|
||||
OraclePriceFeed priceFeed = new OraclePriceFeed(admin, reserveSystem);
|
||||
oraclePriceFeed = address(priceFeed);
|
||||
console.log("OraclePriceFeed deployed at:", oraclePriceFeed);
|
||||
} else {
|
||||
console.log("Using existing OraclePriceFeed:", oraclePriceFeed);
|
||||
}
|
||||
|
||||
OraclePriceFeed priceFeedContract = OraclePriceFeed(oraclePriceFeed);
|
||||
|
||||
// Configuration: Asset addresses and initial prices
|
||||
// For production, use real Chainlink aggregators
|
||||
// For testing, deploy MockPriceFeed contracts
|
||||
|
||||
bool useMockFeeds = vm.envOr("USE_MOCK_FEEDS", true);
|
||||
|
||||
if (useMockFeeds) {
|
||||
console.log("");
|
||||
console.log("=== Deploying Mock Price Feeds ===");
|
||||
|
||||
// Example assets with mock prices (in 8 decimals for Chainlink compatibility)
|
||||
// Gold (XAU) - $2000 per ounce
|
||||
address xauAsset = vm.envOr("XAU_ASSET", address(0x1111111111111111111111111111111111111111));
|
||||
if (xauAsset != address(0)) {
|
||||
console.log("Setting up XAU price feed...");
|
||||
MockPriceFeed xauFeed = new MockPriceFeed(2000 * 1e8, 8);
|
||||
// Multiplier: 1e10 to convert 8 decimals to 18 decimals
|
||||
vm.prank(admin);
|
||||
priceFeedContract.setAggregator(xauAsset, address(xauFeed), 1e10);
|
||||
console.log("XAU MockPriceFeed:", address(xauFeed));
|
||||
}
|
||||
|
||||
// Example: USDC - $1 per token
|
||||
address usdcAsset = vm.envOr("USDC_ASSET", address(0x2222222222222222222222222222222222222222));
|
||||
if (usdcAsset != address(0)) {
|
||||
console.log("Setting up USDC price feed...");
|
||||
MockPriceFeed usdcFeed = new MockPriceFeed(1 * 1e8, 8);
|
||||
vm.prank(admin);
|
||||
priceFeedContract.setAggregator(usdcAsset, address(usdcFeed), 1e10);
|
||||
console.log("USDC MockPriceFeed:", address(usdcFeed));
|
||||
}
|
||||
|
||||
// Example: ETH - $3000 per token
|
||||
address ethAsset = vm.envOr("ETH_ASSET", address(0x3333333333333333333333333333333333333333));
|
||||
if (ethAsset != address(0)) {
|
||||
console.log("Setting up ETH price feed...");
|
||||
MockPriceFeed ethFeed = new MockPriceFeed(3000 * 1e8, 8);
|
||||
vm.prank(admin);
|
||||
priceFeedContract.setAggregator(ethAsset, address(ethFeed), 1e10);
|
||||
console.log("ETH MockPriceFeed:", address(ethFeed));
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Updating Price Feeds ===");
|
||||
|
||||
// Update all price feeds
|
||||
address[] memory assets = new address[](3);
|
||||
if (xauAsset != address(0)) assets[0] = xauAsset;
|
||||
if (usdcAsset != address(0)) assets[1] = usdcAsset;
|
||||
if (ethAsset != address(0)) assets[2] = ethAsset;
|
||||
|
||||
vm.prank(admin);
|
||||
priceFeedContract.updateMultiplePriceFeeds(assets);
|
||||
|
||||
console.log("Price feeds updated successfully");
|
||||
} else {
|
||||
console.log("");
|
||||
console.log("=== Configuring Real Chainlink Aggregators ===");
|
||||
console.log("Set USE_MOCK_FEEDS=false and provide aggregator addresses");
|
||||
console.log("Example environment variables:");
|
||||
console.log(" XAU_AGGREGATOR=<chainlink_xau_usd_aggregator>");
|
||||
console.log(" USDC_AGGREGATOR=<chainlink_usdc_usd_aggregator>");
|
||||
console.log(" ETH_AGGREGATOR=<chainlink_eth_usd_aggregator>");
|
||||
|
||||
// Configure real aggregators if provided
|
||||
address xauAggregator = vm.envOr("XAU_AGGREGATOR", address(0));
|
||||
address xauAsset = vm.envOr("XAU_ASSET", address(0));
|
||||
if (xauAggregator != address(0) && xauAsset != address(0)) {
|
||||
vm.prank(admin);
|
||||
priceFeedContract.setAggregator(xauAsset, xauAggregator, 1e10);
|
||||
console.log("XAU aggregator configured:", xauAggregator);
|
||||
}
|
||||
|
||||
address usdcAggregator = vm.envOr("USDC_AGGREGATOR", address(0));
|
||||
address usdcAsset = vm.envOr("USDC_ASSET", address(0));
|
||||
if (usdcAggregator != address(0) && usdcAsset != address(0)) {
|
||||
vm.prank(admin);
|
||||
priceFeedContract.setAggregator(usdcAsset, usdcAggregator, 1e10);
|
||||
console.log("USDC aggregator configured:", usdcAggregator);
|
||||
}
|
||||
|
||||
address ethAggregator = vm.envOr("ETH_AGGREGATOR", address(0));
|
||||
address ethAsset = vm.envOr("ETH_ASSET", address(0));
|
||||
if (ethAggregator != address(0) && ethAsset != address(0)) {
|
||||
vm.prank(admin);
|
||||
priceFeedContract.setAggregator(ethAsset, ethAggregator, 1e10);
|
||||
console.log("ETH aggregator configured:", ethAggregator);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("");
|
||||
console.log("=== Setup Complete ===");
|
||||
console.log("OraclePriceFeed:", oraclePriceFeed);
|
||||
console.log("");
|
||||
console.log("=== Export to .env ===");
|
||||
console.log("export ORACLE_PRICE_FEED=", vm.toString(oraclePriceFeed));
|
||||
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user