// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Script.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "../src/Coupon.sol"; import "../src/CouponFactory.sol"; import "../src/Settlement.sol"; import "../src/Redemption.sol"; import "../src/Compliance.sol"; import "../src/Treasury.sol"; import "../src/Governance.sol"; import "../src/ExchangeRateOracle.sol"; import "../src/CouponBackedSecurity.sol"; import "../src/CouponBatch.sol"; import "../src/Redemption1155.sol"; /// @title Deploy — Genex 合约系统完整部署脚本 /// @notice 部署所有合约(Transparent Proxy 模式) + 角色授权 + 初始化 contract Deploy is Script { // 部署后的合约地址 ProxyAdmin public proxyAdmin; address public coupon; address public couponFactory; address public settlement; address public redemption; address public compliance; address public treasury; address public governance; address public oracle; address public cbs; address public couponBatch; address public redemption1155; function run() external { uint256 deployerKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); address deployer = vm.addr(deployerKey); address usdc = vm.envAddress("USDC_ADDRESS"); address platformFeeCollector = vm.envOr("FEE_COLLECTOR", deployer); // 多签成员地址 address[] memory multisigMembers = new address[](5); multisigMembers[0] = vm.envOr("MULTISIG_1", deployer); multisigMembers[1] = vm.envOr("MULTISIG_2", deployer); multisigMembers[2] = vm.envOr("MULTISIG_3", deployer); multisigMembers[3] = vm.envOr("MULTISIG_4", deployer); multisigMembers[4] = vm.envOr("MULTISIG_5", deployer); vm.startBroadcast(deployerKey); // ========================================== // 1. 部署 ProxyAdmin // ========================================== proxyAdmin = new ProxyAdmin(); console.log("ProxyAdmin:", address(proxyAdmin)); // ========================================== // 2. 部署 Compliance(最先,其他合约依赖它) // ========================================== Compliance complianceImpl = new Compliance(); compliance = _deployProxy( address(complianceImpl), abi.encodeCall(Compliance.initialize, (deployer)) ); console.log("Compliance:", compliance); // ========================================== // 3. 部署 Coupon // ========================================== Coupon couponImpl = new Coupon(); coupon = _deployProxy( address(couponImpl), abi.encodeCall(Coupon.initialize, ("Genex Coupon", "GXC", deployer)) ); console.log("Coupon:", coupon); // ========================================== // 4. 部署 CouponFactory // ========================================== CouponFactory factoryImpl = new CouponFactory(); couponFactory = _deployProxy( address(factoryImpl), abi.encodeCall(CouponFactory.initialize, (coupon, compliance, deployer)) ); console.log("CouponFactory:", couponFactory); // ========================================== // 5. 部署 Settlement // ========================================== Settlement settlementImpl = new Settlement(); settlement = _deployProxy( address(settlementImpl), abi.encodeCall(Settlement.initialize, (coupon, compliance, usdc, deployer)) ); console.log("Settlement:", settlement); // ========================================== // 6. 部署 Redemption // ========================================== Redemption redemptionImpl = new Redemption(); redemption = _deployProxy( address(redemptionImpl), abi.encodeCall(Redemption.initialize, (coupon, compliance, deployer)) ); console.log("Redemption:", redemption); // ========================================== // 7. 部署 Treasury // ========================================== Treasury treasuryImpl = new Treasury(); treasury = _deployProxy( address(treasuryImpl), abi.encodeCall(Treasury.initialize, (usdc, platformFeeCollector, deployer)) ); console.log("Treasury:", treasury); // ========================================== // 8. 部署 Governance // ========================================== Governance governanceImpl = new Governance(); governance = _deployProxy( address(governanceImpl), abi.encodeCall(Governance.initialize, (multisigMembers, deployer)) ); console.log("Governance:", governance); // ========================================== // 9. 部署 ExchangeRateOracle // ========================================== ExchangeRateOracle oracleImpl = new ExchangeRateOracle(); oracle = _deployProxy( address(oracleImpl), abi.encodeCall(ExchangeRateOracle.initialize, (900, deployer)) ); console.log("ExchangeRateOracle:", oracle); // ========================================== // 10. 部署 CouponBatch (ERC-1155) // ========================================== CouponBatch couponBatchImpl = new CouponBatch(); couponBatch = _deployProxy( address(couponBatchImpl), abi.encodeCall(CouponBatch.initialize, ("https://genex.io/api/coupon-batch/{id}.json", deployer)) ); console.log("CouponBatch:", couponBatch); // ========================================== // 11. 部署 Redemption1155 // ========================================== Redemption1155 redemption1155Impl = new Redemption1155(); redemption1155 = _deployProxy( address(redemption1155Impl), abi.encodeCall(Redemption1155.initialize, (couponBatch, compliance, deployer)) ); console.log("Redemption1155:", redemption1155); // ========================================== // 12. 部署 CouponBackedSecurity // ========================================== CouponBackedSecurity cbsImpl = new CouponBackedSecurity(); cbs = _deployProxy( address(cbsImpl), abi.encodeCall(CouponBackedSecurity.initialize, (coupon, compliance, usdc, deployer)) ); console.log("CouponBackedSecurity:", cbs); // ========================================== // 13. CouponFactory 关联 CouponBatch // ========================================== CouponFactory(couponFactory).setCouponBatchContract(couponBatch); // ========================================== // 14. 角色授权 // ========================================== _grantRoles(deployer); vm.stopBroadcast(); // 输出部署摘要 console.log("\n========== Deployment Summary =========="); console.log("ProxyAdmin: ", address(proxyAdmin)); console.log("Compliance: ", compliance); console.log("Coupon: ", coupon); console.log("CouponFactory: ", couponFactory); console.log("Settlement: ", settlement); console.log("Redemption: ", redemption); console.log("Treasury: ", treasury); console.log("Governance: ", governance); console.log("ExchangeRateOracle: ", oracle); console.log("CouponBatch: ", couponBatch); console.log("Redemption1155: ", redemption1155); console.log("CouponBackedSecurity:", cbs); console.log("========================================="); } /// @dev 部署 Transparent Proxy function _deployProxy(address implementation, bytes memory initData) internal returns (address) { TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( implementation, address(proxyAdmin), initData ); return address(proxy); } /// @dev 授予各合约之间的角色 function _grantRoles(address deployer) internal { // CouponFactory 需要 Coupon 的 FACTORY_ROLE Coupon(coupon).grantRole( keccak256("FACTORY_ROLE"), couponFactory ); // Settlement 需要 Coupon 的 SETTLER_ROLE Coupon(coupon).grantRole( keccak256("SETTLER_ROLE"), settlement ); // Redemption 需要通过 Coupon.burn 权限(owner 或 approved) // — Redemption 合约中 burn 通过 ownerOf 检查,无需额外角色 // CouponFactory 需要 CouponBatch 的 FACTORY_ROLE CouponBatch(couponBatch).grantRole( keccak256("FACTORY_ROLE"), couponFactory ); // Redemption1155 需要 CouponBatch 的 BURNER_ROLE CouponBatch(couponBatch).grantRole( keccak256("BURNER_ROLE"), redemption1155 ); // Governance 的 MULTISIG_ROLE 在 initialize 中已设置 console.log("Roles granted successfully"); } }