diff --git a/script/res/known-cyber-corps-v3-dev.json b/script/res/known-cyber-corps-v3-dev.json new file mode 100644 index 00000000..78169c52 --- /dev/null +++ b/script/res/known-cyber-corps-v3-dev.json @@ -0,0 +1,96 @@ +{ + "data": [ + { + "chainId": 84532, + "address": "0x738B533fB2a4183b69E38c14E359a2FcaB5Fbc87" + }, + { + "chainId": 84532, + "address": "0x6e71076A1396E468490ed5E0F427b895E8F01E09" + }, + { + "chainId": 84532, + "address": "0x274c7B5edc5f088D880839a0d1287e5DA7Df3504" + }, + { + "chainId": 84532, + "address": "0x08D471C689e8aaB6dF2ea6860daa039C036810c2" + }, + { + "chainId": 84532, + "address": "0x1f1592BEAa33AF86C34cA6AB42b03E812e331e2D" + }, + { + "chainId": 84532, + "address": "0x62F767A4538dFF18c43EAAeA84ec721B7f289a1d" + }, + { + "chainId": 84532, + "address": "0xa2611914370b8ff3973573833C1cAe2D4bc754e6" + }, + { + "chainId": 84532, + "address": "0xFC870033B8DD920aE0227F2dbBE984EFE62F850C" + }, + { + "chainId": 84532, + "address": "0x3Aa81226f2E952fEdf6055c8c909F620b89B68aF" + }, + { + "chainId": 84532, + "address": "0xc2Bb4af9b2d65Ec277F813FCF0b17cbc5bD9DDa1" + }, + { + "chainId": 84532, + "address": "0x170a7b6225992a3605C6DcB5E0E46396f4E4E3B6" + }, + { + "chainId": 84532, + "address": "0x085073B6e8cbDAE2E24668FCfE212bBD56Cc2dB3" + }, + { + "chainId": 84532, + "address": "0x0423Aa59402624D6f17685DF388B682be515A978" + }, + { + "chainId": 84532, + "address": "0x9C33033f1D7E7316c936aBb30A368F93c1D02CCf" + }, + { + "chainId": 84532, + "address": "0x8412329B3CB87D125Adfc14904DAE896424b8d01" + }, + { + "chainId": 84532, + "address": "0x71E5249396811547d9C654A29153eF3Cc0AA045d" + }, + { + "chainId": 84532, + "address": "0xB49c65A5626f266a735cb319Af4b623D5A8dAC5e" + }, + { + "chainId": 84532, + "address": "0xD2cD7416F07381203b4e5096667E7483cb371A37" + }, + { + "chainId": 84532, + "address": "0x3231DF81Db0F50680067b627C4335509A3D74613" + }, + { + "chainId": 84532, + "address": "0xD8e877608a71A1d79181178d84C76989D7ea1DfB" + }, + { + "chainId": 84532, + "address": "0x074fb622a4A2CCB6dB81b2871Bd49f379b6E20c8" + }, + { + "chainId": 84532, + "address": "0x89812667009AA0B51b19a4Ed0228b0920d8F5d91" + }, + { + "chainId": 84532, + "address": "0x04812316D6a64B32d5DdEe21F8E12d2a87bbF32A" + } + ] +} diff --git a/script/upgrade-and-migrate-base-sep-im-rm-factory-addrs.s.sol b/script/upgrade-and-migrate-base-sep-im-rm-factory-addrs.s.sol new file mode 100644 index 00000000..739be3d8 --- /dev/null +++ b/script/upgrade-and-migrate-base-sep-im-rm-factory-addrs.s.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.18; + +import {Script} from "forge-std/Script.sol"; +import {Test, console2} from "forge-std/Test.sol"; +import {CyberCorpFactory} from "../src/CyberCorpFactory.sol"; +import {CyberCertPrinter} from "../src/CyberCertPrinter.sol"; +import {IIssuanceManager} from "../src/interfaces/IIssuanceManager.sol"; +import {CyberCorpSingleFactory} from "../src/CyberCorpSingleFactory.sol"; +import {BorgAuth} from "../src/libs/auth.sol"; +import {CyberAgreementRegistry} from "../src/CyberAgreementRegistry.sol"; +import {CyberCorpSingleFactory} from "../src/CyberCorpSingleFactory.sol"; +import {IDealManager} from "../src/interfaces/IDealManager.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {CertificateDetails} from "../src/storage/CyberCertPrinterStorage.sol"; +import "../src/CyberCorpConstants.sol"; +import {CertificateUriBuilder} from "../src/CertificateUriBuilder.sol"; +import {SAFTExtension} from "../src/storage/extensions/SAFTExtension.sol"; +import {DealManagerStorage} from "../src/storage/DealManagerStorage.sol"; +import {CyberCorp} from "../src/CyberCorp.sol"; +import {ILegacyFactory} from "./interfaces/ILegacyFactory.sol"; +import {KnownAddressesLoader} from "./libs/KnownAddressesLoader.sol"; +import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol"; +import {IssuanceManagerWithFactoryMigration} from "../src/IssuanceManagerWithFactoryMigration.sol"; +import {DealManagerFactory} from "../src/DealManagerFactory.sol"; +import {DealManager} from "../src/DealManager.sol"; +import {RoundManagerFactory} from "../src/RoundManagerFactory.sol"; +import {RoundManagerWithFactoryMigration} from "../src/RoundManagerWithFactoryMigration.sol"; + +contract UpgradeAndMigrateBaseSepImRmFactoryAddrsScript is Script { + mapping(address => uint256) private corpOwnerPrivateKeyLookup; + + function run() public { + runWithArgs( + vm.envUint("PRIVATE_KEY_MAIN"), // deployerPrivateKey + vm.envUint("CORP_OWNER_PKS", ","), // corpOwnerPrivateKeys + type(uint256).max // maxCount + ); + } + + /// @dev Input argument is not private key because tests will prank the deployer for real-world simulation + function runWithArgs( + uint256 deployerPrivateKey, + uint256[] memory corpOwnerPrivateKeys, + uint256 maxCount + ) public { + address deployer = vm.addr(deployerPrivateKey); + string memory saltStr = "MetaLexCyberCorp.PublicRounds.UpgradeV3.0.1"; + bytes32 salt = bytes32(keccak256(bytes(saltStr))); + + // Compile a lookup table of corp owners (for accepting upgrades) + for (uint256 i = 0; i < corpOwnerPrivateKeys.length; i++) { + address corpOwner = vm.addr(corpOwnerPrivateKeys[i]); + corpOwnerPrivateKeyLookup[corpOwner] = corpOwnerPrivateKeys[i]; + } + + console2.log("deployer: %s", deployer); + console2.log("salt string: %s", saltStr); + console2.log("loaded corp owners: %d", corpOwnerPrivateKeys.length); + + CyberCorpFactory cyberCorpFactory = CyberCorpFactory(0x51413048f3Dfc4516e95BC8e249341B1D53B6cB2); + CyberCorpSingleFactory cyberCorpSingleFactory = CyberCorpSingleFactory(cyberCorpFactory.cyberCorpSingleFactory()); + DealManagerFactory dmFactory = DealManagerFactory(cyberCorpFactory.dealManagerFactory()); + + // Legacy corp's IssuanceManagerFactory (for upgrading beacons) + ILegacyFactory legacyImFactory = ILegacyFactory(0xA32547aAdAA4975082D729c79e79dBaE4385EBCf); + + // Deprecated develop-version of v3 RoundManagerFactory (we need it later for providing reference implementation with migration features) + IssuanceManagerFactory deprecatingImFactory = IssuanceManagerFactory(0xbbD386D237f3b407E6511A52488850b1Da0cCad2); + RoundManagerFactory deprecatingRmFactory = RoundManagerFactory(0x9E2A3a07711Ce4b5A2F4D62a5c8f8B5307Af9C34); + + // Newly deployed factories that we want to use + IssuanceManagerFactory imFactory = IssuanceManagerFactory(0xD353972D7955F421d94d0eA8c42c88c417F7155A); + RoundManagerFactory rmFactory = RoundManagerFactory(0xc9d5d0DeDD124f9351E5880469f25AB41869aeb9); + + vm.startBroadcast(deployerPrivateKey); + + // 1) Replace CyberCorpFactory's IssuanceManagerFactory with the newly deployed ones + // Set new IssuanceManager's reference implementation to the old one since they are functionally identical + address refIm = deprecatingImFactory.getRefImplementation(); + imFactory.setRefImplementation(refIm); + cyberCorpFactory.setIssuanceManagerFactory(address(imFactory)); + vm.assertEq(cyberCorpFactory.issuanceManagerFactory(), address(imFactory), "unexpected IssuanceManagerFactory"); + vm.assertEq(imFactory.getRefImplementation(), refIm, "unexpected IssuanceManager reference implementation"); + console2.log("CyberCorpFactory.issuanceManagerFactory set to: %s", address(imFactory)); + + // 2) Replace CyberCorpFactory's RoundManagerFactory with the newly deployed ones + cyberCorpFactory.setRoundManagerFactory(address(rmFactory)); + vm.assertEq(cyberCorpFactory.roundManagerFactory(), address(rmFactory), "unexpected RoundManagerFactory"); + console2.log("CyberCorpFactory.roundManagerFactory set to: %s", address(rmFactory)); + + // Load all known cyber corps + address[] memory knownLegacyCyberCorps = KnownAddressesLoader.load(block.chainid, "/script/res/known-cyber-corps.json", maxCount); + address[] memory knownDevV3CyberCorps = KnownAddressesLoader.load(block.chainid, "/script/res/known-cyber-corps-v3-dev.json", maxCount); + + // 3) Deploy temporary contracts for migration + + IssuanceManagerWithFactoryMigration imWithMigrationImpl = new IssuanceManagerWithFactoryMigration(); + RoundManagerWithFactoryMigration rmWithMigrationImpl = new RoundManagerWithFactoryMigration(); + + // Sanity check: the hard-coded factory addresses should match the current factories + vm.assertEq( + imWithMigrationImpl.NEW_UPGRADE_FACTORY(), + address(imFactory), + string(abi.encodePacked("IssuanceManagerWithFactoryMigration.NEW_UPGRADE_FACTORY should point to the current factory")) + ); + vm.assertEq( + rmWithMigrationImpl.NEW_UPGRADE_FACTORY(), + address(rmFactory), + string(abi.encodePacked("RoundManagerWithFactoryMigration.NEW_UPGRADE_FACTORY should point to the current factory")) + ); + + // 4a) Upgrade issuance manager beacon to a special implementation with migration features + legacyImFactory.upgradeImplementation(address(imWithMigrationImpl)); + vm.assertEq(legacyImFactory.getBeaconImplementation(), address(imWithMigrationImpl), "beacon implementation should be upgraded with migration features by now"); + console2.log("Set new beacon implementation (with migration features): %s for legacy IssuanceManagerFactory: %s", address(imWithMigrationImpl), address(legacyImFactory)); + + // 4b) Set the reference implementation on the deprecating IssuanceManagerFactory (so the dev-v3 corps can accept it) + deprecatingImFactory.setRefImplementation(address(imWithMigrationImpl)); + + // 4c) Set the reference implementation on the deprecating RoundManagerFactory (so the corps can accept it) + deprecatingRmFactory.setRefImplementation(address(rmWithMigrationImpl)); + + vm.stopBroadcast(); + + // 5) Migrate each legacy corp one-by-one + for (uint256 i = 0; i < knownLegacyCyberCorps.length; i++) { + CyberCorp corp = CyberCorp(knownLegacyCyberCorps[i]); + + // If we don't have the corp owner's private key, we will skip migrating the corp completely so it does not stuck in an intermediate state + uint256 corpOwnerPrivateKey = corpOwnerPrivateKeyLookup[corp.companyPayable()]; + if (corpOwnerPrivateKey == 0) { + console2.log("private key not found for legacy corp owner: %s, skipping corp: %s", corp.companyPayable(), address(corp)); + continue; + } + + // Sanity check: all other factories should match + vm.assertEq( + corp.upgradeFactory(), + address(cyberCorpSingleFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current CyberCorpSingleFactory")) + ); + vm.assertEq( + _getDealManagerUpgradeFactory(corp.dealManager()), + address(dmFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current DealManagerFactory")) + ); + + // Migrate legacy corp's IssuanceManager (beacon-based) + vm.startBroadcast(deployerPrivateKey); + + IssuanceManagerWithFactoryMigration im = IssuanceManagerWithFactoryMigration(corp.issuanceManager()); + im.migrateUpgradeFactory(); + vm.assertEq( + im.getUpgradeFactory(), + address(imFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current IssuanceManagerFactory after migration")) + ); + + vm.stopBroadcast(); + + // Migrate legacy corp's RoundManager (UUPSUpgradeable-based, need co-approval) + vm.startBroadcast(corpOwnerPrivateKey); + + // Accept round manager upgrade to the temporary implementation with migration feature + RoundManagerWithFactoryMigration rm = RoundManagerWithFactoryMigration(corp.roundManager()); + rm.upgradeToAndCall( + address(rmWithMigrationImpl), + abi.encodeWithSelector(rm.migrateUpgradeFactory.selector) // perform migration atomically + ); + vm.assertEq( + rm.getUpgradeFactory(), + address(rmFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current RoundManagerFactory after migration")) + ); + + vm.stopBroadcast(); + + console2.log("Migrated legacy CyberCorp: %s", address(corp)); + } + + // 6) Migrate each dev-v3 corp one-by-one + for (uint256 i = 0; i < knownDevV3CyberCorps.length; i++) { + CyberCorp corp = CyberCorp(knownDevV3CyberCorps[i]); + + // If we don't have the corp owner's private key, we will skip migrating the corp completely so it does not stuck in an intermediate state + uint256 corpOwnerPrivateKey = corpOwnerPrivateKeyLookup[corp.companyPayable()]; + if (corpOwnerPrivateKey == 0) { + console2.log("private key not found for dev-v3 corp owner: %s, skipping corp: %s", corp.companyPayable(), address(corp)); + continue; + } + + // Sanity check: all other factories should match + vm.assertEq( + corp.upgradeFactory(), + address(cyberCorpSingleFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current CyberCorpSingleFactory")) + ); + vm.assertEq( + _getDealManagerUpgradeFactory(corp.dealManager()), + address(dmFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current DealManagerFactory")) + ); + + vm.startBroadcast(corpOwnerPrivateKey); + + // Migrate legacy corp's IssuanceManager (UUPSUpgradeable-based, need co-approval) + // Accept round manager upgrade to the temporary implementation with migration feature + IssuanceManagerWithFactoryMigration im = IssuanceManagerWithFactoryMigration(corp.issuanceManager()); + im.upgradeToAndCall( + address(imWithMigrationImpl), + abi.encodeWithSelector(im.migrateUpgradeFactory.selector) // perform migration atomically + ); + vm.assertEq( + im.getUpgradeFactory(), + address(imFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current IssuanceManagerFactory after migration")) + ); + + // Migrate legacy corp's RoundManager (UUPSUpgradeable-based, need co-approval) + // Accept round manager upgrade to the temporary implementation with migration feature + RoundManagerWithFactoryMigration rm = RoundManagerWithFactoryMigration(corp.roundManager()); + rm.upgradeToAndCall( + address(rmWithMigrationImpl), + abi.encodeWithSelector(rm.migrateUpgradeFactory.selector) // perform migration atomically + ); + vm.assertEq( + rm.getUpgradeFactory(), + address(rmFactory), + string(abi.encodePacked("legacy cyberCorp: ", vm.toString(address(corp)), " should point to the current RoundManagerFactory after migration")) + ); + + vm.stopBroadcast(); + + console2.log("Migrated dev-v3 CyberCorp: %s", address(corp)); + } + + // 7a) Revert to the normal implementation since migration is done + vm.startBroadcast(deployerPrivateKey); + + address imRefImpl = imFactory.getRefImplementation(); + legacyImFactory.upgradeImplementation(imRefImpl); + vm.assertEq(legacyImFactory.getBeaconImplementation(), imRefImpl, "beacon implementation should be upgraded without migration features by now"); + console2.log("Set new beacon implementation (without migration features): %s for legacy IssuanceManagerFactory: %s", address(imRefImpl), address(legacyImFactory)); + + // 7b) No need to revert deprecatingImFactory.refImplementation() since it is deprecating + // 7c) No need to revert deprecatingRmFactory.refImplementation() since it is deprecating + + vm.stopBroadcast(); + } + + function _getDealManagerUpgradeFactory(address target) internal view returns (address) { + // `upgradeFactory` is at slot 1 of `DealManagerStorage.STORAGE_POSITION` + bytes32 slotData = vm.load(target, bytes32(uint256(DealManagerStorage.STORAGE_POSITION) + 1)); + return address(uint160(uint256(slotData))); + } +} diff --git a/script/upgrade-public-rounds-base-sep.s.sol b/script/upgrade-public-rounds-base-sep.s.sol new file mode 100644 index 00000000..8cc45373 --- /dev/null +++ b/script/upgrade-public-rounds-base-sep.s.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {CompanyOfficer, SecurityClass, SecuritySeries} from "../src/CyberCorpConstants.sol"; +import {CyberAgreementRegistry} from "../src/CyberAgreementRegistry.sol"; +import {CyberCorpFactory} from "../src/CyberCorpFactory.sol"; +import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol"; +import {IssuanceManager} from "../src/IssuanceManager.sol"; +import {CyberCorpSingleFactory} from "../src/CyberCorpSingleFactory.sol"; +import {DealManagerFactory} from "../src/DealManagerFactory.sol"; +import {DealManager} from "../src/DealManager.sol"; +import {RoundManagerFactory} from "../src/RoundManagerFactory.sol"; +import {RoundManager} from "../src/RoundManager.sol"; +import {CyberCorp} from "../src/CyberCorp.sol"; +import {BorgAuth} from "../src/libs/auth.sol"; +import "openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {CyberCertPrinter} from "../src/CyberCertPrinter.sol"; +import {CyberScrip} from "../src/CyberScrip.sol"; +import {ILegacyFactory} from "../script/interfaces/ILegacyFactory.sol"; + +interface IUUPS { + function upgradeTo(address newImplementation) external; + function upgradeToAndCall( + address newImplementation, + bytes calldata data + ) external payable; +} + +contract UpgradePublicRoundsBaseSepoliaScript is Script { + function run() public returns ( + IssuanceManagerFactory newImFactory, + RoundManagerFactory roundManagerFactory + ) { + return runWithArgs(vm.envUint("PRIVATE_KEY_MAIN")); + } + + function runWithArgs(uint256 deployerPrivateKey) public returns ( + IssuanceManagerFactory newImFactory, + RoundManagerFactory roundManagerFactory + ) { + address deployer = vm.addr(deployerPrivateKey); + // Config + bytes32 salt = bytes32( + keccak256("MetaLexCyberCorp.PublicRounds.UpgradeV3.0.1") + ); + + // Required existing addresses + address cyberCorpFactoryProxyAddr = 0x51413048f3Dfc4516e95BC8e249341B1D53B6cB2; + address legacyCyberCorpSingleFactoryAddr = 0xc8e084D3f8B3b326FCc894C7afD28F4904196406; + address legacyIssuanceManagerFactoryAddr = 0xA32547aAdAA4975082D729c79e79dBaE4385EBCf; + address registry = 0xa9E808B8eCBB60Bb19abF026B5b863215BC4c134; + address deployedLexChexAddrAuth = 0xeAdeaD5C4A6747D4959489742c143bCDb95a01c2; + address multisig = 0x68Ab3F79622cBe74C9683aA54D7E1BBdCAE8003C; + + address stable; + uint256 currentChainId = block.chainid; + if (currentChainId == 1) { + stable = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // Mainnet + } else if (currentChainId == 42161) { + stable = 0xaf88d065e77c8cC2239327C5EDb3A432268e5831; // Arbitrum + } else if (currentChainId == 8453) { + stable = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; // Base + } else if (currentChainId == 84532) { + stable = 0x036CbD53842c5426634e7929541eC2318f3dCF7e; // Base Sepolia + } else if (currentChainId == 11155111) { + stable = 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238; // Sepolia + } else { + revert("Unsupported chain ID"); // Handle unsupported chains + } + + CyberCorpFactory factoryProxy = CyberCorpFactory( + cyberCorpFactoryProxyAddr + ); + + // Uses existing AUTH from factory + address auth = address( + CyberCorpFactory(cyberCorpFactoryProxyAddr).AUTH() + ); + vm.assertEq(address(auth), 0x033012a1eDA6e2E00D12CD37c5b63B9440ef5E01, "should match universal AUTH address"); + + console.log("Deployer:", deployer); + uint256 role = BorgAuth(auth).userRoles(deployer); + console.log("Upgrader role:", role); + if (role < BorgAuth(auth).OWNER_ROLE()) { + revert( + "Deployer is not AUTH owner; use the AUTH owner key to upgrade" + ); + } + + vm.startBroadcast(deployerPrivateKey); + + // 1) Deploy RoundManagerFactory + roundManagerFactory = RoundManagerFactory(address( + new ERC1967Proxy{salt: salt}( + address(new RoundManagerFactory{salt: salt}()), + abi.encodeWithSelector( + RoundManagerFactory.initialize.selector, + address(auth), + address(new RoundManager{salt: salt}()) + ) + ) + )); + console.log( + "RoundManagerFactory deployed:", + address(roundManagerFactory) + ); + + roundManagerFactory.setWhitelistedToken(stable, true); + + // 2) Set the RoundManagerFactory address in CyberCorpFactory + factoryProxy.setRoundManagerFactory(address(roundManagerFactory)); + console.log( + "CyberCorpFactory.roundManagerFactory set to:", + address(roundManagerFactory) + ); + + // 3) Deploy new IssuanceManagerFactory + // Deploy new reference implementations + IssuanceManager refIm = new IssuanceManager{salt: salt}(); + CyberCertPrinter refCertPrinter = new CyberCertPrinter{salt: salt}(); + CyberScrip refScrip = new CyberScrip{salt: salt}(); + console.log( + "New IssuanceManager implementation:", + address(refIm) + ); + console.log( + "New CyberCertPrinter implementation:", + address(refCertPrinter) + ); + console.log( + "New CyberScrip implementation:", + address(refScrip) + ); + // Deploy new UUPSUpgradeable + newImFactory = IssuanceManagerFactory( + address( + new ERC1967Proxy{salt: salt}( + address(new IssuanceManagerFactory{salt: salt}()), + abi.encodeWithSelector( + IssuanceManagerFactory.initialize.selector, + address(auth), + address(refIm), + address(refCertPrinter), + address(refScrip) + ) + ) + ) + ); + console.log( + "IssuanceManagerFactory deployed:", + address(newImFactory) + ); + // Replace the old one in CyberCorpFactory + factoryProxy.setIssuanceManagerFactory(address(newImFactory)); + // Verify the upgrade was successful + vm.assertEq(newImFactory.getRefImplementation(), address(refIm), "unexpected IssuanceManager reference implementation"); + console.log( + "CyberCorpFactory.issuanceManagerFactory set to:", + address(newImFactory) + ); + + vm.stopBroadcast(); + } +} diff --git a/src/CyberCorpWithMigrationFactories.sol b/src/CyberCorpWithMigrationFactories.sol new file mode 100644 index 00000000..38f745ea --- /dev/null +++ b/src/CyberCorpWithMigrationFactories.sol @@ -0,0 +1,73 @@ +/* .o. + .888. + .8"888. + .8' `888. + .88ooo8888. + .8' `888. +o88o o8888o + + + +ooo ooooo . ooooo ooooooo ooooo +`88. .888' .o8 `888' `8888 d8' + 888b d'888 .ooooo. .o888oo .oooo. 888 .ooooo. Y888..8P + 8 Y88. .P 888 d88' `88b 888 `P )88b 888 d88' `88b `8888' + 8 `888' 888 888ooo888 888 .oP"888 888 888ooo888 .8PY888. + 8 Y 888 888 .o 888 . d8( 888 888 o 888 .o d8' `888b +o8o o888o `Y8bod8P' "888" `Y888""8o o888ooooood8 `Y8bod8P' o888o o88888o + + + + .oooooo. .o8 .oooooo. + d8P' `Y8b "888 d8P' `Y8b +888 oooo ooo 888oooo. .ooooo. oooo d8b 888 .ooooo. oooo d8b oo.ooooo. +888 `88. .8' d88' `88b d88' `88b `888""8P 888 d88' `88b `888""8P 888' `88b +888 `88..8' 888 888 888ooo888 888 888 888 888 888 888 888 +`88b ooo `888' 888 888 888 .o 888 `88b ooo 888 888 888 888 888 .o. + `Y8bood8P' .8' `Y8bod8P' `Y8bod8P' d888b `Y8bood8P' `Y8bod8P' d888b 888bod8P' Y8P + .o..P' 888 + `Y8P' o888o +_______________________________________________________________________________________________________ + +All software, documentation and other files and information in this repository (collectively, the "Software") +are copyright MetaLeX Labs, Inc., a Delaware corporation. + +All rights reserved. + +The Software is proprietary and shall not, in part or in whole, be used, copied, modified, merged, published, +distributed, transmitted, sublicensed, sold, or otherwise used in any form or by any means, electronic or +mechanical, including photocopying, recording, or by any information storage and retrieval system, +except with the express prior written permission of the copyright holder.*/ + +pragma solidity 0.8.28; + +import {CyberCorp} from "./CyberCorp.sol"; +import {CyberCorpFactory} from "./CyberCorpFactory.sol"; +import {BorgAuth} from "./libs/auth.sol"; +import {IRoundManagerFactory} from "./interfaces/IRoundManagerFactory.sol"; +import {IRoundManagerInit} from "./helpers/RoundManagerUpgradeHelper.sol"; + +contract CyberCorpWithMigrationFactories is CyberCorp { + + // TODO WIP + + address public constant NEW_UPGRADE_FACTORY = 0x50C26cd5750aBbb81A97276A521D70606f4bAFee; // TODO TBD + CyberCorpFactory public constant CYBER_CORP_FACTORY = CyberCorpFactory(0x51413048f3Dfc4516e95BC8e249341B1D53B6cB2); + + /// @notice Migrate legacy contracts and set upgradeFactory to the known new contract (for reference implementation lookup) + /// @dev Since the migration target is predefined, it doesn't matter who called it or when it is called + function migrateUpgradeFactory() public { + // Update to the new permanent address of CyberCorpSingleFactory + upgradeFactory = NEW_UPGRADE_FACTORY; + + // Deploy a new RoundManager if not setup yet + if (roundManager == address(0)) { + // Ask CyberCorpFactory to prepare one for us + bytes32 salt = keccak256(abi.encodePacked("MetaLexCyberCorp.PublicRounds.migration.", address(this))); + roundManager = CYBER_CORP_FACTORY.deployAndInitializeRoundManager(salt, address(this)); + + // Authorize the round manager + AUTH.updateRole(roundManager, 99); + } + } +} diff --git a/src/IssuanceManagerWithFactoryMigration.sol b/src/IssuanceManagerWithFactoryMigration.sol new file mode 100644 index 00000000..f2a4f06f --- /dev/null +++ b/src/IssuanceManagerWithFactoryMigration.sol @@ -0,0 +1,58 @@ +/* .o. + .888. + .8"888. + .8' `888. + .88ooo8888. + .8' `888. +o88o o8888o + + + +ooo ooooo . ooooo ooooooo ooooo +`88. .888' .o8 `888' `8888 d8' + 888b d'888 .ooooo. .o888oo .oooo. 888 .ooooo. Y888..8P + 8 Y88. .P 888 d88' `88b 888 `P )88b 888 d88' `88b `8888' + 8 `888' 888 888ooo888 888 .oP"888 888 888ooo888 .8PY888. + 8 Y 888 888 .o 888 . d8( 888 888 o 888 .o d8' `888b +o8o o888o `Y8bod8P' "888" `Y888""8o o888ooooood8 `Y8bod8P' o888o o88888o + + + + .oooooo. .o8 .oooooo. + d8P' `Y8b "888 d8P' `Y8b +888 oooo ooo 888oooo. .ooooo. oooo d8b 888 .ooooo. oooo d8b oo.ooooo. +888 `88. .8' d88' `88b d88' `88b `888""8P 888 d88' `88b `888""8P 888' `88b +888 `88..8' 888 888 888ooo888 888 888 888 888 888 888 888 +`88b ooo `888' 888 888 888 .o 888 `88b ooo 888 888 888 888 888 .o. + `Y8bood8P' .8' `Y8bod8P' `Y8bod8P' d888b `Y8bood8P' `Y8bod8P' d888b 888bod8P' Y8P + .o..P' 888 + `Y8P' o888o +_______________________________________________________________________________________________________ + +All software, documentation and other files and information in this repository (collectively, the "Software") +are copyright MetaLeX Labs, Inc., a Delaware corporation. + +All rights reserved. + +The Software is proprietary and shall not, in part or in whole, be used, copied, modified, merged, published, +distributed, transmitted, sublicensed, sold, or otherwise used in any form or by any means, electronic or +mechanical, including photocopying, recording, or by any information storage and retrieval system, +except with the express prior written permission of the copyright holder.*/ + +pragma solidity 0.8.28; + +import {UpgradeableBeacon} from "openzeppelin-contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {IssuanceManager} from "./IssuanceManager.sol"; +import {IssuanceManagerStorage} from "./storage/IssuanceManagerStorage.sol"; +import {IIssuanceManagerFactory} from "./interfaces/IIssuanceManagerFactory.sol"; + +contract IssuanceManagerWithFactoryMigration is IssuanceManager { + + address public constant NEW_UPGRADE_FACTORY = 0xD353972D7955F421d94d0eA8c42c88c417F7155A; + + /// @notice Migrate legacy contracts and set upgradeFactory to the known new contract (for reference implementation lookup) + /// @dev Since the migration target is predefined, it doesn't matter who called it or when it is called + function migrateUpgradeFactory() public { + IssuanceManagerStorage.setUpgradeFactory(NEW_UPGRADE_FACTORY); + } +} diff --git a/src/RoundManagerWithFactoryMigration.sol b/src/RoundManagerWithFactoryMigration.sol new file mode 100644 index 00000000..e9d6e7bc --- /dev/null +++ b/src/RoundManagerWithFactoryMigration.sol @@ -0,0 +1,62 @@ +/* .o. + .888. + .8"888. + .8' `888. + .88ooo8888. + .8' `888. +o88o o8888o + + + +ooo ooooo . ooooo ooooooo ooooo +`88. .888' .o8 `888' `8888 d8' + 888b d'888 .ooooo. .o888oo .oooo. 888 .ooooo. Y888..8P + 8 Y88. .P 888 d88' `88b 888 `P )88b 888 d88' `88b `8888' + 8 `888' 888 888ooo888 888 .oP"888 888 888ooo888 .8PY888. + 8 Y 888 888 .o 888 . d8( 888 888 o 888 .o d8' `888b +o8o o888o `Y8bod8P' "888" `Y888""8o o888ooooood8 `Y8bod8P' o888o o88888o + + + + .oooooo. .o8 .oooooo. + d8P' `Y8b "888 d8P' `Y8b +888 oooo ooo 888oooo. .ooooo. oooo d8b 888 .ooooo. oooo d8b oo.ooooo. +888 `88. .8' d88' `88b d88' `88b `888""8P 888 d88' `88b `888""8P 888' `88b +888 `88..8' 888 888 888ooo888 888 888 888 888 888 888 888 +`88b ooo `888' 888 888 888 .o 888 `88b ooo 888 888 888 888 888 .o. + `Y8bood8P' .8' `Y8bod8P' `Y8bod8P' d888b `Y8bood8P' `Y8bod8P' d888b 888bod8P' Y8P + .o..P' 888 + `Y8P' o888o +_______________________________________________________________________________________________________ + +All software, documentation and other files and information in this repository (collectively, the "Software") +are copyright MetaLeX Labs, Inc., a Delaware corporation. + +All rights reserved. + +The Software is proprietary and shall not, in part or in whole, be used, copied, modified, merged, published, +distributed, transmitted, sublicensed, sold, or otherwise used in any form or by any means, electronic or +mechanical, including photocopying, recording, or by any information storage and retrieval system, +except with the express prior written permission of the copyright holder.*/ + +pragma solidity 0.8.28; + +import {UpgradeableBeacon} from "openzeppelin-contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {RoundManager} from "./RoundManager.sol"; +import {RoundManagerStorage} from "./storage/RoundManagerStorage.sol"; +import {IRoundManagerFactory} from "./interfaces/IRoundManagerFactory.sol"; + +contract RoundManagerWithFactoryMigration is RoundManager { + + address public constant NEW_UPGRADE_FACTORY = 0xc9d5d0DeDD124f9351E5880469f25AB41869aeb9; + + /// @notice Migrate legacy contracts and set upgradeFactory to the known new contract (for reference implementation lookup) + /// @dev Since the migration target is predefined, it doesn't matter who called it or when it is called + function migrateUpgradeFactory() public { + RoundManagerStorage.setUpgradeFactory(NEW_UPGRADE_FACTORY); + } + + function getUpgradeFactory() public view returns (address) { + return RoundManagerStorage.getUpgradeFactory(); + } +} diff --git a/test/MigrateBaseSepImRmFactoryAddrsTest.t.sol b/test/MigrateBaseSepImRmFactoryAddrsTest.t.sol new file mode 100644 index 00000000..d4424ba4 --- /dev/null +++ b/test/MigrateBaseSepImRmFactoryAddrsTest.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import {Test, console2} from "forge-std/Test.sol"; +import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol"; +import {ERC1967Proxy} from "openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {CyberCorpHelper} from "../test/RoundManagerTest.t.sol"; +import {CyberAgreementUtils} from "../test/libs/CyberAgreementUtils.sol"; +import {UpgradePublicRoundsBaseSepoliaScript} from "../script/upgrade-public-rounds-base-sep.s.sol"; +import {UpgradeAndMigrateBaseSepImRmFactoryAddrsScript} from "../script/upgrade-and-migrate-base-sep-im-rm-factory-addrs.s.sol"; +import {GnosisTransaction} from "../script/libs/safe.sol"; +import {ILegacyFactory} from "../script/interfaces/ILegacyFactory.sol"; +import {CompanyOfficer, SecurityClass, SecuritySeries} from "../src/CyberCorpConstants.sol"; +import {CyberAgreementRegistry} from "../src/CyberAgreementRegistry.sol"; +import {CyberCorpFactory} from "../src/CyberCorpFactory.sol"; +import {CyberCorpSingleFactory} from "../src/CyberCorpSingleFactory.sol"; +import {IssuanceManager} from "../src/IssuanceManager.sol"; +import {IssuanceManagerFactory} from "../src/IssuanceManagerFactory.sol"; +import {DealManagerFactory} from "../src/DealManagerFactory.sol"; +import {RoundManager} from "../src/RoundManager.sol"; +import {RoundManagerFactory} from "../src/RoundManagerFactory.sol"; +import {LeXcheX} from "../src/creds/lexchex.sol"; +import {CyberCertData, RoundType} from "../src/interfaces/IRoundManager.sol"; +import {EOI, LexChexDetails, MintRequest} from "../src/storage/RoundManagerStorage.sol"; +import {Accreditation} from "../src/creds/storage/lexchexStorage.sol"; +import {LeXcheXMinter} from "../src/creds/lexchexMinter.sol"; +import {BorgAuth} from "../src/libs/auth.sol"; +import {CyberCertPrinter} from "../src/CyberCertPrinter.sol"; +import {CyberScrip} from "../src/CyberScrip.sol"; + +contract MigrateBaseSepImRmFactoryAddrsTest is Test { + address metalexSafe = 0x68Ab3F79622cBe74C9683aA54D7E1BBdCAE8003C; + + // Assume Base-sepolia + ERC20 usdc = ERC20(0x036CbD53842c5426634e7929541eC2318f3dCF7e); + CyberCorpFactory cyberCorpFactory = CyberCorpFactory(0x51413048f3Dfc4516e95BC8e249341B1D53B6cB2); + CyberAgreementRegistry registry = CyberAgreementRegistry(0xa9E808B8eCBB60Bb19abF026B5b863215BC4c134); + BorgAuth lexChexAuth = BorgAuth(0xeAdeaD5C4A6747D4959489742c143bCDb95a01c2); + LeXcheX lexchex = LeXcheX(0xc8db0c3f47656aee725b0AD1835F9A3FbD0a0b62); + LeXcheXMinter leXcheXMinter = LeXcheXMinter(0x0dD1a2a89eC172ac322B6a7a6c869180CBD0F960); + address lexchexConditionAddr = 0x4a08547d57C8d01e59bA8F884aB90CEe0d6d5b42; + + address deployer; + uint256 deployerPrivateKey; + + function setUp() public { + vm.label(address(cyberCorpFactory), "CyberCorpFactory"); + vm.label(address(usdc), "USDC"); + vm.label(address(registry), "CyberAgreementRegistry"); + vm.label(address(lexChexAuth), "lexChexAuth"); + vm.label(address(lexChexAuth), "lexChexAuth"); + vm.label(address(lexchex), "LeXcheX"); + vm.label(address(leXcheXMinter), "LeXcheXMinter"); + vm.label(address(lexchexConditionAddr), "lexchexCondition"); + + (deployer, deployerPrivateKey) = makeAddrAndKey("deployer"); + + // Simulate granting the test deployer admin access so it can perform upgrades + vm.startPrank(metalexSafe); + CyberAgreementRegistry(registry).AUTH().updateRole( + deployer, + CyberAgreementRegistry(registry).AUTH().OWNER_ROLE() + ); + lexChexAuth.updateRole( + deployer, + lexChexAuth.OWNER_ROLE() + ); // so deployer can grant cyberCorpFactory permissions to it + vm.stopPrank(); + + // simulate migrations + (new UpgradeAndMigrateBaseSepImRmFactoryAddrsScript()).runWithArgs( + deployerPrivateKey, + vm.envUint("CORP_OWNER_PKS", ","), // deployer is also the test corp owner + 4 + ); + + // Revoke deployer admin access + vm.startPrank(metalexSafe); + CyberAgreementRegistry(registry).AUTH().updateRole(deployer, 0); + lexChexAuth.updateRole(deployer, 0); + vm.stopPrank(); + } + + function test_SanityCheck() public { + } +}