242 lines
9.3 KiB
Solidity
242 lines
9.3 KiB
Solidity
// 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");
|
||
}
|
||
}
|