From 17dd13cbdf394f0ee9c60df719318f175d938931 Mon Sep 17 00:00:00 2001 From: ilin Date: Fri, 12 Jul 2024 13:10:42 +0200 Subject: [PATCH 01/21] add simulation for tranche token migration --- deployments/mainnet/ethereum-mainnet.json | 2 +- script/Deployer.sol | 2 +- test/fork/Migration.t.sol | 159 ++++++++++++++++++++++ 3 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 test/fork/Migration.t.sol diff --git a/deployments/mainnet/ethereum-mainnet.json b/deployments/mainnet/ethereum-mainnet.json index 75032662..ad21e8ec 100644 --- a/deployments/mainnet/ethereum-mainnet.json +++ b/deployments/mainnet/ethereum-mainnet.json @@ -1,6 +1,6 @@ { "chainId": 1, - "rpcUrl": "https://mainnet.infura.io/v3/ed5e0e19bcbc427cbf8f661736d44516", + "rpcUrl": "https://mainnet.infura.io/v3/e5a02bbddefe47f88c2d087ec4a37744", "config": { "commitHash": "da5c31462b5fe615d3510ca35f884018fd8055c7", "deployer": "0x7270b20603FbB3dF0921381670fbd62b9991aDa4", diff --git a/script/Deployer.sol b/script/Deployer.sol index 63a9ede3..4e86c580 100644 --- a/script/Deployer.sol +++ b/script/Deployer.sol @@ -19,7 +19,7 @@ import "forge-std/Script.sol"; contract Deployer is Script { uint256 internal constant delay = 48 hours; - address adminSafe; + address adminSafe = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; // safe wallet for fork testing address[] adapters; Root public root; diff --git a/test/fork/Migration.t.sol b/test/fork/Migration.t.sol new file mode 100644 index 00000000..78be8800 --- /dev/null +++ b/test/fork/Migration.t.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.26; + +import {Tranche} from "src/token/Tranche.sol"; +import {Guardian} from "src/admin/Guardian.sol"; +import {PermissionlessAdapter} from "test/mocks/PermissionlessAdapter.sol"; +import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; +import {BytesLib} from "src/libraries/BytesLib.sol"; +import {CastLib} from "src/libraries/CastLib.sol"; +import {MathLib} from "src/libraries/MathLib.sol"; +import "forge-std/Test.sol"; +import "forge-std/StdJson.sol"; +import "script/Deployer.sol"; + +interface TrancheTokenOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +contract ForkTest is Deployer, Test { + using BytesLib for bytes; + using MathLib for uint256; + using CastLib for *; + using stdJson for string; + + string[] deployments; + Tranche trancheTokenToMigrate; + Tranche trancheToken; + Guardian guardianOld; + Root rootOld; + + address tokenToMigrate_ = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; + address guardianOld_ = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + address rootOld_ = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + + uint64 poolId = 4139607887; + bytes16 trancheId = 0x97aa65f23e7be09fcd62d0554d2e9273; + uint8 decimals = 6; + string name = "Anemoy Liquid Treasury Fund 1"; + string symbol = "LTF"; + uint128 currencyId = 242333941209166991950178742833476896417; // USDC 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 + address currency = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + // old lp 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd + + address self; + + function setUp() public virtual { + self = address(this); + _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet + _loadFork(0); + trancheTokenToMigrate = Tranche(address(tokenToMigrate_)); // Anemoy Liquid Treasury Fund 1 (LTF) + guardianOld = Guardian(address(guardianOld_)); + rootOld = Root(rootOld_); + + deployNewContracts(); // Deploy Liquidity Pools v2 + + // _loadDeployment("mainnet", "base-mainnet"); + // _loadDeployment("mainnet", "arbitrum-mainnet"); + // _loadDeployment("mainnet", "celo-mainnet"); + } + + function testTrancheTokenMigration() public { + address holder1 = 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997; + address holder2 = 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E; + address holder3 = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + + // load all holder balances and check whether they all add up to totalSupply + uint256 holderBalance1 = trancheTokenToMigrate.balanceOf(holder1); + uint256 holderBalance2 = trancheTokenToMigrate.balanceOf(holder2); + uint256 holderBalance3 = trancheTokenToMigrate.balanceOf(holder3); + assertEq((holderBalance1 + holderBalance2 + holderBalance3), trancheTokenToMigrate.totalSupply()); + + // get auth on old TrancheToken through DelayedAdmin - simulate governance + vm.startPrank(adminMultiSig); + guardianOld.scheduleRely(self); + // get auth on old TrancheToken through Guardian - simulate governance + guardian.scheduleRely(self); + vm.stopPrank(); + // warp delay time = 48H & exec relies + vm.warp(block.timestamp + 2 days); + rootOld.executeScheduledRely(self); + root.executeScheduledRely(self); + // exec auth relies + rootOld.relyContract(address(trancheTokenToMigrate), self); + root.relyContract(address(trancheToken), self); + root.relyContract(address(poolManager), self); + + // // add holders to the allowlist of new token - simulate governance + bytes memory update1 = + abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder1).toBytes32(), type(uint64).max); + bytes memory update2 = + abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder2).toBytes32(), type(uint64).max); + bytes memory update3 = + abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder3).toBytes32(), type(uint64).max); + + poolManager.updateRestriction(poolId, trancheId, update1); + poolManager.updateRestriction(poolId, trancheId, update2); + poolManager.updateRestriction(poolId, trancheId, update3); + + // mint new tranche Tokens to users and make sure the balance equals with old token balances + trancheToken.mint(holder1, holderBalance1); + trancheToken.mint(holder2, holderBalance2); + trancheToken.mint(holder3, holderBalance3); + + assertEq(holderBalance1, trancheToken.balanceOf(holder1)); + assertEq(holderBalance2, trancheToken.balanceOf(holder2)); + assertEq(holderBalance3, trancheToken.balanceOf(holder3)); + assertEq(trancheTokenToMigrate.totalSupply(), trancheToken.totalSupply()); + + // burn old tranche tokens using auth transfers + TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder1, self, holderBalance1); + TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder2, self, holderBalance2); + TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder3, self, holderBalance3); + trancheTokenToMigrate.burn(self, holderBalance1); + trancheTokenToMigrate.burn(self, holderBalance2); + trancheTokenToMigrate.burn(self, holderBalance3); + + assertEq(trancheTokenToMigrate.balanceOf(holder1), 0); + assertEq(trancheTokenToMigrate.balanceOf(holder2), 0); + assertEq(trancheTokenToMigrate.balanceOf(holder3), 0); + assertEq(trancheTokenToMigrate.totalSupply(), 0); + + // rename token + trancheTokenToMigrate.file("name", "test"); + trancheTokenToMigrate.file("symbol", "test"); + assertEq(trancheTokenToMigrate.name(), "test"); + assertEq(trancheTokenToMigrate.symbol(), "test"); + } + + function deployNewContracts() internal { + deploy(address(this)); + PermissionlessAdapter adapter = new PermissionlessAdapter(address(gateway)); + wire(address(adapter)); + + // simulate tranche & pool deployments - test is ward on poolManager + // deploy tranche token + poolManager.addPool(poolId); + poolManager.addTranche(poolId, trancheId, name, symbol, decimals, restrictionManager); + trancheToken = Tranche(poolManager.deployTranche(poolId, trancheId)); + // deploy LiquidityPool + poolManager.addAsset(currencyId, currency); + poolManager.allowAsset(poolId, currencyId); + poolManager.deployVault(poolId, trancheId, currency); + } + + function _loadDeployment(string memory folder, string memory name) internal { + deployments.push(vm.readFile(string.concat(vm.projectRoot(), "/deployments/", folder, "/", name, ".json"))); + } + + function _loadFork(uint256 id) internal { + string memory rpcUrl = abi.decode(deployments[id].parseRaw(".rpcUrl"), (string)); + uint256 forkId = vm.createFork(rpcUrl); + vm.selectFork(forkId); + } + + function _get(uint256 id, string memory key) internal view returns (address) { + return abi.decode(deployments[id].parseRaw(key), (address)); + } +} From 8dfcbf25479417b3383c5a9a33e3a6238f895118 Mon Sep 17 00:00:00 2001 From: ilin Date: Fri, 12 Jul 2024 13:14:29 +0200 Subject: [PATCH 02/21] add comments --- test/fork/Migration.t.sol | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/fork/Migration.t.sol b/test/fork/Migration.t.sol index 78be8800..d8565401 100644 --- a/test/fork/Migration.t.sol +++ b/test/fork/Migration.t.sol @@ -40,7 +40,6 @@ contract ForkTest is Deployer, Test { uint128 currencyId = 242333941209166991950178742833476896417; // USDC 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 address currency = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; - // old lp 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd address self; @@ -73,7 +72,7 @@ contract ForkTest is Deployer, Test { // get auth on old TrancheToken through DelayedAdmin - simulate governance vm.startPrank(adminMultiSig); guardianOld.scheduleRely(self); - // get auth on old TrancheToken through Guardian - simulate governance + // get auth on new TrancheToken through Guardian - simulate governance guardian.scheduleRely(self); vm.stopPrank(); // warp delay time = 48H & exec relies @@ -92,35 +91,32 @@ contract ForkTest is Deployer, Test { abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder2).toBytes32(), type(uint64).max); bytes memory update3 = abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder3).toBytes32(), type(uint64).max); - poolManager.updateRestriction(poolId, trancheId, update1); poolManager.updateRestriction(poolId, trancheId, update2); poolManager.updateRestriction(poolId, trancheId, update3); - // mint new tranche Tokens to users and make sure the balance equals with old token balances + // mint new tranche Tokens to users and make sure the balance equals to old tranche token balances trancheToken.mint(holder1, holderBalance1); trancheToken.mint(holder2, holderBalance2); trancheToken.mint(holder3, holderBalance3); - assertEq(holderBalance1, trancheToken.balanceOf(holder1)); assertEq(holderBalance2, trancheToken.balanceOf(holder2)); assertEq(holderBalance3, trancheToken.balanceOf(holder3)); assertEq(trancheTokenToMigrate.totalSupply(), trancheToken.totalSupply()); - // burn old tranche tokens using auth transfers + // burn old tranche tokens using auth transfers & make sure old tranche token supply equals zero TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder1, self, holderBalance1); TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder2, self, holderBalance2); TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder3, self, holderBalance3); trancheTokenToMigrate.burn(self, holderBalance1); trancheTokenToMigrate.burn(self, holderBalance2); trancheTokenToMigrate.burn(self, holderBalance3); - assertEq(trancheTokenToMigrate.balanceOf(holder1), 0); assertEq(trancheTokenToMigrate.balanceOf(holder2), 0); assertEq(trancheTokenToMigrate.balanceOf(holder3), 0); assertEq(trancheTokenToMigrate.totalSupply(), 0); - // rename token + // rename old tranche token trancheTokenToMigrate.file("name", "test"); trancheTokenToMigrate.file("symbol", "test"); assertEq(trancheTokenToMigrate.name(), "test"); From a23c86c4f0e1c5f6adc0ed674164b228fd12df0f Mon Sep 17 00:00:00 2001 From: ilin Date: Mon, 29 Jul 2024 14:07:07 +0200 Subject: [PATCH 03/21] add migration spell --- src/spell/MigrationSpell-mainnet.sol | 100 +++++++++++++++++++++++++++ src/spell/MigrationSpell.t.sol | 89 ++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 src/spell/MigrationSpell-mainnet.sol create mode 100644 src/spell/MigrationSpell.t.sol diff --git a/src/spell/MigrationSpell-mainnet.sol b/src/spell/MigrationSpell-mainnet.sol new file mode 100644 index 00000000..f94bfaab --- /dev/null +++ b/src/spell/MigrationSpell-mainnet.sol @@ -0,0 +1,100 @@ +pragma solidity 0.8.26; + +import {IRoot} from "src/interfaces/IRoot.sol"; +import {IPoolManager} from "src/interfaces/IPoolManager.sol"; +import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; +import {ITranche} from "src/interfaces/token/ITranche.sol"; +import {CastLib} from "src/libraries/CastLib.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +// spell to migrate tranche tokens +contract MigrationSpell { + using CastLib for *; + + // addresses of the old liquidity pool deployment + address public constant TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; + address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + + // addresses of the new liquidity pool deployment + address public constant ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + address public constant POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set + address public constant RESTRICTIONMANEGER = 0x0000000000000000000000000000000000000000; // TODO - set + ITranche public trancheTokenNew; // to be deployed during spell exec + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + uint64 public constant POOL_ID = 4139607887; + bytes16 public constant TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; + uint8 public constant DECIMALS = 6; + string public constant NAME = "Anemoy Liquid Treasury Fund 1"; + string public constant SYMBOL = "LTF"; + + string public constant NAME_OLD = "DEPRECATED"; + string public constant SYMBOL_OLD = "DEPRECATED"; + + // addresses of the holders of the old tranche token + address[] public trancheTokenHolders = [ + 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997, + 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E, + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936 + ]; + + bool public done; + + uint256 constant ONE = 10 ** 27; + address self; + + function cast() public { + require(!done, "spell-already-cast"); + done = true; + execute(); + } + + function execute() internal { + self = address(this); + IRoot rootOld = IRoot(address(ROOT_OLD)); + IRoot rootNew = IRoot(address(ROOT_NEW)); + IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); + ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); + + // deploy new tranche token + rootNew.relyContract(address(POOLMANAGER), self); + poolManager.addPool(POOL_ID); + poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANEGER); + trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); + rootNew.relyContract(address(trancheTokenNew), self); + + // transfer old tokens from holders` wallets + // add holders to the allowlist of new tranche token + // mint new tokens to holders' wallets + uint256 holderBalance; + for (uint8 i; i < trancheTokenHolders.length; i++) { + holderBalance = trancheTokenOld.balanceOf(trancheTokenHolders[i]); + + // mint new token to the holders wallet + poolManager.updateRestriction( + POOL_ID, + TRANCHE_ID, + abi.encodePacked( + uint8(RestrictionUpdate.UpdateMember), address(trancheTokenHolders[i]).toBytes32(), type(uint64).max + ) + ); // add to allowlist + trancheTokenNew.mint(trancheTokenHolders[i], holderBalance); + ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(trancheTokenHolders[i], self, holderBalance); + } + // burn entire supply of old tranche tokens + trancheTokenOld.burn(self, trancheTokenOld.balanceOf(self)); + + // rename old tranche token + trancheTokenOld.file("name", NAME_OLD); + trancheTokenOld.file("symbol", SYMBOL_OLD); + + // denies + } + + function getNumberOfMigratedHolders() public view returns (uint256) { + return trancheTokenHolders.length; + } +} diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol new file mode 100644 index 00000000..05dea871 --- /dev/null +++ b/src/spell/MigrationSpell.t.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.26; + +import {Guardian} from "src/admin/Guardian.sol"; +import "./MigrationSpell-mainnet.sol"; +import "forge-std/Test.sol"; +import "forge-std/StdJson.sol"; + +contract MigrationSpellTest is Test { + using stdJson for string; + + string[] deployments; + MigrationSpell spell; + + // set this variables custom for each network + Guardian guardianOld = Guardian(address(0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028)); + Guardian guardianNew = Guardian(address(0x0000000000000000000000000000000000000000)); // Todo set address + address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + + address self; + + ITranche trancheTokenOld; + + function setUp() public { + self = address(this); + _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet + _loadFork(0); + spell = new MigrationSpell(); + + trancheTokenOld = ITranche(spell.TRANCHE_TOKEN_OLD()); + } + + function testMigration() public { + // check if spell is migrating all the current token holders + uint256 holdersSupplySum; + uint256[] memory trancheTokenHolderBalancesOld = new uint256[](spell.getNumberOfMigratedHolders()); + uint256 balanceOld; + + for (uint8 i; i < spell.getNumberOfMigratedHolders(); i++) { + balanceOld = trancheTokenOld.balanceOf(spell.trancheTokenHolders(i)); + trancheTokenHolderBalancesOld[i] = balanceOld; + holdersSupplySum += balanceOld; + } + assertEq(trancheTokenOld.totalSupply(), holdersSupplySum); + + // simulate manual governance steps + vm.startPrank(adminMultiSig); + guardianOld.scheduleRely(self); + guardianNew.scheduleRely(self); + vm.stopPrank(); + // warp delay time = 48H & exec relies + vm.warp(block.timestamp + 2 days); + IRoot(spell.ROOT_OLD()).executeScheduledRely(self); + IRoot(spell.ROOT_NEW()).executeScheduledRely(self); + + // cast spell + spell.cast(); + + // for all holders check if balance was migrated correctly + uint256 balanceNew; + for (uint8 i; i < spell.getNumberOfMigratedHolders(); i++) { + balanceNew = spell.trancheTokenNew().balanceOf(spell.trancheTokenHolders(i)); + // assert users new token balance equals old token balance + assertEq(trancheTokenHolderBalancesOld[i], balanceNew); + // assert old tokens got removed from user wallet + assertEq(trancheTokenOld.balanceOf(spell.trancheTokenHolders(i)), 0); + } + // assert total new supply equeals total old supply + assertEq(spell.trancheTokenNew().totalSupply(), holdersSupplySum); + // assert all old tokens burned + assertEq(trancheTokenOld.totalSupply(), 0); + + // assert renaming worked + } + + function _loadDeployment(string memory folder, string memory name) internal { + deployments.push(vm.readFile(string.concat(vm.projectRoot(), "/deployments/", folder, "/", name, ".json"))); + } + + function _loadFork(uint256 id) internal { + string memory rpcUrl = abi.decode(deployments[id].parseRaw(".rpcUrl"), (string)); + uint256 forkId = vm.createFork(rpcUrl); + vm.selectFork(forkId); + } + + function _get(uint256 id, string memory key) internal view returns (address) { + return abi.decode(deployments[id].parseRaw(key), (address)); + } +} From ac67490d2adf2c1db83fec7169ca6c4b7abd9bf8 Mon Sep 17 00:00:00 2001 From: ilin Date: Mon, 29 Jul 2024 14:11:06 +0200 Subject: [PATCH 04/21] add migration spell --- src/spell/MigrationSpell.t.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol index 05dea871..396dec29 100644 --- a/src/spell/MigrationSpell.t.sol +++ b/src/spell/MigrationSpell.t.sol @@ -70,7 +70,9 @@ contract MigrationSpellTest is Test { // assert all old tokens burned assertEq(trancheTokenOld.totalSupply(), 0); - // assert renaming worked + // assert renaming of old trancheToken worked + assertEq(trancheTokenOld.name(), spell.NAME_OLD()); + assertEq(trancheTokenOld.symbol(), spell.SYMBOL_OLD()); } function _loadDeployment(string memory folder, string memory name) internal { From f0e494554415e43ca83cab240770d7edbbdf63ff Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Tue, 30 Jul 2024 14:47:51 -0400 Subject: [PATCH 05/21] migrate all members to new memberlist and claim any unclaimed tokens --- src/spell/MigrationSpell-mainnet.sol | 72 ++++++++++++++++++++-------- src/spell/MigrationSpell.t.sol | 14 +++--- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/spell/MigrationSpell-mainnet.sol b/src/spell/MigrationSpell-mainnet.sol index f94bfaab..5128d0a8 100644 --- a/src/spell/MigrationSpell-mainnet.sol +++ b/src/spell/MigrationSpell-mainnet.sol @@ -4,6 +4,7 @@ import {IRoot} from "src/interfaces/IRoot.sol"; import {IPoolManager} from "src/interfaces/IPoolManager.sol"; import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; import {ITranche} from "src/interfaces/token/ITranche.sol"; +import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {CastLib} from "src/libraries/CastLib.sol"; interface ITrancheOld { @@ -17,11 +18,14 @@ contract MigrationSpell { // addresses of the old liquidity pool deployment address public constant TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + address public constant VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; // liquidityPool // addresses of the new liquidity pool deployment address public constant ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set address public constant POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set - address public constant RESTRICTIONMANEGER = 0x0000000000000000000000000000000000000000; // TODO - set + address public constant RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set ITranche public trancheTokenNew; // to be deployed during spell exec // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens @@ -34,18 +38,38 @@ contract MigrationSpell { string public constant NAME_OLD = "DEPRECATED"; string public constant SYMBOL_OLD = "DEPRECATED"; - // addresses of the holders of the old tranche token - address[] public trancheTokenHolders = [ + // // addresses of the holders of the old tranche token + // address[] public trancheTokenHolders = [ + // 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997, + // 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E, + // 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936 + // ]; + + address[] public memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0xeF08Bb6F5F9494faf2316402802e54089E6322eb, 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997, + 0xeEDC395aAAb05e5fb6130A8C5AEbAE48E7739B78, 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E, - 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936 + 0x14FFe68D005e58f08c27dC0c999f75639682276c, + 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 ]; + mapping(address => uint256) public validUntil; bool public done; - uint256 constant ONE = 10 ** 27; address self; + constructor() { + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0xeF08Bb6F5F9494faf2316402802e54089E6322eb] = 2017150288; + validUntil[0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997] = 2017323212; + validUntil[0xeEDC395aAAb05e5fb6130A8C5AEbAE48E7739B78] = 3745713365; + validUntil[0x2923c1B5313F7375fdaeE80b7745106deBC1b53E] = 2031229099; + validUntil[0x14FFe68D005e58f08c27dC0c999f75639682276c] = 2035299660; + validUntil[0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561] = 2037188261; + } + function cast() public { require(!done, "spell-already-cast"); done = true; @@ -57,33 +81,43 @@ contract MigrationSpell { IRoot rootOld = IRoot(address(ROOT_OLD)); IRoot rootNew = IRoot(address(ROOT_NEW)); IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); + IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); // deploy new tranche token rootNew.relyContract(address(POOLMANAGER), self); poolManager.addPool(POOL_ID); - poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANEGER); + poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); rootNew.relyContract(address(trancheTokenNew), self); - // transfer old tokens from holders` wallets - // add holders to the allowlist of new tranche token - // mint new tokens to holders' wallets - uint256 holderBalance; - for (uint8 i; i < trancheTokenHolders.length; i++) { - holderBalance = trancheTokenOld.balanceOf(trancheTokenHolders[i]); - // mint new token to the holders wallet + // add all old members to new memberlist and claim any tokens + uint256 holderBalance; + uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); + for (uint8 i; i < memberlistMembers.length; i++) { + // add member to new memberlist poolManager.updateRestriction( POOL_ID, TRANCHE_ID, abi.encodePacked( - uint8(RestrictionUpdate.UpdateMember), address(trancheTokenHolders[i]).toBytes32(), type(uint64).max + uint8(RestrictionUpdate.UpdateMember), address(memberlistMembers[i]).toBytes32(), validUntil[memberlistMembers[i]] ) - ); // add to allowlist - trancheTokenNew.mint(trancheTokenHolders[i], holderBalance); - ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(trancheTokenHolders[i], self, holderBalance); + ); + + if (escrowBalance > 0) { + // Claim any unclaimed tokens the user may have + investmentManagerOld.mint(VAULT_OLD, investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), memberlistMembers[i], memberlistMembers[i]); + } + holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); + if (holderBalance > 0) { + // mint new token to the holder's wallet + trancheTokenNew.mint(memberlistMembers[i], holderBalance); + // transfer old tokens from holders' wallets + ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); + } } + // burn entire supply of old tranche tokens trancheTokenOld.burn(self, trancheTokenOld.balanceOf(self)); @@ -94,7 +128,7 @@ contract MigrationSpell { // denies } - function getNumberOfMigratedHolders() public view returns (uint256) { - return trancheTokenHolders.length; + function getNumberOfMigratedMembers() public view returns (uint256) { + return memberlistMembers.length; } } diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol index 396dec29..384b41ad 100644 --- a/src/spell/MigrationSpell.t.sol +++ b/src/spell/MigrationSpell.t.sol @@ -14,7 +14,7 @@ contract MigrationSpellTest is Test { // set this variables custom for each network Guardian guardianOld = Guardian(address(0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028)); - Guardian guardianNew = Guardian(address(0x0000000000000000000000000000000000000000)); // Todo set address + Guardian guardianNew = Guardian(address(0x0000000000000000000000000000000000000000)); // TODO set address address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; address self; @@ -33,11 +33,11 @@ contract MigrationSpellTest is Test { function testMigration() public { // check if spell is migrating all the current token holders uint256 holdersSupplySum; - uint256[] memory trancheTokenHolderBalancesOld = new uint256[](spell.getNumberOfMigratedHolders()); + uint256[] memory trancheTokenHolderBalancesOld = new uint256[](spell.getNumberOfMigratedMembers()); uint256 balanceOld; - for (uint8 i; i < spell.getNumberOfMigratedHolders(); i++) { - balanceOld = trancheTokenOld.balanceOf(spell.trancheTokenHolders(i)); + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + balanceOld = trancheTokenOld.balanceOf(spell.memberlistMembers(i)); trancheTokenHolderBalancesOld[i] = balanceOld; holdersSupplySum += balanceOld; } @@ -58,12 +58,12 @@ contract MigrationSpellTest is Test { // for all holders check if balance was migrated correctly uint256 balanceNew; - for (uint8 i; i < spell.getNumberOfMigratedHolders(); i++) { - balanceNew = spell.trancheTokenNew().balanceOf(spell.trancheTokenHolders(i)); + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + balanceNew = spell.trancheTokenNew().balanceOf(spell.memberlistMembers(i)); // assert users new token balance equals old token balance assertEq(trancheTokenHolderBalancesOld[i], balanceNew); // assert old tokens got removed from user wallet - assertEq(trancheTokenOld.balanceOf(spell.trancheTokenHolders(i)), 0); + assertEq(trancheTokenOld.balanceOf(spell.memberlistMembers(i)), 0); } // assert total new supply equeals total old supply assertEq(spell.trancheTokenNew().totalSupply(), holdersSupplySum); From 1c2bbbb32b34e3ab4670f674d154a932dabd1aca Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Tue, 30 Jul 2024 15:03:49 -0400 Subject: [PATCH 06/21] Add denies --- src/spell/MigrationSpell-mainnet.sol | 8 +++++++- src/spell/MigrationSpell.t.sol | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/spell/MigrationSpell-mainnet.sol b/src/spell/MigrationSpell-mainnet.sol index 5128d0a8..7bb95605 100644 --- a/src/spell/MigrationSpell-mainnet.sol +++ b/src/spell/MigrationSpell-mainnet.sol @@ -81,8 +81,9 @@ contract MigrationSpell { IRoot rootOld = IRoot(address(ROOT_OLD)); IRoot rootNew = IRoot(address(ROOT_NEW)); IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); - IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); + IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); + rootOld.relyContract(address(investmentManagerOld), self); // deploy new tranche token rootNew.relyContract(address(POOLMANAGER), self); @@ -126,6 +127,11 @@ contract MigrationSpell { trancheTokenOld.file("symbol", SYMBOL_OLD); // denies + rootNew.denyContract(address(POOLMANAGER), self); + rootNew.denyContract(address(trancheTokenNew), self); + rootOld.denyContract(address(investmentManagerOld), self); + rootOld.deny(self); + rootNew.deny(self); } function getNumberOfMigratedMembers() public view returns (uint256) { diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol index 384b41ad..2d3e7a15 100644 --- a/src/spell/MigrationSpell.t.sol +++ b/src/spell/MigrationSpell.t.sol @@ -73,6 +73,13 @@ contract MigrationSpellTest is Test { // assert renaming of old trancheToken worked assertEq(trancheTokenOld.name(), spell.NAME_OLD()); assertEq(trancheTokenOld.symbol(), spell.SYMBOL_OLD()); + + // assert denies + assertEq(spell.POOLMANAGER().wards(address(spell)), 0); + assertEq(spell.trancheTokenNew().wards(address(spell)), 0); + assertEq(spell.INVESTMENTMANAGER_OLD().wards(address(spell)), 0); + assertEq(spell.ROOT_OLD().wards(address(spell)), 0); + assertEq(spell.ROOT_NEW().wards(address(spell)), 0); } function _loadDeployment(string memory folder, string memory name) internal { From b809f8bfd3d02e06117c2e68b3d8a19cb96fdf9a Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Tue, 30 Jul 2024 15:11:47 -0400 Subject: [PATCH 07/21] fix build --- src/spell/MigrationSpell-mainnet.sol | 5 +++-- src/spell/MigrationSpell.t.sol | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/spell/MigrationSpell-mainnet.sol b/src/spell/MigrationSpell-mainnet.sol index 7bb95605..2fa6c4dc 100644 --- a/src/spell/MigrationSpell-mainnet.sol +++ b/src/spell/MigrationSpell-mainnet.sol @@ -6,6 +6,7 @@ import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; import {ITranche} from "src/interfaces/token/ITranche.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {CastLib} from "src/libraries/CastLib.sol"; +import {IAuth} from "src/interfaces/IAuth.sol"; interface ITrancheOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); @@ -130,8 +131,8 @@ contract MigrationSpell { rootNew.denyContract(address(POOLMANAGER), self); rootNew.denyContract(address(trancheTokenNew), self); rootOld.denyContract(address(investmentManagerOld), self); - rootOld.deny(self); - rootNew.deny(self); + IAuth(address(rootOld)).deny(self); + IAuth(address(rootNew)).deny(self); } function getNumberOfMigratedMembers() public view returns (uint256) { diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol index 2d3e7a15..c7e3d4e2 100644 --- a/src/spell/MigrationSpell.t.sol +++ b/src/spell/MigrationSpell.t.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.26; import {Guardian} from "src/admin/Guardian.sol"; +import {Auth} from "src/Auth.sol"; import "./MigrationSpell-mainnet.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; @@ -75,11 +76,11 @@ contract MigrationSpellTest is Test { assertEq(trancheTokenOld.symbol(), spell.SYMBOL_OLD()); // assert denies - assertEq(spell.POOLMANAGER().wards(address(spell)), 0); - assertEq(spell.trancheTokenNew().wards(address(spell)), 0); - assertEq(spell.INVESTMENTMANAGER_OLD().wards(address(spell)), 0); - assertEq(spell.ROOT_OLD().wards(address(spell)), 0); - assertEq(spell.ROOT_NEW().wards(address(spell)), 0); + assertEq(Auth(spell.POOLMANAGER()).wards(address(spell)), 0); + assertEq(Auth(address(spell.trancheTokenNew())).wards(address(spell)), 0); + assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); + assertEq(Auth(spell.ROOT_OLD()).wards(address(spell)), 0); + assertEq(Auth(spell.ROOT_NEW()).wards(address(spell)), 0); } function _loadDeployment(string memory folder, string memory name) internal { From 192232167edb0c278ec4dabd9b10954c9f20297d Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Tue, 30 Jul 2024 20:34:20 -0400 Subject: [PATCH 08/21] update fork test --- src/spell/MigrationSpell-mainnet.sol | 21 +++- src/spell/MigrationSpell.t.sol | 9 +- test/fork/Migration.t.sol | 148 +++++++++++++++++---------- 3 files changed, 119 insertions(+), 59 deletions(-) diff --git a/src/spell/MigrationSpell-mainnet.sol b/src/spell/MigrationSpell-mainnet.sol index 2fa6c4dc..3f2c8a62 100644 --- a/src/spell/MigrationSpell-mainnet.sol +++ b/src/spell/MigrationSpell-mainnet.sol @@ -16,6 +16,9 @@ interface ITrancheOld { contract MigrationSpell { using CastLib for *; + address public constant CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC + uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896417; + // addresses of the old liquidity pool deployment address public constant TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; @@ -56,7 +59,7 @@ contract MigrationSpell { 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 ]; - mapping(address => uint256) public validUntil; + mapping(address => uint64) public validUntil; bool public done; uint256 constant ONE = 10 ** 27; address self; @@ -90,10 +93,11 @@ contract MigrationSpell { rootNew.relyContract(address(POOLMANAGER), self); poolManager.addPool(POOL_ID); poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); + poolManager.addAsset(CURRENCY_ID, CURRENCY); + poolManager.allowAsset(POOL_ID, CURRENCY_ID); trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); rootNew.relyContract(address(trancheTokenNew), self); - // add all old members to new memberlist and claim any tokens uint256 holderBalance; uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); @@ -103,13 +107,20 @@ contract MigrationSpell { POOL_ID, TRANCHE_ID, abi.encodePacked( - uint8(RestrictionUpdate.UpdateMember), address(memberlistMembers[i]).toBytes32(), validUntil[memberlistMembers[i]] + uint8(RestrictionUpdate.UpdateMember), + address(memberlistMembers[i]).toBytes32(), + validUntil[memberlistMembers[i]] ) ); if (escrowBalance > 0) { // Claim any unclaimed tokens the user may have - investmentManagerOld.mint(VAULT_OLD, investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), memberlistMembers[i], memberlistMembers[i]); + investmentManagerOld.mint( + VAULT_OLD, + investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), + memberlistMembers[i], + memberlistMembers[i] + ); } holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); if (holderBalance > 0) { @@ -133,6 +144,8 @@ contract MigrationSpell { rootOld.denyContract(address(investmentManagerOld), self); IAuth(address(rootOld)).deny(self); IAuth(address(rootNew)).deny(self); + + poolManager.deployVault(POOL_ID, TRANCHE_ID, CURRENCY); } function getNumberOfMigratedMembers() public view returns (uint256) { diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol index c7e3d4e2..b2d2c412 100644 --- a/src/spell/MigrationSpell.t.sol +++ b/src/spell/MigrationSpell.t.sol @@ -57,7 +57,7 @@ contract MigrationSpellTest is Test { // cast spell spell.cast(); - // for all holders check if balance was migrated correctly + // for all members check if balance was migrated correctly uint256 balanceNew; for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { balanceNew = spell.trancheTokenNew().balanceOf(spell.memberlistMembers(i)); @@ -66,6 +66,8 @@ contract MigrationSpellTest is Test { // assert old tokens got removed from user wallet assertEq(trancheTokenOld.balanceOf(spell.memberlistMembers(i)), 0); } + // assert all old tokens were claimed from escrow + assertEq(trancheTokenOld.balanceOf(spell.ESCROW_OLD()), 0); // assert total new supply equeals total old supply assertEq(spell.trancheTokenNew().totalSupply(), holdersSupplySum); // assert all old tokens burned @@ -75,6 +77,11 @@ contract MigrationSpellTest is Test { assertEq(trancheTokenOld.name(), spell.NAME_OLD()); assertEq(trancheTokenOld.symbol(), spell.SYMBOL_OLD()); + // assert new trancheToken metadata + assertEq(spell.trancheTokenNew().name(), spell.NAME()); + assertEq(spell.trancheTokenNew().symbol(), spell.SYMBOL()); + assertEq(spell.trancheTokenNew().decimals(), spell.DECIMALS()); + // assert denies assertEq(Auth(spell.POOLMANAGER()).wards(address(spell)), 0); assertEq(Auth(address(spell.trancheTokenNew())).wards(address(spell)), 0); diff --git a/test/fork/Migration.t.sol b/test/fork/Migration.t.sol index d8565401..ec78a17d 100644 --- a/test/fork/Migration.t.sol +++ b/test/fork/Migration.t.sol @@ -8,6 +8,9 @@ import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; import {BytesLib} from "src/libraries/BytesLib.sol"; import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; +import {MigrationSpell} from "src/spell/MigrationSpell-mainnet.sol"; +import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; +import {Auth} from "src/Auth.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; @@ -32,19 +35,17 @@ contract ForkTest is Deployer, Test { address guardianOld_ = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; address rootOld_ = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; - uint64 poolId = 4139607887; - bytes16 trancheId = 0x97aa65f23e7be09fcd62d0554d2e9273; - uint8 decimals = 6; - string name = "Anemoy Liquid Treasury Fund 1"; - string symbol = "LTF"; - uint128 currencyId = 242333941209166991950178742833476896417; // USDC 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 - address currency = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + MigrationSpell spell; + address self; function setUp() public virtual { self = address(this); + + spell = new MigrationSpell(); + _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet _loadFork(0); trancheTokenToMigrate = Tranche(address(tokenToMigrate_)); // Anemoy Liquid Treasury Fund 1 (LTF) @@ -59,15 +60,11 @@ contract ForkTest is Deployer, Test { } function testTrancheTokenMigration() public { - address holder1 = 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997; - address holder2 = 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E; - address holder3 = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - - // load all holder balances and check whether they all add up to totalSupply - uint256 holderBalance1 = trancheTokenToMigrate.balanceOf(holder1); - uint256 holderBalance2 = trancheTokenToMigrate.balanceOf(holder2); - uint256 holderBalance3 = trancheTokenToMigrate.balanceOf(holder3); - assertEq((holderBalance1 + holderBalance2 + holderBalance3), trancheTokenToMigrate.totalSupply()); + uint256 totalSupply = 0; + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + totalSupply += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); + } + assertEq(trancheTokenToMigrate.totalSupply(), totalSupply); // get auth on old TrancheToken through DelayedAdmin - simulate governance vm.startPrank(adminMultiSig); @@ -81,46 +78,87 @@ contract ForkTest is Deployer, Test { root.executeScheduledRely(self); // exec auth relies rootOld.relyContract(address(trancheTokenToMigrate), self); + rootOld.relyContract(spell.INVESTMENTMANAGER_OLD(), self); root.relyContract(address(trancheToken), self); root.relyContract(address(poolManager), self); - // // add holders to the allowlist of new token - simulate governance - bytes memory update1 = - abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder1).toBytes32(), type(uint64).max); - bytes memory update2 = - abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder2).toBytes32(), type(uint64).max); - bytes memory update3 = - abi.encodePacked(uint8(RestrictionUpdate.UpdateMember), address(holder3).toBytes32(), type(uint64).max); - poolManager.updateRestriction(poolId, trancheId, update1); - poolManager.updateRestriction(poolId, trancheId, update2); - poolManager.updateRestriction(poolId, trancheId, update3); - - // mint new tranche Tokens to users and make sure the balance equals to old tranche token balances - trancheToken.mint(holder1, holderBalance1); - trancheToken.mint(holder2, holderBalance2); - trancheToken.mint(holder3, holderBalance3); - assertEq(holderBalance1, trancheToken.balanceOf(holder1)); - assertEq(holderBalance2, trancheToken.balanceOf(holder2)); - assertEq(holderBalance3, trancheToken.balanceOf(holder3)); + // add holders to the allowlist of new token - simulate governance + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + bytes memory update = abi.encodePacked( + uint8(RestrictionUpdate.UpdateMember), + spell.memberlistMembers(i).toBytes32(), + spell.validUntil(spell.memberlistMembers(i)) + ); + poolManager.updateRestriction(spell.POOL_ID(), spell.TRANCHE_ID(), update); + + uint256 escrowBalance = trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()); + if (escrowBalance > 0) { + uint256 maxMint = IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).maxMint( + spell.VAULT_OLD(), spell.memberlistMembers(i) + ); + if (maxMint > 0) { + IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).mint( + spell.VAULT_OLD(), maxMint, spell.memberlistMembers(i), spell.memberlistMembers(i) + ); + } + } + uint256 holderBalance = trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); + if (holderBalance > 0) { + trancheToken.mint(spell.memberlistMembers(i), holderBalance); + assertEq(trancheToken.balanceOf(spell.memberlistMembers(i)), holderBalance); + TrancheTokenOld(address(trancheTokenToMigrate)).authTransferFrom( + spell.memberlistMembers(i), self, holderBalance + ); + } + } + + // check if all holders have been migrated correctly + uint256 totalSupplyNew = 0; + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + uint256 balanceNew = trancheToken.balanceOf(spell.memberlistMembers(i)); + totalSupplyNew += balanceNew; + assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); + } + assertEq(trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()), 0); + assertEq(trancheToken.totalSupply(), totalSupplyNew); assertEq(trancheTokenToMigrate.totalSupply(), trancheToken.totalSupply()); // burn old tranche tokens using auth transfers & make sure old tranche token supply equals zero - TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder1, self, holderBalance1); - TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder2, self, holderBalance2); - TrancheTokenOld(tokenToMigrate_).authTransferFrom(holder3, self, holderBalance3); - trancheTokenToMigrate.burn(self, holderBalance1); - trancheTokenToMigrate.burn(self, holderBalance2); - trancheTokenToMigrate.burn(self, holderBalance3); - assertEq(trancheTokenToMigrate.balanceOf(holder1), 0); - assertEq(trancheTokenToMigrate.balanceOf(holder2), 0); - assertEq(trancheTokenToMigrate.balanceOf(holder3), 0); + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + uint256 balance = trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); + if (balance > 0) { + TrancheTokenOld(tokenToMigrate_).authTransferFrom(spell.memberlistMembers(i), self, balance); + } + assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); + } + uint256 balance = trancheTokenToMigrate.balanceOf(self); + trancheTokenToMigrate.burn(self, balance); + assertEq(trancheTokenToMigrate.totalSupply(), 0); // rename old tranche token - trancheTokenToMigrate.file("name", "test"); - trancheTokenToMigrate.file("symbol", "test"); - assertEq(trancheTokenToMigrate.name(), "test"); - assertEq(trancheTokenToMigrate.symbol(), "test"); + trancheTokenToMigrate.file("name", spell.NAME_OLD()); + trancheTokenToMigrate.file("symbol", spell.SYMBOL_OLD()); + assertEq(trancheTokenToMigrate.name(), spell.SYMBOL_OLD()); + assertEq(trancheTokenToMigrate.symbol(), spell.SYMBOL_OLD()); + + // assert new trancheToken metadata + assertEq(trancheToken.name(), spell.NAME()); + assertEq(trancheToken.symbol(), spell.SYMBOL()); + assertEq(trancheToken.decimals(), spell.DECIMALS()); + + // deny contracts + rootOld.denyContract(address(trancheTokenToMigrate), self); + rootOld.denyContract(spell.INVESTMENTMANAGER_OLD(), self); + root.denyContract(address(trancheToken), self); + + root.denyContract(address(poolManager), self); + // assert denies + assertEq(Auth(address(poolManager)).wards(address(spell)), 0); + assertEq(Auth(address(trancheToken)).wards(address(spell)), 0); + assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); + assertEq(Auth(address(rootOld)).wards(address(spell)), 0); + } function deployNewContracts() internal { @@ -130,13 +168,15 @@ contract ForkTest is Deployer, Test { // simulate tranche & pool deployments - test is ward on poolManager // deploy tranche token - poolManager.addPool(poolId); - poolManager.addTranche(poolId, trancheId, name, symbol, decimals, restrictionManager); - trancheToken = Tranche(poolManager.deployTranche(poolId, trancheId)); - // deploy LiquidityPool - poolManager.addAsset(currencyId, currency); - poolManager.allowAsset(poolId, currencyId); - poolManager.deployVault(poolId, trancheId, currency); + poolManager.addPool(spell.POOL_ID()); + poolManager.addTranche( + spell.POOL_ID(), spell.TRANCHE_ID(), spell.NAME(), spell.SYMBOL(), spell.DECIMALS(), restrictionManager + ); + trancheToken = Tranche(poolManager.deployTranche(spell.POOL_ID(), spell.TRANCHE_ID())); + + poolManager.addAsset(spell.CURRENCY_ID(), spell.CURRENCY()); + poolManager.allowAsset(spell.POOL_ID(), spell.CURRENCY_ID()); + poolManager.deployVault(spell.POOL_ID(), spell.TRANCHE_ID(), spell.CURRENCY()); } function _loadDeployment(string memory folder, string memory name) internal { From 77f62b1a13c4ea855e225c039ff3d599d33b2ba0 Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Wed, 31 Jul 2024 16:34:54 -0400 Subject: [PATCH 09/21] upgrade fork test, fix a missing rely and use maxMint instead of escrow balance --- src/spell/MigrationSpell.t.sol | 2 +- src/spell/ShareMigrationDYFEVM.sol | 149 +++++++++++++ ...l-mainnet.sol => ShareMigrationLTFEVM.sol} | 73 ++++--- test/fork/Migration.t.sol | 195 ------------------ test/fork/ShareMigration.t.sol | 137 ++++++++++++ 5 files changed, 328 insertions(+), 228 deletions(-) create mode 100644 src/spell/ShareMigrationDYFEVM.sol rename src/spell/{MigrationSpell-mainnet.sol => ShareMigrationLTFEVM.sol} (72%) delete mode 100644 test/fork/Migration.t.sol create mode 100644 test/fork/ShareMigration.t.sol diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol index b2d2c412..218b56cb 100644 --- a/src/spell/MigrationSpell.t.sol +++ b/src/spell/MigrationSpell.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.26; import {Guardian} from "src/admin/Guardian.sol"; import {Auth} from "src/Auth.sol"; -import "./MigrationSpell-mainnet.sol"; +import "./ShareMigrationLTFEVM.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; diff --git a/src/spell/ShareMigrationDYFEVM.sol b/src/spell/ShareMigrationDYFEVM.sol new file mode 100644 index 00000000..72cf011a --- /dev/null +++ b/src/spell/ShareMigrationDYFEVM.sol @@ -0,0 +1,149 @@ +pragma solidity 0.8.26; + +import {IRoot} from "src/interfaces/IRoot.sol"; +import {IPoolManager} from "src/interfaces/IPoolManager.sol"; +import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; +import {ITranche} from "src/interfaces/token/ITranche.sol"; +import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; +import {CastLib} from "src/libraries/CastLib.sol"; +import {IAuth} from "src/interfaces/IAuth.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +// spell to migrate tranche tokens +contract MigrationSpell { + using CastLib for *; + + // old deployment addresses + address public constant CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC + uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896417; + address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + address public constant ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + address public constant GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + address public constant TRANCHE_TOKEN_OLD = 0x143dB3a0d0679DFd3372e7F3877BbBB27da3f5e4; + address public constant VAULT_OLD = 0x110379504D933BeD2E485E281bc3909D1E7C9E5D; + + // new deployment addresses + address public ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + address public POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set + address public RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set + ITranche public trancheTokenNew; // to be deployed during spell exec + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + uint64 public constant POOL_ID = 1655476167; + bytes16 public constant TRANCHE_ID = 0x4859c6f181b1b993c35b313bedb949cf; + uint8 public constant DECIMALS = 6; + string public constant NAME = "Anemoy DeFi Yield Fund 1 SP DeFi Yield Fund Token"; + string public constant SYMBOL = "DYF"; + + string public constant NAME_OLD = "DEPRECATED"; + string public constant SYMBOL_OLD = "DEPRECATED"; + + address[] public memberlistMembers = + [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997]; + + mapping(address => uint64) public validUntil; + bool public done; + uint256 constant ONE = 10 ** 27; + address self; + + constructor() { + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997] = 2032178598; + } + + function cast() public { + require(!done, "spell-already-cast"); + done = true; + execute(); + } + + function testCast(address ROOT_NEW_, address POOLMANAGER_, address RESTRICTIONMANAGER_) public { + require(!done, "spell-already-cast"); + done = true; + ROOT_NEW = ROOT_NEW_; + POOLMANAGER = POOLMANAGER_; + RESTRICTIONMANAGER = RESTRICTIONMANAGER_; + execute(); + } + + function execute() internal { + self = address(this); + IRoot rootOld = IRoot(address(ROOT_OLD)); + IRoot rootNew = IRoot(address(ROOT_NEW)); + IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); + ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); + IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); + rootOld.relyContract(address(investmentManagerOld), self); + rootOld.relyContract(address(trancheTokenOld), self); + + // deploy new tranche token + rootNew.relyContract(address(POOLMANAGER), self); + poolManager.addPool(POOL_ID); + poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); + poolManager.addAsset(CURRENCY_ID, CURRENCY); + poolManager.allowAsset(POOL_ID, CURRENCY_ID); + trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); + rootNew.relyContract(address(trancheTokenNew), self); + + // add all old members to new memberlist and claim any tokens + uint256 holderBalance; + uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); + for (uint8 i; i < memberlistMembers.length; i++) { + // add member to new memberlist + poolManager.updateRestriction( + POOL_ID, + TRANCHE_ID, + abi.encodePacked( + uint8(RestrictionUpdate.UpdateMember), + address(memberlistMembers[i]).toBytes32(), + validUntil[memberlistMembers[i]] + ) + ); + + if (escrowBalance > 0) { + // Claim any unclaimed tokens the user may have + investmentManagerOld.mint( + VAULT_OLD, + investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), + memberlistMembers[i], + memberlistMembers[i] + ); + } + holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); + if (holderBalance > 0) { + // mint new token to the holder's wallet + trancheTokenNew.mint(memberlistMembers[i], holderBalance); + // transfer old tokens from holders' wallets + ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); + } + } + + // burn entire supply of old tranche tokens + trancheTokenOld.burn(self, trancheTokenOld.balanceOf(self)); + + // rename old tranche token + trancheTokenOld.file("name", NAME_OLD); + trancheTokenOld.file("symbol", SYMBOL_OLD); + + // denies + rootNew.denyContract(address(POOLMANAGER), self); + rootNew.denyContract(address(trancheTokenNew), self); + rootOld.denyContract(address(trancheTokenOld), self); + rootOld.denyContract(address(investmentManagerOld), self); + IAuth(address(rootOld)).deny(self); + IAuth(address(rootNew)).deny(self); + + poolManager.deployVault(POOL_ID, TRANCHE_ID, CURRENCY); + } + + function getNumberOfMigratedMembers() public view returns (uint256) { + return memberlistMembers.length; + } +} diff --git a/src/spell/MigrationSpell-mainnet.sol b/src/spell/ShareMigrationLTFEVM.sol similarity index 72% rename from src/spell/MigrationSpell-mainnet.sol rename to src/spell/ShareMigrationLTFEVM.sol index 3f2c8a62..6e476431 100644 --- a/src/spell/MigrationSpell-mainnet.sol +++ b/src/spell/ShareMigrationLTFEVM.sol @@ -16,20 +16,23 @@ interface ITrancheOld { contract MigrationSpell { using CastLib for *; + // old deployment addresses address public constant CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896417; - - // addresses of the old liquidity pool deployment - address public constant TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; - address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; - address public constant VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; // liquidityPool + address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + address public constant ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + address public constant GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; - // addresses of the new liquidity pool deployment - address public constant ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set - address public constant POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set - address public constant RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set + // old pool addresses + address public constant TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; + address public constant VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; + + // new deployment addresses + address public ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + address public POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + address public RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant ITranche public trancheTokenNew; // to be deployed during spell exec // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens @@ -42,13 +45,6 @@ contract MigrationSpell { string public constant NAME_OLD = "DEPRECATED"; string public constant SYMBOL_OLD = "DEPRECATED"; - // // addresses of the holders of the old tranche token - // address[] public trancheTokenHolders = [ - // 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997, - // 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E, - // 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936 - // ]; - address[] public memberlistMembers = [ 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0xeF08Bb6F5F9494faf2316402802e54089E6322eb, @@ -80,6 +76,15 @@ contract MigrationSpell { execute(); } + function testCast(address ROOT_NEW_, address POOLMANAGER_, address RESTRICTIONMANAGER_) public { + require(!done, "spell-already-cast"); + done = true; + ROOT_NEW = ROOT_NEW_; + POOLMANAGER = POOLMANAGER_; + RESTRICTIONMANAGER = RESTRICTIONMANAGER_; + execute(); + } + function execute() internal { self = address(this); IRoot rootOld = IRoot(address(ROOT_OLD)); @@ -88,6 +93,7 @@ contract MigrationSpell { ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); rootOld.relyContract(address(investmentManagerOld), self); + rootOld.relyContract(address(trancheTokenOld), self); // deploy new tranche token rootNew.relyContract(address(POOLMANAGER), self); @@ -112,22 +118,24 @@ contract MigrationSpell { validUntil[memberlistMembers[i]] ) ); - - if (escrowBalance > 0) { - // Claim any unclaimed tokens the user may have - investmentManagerOld.mint( - VAULT_OLD, - investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), - memberlistMembers[i], - memberlistMembers[i] - ); - } - holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); - if (holderBalance > 0) { - // mint new token to the holder's wallet - trancheTokenNew.mint(memberlistMembers[i], holderBalance); - // transfer old tokens from holders' wallets - ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); + if (memberlistMembers[i] != ESCROW_OLD) { + uint256 maxMint = investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]); + if (maxMint > 0) { + // Claim any unclaimed tokens the user may have + investmentManagerOld.mint( + VAULT_OLD, + investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), + memberlistMembers[i], + memberlistMembers[i] + ); + } + holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); + if (holderBalance > 0) { + // mint new token to the holder's wallet + trancheTokenNew.mint(memberlistMembers[i], holderBalance); + // transfer old tokens from holders' wallets + ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); + } } } @@ -141,6 +149,7 @@ contract MigrationSpell { // denies rootNew.denyContract(address(POOLMANAGER), self); rootNew.denyContract(address(trancheTokenNew), self); + rootOld.denyContract(address(trancheTokenOld), self); rootOld.denyContract(address(investmentManagerOld), self); IAuth(address(rootOld)).deny(self); IAuth(address(rootNew)).deny(self); diff --git a/test/fork/Migration.t.sol b/test/fork/Migration.t.sol deleted file mode 100644 index ec78a17d..00000000 --- a/test/fork/Migration.t.sol +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.26; - -import {Tranche} from "src/token/Tranche.sol"; -import {Guardian} from "src/admin/Guardian.sol"; -import {PermissionlessAdapter} from "test/mocks/PermissionlessAdapter.sol"; -import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; -import {BytesLib} from "src/libraries/BytesLib.sol"; -import {CastLib} from "src/libraries/CastLib.sol"; -import {MathLib} from "src/libraries/MathLib.sol"; -import {MigrationSpell} from "src/spell/MigrationSpell-mainnet.sol"; -import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; -import {Auth} from "src/Auth.sol"; -import "forge-std/Test.sol"; -import "forge-std/StdJson.sol"; -import "script/Deployer.sol"; - -interface TrancheTokenOld { - function authTransferFrom(address from, address to, uint256 value) external returns (bool); -} - -contract ForkTest is Deployer, Test { - using BytesLib for bytes; - using MathLib for uint256; - using CastLib for *; - using stdJson for string; - - string[] deployments; - Tranche trancheTokenToMigrate; - Tranche trancheToken; - Guardian guardianOld; - Root rootOld; - - address tokenToMigrate_ = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; - address guardianOld_ = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; - address rootOld_ = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; - - address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; - - MigrationSpell spell; - - address self; - - function setUp() public virtual { - self = address(this); - - spell = new MigrationSpell(); - - _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet - _loadFork(0); - trancheTokenToMigrate = Tranche(address(tokenToMigrate_)); // Anemoy Liquid Treasury Fund 1 (LTF) - guardianOld = Guardian(address(guardianOld_)); - rootOld = Root(rootOld_); - - deployNewContracts(); // Deploy Liquidity Pools v2 - - // _loadDeployment("mainnet", "base-mainnet"); - // _loadDeployment("mainnet", "arbitrum-mainnet"); - // _loadDeployment("mainnet", "celo-mainnet"); - } - - function testTrancheTokenMigration() public { - uint256 totalSupply = 0; - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - totalSupply += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); - } - assertEq(trancheTokenToMigrate.totalSupply(), totalSupply); - - // get auth on old TrancheToken through DelayedAdmin - simulate governance - vm.startPrank(adminMultiSig); - guardianOld.scheduleRely(self); - // get auth on new TrancheToken through Guardian - simulate governance - guardian.scheduleRely(self); - vm.stopPrank(); - // warp delay time = 48H & exec relies - vm.warp(block.timestamp + 2 days); - rootOld.executeScheduledRely(self); - root.executeScheduledRely(self); - // exec auth relies - rootOld.relyContract(address(trancheTokenToMigrate), self); - rootOld.relyContract(spell.INVESTMENTMANAGER_OLD(), self); - root.relyContract(address(trancheToken), self); - root.relyContract(address(poolManager), self); - - // add holders to the allowlist of new token - simulate governance - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - bytes memory update = abi.encodePacked( - uint8(RestrictionUpdate.UpdateMember), - spell.memberlistMembers(i).toBytes32(), - spell.validUntil(spell.memberlistMembers(i)) - ); - poolManager.updateRestriction(spell.POOL_ID(), spell.TRANCHE_ID(), update); - - uint256 escrowBalance = trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()); - if (escrowBalance > 0) { - uint256 maxMint = IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).maxMint( - spell.VAULT_OLD(), spell.memberlistMembers(i) - ); - if (maxMint > 0) { - IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).mint( - spell.VAULT_OLD(), maxMint, spell.memberlistMembers(i), spell.memberlistMembers(i) - ); - } - } - uint256 holderBalance = trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); - if (holderBalance > 0) { - trancheToken.mint(spell.memberlistMembers(i), holderBalance); - assertEq(trancheToken.balanceOf(spell.memberlistMembers(i)), holderBalance); - TrancheTokenOld(address(trancheTokenToMigrate)).authTransferFrom( - spell.memberlistMembers(i), self, holderBalance - ); - } - } - - // check if all holders have been migrated correctly - uint256 totalSupplyNew = 0; - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - uint256 balanceNew = trancheToken.balanceOf(spell.memberlistMembers(i)); - totalSupplyNew += balanceNew; - assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); - } - assertEq(trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()), 0); - assertEq(trancheToken.totalSupply(), totalSupplyNew); - assertEq(trancheTokenToMigrate.totalSupply(), trancheToken.totalSupply()); - - // burn old tranche tokens using auth transfers & make sure old tranche token supply equals zero - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - uint256 balance = trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); - if (balance > 0) { - TrancheTokenOld(tokenToMigrate_).authTransferFrom(spell.memberlistMembers(i), self, balance); - } - assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); - } - uint256 balance = trancheTokenToMigrate.balanceOf(self); - trancheTokenToMigrate.burn(self, balance); - - assertEq(trancheTokenToMigrate.totalSupply(), 0); - - // rename old tranche token - trancheTokenToMigrate.file("name", spell.NAME_OLD()); - trancheTokenToMigrate.file("symbol", spell.SYMBOL_OLD()); - assertEq(trancheTokenToMigrate.name(), spell.SYMBOL_OLD()); - assertEq(trancheTokenToMigrate.symbol(), spell.SYMBOL_OLD()); - - // assert new trancheToken metadata - assertEq(trancheToken.name(), spell.NAME()); - assertEq(trancheToken.symbol(), spell.SYMBOL()); - assertEq(trancheToken.decimals(), spell.DECIMALS()); - - // deny contracts - rootOld.denyContract(address(trancheTokenToMigrate), self); - rootOld.denyContract(spell.INVESTMENTMANAGER_OLD(), self); - root.denyContract(address(trancheToken), self); - - root.denyContract(address(poolManager), self); - // assert denies - assertEq(Auth(address(poolManager)).wards(address(spell)), 0); - assertEq(Auth(address(trancheToken)).wards(address(spell)), 0); - assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); - assertEq(Auth(address(rootOld)).wards(address(spell)), 0); - - } - - function deployNewContracts() internal { - deploy(address(this)); - PermissionlessAdapter adapter = new PermissionlessAdapter(address(gateway)); - wire(address(adapter)); - - // simulate tranche & pool deployments - test is ward on poolManager - // deploy tranche token - poolManager.addPool(spell.POOL_ID()); - poolManager.addTranche( - spell.POOL_ID(), spell.TRANCHE_ID(), spell.NAME(), spell.SYMBOL(), spell.DECIMALS(), restrictionManager - ); - trancheToken = Tranche(poolManager.deployTranche(spell.POOL_ID(), spell.TRANCHE_ID())); - - poolManager.addAsset(spell.CURRENCY_ID(), spell.CURRENCY()); - poolManager.allowAsset(spell.POOL_ID(), spell.CURRENCY_ID()); - poolManager.deployVault(spell.POOL_ID(), spell.TRANCHE_ID(), spell.CURRENCY()); - } - - function _loadDeployment(string memory folder, string memory name) internal { - deployments.push(vm.readFile(string.concat(vm.projectRoot(), "/deployments/", folder, "/", name, ".json"))); - } - - function _loadFork(uint256 id) internal { - string memory rpcUrl = abi.decode(deployments[id].parseRaw(".rpcUrl"), (string)); - uint256 forkId = vm.createFork(rpcUrl); - vm.selectFork(forkId); - } - - function _get(uint256 id, string memory key) internal view returns (address) { - return abi.decode(deployments[id].parseRaw(key), (address)); - } -} diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol new file mode 100644 index 00000000..d90bb454 --- /dev/null +++ b/test/fork/ShareMigration.t.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.26; + +import {Tranche} from "src/token/Tranche.sol"; +import {Guardian} from "src/admin/Guardian.sol"; +import {PermissionlessAdapter} from "test/mocks/PermissionlessAdapter.sol"; +import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; +import {BytesLib} from "src/libraries/BytesLib.sol"; +import {CastLib} from "src/libraries/CastLib.sol"; +import {MathLib} from "src/libraries/MathLib.sol"; +import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; +import {Auth} from "src/Auth.sol"; +import {MigrationSpell} from "src/spell/ShareMigrationDYFEVM.sol"; +import "forge-std/Test.sol"; +import "forge-std/StdJson.sol"; +import "script/Deployer.sol"; + +interface TrancheTokenOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +contract ForkTest is Deployer, Test { + using BytesLib for bytes; + using MathLib for uint256; + using CastLib for *; + using stdJson for string; + + string[] deployments; + Tranche trancheTokenToMigrate; + Guardian guardianOld; + Root rootOld; + mapping(address => uint256) balancesOld; + + MigrationSpell spell; + + address self; + + function setUp() public virtual { + self = address(this); + + spell = new MigrationSpell(); + + _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet + _loadFork(0); + trancheTokenToMigrate = Tranche(address(spell.TRANCHE_TOKEN_OLD())); // Anemoy Liquid Treasury Fund 1 (LTF) + guardianOld = Guardian(spell.GUARDIAN_OLD()); + rootOld = Root(spell.ROOT_OLD()); + + deployNewContracts(); // Deploy Liquidity Pools v2 + } + + function testShareMigration() public { + uint256 totalSupplyOld = 0; + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + totalSupplyOld += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); + } + // Check that total supply is accounted for + assertEq(trancheTokenToMigrate.totalSupply(), totalSupplyOld); + + // get auth on old TrancheToken through DelayedAdmin - simulate governance + vm.startPrank(spell.ADMIN_MULTISIG()); + guardianOld.scheduleRely(address(spell)); + // get auth on new TrancheToken through Guardian - simulate governance + guardian.scheduleRely(address(spell)); + vm.stopPrank(); + // warp delay time = 48H & exec relies + vm.warp(block.timestamp + 2 days); + rootOld.executeScheduledRely(address(spell)); + root.executeScheduledRely(address(spell)); + + + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + if (spell.memberlistMembers(i) != spell.ESCROW_OLD()) { + uint256 maxMint = + IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).maxMint(spell.VAULT_OLD(), spell.memberlistMembers(i)); + balancesOld[spell.memberlistMembers(i)] = + trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)) + maxMint; + } + } + + spell.testCast(address(root), address(poolManager), address(restrictionManager)); + + Tranche trancheToken = Tranche(address(poolManager.getTranche(spell.POOL_ID(), spell.TRANCHE_ID()))); + + // check if all holders have been migrated correctly + uint256 totalSupplyNew = 0; + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { + uint256 balanceNew = trancheToken.balanceOf(spell.memberlistMembers(i)); + totalSupplyNew += balanceNew; + assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); + if (spell.memberlistMembers(i) != spell.ESCROW_OLD()) { + assertEq(balanceNew, balancesOld[spell.memberlistMembers(i)]); + } + } + assertEq(trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()), 0); + + // check total supply + assertEq(trancheToken.totalSupply(), totalSupplyNew); + assertEq(trancheToken.totalSupply(), totalSupplyOld); + assertEq(trancheTokenToMigrate.totalSupply(), 0); + + // check trancheToken metadata + assertEq(trancheTokenToMigrate.name(), spell.SYMBOL_OLD()); + assertEq(trancheTokenToMigrate.symbol(), spell.SYMBOL_OLD()); + assertEq(trancheToken.name(), spell.NAME()); + assertEq(trancheToken.symbol(), spell.SYMBOL()); + assertEq(trancheToken.decimals(), spell.DECIMALS()); + + // assert denies + assertEq(Auth(address(poolManager)).wards(address(spell)), 0); + assertEq(Auth(address(trancheToken)).wards(address(spell)), 0); + assertEq(Auth(address(trancheTokenToMigrate)).wards(address(spell)), 0); + assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); + assertEq(Auth(address(rootOld)).wards(address(spell)), 0); + assertEq(Auth(address(root)).wards(address(spell)), 0); + } + + function deployNewContracts() internal { + deploy(address(this)); + PermissionlessAdapter adapter = new PermissionlessAdapter(address(gateway)); + wire(address(adapter)); + } + + function _loadDeployment(string memory folder, string memory name) internal { + deployments.push(vm.readFile(string.concat(vm.projectRoot(), "/deployments/", folder, "/", name, ".json"))); + } + + function _loadFork(uint256 id) internal { + string memory rpcUrl = abi.decode(deployments[id].parseRaw(".rpcUrl"), (string)); + uint256 forkId = vm.createFork(rpcUrl); + vm.selectFork(forkId); + } + + function _get(uint256 id, string memory key) internal view returns (address) { + return abi.decode(deployments[id].parseRaw(key), (address)); + } +} From 0f8e7901d4194b2803675558b5050d7a4b60906a Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Wed, 31 Jul 2024 17:41:19 -0400 Subject: [PATCH 10/21] wip: add test for fork testing against a real deployment --- src/spell/ShareMigrationDYFEVM.sol | 9 -- src/spell/ShareMigrationLTFBase.sol | 146 ++++++++++++++++++++++++++++ src/spell/ShareMigrationLTFEVM.sol | 9 -- test/fork/ShareMigration.t.sol | 39 ++++++-- 4 files changed, 178 insertions(+), 25 deletions(-) create mode 100644 src/spell/ShareMigrationLTFBase.sol diff --git a/src/spell/ShareMigrationDYFEVM.sol b/src/spell/ShareMigrationDYFEVM.sol index 72cf011a..470f151f 100644 --- a/src/spell/ShareMigrationDYFEVM.sol +++ b/src/spell/ShareMigrationDYFEVM.sol @@ -64,15 +64,6 @@ contract MigrationSpell { execute(); } - function testCast(address ROOT_NEW_, address POOLMANAGER_, address RESTRICTIONMANAGER_) public { - require(!done, "spell-already-cast"); - done = true; - ROOT_NEW = ROOT_NEW_; - POOLMANAGER = POOLMANAGER_; - RESTRICTIONMANAGER = RESTRICTIONMANAGER_; - execute(); - } - function execute() internal { self = address(this); IRoot rootOld = IRoot(address(ROOT_OLD)); diff --git a/src/spell/ShareMigrationLTFBase.sol b/src/spell/ShareMigrationLTFBase.sol new file mode 100644 index 00000000..19cbd562 --- /dev/null +++ b/src/spell/ShareMigrationLTFBase.sol @@ -0,0 +1,146 @@ +pragma solidity 0.8.26; + +import {IRoot} from "src/interfaces/IRoot.sol"; +import {IPoolManager} from "src/interfaces/IPoolManager.sol"; +import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; +import {ITranche} from "src/interfaces/token/ITranche.sol"; +import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; +import {CastLib} from "src/libraries/CastLib.sol"; +import {IAuth} from "src/interfaces/IAuth.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +// spell to migrate tranche tokens +contract MigrationSpell { + using CastLib for *; + + // old deployment addresses + address public constant CURRENCY = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; // USDC + uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896418; + address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + address public constant ADMIN_MULTISIG = 0x8b83962fB9dB346a20c95D98d4E312f17f4C0d9b; + address public constant GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + address public constant TRANCHE_TOKEN_OLD = 0x6D2B49608a716E30bC7aBcFE00181bF261Bf6FC5; + address public constant VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; + + // new deployment addresses + address public ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + address public POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + address public RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + ITranche public trancheTokenNew; // to be deployed during spell exec + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + uint64 public constant POOL_ID = 4139607887; + bytes16 public constant TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; + uint8 public constant DECIMALS = 6; + string public constant NAME = "Anemoy Liquid Treasury Fund 1"; + string public constant SYMBOL = "LTF"; + + string public constant NAME_OLD = "DEPRECATED"; + string public constant SYMBOL_OLD = "DEPRECATED"; + + address[] public memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb, + 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 + ]; + + mapping(address => uint64) public validUntil; + bool public done; + uint256 constant ONE = 10 ** 27; + address self; + + constructor() { + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb] = 2035284942; + validUntil[0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561] = 2037188297; + } + + function cast() public { + require(!done, "spell-already-cast"); + done = true; + execute(); + } + + function execute() internal { + self = address(this); + IRoot rootOld = IRoot(address(ROOT_OLD)); + IRoot rootNew = IRoot(address(ROOT_NEW)); + IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); + ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); + IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); + rootOld.relyContract(address(investmentManagerOld), self); + rootOld.relyContract(address(trancheTokenOld), self); + + // deploy new tranche token + rootNew.relyContract(address(POOLMANAGER), self); + poolManager.addPool(POOL_ID); + poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); + poolManager.addAsset(CURRENCY_ID, CURRENCY); + poolManager.allowAsset(POOL_ID, CURRENCY_ID); + trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); + rootNew.relyContract(address(trancheTokenNew), self); + + // add all old members to new memberlist and claim any tokens + uint256 holderBalance; + uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); + for (uint8 i; i < memberlistMembers.length; i++) { + // add member to new memberlist + poolManager.updateRestriction( + POOL_ID, + TRANCHE_ID, + abi.encodePacked( + uint8(RestrictionUpdate.UpdateMember), + address(memberlistMembers[i]).toBytes32(), + validUntil[memberlistMembers[i]] + ) + ); + if (memberlistMembers[i] != ESCROW_OLD) { + uint256 maxMint = investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]); + if (maxMint > 0) { + // Claim any unclaimed tokens the user may have + investmentManagerOld.mint( + VAULT_OLD, + investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), + memberlistMembers[i], + memberlistMembers[i] + ); + } + holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); + if (holderBalance > 0) { + // mint new token to the holder's wallet + trancheTokenNew.mint(memberlistMembers[i], holderBalance); + // transfer old tokens from holders' wallets + ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); + } + } + } + + // burn entire supply of old tranche tokens + trancheTokenOld.burn(self, trancheTokenOld.balanceOf(self)); + + // rename old tranche token + trancheTokenOld.file("name", NAME_OLD); + trancheTokenOld.file("symbol", SYMBOL_OLD); + + // denies + rootNew.denyContract(address(POOLMANAGER), self); + rootNew.denyContract(address(trancheTokenNew), self); + rootOld.denyContract(address(trancheTokenOld), self); + rootOld.denyContract(address(investmentManagerOld), self); + IAuth(address(rootOld)).deny(self); + IAuth(address(rootNew)).deny(self); + + poolManager.deployVault(POOL_ID, TRANCHE_ID, CURRENCY); + } + + function getNumberOfMigratedMembers() public view returns (uint256) { + return memberlistMembers.length; + } +} diff --git a/src/spell/ShareMigrationLTFEVM.sol b/src/spell/ShareMigrationLTFEVM.sol index 6e476431..28eb42da 100644 --- a/src/spell/ShareMigrationLTFEVM.sol +++ b/src/spell/ShareMigrationLTFEVM.sol @@ -76,15 +76,6 @@ contract MigrationSpell { execute(); } - function testCast(address ROOT_NEW_, address POOLMANAGER_, address RESTRICTIONMANAGER_) public { - require(!done, "spell-already-cast"); - done = true; - ROOT_NEW = ROOT_NEW_; - POOLMANAGER = POOLMANAGER_; - RESTRICTIONMANAGER = RESTRICTIONMANAGER_; - execute(); - } - function execute() internal { self = address(this); IRoot rootOld = IRoot(address(ROOT_OLD)); diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index d90bb454..7a938a78 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -10,7 +10,7 @@ import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {Auth} from "src/Auth.sol"; -import {MigrationSpell} from "src/spell/ShareMigrationDYFEVM.sol"; +import {MigrationSpell} from "src/spell/ShareMigrationLTFBase.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; @@ -19,6 +19,17 @@ interface TrancheTokenOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); } +contract TestableSpell is MigrationSpell { + function testCast(address root, address poolManager, address restrictionManager) public { + require(!done, "spell-already-cast"); + done = true; + ROOT_NEW = root; + POOLMANAGER = poolManager; + RESTRICTIONMANAGER = restrictionManager; + execute(); + } +} + contract ForkTest is Deployer, Test { using BytesLib for bytes; using MathLib for uint256; @@ -31,25 +42,39 @@ contract ForkTest is Deployer, Test { Root rootOld; mapping(address => uint256) balancesOld; - MigrationSpell spell; + TestableSpell spell; address self; function setUp() public virtual { self = address(this); - spell = new MigrationSpell(); + spell = new TestableSpell(); - _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet + _loadDeployment("mainnet", "base-mainnet"); // Mainnet _loadFork(0); trancheTokenToMigrate = Tranche(address(spell.TRANCHE_TOKEN_OLD())); // Anemoy Liquid Treasury Fund 1 (LTF) guardianOld = Guardian(spell.GUARDIAN_OLD()); rootOld = Root(spell.ROOT_OLD()); + } + + function testShareMigrationAgainstRealDeployment() public { + address ROOT = 0x468CBaA7b44851C2426b58190030162d18786b6d; + address POOLMANAGER = 0x7829E5ca4286Df66e9F58160544097dB517a3B8c; + address RESTRICTIONMANAGER = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; + address GUARDIAN = 0xA0e3A5709995eF9900ab0F7FA070567Fe89d9e18; + guardian = Guardian(GUARDIAN); + root = Root(ROOT); + migrateShares(ROOT, POOLMANAGER, RESTRICTIONMANAGER); + } + + function testShareMigrationAgainstMockDeployment() public { deployNewContracts(); // Deploy Liquidity Pools v2 + migrateShares(address(root), address(poolManager), address(restrictionManager)); } - function testShareMigration() public { + function migrateShares(address root, address poolManager, address restrictionManager) internal { uint256 totalSupplyOld = 0; for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { totalSupplyOld += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); @@ -66,7 +91,7 @@ contract ForkTest is Deployer, Test { // warp delay time = 48H & exec relies vm.warp(block.timestamp + 2 days); rootOld.executeScheduledRely(address(spell)); - root.executeScheduledRely(address(spell)); + Root(root).executeScheduledRely(address(spell)); for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { @@ -80,7 +105,7 @@ contract ForkTest is Deployer, Test { spell.testCast(address(root), address(poolManager), address(restrictionManager)); - Tranche trancheToken = Tranche(address(poolManager.getTranche(spell.POOL_ID(), spell.TRANCHE_ID()))); + Tranche trancheToken = Tranche(address(PoolManager(poolManager).getTranche(spell.POOL_ID(), spell.TRANCHE_ID()))); // check if all holders have been migrated correctly uint256 totalSupplyNew = 0; From 2bb091423da2ba5ceae6f67867b29e52b8f57db2 Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Wed, 31 Jul 2024 21:14:35 -0400 Subject: [PATCH 11/21] Add base addresses --- src/spell/ShareMigrationLTFBase.sol | 16 ++++++++-------- test/fork/ShareMigration.t.sol | 17 ++++++++--------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/spell/ShareMigrationLTFBase.sol b/src/spell/ShareMigrationLTFBase.sol index 19cbd562..c0a88f74 100644 --- a/src/spell/ShareMigrationLTFBase.sol +++ b/src/spell/ShareMigrationLTFBase.sol @@ -30,9 +30,10 @@ contract MigrationSpell { address public constant VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; // new deployment addresses - address public ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - address public POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - address public RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + address public ROOT_NEW = 0x468CBaA7b44851C2426b58190030162d18786b6d; + address public GUARDIAN_NEW = 0xA0e3A5709995eF9900ab0F7FA070567Fe89d9e18; + address public POOLMANAGER_NEW = 0x7829E5ca4286Df66e9F58160544097dB517a3B8c; + address public RESTRICTIONMANAGER_NEW = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; ITranche public trancheTokenNew; // to be deployed during spell exec // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens @@ -72,16 +73,16 @@ contract MigrationSpell { self = address(this); IRoot rootOld = IRoot(address(ROOT_OLD)); IRoot rootNew = IRoot(address(ROOT_NEW)); - IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); + IPoolManager poolManager = IPoolManager(address(POOLMANAGER_NEW)); ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); rootOld.relyContract(address(investmentManagerOld), self); rootOld.relyContract(address(trancheTokenOld), self); // deploy new tranche token - rootNew.relyContract(address(POOLMANAGER), self); + rootNew.relyContract(address(POOLMANAGER_NEW), self); poolManager.addPool(POOL_ID); - poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); + poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER_NEW); poolManager.addAsset(CURRENCY_ID, CURRENCY); poolManager.allowAsset(POOL_ID, CURRENCY_ID); trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); @@ -89,7 +90,6 @@ contract MigrationSpell { // add all old members to new memberlist and claim any tokens uint256 holderBalance; - uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); for (uint8 i; i < memberlistMembers.length; i++) { // add member to new memberlist poolManager.updateRestriction( @@ -130,7 +130,7 @@ contract MigrationSpell { trancheTokenOld.file("symbol", SYMBOL_OLD); // denies - rootNew.denyContract(address(POOLMANAGER), self); + rootNew.denyContract(address(POOLMANAGER_NEW), self); rootNew.denyContract(address(trancheTokenNew), self); rootOld.denyContract(address(trancheTokenOld), self); rootOld.denyContract(address(investmentManagerOld), self); diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index 7a938a78..171c62bd 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -24,8 +24,8 @@ contract TestableSpell is MigrationSpell { require(!done, "spell-already-cast"); done = true; ROOT_NEW = root; - POOLMANAGER = poolManager; - RESTRICTIONMANAGER = restrictionManager; + POOLMANAGER_NEW = poolManager; + RESTRICTIONMANAGER_NEW = restrictionManager; execute(); } } @@ -60,13 +60,9 @@ contract ForkTest is Deployer, Test { } function testShareMigrationAgainstRealDeployment() public { - address ROOT = 0x468CBaA7b44851C2426b58190030162d18786b6d; - address POOLMANAGER = 0x7829E5ca4286Df66e9F58160544097dB517a3B8c; - address RESTRICTIONMANAGER = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; - address GUARDIAN = 0xA0e3A5709995eF9900ab0F7FA070567Fe89d9e18; - guardian = Guardian(GUARDIAN); - root = Root(ROOT); - migrateShares(ROOT, POOLMANAGER, RESTRICTIONMANAGER); + guardian = Guardian(spell.GUARDIAN_NEW()); + root = Root(spell.ROOT_NEW()); + migrateShares(spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); } function testShareMigrationAgainstMockDeployment() public { @@ -138,6 +134,9 @@ contract ForkTest is Deployer, Test { assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); assertEq(Auth(address(rootOld)).wards(address(spell)), 0); assertEq(Auth(address(root)).wards(address(spell)), 0); + + // assert vault was deployed + assertTrue(PoolManager(poolManager).getVault(spell.POOL_ID(), spell.TRANCHE_ID(), spell.CURRENCY()) != address(0)); } function deployNewContracts() internal { From e6c00e37e100beb469baf18c4349efd015ffac1e Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Wed, 31 Jul 2024 23:46:49 -0400 Subject: [PATCH 12/21] update tests and spells construction --- src/spell/MigrationSpell.t.sol | 106 ------------ ...tionLTFBase.sol => MigrationSpellBase.sol} | 69 +++----- src/spell/ShareMigrationDYFEVM.sol | 140 ---------------- src/spell/ShareMigrationLTFEVM.sol | 154 ------------------ src/spell/ShareMigration_DYF_EVM.sol | 51 ++++++ src/spell/ShareMigration_LTF_Base.sol | 51 ++++++ src/spell/ShareMigration_LTF_Celo.sol | 51 ++++++ src/spell/ShareMigration_LTF_EVM.sol | 57 +++++++ src/spell/ShareMigration_NS3JR_EVM.sol | 49 ++++++ src/spell/ShareMigration_NS3SR_EVM.sol | 49 ++++++ test/fork/ShareMigration.t.sol | 31 ++-- 11 files changed, 350 insertions(+), 458 deletions(-) delete mode 100644 src/spell/MigrationSpell.t.sol rename src/spell/{ShareMigrationLTFBase.sol => MigrationSpellBase.sol} (65%) delete mode 100644 src/spell/ShareMigrationDYFEVM.sol delete mode 100644 src/spell/ShareMigrationLTFEVM.sol create mode 100644 src/spell/ShareMigration_DYF_EVM.sol create mode 100644 src/spell/ShareMigration_LTF_Base.sol create mode 100644 src/spell/ShareMigration_LTF_Celo.sol create mode 100644 src/spell/ShareMigration_LTF_EVM.sol create mode 100644 src/spell/ShareMigration_NS3JR_EVM.sol create mode 100644 src/spell/ShareMigration_NS3SR_EVM.sol diff --git a/src/spell/MigrationSpell.t.sol b/src/spell/MigrationSpell.t.sol deleted file mode 100644 index 218b56cb..00000000 --- a/src/spell/MigrationSpell.t.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.26; - -import {Guardian} from "src/admin/Guardian.sol"; -import {Auth} from "src/Auth.sol"; -import "./ShareMigrationLTFEVM.sol"; -import "forge-std/Test.sol"; -import "forge-std/StdJson.sol"; - -contract MigrationSpellTest is Test { - using stdJson for string; - - string[] deployments; - MigrationSpell spell; - - // set this variables custom for each network - Guardian guardianOld = Guardian(address(0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028)); - Guardian guardianNew = Guardian(address(0x0000000000000000000000000000000000000000)); // TODO set address - address adminMultiSig = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; - - address self; - - ITranche trancheTokenOld; - - function setUp() public { - self = address(this); - _loadDeployment("mainnet", "ethereum-mainnet"); // Mainnet - _loadFork(0); - spell = new MigrationSpell(); - - trancheTokenOld = ITranche(spell.TRANCHE_TOKEN_OLD()); - } - - function testMigration() public { - // check if spell is migrating all the current token holders - uint256 holdersSupplySum; - uint256[] memory trancheTokenHolderBalancesOld = new uint256[](spell.getNumberOfMigratedMembers()); - uint256 balanceOld; - - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - balanceOld = trancheTokenOld.balanceOf(spell.memberlistMembers(i)); - trancheTokenHolderBalancesOld[i] = balanceOld; - holdersSupplySum += balanceOld; - } - assertEq(trancheTokenOld.totalSupply(), holdersSupplySum); - - // simulate manual governance steps - vm.startPrank(adminMultiSig); - guardianOld.scheduleRely(self); - guardianNew.scheduleRely(self); - vm.stopPrank(); - // warp delay time = 48H & exec relies - vm.warp(block.timestamp + 2 days); - IRoot(spell.ROOT_OLD()).executeScheduledRely(self); - IRoot(spell.ROOT_NEW()).executeScheduledRely(self); - - // cast spell - spell.cast(); - - // for all members check if balance was migrated correctly - uint256 balanceNew; - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - balanceNew = spell.trancheTokenNew().balanceOf(spell.memberlistMembers(i)); - // assert users new token balance equals old token balance - assertEq(trancheTokenHolderBalancesOld[i], balanceNew); - // assert old tokens got removed from user wallet - assertEq(trancheTokenOld.balanceOf(spell.memberlistMembers(i)), 0); - } - // assert all old tokens were claimed from escrow - assertEq(trancheTokenOld.balanceOf(spell.ESCROW_OLD()), 0); - // assert total new supply equeals total old supply - assertEq(spell.trancheTokenNew().totalSupply(), holdersSupplySum); - // assert all old tokens burned - assertEq(trancheTokenOld.totalSupply(), 0); - - // assert renaming of old trancheToken worked - assertEq(trancheTokenOld.name(), spell.NAME_OLD()); - assertEq(trancheTokenOld.symbol(), spell.SYMBOL_OLD()); - - // assert new trancheToken metadata - assertEq(spell.trancheTokenNew().name(), spell.NAME()); - assertEq(spell.trancheTokenNew().symbol(), spell.SYMBOL()); - assertEq(spell.trancheTokenNew().decimals(), spell.DECIMALS()); - - // assert denies - assertEq(Auth(spell.POOLMANAGER()).wards(address(spell)), 0); - assertEq(Auth(address(spell.trancheTokenNew())).wards(address(spell)), 0); - assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); - assertEq(Auth(spell.ROOT_OLD()).wards(address(spell)), 0); - assertEq(Auth(spell.ROOT_NEW()).wards(address(spell)), 0); - } - - function _loadDeployment(string memory folder, string memory name) internal { - deployments.push(vm.readFile(string.concat(vm.projectRoot(), "/deployments/", folder, "/", name, ".json"))); - } - - function _loadFork(uint256 id) internal { - string memory rpcUrl = abi.decode(deployments[id].parseRaw(".rpcUrl"), (string)); - uint256 forkId = vm.createFork(rpcUrl); - vm.selectFork(forkId); - } - - function _get(uint256 id, string memory key) internal view returns (address) { - return abi.decode(deployments[id].parseRaw(key), (address)); - } -} diff --git a/src/spell/ShareMigrationLTFBase.sol b/src/spell/MigrationSpellBase.sol similarity index 65% rename from src/spell/ShareMigrationLTFBase.sol rename to src/spell/MigrationSpellBase.sol index c0a88f74..48aba2a3 100644 --- a/src/spell/ShareMigrationLTFBase.sol +++ b/src/spell/MigrationSpellBase.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.26; import {IRoot} from "src/interfaces/IRoot.sol"; @@ -12,57 +13,37 @@ interface ITrancheOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); } -// spell to migrate tranche tokens -contract MigrationSpell { +contract MigrationSpellBase { using CastLib for *; - // old deployment addresses - address public constant CURRENCY = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; // USDC - uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896418; - address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; - address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; - address public constant ADMIN_MULTISIG = 0x8b83962fB9dB346a20c95D98d4E312f17f4C0d9b; - address public constant GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; - - // old pool addresses - address public constant TRANCHE_TOKEN_OLD = 0x6D2B49608a716E30bC7aBcFE00181bF261Bf6FC5; - address public constant VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; - - // new deployment addresses - address public ROOT_NEW = 0x468CBaA7b44851C2426b58190030162d18786b6d; - address public GUARDIAN_NEW = 0xA0e3A5709995eF9900ab0F7FA070567Fe89d9e18; - address public POOLMANAGER_NEW = 0x7829E5ca4286Df66e9F58160544097dB517a3B8c; - address public RESTRICTIONMANAGER_NEW = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; - ITranche public trancheTokenNew; // to be deployed during spell exec - - // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - uint64 public constant POOL_ID = 4139607887; - bytes16 public constant TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; - uint8 public constant DECIMALS = 6; - string public constant NAME = "Anemoy Liquid Treasury Fund 1"; - string public constant SYMBOL = "LTF"; - - string public constant NAME_OLD = "DEPRECATED"; - string public constant SYMBOL_OLD = "DEPRECATED"; - - address[] public memberlistMembers = [ - 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, - 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb, - 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 - ]; - + string public NETWORK; + address public CURRENCY; + uint128 public CURRENCY_ID; + address public ESCROW_OLD; + address public INVESTMENTMANAGER_OLD; + address public ROOT_OLD; + address public ADMIN_MULTISIG; + address public GUARDIAN_OLD; + address public TRANCHE_TOKEN_OLD; + address public VAULT_OLD; + address public ROOT_NEW; + address public GUARDIAN_NEW; + address public POOLMANAGER_NEW; + address public RESTRICTIONMANAGER_NEW; + ITranche public trancheTokenNew; + uint64 public POOL_ID; + bytes16 public TRANCHE_ID; + uint8 public DECIMALS; + string public NAME; + string public SYMBOL; + string public NAME_OLD; + string public SYMBOL_OLD; + address[] public memberlistMembers; mapping(address => uint64) public validUntil; bool public done; uint256 constant ONE = 10 ** 27; address self; - constructor() { - validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; - validUntil[0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb] = 2035284942; - validUntil[0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561] = 2037188297; - } - function cast() public { require(!done, "spell-already-cast"); done = true; diff --git a/src/spell/ShareMigrationDYFEVM.sol b/src/spell/ShareMigrationDYFEVM.sol deleted file mode 100644 index 470f151f..00000000 --- a/src/spell/ShareMigrationDYFEVM.sol +++ /dev/null @@ -1,140 +0,0 @@ -pragma solidity 0.8.26; - -import {IRoot} from "src/interfaces/IRoot.sol"; -import {IPoolManager} from "src/interfaces/IPoolManager.sol"; -import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; -import {ITranche} from "src/interfaces/token/ITranche.sol"; -import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; -import {CastLib} from "src/libraries/CastLib.sol"; -import {IAuth} from "src/interfaces/IAuth.sol"; - -interface ITrancheOld { - function authTransferFrom(address from, address to, uint256 value) external returns (bool); -} - -// spell to migrate tranche tokens -contract MigrationSpell { - using CastLib for *; - - // old deployment addresses - address public constant CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC - uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896417; - address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; - address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; - address public constant ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; - address public constant GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; - - // old pool addresses - address public constant TRANCHE_TOKEN_OLD = 0x143dB3a0d0679DFd3372e7F3877BbBB27da3f5e4; - address public constant VAULT_OLD = 0x110379504D933BeD2E485E281bc3909D1E7C9E5D; - - // new deployment addresses - address public ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set - address public POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set - address public RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO - set - ITranche public trancheTokenNew; // to be deployed during spell exec - - // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - uint64 public constant POOL_ID = 1655476167; - bytes16 public constant TRANCHE_ID = 0x4859c6f181b1b993c35b313bedb949cf; - uint8 public constant DECIMALS = 6; - string public constant NAME = "Anemoy DeFi Yield Fund 1 SP DeFi Yield Fund Token"; - string public constant SYMBOL = "DYF"; - - string public constant NAME_OLD = "DEPRECATED"; - string public constant SYMBOL_OLD = "DEPRECATED"; - - address[] public memberlistMembers = - [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997]; - - mapping(address => uint64) public validUntil; - bool public done; - uint256 constant ONE = 10 ** 27; - address self; - - constructor() { - validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; - validUntil[0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997] = 2032178598; - } - - function cast() public { - require(!done, "spell-already-cast"); - done = true; - execute(); - } - - function execute() internal { - self = address(this); - IRoot rootOld = IRoot(address(ROOT_OLD)); - IRoot rootNew = IRoot(address(ROOT_NEW)); - IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); - ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); - IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); - rootOld.relyContract(address(investmentManagerOld), self); - rootOld.relyContract(address(trancheTokenOld), self); - - // deploy new tranche token - rootNew.relyContract(address(POOLMANAGER), self); - poolManager.addPool(POOL_ID); - poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); - poolManager.addAsset(CURRENCY_ID, CURRENCY); - poolManager.allowAsset(POOL_ID, CURRENCY_ID); - trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); - rootNew.relyContract(address(trancheTokenNew), self); - - // add all old members to new memberlist and claim any tokens - uint256 holderBalance; - uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); - for (uint8 i; i < memberlistMembers.length; i++) { - // add member to new memberlist - poolManager.updateRestriction( - POOL_ID, - TRANCHE_ID, - abi.encodePacked( - uint8(RestrictionUpdate.UpdateMember), - address(memberlistMembers[i]).toBytes32(), - validUntil[memberlistMembers[i]] - ) - ); - - if (escrowBalance > 0) { - // Claim any unclaimed tokens the user may have - investmentManagerOld.mint( - VAULT_OLD, - investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), - memberlistMembers[i], - memberlistMembers[i] - ); - } - holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); - if (holderBalance > 0) { - // mint new token to the holder's wallet - trancheTokenNew.mint(memberlistMembers[i], holderBalance); - // transfer old tokens from holders' wallets - ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); - } - } - - // burn entire supply of old tranche tokens - trancheTokenOld.burn(self, trancheTokenOld.balanceOf(self)); - - // rename old tranche token - trancheTokenOld.file("name", NAME_OLD); - trancheTokenOld.file("symbol", SYMBOL_OLD); - - // denies - rootNew.denyContract(address(POOLMANAGER), self); - rootNew.denyContract(address(trancheTokenNew), self); - rootOld.denyContract(address(trancheTokenOld), self); - rootOld.denyContract(address(investmentManagerOld), self); - IAuth(address(rootOld)).deny(self); - IAuth(address(rootNew)).deny(self); - - poolManager.deployVault(POOL_ID, TRANCHE_ID, CURRENCY); - } - - function getNumberOfMigratedMembers() public view returns (uint256) { - return memberlistMembers.length; - } -} diff --git a/src/spell/ShareMigrationLTFEVM.sol b/src/spell/ShareMigrationLTFEVM.sol deleted file mode 100644 index 28eb42da..00000000 --- a/src/spell/ShareMigrationLTFEVM.sol +++ /dev/null @@ -1,154 +0,0 @@ -pragma solidity 0.8.26; - -import {IRoot} from "src/interfaces/IRoot.sol"; -import {IPoolManager} from "src/interfaces/IPoolManager.sol"; -import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; -import {ITranche} from "src/interfaces/token/ITranche.sol"; -import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; -import {CastLib} from "src/libraries/CastLib.sol"; -import {IAuth} from "src/interfaces/IAuth.sol"; - -interface ITrancheOld { - function authTransferFrom(address from, address to, uint256 value) external returns (bool); -} - -// spell to migrate tranche tokens -contract MigrationSpell { - using CastLib for *; - - // old deployment addresses - address public constant CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC - uint128 public constant CURRENCY_ID = 242333941209166991950178742833476896417; - address public constant ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - address public constant INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; - address public constant ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; - address public constant ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; - address public constant GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; - - // old pool addresses - address public constant TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; - address public constant VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; - - // new deployment addresses - address public ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - address public POOLMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - address public RESTRICTIONMANAGER = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - ITranche public trancheTokenNew; // to be deployed during spell exec - - // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - uint64 public constant POOL_ID = 4139607887; - bytes16 public constant TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; - uint8 public constant DECIMALS = 6; - string public constant NAME = "Anemoy Liquid Treasury Fund 1"; - string public constant SYMBOL = "LTF"; - - string public constant NAME_OLD = "DEPRECATED"; - string public constant SYMBOL_OLD = "DEPRECATED"; - - address[] public memberlistMembers = [ - 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, - 0xeF08Bb6F5F9494faf2316402802e54089E6322eb, - 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997, - 0xeEDC395aAAb05e5fb6130A8C5AEbAE48E7739B78, - 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E, - 0x14FFe68D005e58f08c27dC0c999f75639682276c, - 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 - ]; - - mapping(address => uint64) public validUntil; - bool public done; - uint256 constant ONE = 10 ** 27; - address self; - - constructor() { - validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; - validUntil[0xeF08Bb6F5F9494faf2316402802e54089E6322eb] = 2017150288; - validUntil[0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997] = 2017323212; - validUntil[0xeEDC395aAAb05e5fb6130A8C5AEbAE48E7739B78] = 3745713365; - validUntil[0x2923c1B5313F7375fdaeE80b7745106deBC1b53E] = 2031229099; - validUntil[0x14FFe68D005e58f08c27dC0c999f75639682276c] = 2035299660; - validUntil[0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561] = 2037188261; - } - - function cast() public { - require(!done, "spell-already-cast"); - done = true; - execute(); - } - - function execute() internal { - self = address(this); - IRoot rootOld = IRoot(address(ROOT_OLD)); - IRoot rootNew = IRoot(address(ROOT_NEW)); - IPoolManager poolManager = IPoolManager(address(POOLMANAGER)); - ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); - IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); - rootOld.relyContract(address(investmentManagerOld), self); - rootOld.relyContract(address(trancheTokenOld), self); - - // deploy new tranche token - rootNew.relyContract(address(POOLMANAGER), self); - poolManager.addPool(POOL_ID); - poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER); - poolManager.addAsset(CURRENCY_ID, CURRENCY); - poolManager.allowAsset(POOL_ID, CURRENCY_ID); - trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); - rootNew.relyContract(address(trancheTokenNew), self); - - // add all old members to new memberlist and claim any tokens - uint256 holderBalance; - uint256 escrowBalance = trancheTokenOld.balanceOf(ESCROW_OLD); - for (uint8 i; i < memberlistMembers.length; i++) { - // add member to new memberlist - poolManager.updateRestriction( - POOL_ID, - TRANCHE_ID, - abi.encodePacked( - uint8(RestrictionUpdate.UpdateMember), - address(memberlistMembers[i]).toBytes32(), - validUntil[memberlistMembers[i]] - ) - ); - if (memberlistMembers[i] != ESCROW_OLD) { - uint256 maxMint = investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]); - if (maxMint > 0) { - // Claim any unclaimed tokens the user may have - investmentManagerOld.mint( - VAULT_OLD, - investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), - memberlistMembers[i], - memberlistMembers[i] - ); - } - holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); - if (holderBalance > 0) { - // mint new token to the holder's wallet - trancheTokenNew.mint(memberlistMembers[i], holderBalance); - // transfer old tokens from holders' wallets - ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); - } - } - } - - // burn entire supply of old tranche tokens - trancheTokenOld.burn(self, trancheTokenOld.balanceOf(self)); - - // rename old tranche token - trancheTokenOld.file("name", NAME_OLD); - trancheTokenOld.file("symbol", SYMBOL_OLD); - - // denies - rootNew.denyContract(address(POOLMANAGER), self); - rootNew.denyContract(address(trancheTokenNew), self); - rootOld.denyContract(address(trancheTokenOld), self); - rootOld.denyContract(address(investmentManagerOld), self); - IAuth(address(rootOld)).deny(self); - IAuth(address(rootNew)).deny(self); - - poolManager.deployVault(POOL_ID, TRANCHE_ID, CURRENCY); - } - - function getNumberOfMigratedMembers() public view returns (uint256) { - return memberlistMembers.length; - } -} diff --git a/src/spell/ShareMigration_DYF_EVM.sol b/src/spell/ShareMigration_DYF_EVM.sol new file mode 100644 index 00000000..d87cf346 --- /dev/null +++ b/src/spell/ShareMigration_DYF_EVM.sol @@ -0,0 +1,51 @@ +pragma solidity 0.8.26; + +import {IRoot} from "src/interfaces/IRoot.sol"; +import {IPoolManager} from "src/interfaces/IPoolManager.sol"; +import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; +import {ITranche} from "src/interfaces/token/ITranche.sol"; +import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; +import {IAuth} from "src/interfaces/IAuth.sol"; +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +// spell to migrate tranche tokens +contract MigrationSpell is MigrationSpellBase { + constructor() { + NETWORK = "ethereum-mainnet"; + // old deployment addresses + CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC + CURRENCY_ID = 242333941209166991950178742833476896417; + ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + TRANCHE_TOKEN_OLD = 0x143dB3a0d0679DFd3372e7F3877BbBB27da3f5e4; + VAULT_OLD = 0x110379504D933BeD2E485E281bc3909D1E7C9E5D; + + // new deployment addresses + ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + POOL_ID = 1655476167; + TRANCHE_ID = 0x4859c6f181b1b993c35b313bedb949cf; + DECIMALS = 6; + NAME = "Anemoy DeFi Yield Fund 1 SP DeFi Yield Fund Token"; + SYMBOL = "DYF"; + NAME_OLD = "DEPRECATED"; + SYMBOL_OLD = "DEPRECATED"; + + memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997]; + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997] = 2032178598; + } +} diff --git a/src/spell/ShareMigration_LTF_Base.sol b/src/spell/ShareMigration_LTF_Base.sol new file mode 100644 index 00000000..4cfc04aa --- /dev/null +++ b/src/spell/ShareMigration_LTF_Base.sol @@ -0,0 +1,51 @@ +pragma solidity 0.8.26; + +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +contract MigrationSpell is MigrationSpellBase { + constructor() { + NETWORK = "base-mainnet"; + // old deployment addresses + CURRENCY = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; // USDC + CURRENCY_ID = 242333941209166991950178742833476896418; + ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + ADMIN_MULTISIG = 0x8b83962fB9dB346a20c95D98d4E312f17f4C0d9b; + GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + TRANCHE_TOKEN_OLD = 0x6D2B49608a716E30bC7aBcFE00181bF261Bf6FC5; + VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; + + // new deployment addresses + ROOT_NEW = 0x468CBaA7b44851C2426b58190030162d18786b6d; + GUARDIAN_NEW = 0xA0e3A5709995eF9900ab0F7FA070567Fe89d9e18; + POOLMANAGER_NEW = 0x7829E5ca4286Df66e9F58160544097dB517a3B8c; + RESTRICTIONMANAGER_NEW = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + POOL_ID = 4139607887; + TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; + DECIMALS = 6; + NAME = "Anemoy Liquid Treasury Fund 1"; + SYMBOL = "LTF"; + + NAME_OLD = "DEPRECATED"; + SYMBOL_OLD = "DEPRECATED"; + + memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb, + 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 + ]; + + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb] = 2035284942; + validUntil[0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561] = 2037188297; + } +} diff --git a/src/spell/ShareMigration_LTF_Celo.sol b/src/spell/ShareMigration_LTF_Celo.sol new file mode 100644 index 00000000..6b72a721 --- /dev/null +++ b/src/spell/ShareMigration_LTF_Celo.sol @@ -0,0 +1,51 @@ +pragma solidity 0.8.26; + +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +contract MigrationSpell is MigrationSpellBase { + constructor() { + NETWORK = "celo-mainnet"; + // old deployment addresses + CURRENCY = 0x37f750B7cC259A2f741AF45294f6a16572CF5cAd; + CURRENCY_ID = 242333941209166991950178742833476896420; + ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + ADMIN_MULTISIG = 0x2464f95F6901233bF4a0130A3611d5B4CBd83195; + GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + TRANCHE_TOKEN_OLD = 0x6D2B49608a716E30bC7aBcFE00181bF261Bf6FC5; + VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; + + // new deployment addresses + ROOT_NEW = 0x0000000000000000000000000000000000000000; + GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; + POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; + RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + POOL_ID = 4139607887; + TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; + DECIMALS = 6; + NAME = "Anemoy Liquid Treasury Fund 1"; + SYMBOL = "LTF"; + + NAME_OLD = "DEPRECATED"; + SYMBOL_OLD = "DEPRECATED"; + + memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0x0D9E269ECc319BAE886Dd8c8B98F7B89269C2B1B, + 0x6854f6671c1934c77cf7592B0b264f762614014E + ]; + + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0x0D9E269ECc319BAE886Dd8c8B98F7B89269C2B1B] = 2020186137; + validUntil[0x6854f6671c1934c77cf7592B0b264f762614014E] = 2020262249; + } +} diff --git a/src/spell/ShareMigration_LTF_EVM.sol b/src/spell/ShareMigration_LTF_EVM.sol new file mode 100644 index 00000000..4d465dff --- /dev/null +++ b/src/spell/ShareMigration_LTF_EVM.sol @@ -0,0 +1,57 @@ +pragma solidity 0.8.26; + +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; + +// spell to migrate tranche tokens +contract MigrationSpell is MigrationSpellBase { + + constructor() { + NETWORK = "ethereum-mainnet"; + // old deployment addresses + CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC + CURRENCY_ID = 242333941209166991950178742833476896417; + ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; + VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; + + // new deployment addresses + ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + POOL_ID = 4139607887; + TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; + DECIMALS = 6; + NAME = "Anemoy Liquid Treasury Fund 1"; + SYMBOL = "LTF"; + + NAME_OLD = "DEPRECATED"; + SYMBOL_OLD = "DEPRECATED"; + + memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0xeF08Bb6F5F9494faf2316402802e54089E6322eb, + 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997, + 0xeEDC395aAAb05e5fb6130A8C5AEbAE48E7739B78, + 0x2923c1B5313F7375fdaeE80b7745106deBC1b53E, + 0x14FFe68D005e58f08c27dC0c999f75639682276c, + 0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561 + ]; + + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0xeF08Bb6F5F9494faf2316402802e54089E6322eb] = 2017150288; + validUntil[0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997] = 2017323212; + validUntil[0xeEDC395aAAb05e5fb6130A8C5AEbAE48E7739B78] = 3745713365; + validUntil[0x2923c1B5313F7375fdaeE80b7745106deBC1b53E] = 2031229099; + validUntil[0x14FFe68D005e58f08c27dC0c999f75639682276c] = 2035299660; + validUntil[0x86552B8d4F4a600D92d516eE8eA8B922EFEcB561] = 2037188261; + } +} diff --git a/src/spell/ShareMigration_NS3JR_EVM.sol b/src/spell/ShareMigration_NS3JR_EVM.sol new file mode 100644 index 00000000..09b9241b --- /dev/null +++ b/src/spell/ShareMigration_NS3JR_EVM.sol @@ -0,0 +1,49 @@ +pragma solidity 0.8.26; + +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +contract MigrationSpell is MigrationSpellBase { + constructor() { + NETWORK = "ethereum-mainnet"; + // old deployment addresses + CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + CURRENCY_ID = 242333941209166991950178742833476896417; + ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + TRANCHE_TOKEN_OLD = 0xeC9106d0BA35B2228d7Ef3a7c3e7400Cd0f430BD; + VAULT_OLD = 0xd0C7E8C9b0c82b74771AE13e184432240A3a2F54; + + // new deployment addresses + ROOT_NEW = 0x0000000000000000000000000000000000000000; + GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; + POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; + RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + POOL_ID = 1615768079; + TRANCHE_ID = 0x6756e091ae798a8e51e12e27ee8facdf; + DECIMALS = 6; + NAME = "New Silver Series 3 Junior"; + SYMBOL = "NS3JR"; + + NAME_OLD = "DEPRECATED"; + SYMBOL_OLD = "DEPRECATED"; + + memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14 + ]; + + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14] = 2030638540; + } +} diff --git a/src/spell/ShareMigration_NS3SR_EVM.sol b/src/spell/ShareMigration_NS3SR_EVM.sol new file mode 100644 index 00000000..3a1ae0d7 --- /dev/null +++ b/src/spell/ShareMigration_NS3SR_EVM.sol @@ -0,0 +1,49 @@ +pragma solidity 0.8.26; + +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; + +interface ITrancheOld { + function authTransferFrom(address from, address to, uint256 value) external returns (bool); +} + +contract MigrationSpell is MigrationSpellBase { + constructor() { + NETWORK = "ethereum-mainnet"; + // old deployment addresses + CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + CURRENCY_ID = 242333941209166991950178742833476896417; + ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; + INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; + ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; + ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; + GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; + + // old pool addresses + TRANCHE_TOKEN_OLD = 0x8d6825d576827bf8E87a17CDD5684E771fbe221C; + VAULT_OLD = 0x0d3992B5B5c4fd1c08F73DEd3939e242f0ABd78c; + + // new deployment addresses + ROOT_NEW = 0x0000000000000000000000000000000000000000; + GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; + POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; + RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; + + // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens + POOL_ID = 1615768079; + TRANCHE_ID = 0xda64aae939e4d3a981004619f1709d8f; + DECIMALS = 6; + NAME = "New Silver Series 3 Senior"; + SYMBOL = "NS3SR"; + + NAME_OLD = "DEPRECATED"; + SYMBOL_OLD = "DEPRECATED"; + + memberlistMembers = [ + 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, + 0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6 + ]; + + validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; + validUntil[0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6] = 4869492494; + } +} diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index 171c62bd..bf66e935 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -10,7 +10,7 @@ import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {Auth} from "src/Auth.sol"; -import {MigrationSpell} from "src/spell/ShareMigrationLTFBase.sol"; +import {MigrationSpell} from "src/spell/ShareMigration_LTF_Celo.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; @@ -51,26 +51,25 @@ contract ForkTest is Deployer, Test { spell = new TestableSpell(); - _loadDeployment("mainnet", "base-mainnet"); // Mainnet + _loadDeployment("mainnet", spell.NETWORK()); _loadFork(0); trancheTokenToMigrate = Tranche(address(spell.TRANCHE_TOKEN_OLD())); // Anemoy Liquid Treasury Fund 1 (LTF) guardianOld = Guardian(spell.GUARDIAN_OLD()); rootOld = Root(spell.ROOT_OLD()); - } function testShareMigrationAgainstRealDeployment() public { guardian = Guardian(spell.GUARDIAN_NEW()); root = Root(spell.ROOT_NEW()); - migrateShares(spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); + migrateShares(spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW(), spell.ADMIN_MULTISIG()); } function testShareMigrationAgainstMockDeployment() public { deployNewContracts(); // Deploy Liquidity Pools v2 - migrateShares(address(root), address(poolManager), address(restrictionManager)); + migrateShares(address(root), address(poolManager), address(restrictionManager), 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD); } - function migrateShares(address root, address poolManager, address restrictionManager) internal { + function migrateShares(address root, address poolManager, address restrictionManager, address adminMultisig) internal { uint256 totalSupplyOld = 0; for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { totalSupplyOld += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); @@ -79,21 +78,22 @@ contract ForkTest is Deployer, Test { assertEq(trancheTokenToMigrate.totalSupply(), totalSupplyOld); // get auth on old TrancheToken through DelayedAdmin - simulate governance - vm.startPrank(spell.ADMIN_MULTISIG()); + vm.prank(spell.ADMIN_MULTISIG()); guardianOld.scheduleRely(address(spell)); // get auth on new TrancheToken through Guardian - simulate governance + // Deployer.sol always sets adminSafe to the EVM multisig, so we override the spell's multisig here during mock deployments + vm.prank(adminMultisig); guardian.scheduleRely(address(spell)); - vm.stopPrank(); // warp delay time = 48H & exec relies vm.warp(block.timestamp + 2 days); rootOld.executeScheduledRely(address(spell)); Root(root).executeScheduledRely(address(spell)); - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { if (spell.memberlistMembers(i) != spell.ESCROW_OLD()) { - uint256 maxMint = - IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).maxMint(spell.VAULT_OLD(), spell.memberlistMembers(i)); + uint256 maxMint = IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).maxMint( + spell.VAULT_OLD(), spell.memberlistMembers(i) + ); balancesOld[spell.memberlistMembers(i)] = trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)) + maxMint; } @@ -101,7 +101,8 @@ contract ForkTest is Deployer, Test { spell.testCast(address(root), address(poolManager), address(restrictionManager)); - Tranche trancheToken = Tranche(address(PoolManager(poolManager).getTranche(spell.POOL_ID(), spell.TRANCHE_ID()))); + Tranche trancheToken = + Tranche(address(PoolManager(poolManager).getTranche(spell.POOL_ID(), spell.TRANCHE_ID()))); // check if all holders have been migrated correctly uint256 totalSupplyNew = 0; @@ -114,7 +115,7 @@ contract ForkTest is Deployer, Test { } } assertEq(trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()), 0); - + // check total supply assertEq(trancheToken.totalSupply(), totalSupplyNew); assertEq(trancheToken.totalSupply(), totalSupplyOld); @@ -136,7 +137,9 @@ contract ForkTest is Deployer, Test { assertEq(Auth(address(root)).wards(address(spell)), 0); // assert vault was deployed - assertTrue(PoolManager(poolManager).getVault(spell.POOL_ID(), spell.TRANCHE_ID(), spell.CURRENCY()) != address(0)); + assertTrue( + PoolManager(poolManager).getVault(spell.POOL_ID(), spell.TRANCHE_ID(), spell.CURRENCY()) != address(0) + ); } function deployNewContracts() internal { From 1e310d3bc7b64e6af49ae7e90243d997a08ad3e9 Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Wed, 31 Jul 2024 23:51:32 -0400 Subject: [PATCH 13/21] forge fmt --- src/spell/ShareMigration_LTF_EVM.sol | 1 - src/spell/ShareMigration_NS3JR_EVM.sol | 5 +---- src/spell/ShareMigration_NS3SR_EVM.sol | 5 +---- test/fork/ShareMigration.t.sol | 11 ++++++++--- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/spell/ShareMigration_LTF_EVM.sol b/src/spell/ShareMigration_LTF_EVM.sol index 4d465dff..8a689de5 100644 --- a/src/spell/ShareMigration_LTF_EVM.sol +++ b/src/spell/ShareMigration_LTF_EVM.sol @@ -4,7 +4,6 @@ import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; // spell to migrate tranche tokens contract MigrationSpell is MigrationSpellBase { - constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses diff --git a/src/spell/ShareMigration_NS3JR_EVM.sol b/src/spell/ShareMigration_NS3JR_EVM.sol index 09b9241b..97ae4a6c 100644 --- a/src/spell/ShareMigration_NS3JR_EVM.sol +++ b/src/spell/ShareMigration_NS3JR_EVM.sol @@ -38,10 +38,7 @@ contract MigrationSpell is MigrationSpellBase { NAME_OLD = "DEPRECATED"; SYMBOL_OLD = "DEPRECATED"; - memberlistMembers = [ - 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, - 0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14 - ]; + memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14]; validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; validUntil[0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14] = 2030638540; diff --git a/src/spell/ShareMigration_NS3SR_EVM.sol b/src/spell/ShareMigration_NS3SR_EVM.sol index 3a1ae0d7..3b584521 100644 --- a/src/spell/ShareMigration_NS3SR_EVM.sol +++ b/src/spell/ShareMigration_NS3SR_EVM.sol @@ -38,10 +38,7 @@ contract MigrationSpell is MigrationSpellBase { NAME_OLD = "DEPRECATED"; SYMBOL_OLD = "DEPRECATED"; - memberlistMembers = [ - 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, - 0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6 - ]; + memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6]; validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; validUntil[0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6] = 4869492494; diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index bf66e935..4cf38986 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -66,10 +66,14 @@ contract ForkTest is Deployer, Test { function testShareMigrationAgainstMockDeployment() public { deployNewContracts(); // Deploy Liquidity Pools v2 - migrateShares(address(root), address(poolManager), address(restrictionManager), 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD); + migrateShares( + address(root), address(poolManager), address(restrictionManager), 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD + ); } - function migrateShares(address root, address poolManager, address restrictionManager, address adminMultisig) internal { + function migrateShares(address root, address poolManager, address restrictionManager, address adminMultisig) + internal + { uint256 totalSupplyOld = 0; for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { totalSupplyOld += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); @@ -81,7 +85,8 @@ contract ForkTest is Deployer, Test { vm.prank(spell.ADMIN_MULTISIG()); guardianOld.scheduleRely(address(spell)); // get auth on new TrancheToken through Guardian - simulate governance - // Deployer.sol always sets adminSafe to the EVM multisig, so we override the spell's multisig here during mock deployments + // Deployer.sol always sets adminSafe to the EVM multisig, so we override the spell's multisig here during mock + // deployments vm.prank(adminMultisig); guardian.scheduleRely(address(spell)); // warp delay time = 48H & exec relies From 5548e5b1eb2579b6bd9ec14f7d5e57634cb92bed Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 08:58:14 -0400 Subject: [PATCH 14/21] derive some addresses via the old vault --- src/spell/MigrationSpellBase.sol | 39 +++++++++++++------------ src/spell/ShareMigration_DYF_EVM.sol | 7 ----- src/spell/ShareMigration_LTF_Base.sol | 7 ----- src/spell/ShareMigration_LTF_Celo.sol | 7 ----- src/spell/ShareMigration_LTF_EVM.sol | 7 ----- src/spell/ShareMigration_NS3JR_EVM.sol | 7 ----- src/spell/ShareMigration_NS3SR_EVM.sol | 7 ----- test/fork/ShareMigration.t.sol | 40 ++++++++++++++++---------- 8 files changed, 45 insertions(+), 76 deletions(-) diff --git a/src/spell/MigrationSpellBase.sol b/src/spell/MigrationSpellBase.sol index 48aba2a3..398cf54d 100644 --- a/src/spell/MigrationSpellBase.sol +++ b/src/spell/MigrationSpellBase.sol @@ -13,27 +13,29 @@ interface ITrancheOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); } +interface IVaultOld { + function poolId() external view returns (uint64); + function trancheId() external view returns (bytes16); + function share() external view returns (address); + function manager() external view returns (address); + function escrow() external view returns (address); + function asset() external view returns (address); +} + contract MigrationSpellBase { using CastLib for *; string public NETWORK; - address public CURRENCY; uint128 public CURRENCY_ID; - address public ESCROW_OLD; - address public INVESTMENTMANAGER_OLD; address public ROOT_OLD; address public ADMIN_MULTISIG; address public GUARDIAN_OLD; - address public TRANCHE_TOKEN_OLD; address public VAULT_OLD; address public ROOT_NEW; address public GUARDIAN_NEW; address public POOLMANAGER_NEW; address public RESTRICTIONMANAGER_NEW; ITranche public trancheTokenNew; - uint64 public POOL_ID; - bytes16 public TRANCHE_ID; - uint8 public DECIMALS; string public NAME; string public SYMBOL; string public NAME_OLD; @@ -54,9 +56,13 @@ contract MigrationSpellBase { self = address(this); IRoot rootOld = IRoot(address(ROOT_OLD)); IRoot rootNew = IRoot(address(ROOT_NEW)); + IVaultOld vaultOld = IVaultOld(VAULT_OLD); + uint64 POOL_ID = vaultOld.poolId(); + bytes16 TRANCHE_ID = vaultOld.trancheId(); IPoolManager poolManager = IPoolManager(address(POOLMANAGER_NEW)); - ITranche trancheTokenOld = ITranche(TRANCHE_TOKEN_OLD); - IInvestmentManager investmentManagerOld = IInvestmentManager(address(INVESTMENTMANAGER_OLD)); + ITranche trancheTokenOld = ITranche(vaultOld.share()); + uint8 DECIMALS = trancheTokenOld.decimals(); + IInvestmentManager investmentManagerOld = IInvestmentManager(vaultOld.manager()); rootOld.relyContract(address(investmentManagerOld), self); rootOld.relyContract(address(trancheTokenOld), self); @@ -64,7 +70,7 @@ contract MigrationSpellBase { rootNew.relyContract(address(POOLMANAGER_NEW), self); poolManager.addPool(POOL_ID); poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER_NEW); - poolManager.addAsset(CURRENCY_ID, CURRENCY); + poolManager.addAsset(CURRENCY_ID, vaultOld.asset()); poolManager.allowAsset(POOL_ID, CURRENCY_ID); trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); rootNew.relyContract(address(trancheTokenNew), self); @@ -82,23 +88,18 @@ contract MigrationSpellBase { validUntil[memberlistMembers[i]] ) ); - if (memberlistMembers[i] != ESCROW_OLD) { + if (memberlistMembers[i] != vaultOld.escrow()) { uint256 maxMint = investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]); if (maxMint > 0) { // Claim any unclaimed tokens the user may have - investmentManagerOld.mint( - VAULT_OLD, - investmentManagerOld.maxMint(VAULT_OLD, memberlistMembers[i]), - memberlistMembers[i], - memberlistMembers[i] - ); + investmentManagerOld.mint(VAULT_OLD, maxMint, memberlistMembers[i], memberlistMembers[i]); } holderBalance = trancheTokenOld.balanceOf(memberlistMembers[i]); if (holderBalance > 0) { // mint new token to the holder's wallet trancheTokenNew.mint(memberlistMembers[i], holderBalance); // transfer old tokens from holders' wallets - ITrancheOld(TRANCHE_TOKEN_OLD).authTransferFrom(memberlistMembers[i], self, holderBalance); + ITrancheOld(vaultOld.share()).authTransferFrom(memberlistMembers[i], self, holderBalance); } } } @@ -118,7 +119,7 @@ contract MigrationSpellBase { IAuth(address(rootOld)).deny(self); IAuth(address(rootNew)).deny(self); - poolManager.deployVault(POOL_ID, TRANCHE_ID, CURRENCY); + poolManager.deployVault(POOL_ID, TRANCHE_ID, vaultOld.asset()); } function getNumberOfMigratedMembers() public view returns (uint256) { diff --git a/src/spell/ShareMigration_DYF_EVM.sol b/src/spell/ShareMigration_DYF_EVM.sol index d87cf346..eab85fa9 100644 --- a/src/spell/ShareMigration_DYF_EVM.sol +++ b/src/spell/ShareMigration_DYF_EVM.sol @@ -17,16 +17,12 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC CURRENCY_ID = 242333941209166991950178742833476896417; - ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; // old pool addresses - TRANCHE_TOKEN_OLD = 0x143dB3a0d0679DFd3372e7F3877BbBB27da3f5e4; VAULT_OLD = 0x110379504D933BeD2E485E281bc3909D1E7C9E5D; // new deployment addresses @@ -36,9 +32,6 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO - set // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - POOL_ID = 1655476167; - TRANCHE_ID = 0x4859c6f181b1b993c35b313bedb949cf; - DECIMALS = 6; NAME = "Anemoy DeFi Yield Fund 1 SP DeFi Yield Fund Token"; SYMBOL = "DYF"; NAME_OLD = "DEPRECATED"; diff --git a/src/spell/ShareMigration_LTF_Base.sol b/src/spell/ShareMigration_LTF_Base.sol index 4cfc04aa..b68eca8c 100644 --- a/src/spell/ShareMigration_LTF_Base.sol +++ b/src/spell/ShareMigration_LTF_Base.sol @@ -10,16 +10,12 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "base-mainnet"; // old deployment addresses - CURRENCY = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; // USDC CURRENCY_ID = 242333941209166991950178742833476896418; - ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0x8b83962fB9dB346a20c95D98d4E312f17f4C0d9b; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; // old pool addresses - TRANCHE_TOKEN_OLD = 0x6D2B49608a716E30bC7aBcFE00181bF261Bf6FC5; VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; // new deployment addresses @@ -29,9 +25,6 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - POOL_ID = 4139607887; - TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; - DECIMALS = 6; NAME = "Anemoy Liquid Treasury Fund 1"; SYMBOL = "LTF"; diff --git a/src/spell/ShareMigration_LTF_Celo.sol b/src/spell/ShareMigration_LTF_Celo.sol index 6b72a721..14950263 100644 --- a/src/spell/ShareMigration_LTF_Celo.sol +++ b/src/spell/ShareMigration_LTF_Celo.sol @@ -10,16 +10,12 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "celo-mainnet"; // old deployment addresses - CURRENCY = 0x37f750B7cC259A2f741AF45294f6a16572CF5cAd; CURRENCY_ID = 242333941209166991950178742833476896420; - ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0x2464f95F6901233bF4a0130A3611d5B4CBd83195; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; // old pool addresses - TRANCHE_TOKEN_OLD = 0x6D2B49608a716E30bC7aBcFE00181bF261Bf6FC5; VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; // new deployment addresses @@ -29,9 +25,6 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - POOL_ID = 4139607887; - TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; - DECIMALS = 6; NAME = "Anemoy Liquid Treasury Fund 1"; SYMBOL = "LTF"; diff --git a/src/spell/ShareMigration_LTF_EVM.sol b/src/spell/ShareMigration_LTF_EVM.sol index 8a689de5..6165c7c9 100644 --- a/src/spell/ShareMigration_LTF_EVM.sol +++ b/src/spell/ShareMigration_LTF_EVM.sol @@ -7,16 +7,12 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // USDC CURRENCY_ID = 242333941209166991950178742833476896417; - ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; // old pool addresses - TRANCHE_TOKEN_OLD = 0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b; VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; // new deployment addresses @@ -26,9 +22,6 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - POOL_ID = 4139607887; - TRANCHE_ID = 0x97aa65f23e7be09fcd62d0554d2e9273; - DECIMALS = 6; NAME = "Anemoy Liquid Treasury Fund 1"; SYMBOL = "LTF"; diff --git a/src/spell/ShareMigration_NS3JR_EVM.sol b/src/spell/ShareMigration_NS3JR_EVM.sol index 97ae4a6c..708334d0 100644 --- a/src/spell/ShareMigration_NS3JR_EVM.sol +++ b/src/spell/ShareMigration_NS3JR_EVM.sol @@ -10,16 +10,12 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; CURRENCY_ID = 242333941209166991950178742833476896417; - ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; // old pool addresses - TRANCHE_TOKEN_OLD = 0xeC9106d0BA35B2228d7Ef3a7c3e7400Cd0f430BD; VAULT_OLD = 0xd0C7E8C9b0c82b74771AE13e184432240A3a2F54; // new deployment addresses @@ -29,9 +25,6 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - POOL_ID = 1615768079; - TRANCHE_ID = 0x6756e091ae798a8e51e12e27ee8facdf; - DECIMALS = 6; NAME = "New Silver Series 3 Junior"; SYMBOL = "NS3JR"; diff --git a/src/spell/ShareMigration_NS3SR_EVM.sol b/src/spell/ShareMigration_NS3SR_EVM.sol index 3b584521..7eb78a1e 100644 --- a/src/spell/ShareMigration_NS3SR_EVM.sol +++ b/src/spell/ShareMigration_NS3SR_EVM.sol @@ -10,16 +10,12 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; CURRENCY_ID = 242333941209166991950178742833476896417; - ESCROW_OLD = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936; - INVESTMENTMANAGER_OLD = 0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; // old pool addresses - TRANCHE_TOKEN_OLD = 0x8d6825d576827bf8E87a17CDD5684E771fbe221C; VAULT_OLD = 0x0d3992B5B5c4fd1c08F73DEd3939e242f0ABd78c; // new deployment addresses @@ -29,9 +25,6 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - POOL_ID = 1615768079; - TRANCHE_ID = 0xda64aae939e4d3a981004619f1709d8f; - DECIMALS = 6; NAME = "New Silver Series 3 Senior"; SYMBOL = "NS3SR"; diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index 4cf38986..bbf8c547 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -10,11 +10,20 @@ import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {Auth} from "src/Auth.sol"; -import {MigrationSpell} from "src/spell/ShareMigration_LTF_Celo.sol"; +import {MigrationSpell} from "src/spell/ShareMigration_LTF_EVM.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; +interface IVaultOld { + function poolId() external view returns (uint64); + function trancheId() external view returns (bytes16); + function share() external view returns (address); + function manager() external view returns (address); + function escrow() external view returns (address); + function asset() external view returns (address); +} + interface TrancheTokenOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); } @@ -53,7 +62,8 @@ contract ForkTest is Deployer, Test { _loadDeployment("mainnet", spell.NETWORK()); _loadFork(0); - trancheTokenToMigrate = Tranche(address(spell.TRANCHE_TOKEN_OLD())); // Anemoy Liquid Treasury Fund 1 (LTF) + IVaultOld vaultOld = IVaultOld(spell.VAULT_OLD()); + trancheTokenToMigrate = Tranche(vaultOld.share()); guardianOld = Guardian(spell.GUARDIAN_OLD()); rootOld = Root(spell.ROOT_OLD()); } @@ -94,11 +104,14 @@ contract ForkTest is Deployer, Test { rootOld.executeScheduledRely(address(spell)); Root(root).executeScheduledRely(address(spell)); + IVaultOld vaultOld = IVaultOld(spell.VAULT_OLD()); + uint64 poolId = vaultOld.poolId(); + bytes16 trancheId = vaultOld.trancheId(); + for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - if (spell.memberlistMembers(i) != spell.ESCROW_OLD()) { - uint256 maxMint = IInvestmentManager(spell.INVESTMENTMANAGER_OLD()).maxMint( - spell.VAULT_OLD(), spell.memberlistMembers(i) - ); + if (spell.memberlistMembers(i) != vaultOld.escrow()) { + uint256 maxMint = + IInvestmentManager(vaultOld.manager()).maxMint(spell.VAULT_OLD(), spell.memberlistMembers(i)); balancesOld[spell.memberlistMembers(i)] = trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)) + maxMint; } @@ -106,8 +119,7 @@ contract ForkTest is Deployer, Test { spell.testCast(address(root), address(poolManager), address(restrictionManager)); - Tranche trancheToken = - Tranche(address(PoolManager(poolManager).getTranche(spell.POOL_ID(), spell.TRANCHE_ID()))); + Tranche trancheToken = Tranche(address(PoolManager(poolManager).getTranche(poolId, trancheId))); // check if all holders have been migrated correctly uint256 totalSupplyNew = 0; @@ -115,11 +127,11 @@ contract ForkTest is Deployer, Test { uint256 balanceNew = trancheToken.balanceOf(spell.memberlistMembers(i)); totalSupplyNew += balanceNew; assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); - if (spell.memberlistMembers(i) != spell.ESCROW_OLD()) { + if (spell.memberlistMembers(i) != vaultOld.escrow()) { assertEq(balanceNew, balancesOld[spell.memberlistMembers(i)]); } } - assertEq(trancheTokenToMigrate.balanceOf(spell.ESCROW_OLD()), 0); + assertEq(trancheTokenToMigrate.balanceOf(vaultOld.escrow()), 0); // check total supply assertEq(trancheToken.totalSupply(), totalSupplyNew); @@ -131,20 +143,18 @@ contract ForkTest is Deployer, Test { assertEq(trancheTokenToMigrate.symbol(), spell.SYMBOL_OLD()); assertEq(trancheToken.name(), spell.NAME()); assertEq(trancheToken.symbol(), spell.SYMBOL()); - assertEq(trancheToken.decimals(), spell.DECIMALS()); + assertEq(trancheToken.decimals(), trancheTokenToMigrate.decimals()); // assert denies assertEq(Auth(address(poolManager)).wards(address(spell)), 0); assertEq(Auth(address(trancheToken)).wards(address(spell)), 0); assertEq(Auth(address(trancheTokenToMigrate)).wards(address(spell)), 0); - assertEq(Auth(spell.INVESTMENTMANAGER_OLD()).wards(address(spell)), 0); + assertEq(Auth(vaultOld.manager()).wards(address(spell)), 0); assertEq(Auth(address(rootOld)).wards(address(spell)), 0); assertEq(Auth(address(root)).wards(address(spell)), 0); // assert vault was deployed - assertTrue( - PoolManager(poolManager).getVault(spell.POOL_ID(), spell.TRANCHE_ID(), spell.CURRENCY()) != address(0) - ); + assertTrue(PoolManager(poolManager).getVault(poolId, trancheId, vaultOld.asset()) != address(0)); } function deployNewContracts() internal { From 05498a2462525969c19619d98ea766b4808ed252 Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 09:10:54 -0400 Subject: [PATCH 15/21] add new deployments --- src/spell/ShareMigration_DYF_EVM.sol | 8 ++++---- src/spell/ShareMigration_LTF_Base.sol | 8 ++++---- src/spell/ShareMigration_LTF_Celo.sol | 8 ++++---- src/spell/ShareMigration_LTF_EVM.sol | 8 ++++---- src/spell/ShareMigration_NS3JR_EVM.sol | 8 ++++---- src/spell/ShareMigration_NS3SR_EVM.sol | 8 ++++---- test/fork/ShareMigration.t.sol | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/spell/ShareMigration_DYF_EVM.sol b/src/spell/ShareMigration_DYF_EVM.sol index eab85fa9..e3637fbe 100644 --- a/src/spell/ShareMigration_DYF_EVM.sol +++ b/src/spell/ShareMigration_DYF_EVM.sol @@ -26,10 +26,10 @@ contract MigrationSpell is MigrationSpellBase { VAULT_OLD = 0x110379504D933BeD2E485E281bc3909D1E7C9E5D; // new deployment addresses - ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO - set - GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; // TODO - set - POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO - set - RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO - set + ROOT_NEW = 0x0C1fDfd6a1331a875EA013F3897fc8a76ada5DfC; + GUARDIAN_NEW = 0x09ab10a9c3E6Eac1d18270a2322B6113F4C7f5E8; + POOLMANAGER_NEW = 0x91808B5E2F6d7483D41A681034D7c9DbB64B9E29; + RESTRICTIONMANAGER_NEW = 0x4737C3f62Cc265e786b280153fC666cEA2fBc0c0; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens NAME = "Anemoy DeFi Yield Fund 1 SP DeFi Yield Fund Token"; diff --git a/src/spell/ShareMigration_LTF_Base.sol b/src/spell/ShareMigration_LTF_Base.sol index b68eca8c..6df194c5 100644 --- a/src/spell/ShareMigration_LTF_Base.sol +++ b/src/spell/ShareMigration_LTF_Base.sol @@ -19,10 +19,10 @@ contract MigrationSpell is MigrationSpellBase { VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; // new deployment addresses - ROOT_NEW = 0x468CBaA7b44851C2426b58190030162d18786b6d; - GUARDIAN_NEW = 0xA0e3A5709995eF9900ab0F7FA070567Fe89d9e18; - POOLMANAGER_NEW = 0x7829E5ca4286Df66e9F58160544097dB517a3B8c; - RESTRICTIONMANAGER_NEW = 0xd35ec9Bd13bC4483D47c850298D5C285C8D1Ec22; + ROOT_NEW = 0x0C1fDfd6a1331a875EA013F3897fc8a76ada5DfC; + GUARDIAN_NEW = 0x427A1ce127b1775e4Cbd4F58ad468B9F832eA7e9; + POOLMANAGER_NEW = 0x7f192F34499DdB2bE06c4754CFf2a21c4B056994; + RESTRICTIONMANAGER_NEW = 0x4737C3f62Cc265e786b280153fC666cEA2fBc0c0; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens NAME = "Anemoy Liquid Treasury Fund 1"; diff --git a/src/spell/ShareMigration_LTF_Celo.sol b/src/spell/ShareMigration_LTF_Celo.sol index 14950263..e719c1d0 100644 --- a/src/spell/ShareMigration_LTF_Celo.sol +++ b/src/spell/ShareMigration_LTF_Celo.sol @@ -19,10 +19,10 @@ contract MigrationSpell is MigrationSpellBase { VAULT_OLD = 0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5; // new deployment addresses - ROOT_NEW = 0x0000000000000000000000000000000000000000; - GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; - POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; - RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; + ROOT_NEW = 0x89e0E9ef81966BfA7D64BBE76394D36014a685c3; + GUARDIAN_NEW = 0x32043A41F4be198C4f6590312F7A7b91624Cab57; + POOLMANAGER_NEW = 0xa3Ce97352C1469884EEF3547Ec9362329FE78Cf0; + RESTRICTIONMANAGER_NEW = 0x9d5fbC48077863d63a883f44F66aCCde72A9D4e2; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens NAME = "Anemoy Liquid Treasury Fund 1"; diff --git a/src/spell/ShareMigration_LTF_EVM.sol b/src/spell/ShareMigration_LTF_EVM.sol index 6165c7c9..436c5b6a 100644 --- a/src/spell/ShareMigration_LTF_EVM.sol +++ b/src/spell/ShareMigration_LTF_EVM.sol @@ -16,10 +16,10 @@ contract MigrationSpell is MigrationSpellBase { VAULT_OLD = 0xB3AC09cd5201569a821d87446A4aF1b202B10aFd; // new deployment addresses - ROOT_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant - RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; // TODO Set and make constant + ROOT_NEW = 0x0C1fDfd6a1331a875EA013F3897fc8a76ada5DfC; + GUARDIAN_NEW = 0x09ab10a9c3E6Eac1d18270a2322B6113F4C7f5E8; + POOLMANAGER_NEW = 0x91808B5E2F6d7483D41A681034D7c9DbB64B9E29; + RESTRICTIONMANAGER_NEW = 0x4737C3f62Cc265e786b280153fC666cEA2fBc0c0; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens NAME = "Anemoy Liquid Treasury Fund 1"; diff --git a/src/spell/ShareMigration_NS3JR_EVM.sol b/src/spell/ShareMigration_NS3JR_EVM.sol index 708334d0..75260dd4 100644 --- a/src/spell/ShareMigration_NS3JR_EVM.sol +++ b/src/spell/ShareMigration_NS3JR_EVM.sol @@ -19,10 +19,10 @@ contract MigrationSpell is MigrationSpellBase { VAULT_OLD = 0xd0C7E8C9b0c82b74771AE13e184432240A3a2F54; // new deployment addresses - ROOT_NEW = 0x0000000000000000000000000000000000000000; - GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; - POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; - RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; + ROOT_NEW = 0x0C1fDfd6a1331a875EA013F3897fc8a76ada5DfC; + GUARDIAN_NEW = 0x09ab10a9c3E6Eac1d18270a2322B6113F4C7f5E8; + POOLMANAGER_NEW = 0x91808B5E2F6d7483D41A681034D7c9DbB64B9E29; + RESTRICTIONMANAGER_NEW = 0x4737C3f62Cc265e786b280153fC666cEA2fBc0c0; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens NAME = "New Silver Series 3 Junior"; diff --git a/src/spell/ShareMigration_NS3SR_EVM.sol b/src/spell/ShareMigration_NS3SR_EVM.sol index 7eb78a1e..182c4c05 100644 --- a/src/spell/ShareMigration_NS3SR_EVM.sol +++ b/src/spell/ShareMigration_NS3SR_EVM.sol @@ -19,10 +19,10 @@ contract MigrationSpell is MigrationSpellBase { VAULT_OLD = 0x0d3992B5B5c4fd1c08F73DEd3939e242f0ABd78c; // new deployment addresses - ROOT_NEW = 0x0000000000000000000000000000000000000000; - GUARDIAN_NEW = 0x0000000000000000000000000000000000000000; - POOLMANAGER_NEW = 0x0000000000000000000000000000000000000000; - RESTRICTIONMANAGER_NEW = 0x0000000000000000000000000000000000000000; + ROOT_NEW = 0x0C1fDfd6a1331a875EA013F3897fc8a76ada5DfC; + GUARDIAN_NEW = 0x09ab10a9c3E6Eac1d18270a2322B6113F4C7f5E8; + POOLMANAGER_NEW = 0x91808B5E2F6d7483D41A681034D7c9DbB64B9E29; + RESTRICTIONMANAGER_NEW = 0x4737C3f62Cc265e786b280153fC666cEA2fBc0c0; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens NAME = "New Silver Series 3 Senior"; diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index bbf8c547..28db95bf 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -10,7 +10,7 @@ import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {Auth} from "src/Auth.sol"; -import {MigrationSpell} from "src/spell/ShareMigration_LTF_EVM.sol"; +import {MigrationSpell} from "src/spell/ShareMigration_LTF_Celo.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; @@ -131,7 +131,7 @@ contract ForkTest is Deployer, Test { assertEq(balanceNew, balancesOld[spell.memberlistMembers(i)]); } } - assertEq(trancheTokenToMigrate.balanceOf(vaultOld.escrow()), 0); + assertEq(trancheTokenToMigrate.balanceOf(vaultOld.escrow()), 0, 1); // check total supply assertEq(trancheToken.totalSupply(), totalSupplyNew); From 3b202f32e8970489533419763642fef40e9bf61e Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 10:48:31 -0400 Subject: [PATCH 16/21] derive currency id, update token names, use approximate asserts --- src/spell/MigrationSpellBase.sol | 12 +++++++++--- src/spell/ShareMigration_DYF_EVM.sol | 7 +++---- src/spell/ShareMigration_LTF_Base.sol | 5 ++--- src/spell/ShareMigration_LTF_Celo.sol | 5 ++--- src/spell/ShareMigration_LTF_EVM.sol | 5 ++--- src/spell/ShareMigration_NS3JR_EVM.sol | 5 ++--- src/spell/ShareMigration_NS3SR_EVM.sol | 5 ++--- test/fork/ShareMigration.t.sol | 14 +++++++------- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/spell/MigrationSpellBase.sol b/src/spell/MigrationSpellBase.sol index 398cf54d..a9fbf081 100644 --- a/src/spell/MigrationSpellBase.sol +++ b/src/spell/MigrationSpellBase.sol @@ -5,7 +5,7 @@ import {IRoot} from "src/interfaces/IRoot.sol"; import {IPoolManager} from "src/interfaces/IPoolManager.sol"; import {RestrictionUpdate} from "src/interfaces/token/IRestrictionManager.sol"; import {ITranche} from "src/interfaces/token/ITranche.sol"; -import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; +import {InvestmentManager} from "src/InvestmentManager.sol"; import {CastLib} from "src/libraries/CastLib.sol"; import {IAuth} from "src/interfaces/IAuth.sol"; @@ -22,11 +22,15 @@ interface IVaultOld { function asset() external view returns (address); } +interface IPoolManagerOld { + function currencyAddressToId(address currency) external view returns (uint128); +} + contract MigrationSpellBase { using CastLib for *; string public NETWORK; - uint128 public CURRENCY_ID; + // uint128 public CURRENCY_ID; address public ROOT_OLD; address public ADMIN_MULTISIG; address public GUARDIAN_OLD; @@ -62,7 +66,9 @@ contract MigrationSpellBase { IPoolManager poolManager = IPoolManager(address(POOLMANAGER_NEW)); ITranche trancheTokenOld = ITranche(vaultOld.share()); uint8 DECIMALS = trancheTokenOld.decimals(); - IInvestmentManager investmentManagerOld = IInvestmentManager(vaultOld.manager()); + InvestmentManager investmentManagerOld = InvestmentManager(vaultOld.manager()); + IPoolManagerOld poolManagerOld = IPoolManagerOld(address(investmentManagerOld.poolManager())); + uint128 CURRENCY_ID = poolManagerOld.currencyAddressToId(vaultOld.asset()); rootOld.relyContract(address(investmentManagerOld), self); rootOld.relyContract(address(trancheTokenOld), self); diff --git a/src/spell/ShareMigration_DYF_EVM.sol b/src/spell/ShareMigration_DYF_EVM.sol index e3637fbe..c7f85bde 100644 --- a/src/spell/ShareMigration_DYF_EVM.sol +++ b/src/spell/ShareMigration_DYF_EVM.sol @@ -17,7 +17,6 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY_ID = 242333941209166991950178742833476896417; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; @@ -32,10 +31,10 @@ contract MigrationSpell is MigrationSpellBase { RESTRICTIONMANAGER_NEW = 0x4737C3f62Cc265e786b280153fC666cEA2fBc0c0; // information to deploy the new tranche token & liquidity pool to be able to migrate the tokens - NAME = "Anemoy DeFi Yield Fund 1 SP DeFi Yield Fund Token"; + NAME = "Anemoy DeFi Yield Fund 1"; SYMBOL = "DYF"; - NAME_OLD = "DEPRECATED"; - SYMBOL_OLD = "DEPRECATED"; + NAME_OLD = "DYF (deprecated)"; + SYMBOL_OLD = "DYF-DEPRECATED"; memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0x30d3bbAE8623d0e9C0db5c27B82dCDA39De40997]; validUntil[0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936] = type(uint64).max; diff --git a/src/spell/ShareMigration_LTF_Base.sol b/src/spell/ShareMigration_LTF_Base.sol index 6df194c5..aafb0a94 100644 --- a/src/spell/ShareMigration_LTF_Base.sol +++ b/src/spell/ShareMigration_LTF_Base.sol @@ -10,7 +10,6 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "base-mainnet"; // old deployment addresses - CURRENCY_ID = 242333941209166991950178742833476896418; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0x8b83962fB9dB346a20c95D98d4E312f17f4C0d9b; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; @@ -28,8 +27,8 @@ contract MigrationSpell is MigrationSpellBase { NAME = "Anemoy Liquid Treasury Fund 1"; SYMBOL = "LTF"; - NAME_OLD = "DEPRECATED"; - SYMBOL_OLD = "DEPRECATED"; + NAME_OLD = "LTF (deprecated)"; + SYMBOL_OLD = "LTF-DEPRECATED"; memberlistMembers = [ 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, diff --git a/src/spell/ShareMigration_LTF_Celo.sol b/src/spell/ShareMigration_LTF_Celo.sol index e719c1d0..c1d02b1a 100644 --- a/src/spell/ShareMigration_LTF_Celo.sol +++ b/src/spell/ShareMigration_LTF_Celo.sol @@ -10,7 +10,6 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "celo-mainnet"; // old deployment addresses - CURRENCY_ID = 242333941209166991950178742833476896420; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0x2464f95F6901233bF4a0130A3611d5B4CBd83195; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; @@ -28,8 +27,8 @@ contract MigrationSpell is MigrationSpellBase { NAME = "Anemoy Liquid Treasury Fund 1"; SYMBOL = "LTF"; - NAME_OLD = "DEPRECATED"; - SYMBOL_OLD = "DEPRECATED"; + NAME_OLD = "LTF (deprecated)"; + SYMBOL_OLD = "LTF-DEPRECATED"; memberlistMembers = [ 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, diff --git a/src/spell/ShareMigration_LTF_EVM.sol b/src/spell/ShareMigration_LTF_EVM.sol index 436c5b6a..35981d26 100644 --- a/src/spell/ShareMigration_LTF_EVM.sol +++ b/src/spell/ShareMigration_LTF_EVM.sol @@ -7,7 +7,6 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY_ID = 242333941209166991950178742833476896417; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; @@ -25,8 +24,8 @@ contract MigrationSpell is MigrationSpellBase { NAME = "Anemoy Liquid Treasury Fund 1"; SYMBOL = "LTF"; - NAME_OLD = "DEPRECATED"; - SYMBOL_OLD = "DEPRECATED"; + NAME_OLD = "LTF (deprecated)"; + SYMBOL_OLD = "LTF-DEPRECATED"; memberlistMembers = [ 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, diff --git a/src/spell/ShareMigration_NS3JR_EVM.sol b/src/spell/ShareMigration_NS3JR_EVM.sol index 75260dd4..ebaa60cd 100644 --- a/src/spell/ShareMigration_NS3JR_EVM.sol +++ b/src/spell/ShareMigration_NS3JR_EVM.sol @@ -10,7 +10,6 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY_ID = 242333941209166991950178742833476896417; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; @@ -28,8 +27,8 @@ contract MigrationSpell is MigrationSpellBase { NAME = "New Silver Series 3 Junior"; SYMBOL = "NS3JR"; - NAME_OLD = "DEPRECATED"; - SYMBOL_OLD = "DEPRECATED"; + NAME_OLD = "NS3JR (deprecated)"; + SYMBOL_OLD = "NS3JR-DEPRECATED"; memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14]; diff --git a/src/spell/ShareMigration_NS3SR_EVM.sol b/src/spell/ShareMigration_NS3SR_EVM.sol index 182c4c05..5ca9bcad 100644 --- a/src/spell/ShareMigration_NS3SR_EVM.sol +++ b/src/spell/ShareMigration_NS3SR_EVM.sol @@ -10,7 +10,6 @@ contract MigrationSpell is MigrationSpellBase { constructor() { NETWORK = "ethereum-mainnet"; // old deployment addresses - CURRENCY_ID = 242333941209166991950178742833476896417; ROOT_OLD = 0x498016d30Cd5f0db50d7ACE329C07313a0420502; ADMIN_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD; GUARDIAN_OLD = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028; @@ -28,8 +27,8 @@ contract MigrationSpell is MigrationSpellBase { NAME = "New Silver Series 3 Senior"; SYMBOL = "NS3SR"; - NAME_OLD = "DEPRECATED"; - SYMBOL_OLD = "DEPRECATED"; + NAME_OLD = "NS3JR (deprecated)"; + SYMBOL_OLD = "NS3JR-DEPRECATED"; memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6]; diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index 28db95bf..b5e5158d 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -126,20 +126,20 @@ contract ForkTest is Deployer, Test { for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { uint256 balanceNew = trancheToken.balanceOf(spell.memberlistMembers(i)); totalSupplyNew += balanceNew; - assertEq(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0); + assertApproxEqAbs(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0, 1); if (spell.memberlistMembers(i) != vaultOld.escrow()) { - assertEq(balanceNew, balancesOld[spell.memberlistMembers(i)]); + assertApproxEqAbs(balanceNew, balancesOld[spell.memberlistMembers(i)], 1); } } - assertEq(trancheTokenToMigrate.balanceOf(vaultOld.escrow()), 0, 1); + assertApproxEqAbs(trancheTokenToMigrate.balanceOf(vaultOld.escrow()), 0, 1); // check total supply - assertEq(trancheToken.totalSupply(), totalSupplyNew); - assertEq(trancheToken.totalSupply(), totalSupplyOld); - assertEq(trancheTokenToMigrate.totalSupply(), 0); + assertApproxEqAbs(trancheToken.totalSupply(), totalSupplyNew, 1); + assertApproxEqAbs(trancheToken.totalSupply(), totalSupplyOld, 1); + assertApproxEqAbs(trancheTokenToMigrate.totalSupply(), 0, 1); // check trancheToken metadata - assertEq(trancheTokenToMigrate.name(), spell.SYMBOL_OLD()); + assertEq(trancheTokenToMigrate.name(), spell.NAME_OLD()); assertEq(trancheTokenToMigrate.symbol(), spell.SYMBOL_OLD()); assertEq(trancheToken.name(), spell.NAME()); assertEq(trancheToken.symbol(), spell.SYMBOL()); From b283ca562ee022485880e6753f5a4297ef3b58f1 Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 10:54:36 -0400 Subject: [PATCH 17/21] update NS3SR old share metadata --- src/spell/ShareMigration_NS3SR_EVM.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/spell/ShareMigration_NS3SR_EVM.sol b/src/spell/ShareMigration_NS3SR_EVM.sol index 5ca9bcad..3002c095 100644 --- a/src/spell/ShareMigration_NS3SR_EVM.sol +++ b/src/spell/ShareMigration_NS3SR_EVM.sol @@ -27,8 +27,8 @@ contract MigrationSpell is MigrationSpellBase { NAME = "New Silver Series 3 Senior"; SYMBOL = "NS3SR"; - NAME_OLD = "NS3JR (deprecated)"; - SYMBOL_OLD = "NS3JR-DEPRECATED"; + NAME_OLD = "NS3SR (deprecated)"; + SYMBOL_OLD = "NS3SR-DEPRECATED"; memberlistMembers = [0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936, 0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6]; From b359596941ae107300a7815eac4932c1daf9256b Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 14:15:30 -0400 Subject: [PATCH 18/21] break spell into two executable parts --- src/spell/MigrationSpellBase.sol | 69 +++++++++++++++++++++----------- test/fork/ShareMigration.t.sol | 7 ++-- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/spell/MigrationSpellBase.sol b/src/spell/MigrationSpellBase.sol index a9fbf081..4213ac5a 100644 --- a/src/spell/MigrationSpellBase.sol +++ b/src/spell/MigrationSpellBase.sol @@ -30,45 +30,65 @@ contract MigrationSpellBase { using CastLib for *; string public NETWORK; - // uint128 public CURRENCY_ID; - address public ROOT_OLD; - address public ADMIN_MULTISIG; - address public GUARDIAN_OLD; - address public VAULT_OLD; address public ROOT_NEW; + IRoot public rootNew; address public GUARDIAN_NEW; address public POOLMANAGER_NEW; address public RESTRICTIONMANAGER_NEW; ITranche public trancheTokenNew; + IPoolManager poolManager; + + address public ROOT_OLD; + IRoot public rootOld; + address public ADMIN_MULTISIG; + address public GUARDIAN_OLD; + address public VAULT_OLD; + uint64 POOL_ID; + bytes16 TRANCHE_ID; + uint8 DECIMALS; + uint128 CURRENCY_ID; + IVaultOld public vaultOld; + ITranche trancheTokenOld; + InvestmentManager investmentManagerOld; + IPoolManagerOld poolManagerOld; + string public NAME; string public SYMBOL; string public NAME_OLD; string public SYMBOL_OLD; address[] public memberlistMembers; mapping(address => uint64) public validUntil; - bool public done; + bool public partOneDone; + bool public partTwoDone; uint256 constant ONE = 10 ** 27; address self; - function cast() public { - require(!done, "spell-already-cast"); - done = true; - execute(); + function castPartOne() public { + require(!partOneDone, "spell-already-cast"); + partOneDone = true; + executePartOne(); + } + + function castPartTwo() public { + require(partOneDone, "part-one-not-cast"); + require(!partTwoDone, "spell-already-cast"); + partTwoDone = true; + executePartTwo(); } - function execute() internal { + function executePartOne() internal { self = address(this); - IRoot rootOld = IRoot(address(ROOT_OLD)); - IRoot rootNew = IRoot(address(ROOT_NEW)); - IVaultOld vaultOld = IVaultOld(VAULT_OLD); - uint64 POOL_ID = vaultOld.poolId(); - bytes16 TRANCHE_ID = vaultOld.trancheId(); - IPoolManager poolManager = IPoolManager(address(POOLMANAGER_NEW)); - ITranche trancheTokenOld = ITranche(vaultOld.share()); - uint8 DECIMALS = trancheTokenOld.decimals(); - InvestmentManager investmentManagerOld = InvestmentManager(vaultOld.manager()); - IPoolManagerOld poolManagerOld = IPoolManagerOld(address(investmentManagerOld.poolManager())); - uint128 CURRENCY_ID = poolManagerOld.currencyAddressToId(vaultOld.asset()); + rootOld = IRoot(address(ROOT_OLD)); + rootNew = IRoot(address(ROOT_NEW)); + vaultOld = IVaultOld(VAULT_OLD); + POOL_ID = vaultOld.poolId(); + TRANCHE_ID = vaultOld.trancheId(); + poolManager = IPoolManager(address(POOLMANAGER_NEW)); + trancheTokenOld = ITranche(vaultOld.share()); + DECIMALS = trancheTokenOld.decimals(); + investmentManagerOld = InvestmentManager(vaultOld.manager()); + poolManagerOld = IPoolManagerOld(address(investmentManagerOld.poolManager())); + CURRENCY_ID = poolManagerOld.currencyAddressToId(vaultOld.asset()); rootOld.relyContract(address(investmentManagerOld), self); rootOld.relyContract(address(trancheTokenOld), self); @@ -80,7 +100,10 @@ contract MigrationSpellBase { poolManager.allowAsset(POOL_ID, CURRENCY_ID); trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); rootNew.relyContract(address(trancheTokenNew), self); + poolManager.deployVault(POOL_ID, TRANCHE_ID, vaultOld.asset()); + } + function executePartTwo() internal { // add all old members to new memberlist and claim any tokens uint256 holderBalance; for (uint8 i; i < memberlistMembers.length; i++) { @@ -124,8 +147,6 @@ contract MigrationSpellBase { rootOld.denyContract(address(investmentManagerOld), self); IAuth(address(rootOld)).deny(self); IAuth(address(rootNew)).deny(self); - - poolManager.deployVault(POOL_ID, TRANCHE_ID, vaultOld.asset()); } function getNumberOfMigratedMembers() public view returns (uint256) { diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index b5e5158d..d97fbe9e 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -10,7 +10,7 @@ import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {Auth} from "src/Auth.sol"; -import {MigrationSpell} from "src/spell/ShareMigration_LTF_Celo.sol"; +import {MigrationSpell} from "src/spell/ShareMigration_LTF_EVM.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; @@ -30,12 +30,11 @@ interface TrancheTokenOld { contract TestableSpell is MigrationSpell { function testCast(address root, address poolManager, address restrictionManager) public { - require(!done, "spell-already-cast"); - done = true; ROOT_NEW = root; POOLMANAGER_NEW = poolManager; RESTRICTIONMANAGER_NEW = restrictionManager; - execute(); + executePartOne(); + executePartTwo(); } } From c1279654d1b99604955ca8186901928030eb423b Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 14:20:56 -0400 Subject: [PATCH 19/21] update tests to cast both parts seperately --- test/fork/ShareMigration.t.sol | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index d97fbe9e..6dabdcf3 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -36,6 +36,20 @@ contract TestableSpell is MigrationSpell { executePartOne(); executePartTwo(); } + + function testCastPartOne(address root, address poolManager, address restrictionManager) public { + ROOT_NEW = root; + POOLMANAGER_NEW = poolManager; + RESTRICTIONMANAGER_NEW = restrictionManager; + executePartOne(); + } + + function testCastPartTwo(address root, address poolManager, address restrictionManager) public { + ROOT_NEW = root; + POOLMANAGER_NEW = poolManager; + RESTRICTIONMANAGER_NEW = restrictionManager; + executePartTwo(); + } } contract ForkTest is Deployer, Test { @@ -116,7 +130,13 @@ contract ForkTest is Deployer, Test { } } - spell.testCast(address(root), address(poolManager), address(restrictionManager)); + spell.testCastPartOne(address(root), address(poolManager), address(restrictionManager)); + + // assert vault and tranche were deployed + assertTrue(PoolManager(poolManager).getVault(poolId, trancheId, vaultOld.asset()) != address(0)); + assertTrue(PoolManager(poolManager).getTranche(poolId, trancheId) != address(0)); + + spell.testCastPartTwo(address(root), address(poolManager), address(restrictionManager)); Tranche trancheToken = Tranche(address(PoolManager(poolManager).getTranche(poolId, trancheId))); @@ -151,9 +171,6 @@ contract ForkTest is Deployer, Test { assertEq(Auth(vaultOld.manager()).wards(address(spell)), 0); assertEq(Auth(address(rootOld)).wards(address(spell)), 0); assertEq(Auth(address(root)).wards(address(spell)), 0); - - // assert vault was deployed - assertTrue(PoolManager(poolManager).getVault(poolId, trancheId, vaultOld.asset()) != address(0)); } function deployNewContracts() internal { From e0309604f4aca9270452451d86d71bc0185eb2bf Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 16:32:22 -0400 Subject: [PATCH 20/21] update tests to test all spells at once --- test/fork/ShareMigration.t.sol | 468 ++++++++++++++++++++++++++------- 1 file changed, 378 insertions(+), 90 deletions(-) diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index 6dabdcf3..602838a2 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -10,7 +10,13 @@ import {CastLib} from "src/libraries/CastLib.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {IInvestmentManager} from "src/interfaces/IInvestmentManager.sol"; import {Auth} from "src/Auth.sol"; -import {MigrationSpell} from "src/spell/ShareMigration_LTF_EVM.sol"; +import {MigrationSpell as LTF_EVM} from "src/spell/ShareMigration_LTF_EVM.sol"; +import {MigrationSpell as DYF_EVM} from "src/spell/ShareMigration_DYF_EVM.sol"; +import {MigrationSpell as NS3SR_EVM} from "src/spell/ShareMigration_NS3SR_EVM.sol"; +import {MigrationSpell as NS3JR_EVM} from "src/spell/ShareMigration_NS3JR_EVM.sol"; +import {MigrationSpell as LTF_Base} from "src/spell/ShareMigration_LTF_Base.sol"; +import {MigrationSpell as LTF_Celo} from "src/spell/ShareMigration_LTF_Celo.sol"; +import {MigrationSpellBase} from "src/spell/MigrationSpellBase.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "script/Deployer.sol"; @@ -28,7 +34,31 @@ interface TrancheTokenOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); } -contract TestableSpell is MigrationSpell { +contract TestableSpell is MigrationSpellBase { + constructor(MigrationSpellBase _baseSpell) { + // Copy all the properties from the base spell + NETWORK = _baseSpell.NETWORK(); + ROOT_OLD = _baseSpell.ROOT_OLD(); + ADMIN_MULTISIG = _baseSpell.ADMIN_MULTISIG(); + GUARDIAN_OLD = _baseSpell.GUARDIAN_OLD(); + VAULT_OLD = _baseSpell.VAULT_OLD(); + ROOT_NEW = _baseSpell.ROOT_NEW(); + GUARDIAN_NEW = _baseSpell.GUARDIAN_NEW(); + POOLMANAGER_NEW = _baseSpell.POOLMANAGER_NEW(); + RESTRICTIONMANAGER_NEW = _baseSpell.RESTRICTIONMANAGER_NEW(); + NAME = _baseSpell.NAME(); + SYMBOL = _baseSpell.SYMBOL(); + NAME_OLD = _baseSpell.NAME_OLD(); + SYMBOL_OLD = _baseSpell.SYMBOL_OLD(); + + uint256 memberCount = _baseSpell.getNumberOfMigratedMembers(); + for (uint256 i = 0; i < memberCount; i++) { + address member = _baseSpell.memberlistMembers(i); + memberlistMembers.push(member); + validUntil[member] = _baseSpell.validUntil(member); + } + } + function testCast(address root, address poolManager, address restrictionManager) public { ROOT_NEW = root; POOLMANAGER_NEW = poolManager; @@ -58,119 +88,381 @@ contract ForkTest is Deployer, Test { using CastLib for *; using stdJson for string; - string[] deployments; - Tranche trancheTokenToMigrate; - Guardian guardianOld; - Root rootOld; + address self; mapping(address => uint256) balancesOld; + string[] deployments; - TestableSpell spell; - - address self; + struct MigrationContext { + TestableSpell spell; + IVaultOld vaultOld; + Tranche trancheTokenToMigrate; + Tranche trancheToken; + uint64 poolId; + bytes16 trancheId; + uint256 totalSupplyOld; + uint256 totalSupplyNew; + } function setUp() public virtual { self = address(this); + } + + function test_LTF_EVM_MigrationAgainstRealDeployment() public { + TestableSpell spell = new TestableSpell(new LTF_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + spell.ROOT_NEW(), + spell.POOLMANAGER_NEW(), + spell.RESTRICTIONMANAGER_NEW(), + spell.ADMIN_MULTISIG(), + spell.GUARDIAN_NEW() + ); + migrateSharesPartTwo(ctx, spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); + } + + function test_LTF_EVM_MigrationAgainstMockDeployment() public { + TestableSpell spell = new TestableSpell(new LTF_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + deployNewContracts(); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + address(root), + address(poolManager), + address(restrictionManager), + 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD, + address(guardian) + ); + migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); + } - spell = new TestableSpell(); + function test_DYF_EVM_MigrationAgainstRealDeployment() public { + TestableSpell spell = new TestableSpell(new DYF_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + spell.ROOT_NEW(), + spell.POOLMANAGER_NEW(), + spell.RESTRICTIONMANAGER_NEW(), + spell.ADMIN_MULTISIG(), + spell.GUARDIAN_NEW() + ); + migrateSharesPartTwo(ctx, spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); + } + function test_DYF_EVM_MigrationAgainstMockDeployment() public { + TestableSpell spell = new TestableSpell(new DYF_EVM()); _loadDeployment("mainnet", spell.NETWORK()); _loadFork(0); - IVaultOld vaultOld = IVaultOld(spell.VAULT_OLD()); - trancheTokenToMigrate = Tranche(vaultOld.share()); - guardianOld = Guardian(spell.GUARDIAN_OLD()); - rootOld = Root(spell.ROOT_OLD()); + deployNewContracts(); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + address(root), + address(poolManager), + address(restrictionManager), + 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD, + address(guardian) + ); + migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); } - function testShareMigrationAgainstRealDeployment() public { - guardian = Guardian(spell.GUARDIAN_NEW()); - root = Root(spell.ROOT_NEW()); - migrateShares(spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW(), spell.ADMIN_MULTISIG()); + function test_NS3SR_EVM_MigrationAgainstRealDeployment() public { + TestableSpell spell = new TestableSpell(new NS3SR_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + spell.ROOT_NEW(), + spell.POOLMANAGER_NEW(), + spell.RESTRICTIONMANAGER_NEW(), + spell.ADMIN_MULTISIG(), + spell.GUARDIAN_NEW() + ); + migrateSharesPartTwo(ctx, spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); } - function testShareMigrationAgainstMockDeployment() public { - deployNewContracts(); // Deploy Liquidity Pools v2 - migrateShares( - address(root), address(poolManager), address(restrictionManager), 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD + function test_NS3SR_EVM_MigrationAgainstMockDeployment() public { + TestableSpell spell = new TestableSpell(new NS3SR_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + deployNewContracts(); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + address(root), + address(poolManager), + address(restrictionManager), + 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD, + address(guardian) ); + migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); } - function migrateShares(address root, address poolManager, address restrictionManager, address adminMultisig) - internal - { - uint256 totalSupplyOld = 0; - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - totalSupplyOld += trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)); - } - // Check that total supply is accounted for - assertEq(trancheTokenToMigrate.totalSupply(), totalSupplyOld); - - // get auth on old TrancheToken through DelayedAdmin - simulate governance - vm.prank(spell.ADMIN_MULTISIG()); - guardianOld.scheduleRely(address(spell)); - // get auth on new TrancheToken through Guardian - simulate governance - // Deployer.sol always sets adminSafe to the EVM multisig, so we override the spell's multisig here during mock - // deployments - vm.prank(adminMultisig); - guardian.scheduleRely(address(spell)); - // warp delay time = 48H & exec relies - vm.warp(block.timestamp + 2 days); - rootOld.executeScheduledRely(address(spell)); - Root(root).executeScheduledRely(address(spell)); - - IVaultOld vaultOld = IVaultOld(spell.VAULT_OLD()); - uint64 poolId = vaultOld.poolId(); - bytes16 trancheId = vaultOld.trancheId(); - - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - if (spell.memberlistMembers(i) != vaultOld.escrow()) { - uint256 maxMint = - IInvestmentManager(vaultOld.manager()).maxMint(spell.VAULT_OLD(), spell.memberlistMembers(i)); - balancesOld[spell.memberlistMembers(i)] = - trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)) + maxMint; - } - } + function test_NS3JR_EVM_MigrationAgainstRealDeployment() public { + TestableSpell spell = new TestableSpell(new NS3JR_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + spell.ROOT_NEW(), + spell.POOLMANAGER_NEW(), + spell.RESTRICTIONMANAGER_NEW(), + spell.ADMIN_MULTISIG(), + spell.GUARDIAN_NEW() + ); + migrateSharesPartTwo(ctx, spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); + } + + function test_NS3JR_EVM_MigrationAgainstMockDeployment() public { + TestableSpell spell = new TestableSpell(new NS3JR_EVM()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + deployNewContracts(); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + address(root), + address(poolManager), + address(restrictionManager), + 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD, + address(guardian) + ); + migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); + } + + function test_LTF_Base_MigrationAgainstRealDeployment() public { + TestableSpell spell = new TestableSpell(new LTF_Base()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + spell.ROOT_NEW(), + spell.POOLMANAGER_NEW(), + spell.RESTRICTIONMANAGER_NEW(), + spell.ADMIN_MULTISIG(), + spell.GUARDIAN_NEW() + ); + migrateSharesPartTwo(ctx, spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); + } + + function test_LTF_Base_MigrationAgainstMockDeployment() public { + TestableSpell spell = new TestableSpell(new LTF_Base()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + deployNewContracts(); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + address(root), + address(poolManager), + address(restrictionManager), + 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD, + address(guardian) + ); + migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); + } + + function test_LTF_Celo_MigrationAgainstRealDeployment() public { + TestableSpell spell = new TestableSpell(new LTF_Celo()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + spell.ROOT_NEW(), + spell.POOLMANAGER_NEW(), + spell.RESTRICTIONMANAGER_NEW(), + spell.ADMIN_MULTISIG(), + spell.GUARDIAN_NEW() + ); + migrateSharesPartTwo(ctx, spell.ROOT_NEW(), spell.POOLMANAGER_NEW(), spell.RESTRICTIONMANAGER_NEW()); + } + + function test_LTF_Celo_MigrationAgainstMockDeployment() public { + TestableSpell spell = new TestableSpell(new LTF_Celo()); + _loadDeployment("mainnet", spell.NETWORK()); + _loadFork(0); + deployNewContracts(); + MigrationContext memory ctx = migrateSharesPartOne( + spell, + address(root), + address(poolManager), + address(restrictionManager), + 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD, + address(guardian) + ); + migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); + } + + // function testAllEVMMigrationsAgainstRealDeployment() public { + // TestableSpell spellLTF = new TestableSpell(new LTF_EVM()); + // _loadDeployment("mainnet", spellLTF.NETWORK()); + // _loadFork(0); + // MigrationContext memory ctxLTF = migrateSharesPartOne( + // spellLTF, + // spellLTF.ROOT_NEW(), + // spellLTF.POOLMANAGER_NEW(), + // spellLTF.RESTRICTIONMANAGER_NEW(), + // spellLTF.ADMIN_MULTISIG(), + // spellLTF.GUARDIAN_NEW() + // ); + // TestableSpell spellDYF = new TestableSpell(new DYF_EVM()); + // MigrationContext memory ctxDYF = migrateSharesPartOne( + // spellDYF, + // spellDYF.ROOT_NEW(), + // spellDYF.POOLMANAGER_NEW(), + // spellDYF.RESTRICTIONMANAGER_NEW(), + // spellDYF.ADMIN_MULTISIG(), + // spellDYF.GUARDIAN_NEW() + // ); + // TestableSpell spellNS3SR = new TestableSpell(new NS3SR_EVM()); + // MigrationContext memory ctxNS3SR = migrateSharesPartOne( + // spellNS3SR, + // spellNS3SR.ROOT_NEW(), + // spellNS3SR.POOLMANAGER_NEW(), + // spellNS3SR.RESTRICTIONMANAGER_NEW(), + // spellNS3SR.ADMIN_MULTISIG(), + // spellNS3SR.GUARDIAN_NEW() + // ); + // TestableSpell spellNS3JR = new TestableSpell(new NS3JR_EVM()); + // MigrationContext memory ctxNS3JR = migrateSharesPartOne( + // spellNS3JR, + // spellNS3JR.ROOT_NEW(), + // spellNS3JR.POOLMANAGER_NEW(), + // spellNS3JR.RESTRICTIONMANAGER_NEW(), + // spellNS3JR.ADMIN_MULTISIG(), + // spellNS3JR.GUARDIAN_NEW() + // ); + // migrateSharesPartTwo( + // ctxLTF, + // spellLTF.ROOT_NEW(), + // spellLTF.POOLMANAGER_NEW(), + // spellLTF.RESTRICTIONMANAGER_NEW() + // ); + // migrateSharesPartTwo( + // ctxDYF, + // spellDYF.ROOT_NEW(), + // spellDYF.POOLMANAGER_NEW(), + // spellDYF.RESTRICTIONMANAGER_NEW() + // ); + // migrateSharesPartTwo( + // ctxNS3SR, + // spellNS3SR.ROOT_NEW(), + // spellNS3SR.POOLMANAGER_NEW(), + // spellNS3SR.RESTRICTIONMANAGER_NEW() + // ); + // migrateSharesPartTwo( + // ctxNS3JR, + // spellNS3JR.ROOT_NEW(), + // spellNS3JR.POOLMANAGER_NEW(), + // spellNS3JR.RESTRICTIONMANAGER_NEW() + // ); + // } + + function migrateSharesPartOne( + TestableSpell spell, + address root, + address poolManager, + address restrictionManager, + address adminMultisig, + address guardian + ) internal returns (MigrationContext memory ctx) { + MigrationContext memory ctx; + ctx.spell = spell; + ctx.vaultOld = IVaultOld(spell.VAULT_OLD()); + ctx.trancheTokenToMigrate = Tranche(ctx.vaultOld.share()); + ctx.poolId = ctx.vaultOld.poolId(); + ctx.trancheId = ctx.vaultOld.trancheId(); + + setupAuthAndBalances(ctx, root, poolManager, restrictionManager, adminMultisig, guardian); spell.testCastPartOne(address(root), address(poolManager), address(restrictionManager)); // assert vault and tranche were deployed - assertTrue(PoolManager(poolManager).getVault(poolId, trancheId, vaultOld.asset()) != address(0)); - assertTrue(PoolManager(poolManager).getTranche(poolId, trancheId) != address(0)); + assertTrue(PoolManager(poolManager).getVault(ctx.poolId, ctx.trancheId, ctx.vaultOld.asset()) != address(0)); + assertTrue(PoolManager(poolManager).getTranche(ctx.poolId, ctx.trancheId) != address(0)); + return ctx; + } + function migrateSharesPartTwo( + MigrationContext memory ctx, + address root, + address poolManager, + address restrictionManager + ) internal { + TestableSpell spell = ctx.spell; spell.testCastPartTwo(address(root), address(poolManager), address(restrictionManager)); - Tranche trancheToken = Tranche(address(PoolManager(poolManager).getTranche(poolId, trancheId))); + ctx.trancheToken = Tranche(address(PoolManager(poolManager).getTranche(ctx.poolId, ctx.trancheId))); + + verifyMigration(ctx, root, poolManager); + } + + function setupAuthAndBalances( + MigrationContext memory ctx, + address root, + address poolManager, + address restrictionManager, + address adminMultisig, + address guardian + ) internal { + ctx.totalSupplyOld = 0; + for (uint8 i; i < ctx.spell.getNumberOfMigratedMembers(); i++) { + ctx.totalSupplyOld += ctx.trancheTokenToMigrate.balanceOf(ctx.spell.memberlistMembers(i)); + } + assertEq(ctx.trancheTokenToMigrate.totalSupply(), ctx.totalSupplyOld); + + Guardian guardianOld = Guardian(ctx.spell.GUARDIAN_OLD()); + vm.prank(ctx.spell.ADMIN_MULTISIG()); + guardianOld.scheduleRely(address(ctx.spell)); - // check if all holders have been migrated correctly - uint256 totalSupplyNew = 0; - for (uint8 i; i < spell.getNumberOfMigratedMembers(); i++) { - uint256 balanceNew = trancheToken.balanceOf(spell.memberlistMembers(i)); - totalSupplyNew += balanceNew; - assertApproxEqAbs(trancheTokenToMigrate.balanceOf(spell.memberlistMembers(i)), 0, 1); - if (spell.memberlistMembers(i) != vaultOld.escrow()) { - assertApproxEqAbs(balanceNew, balancesOld[spell.memberlistMembers(i)], 1); + Guardian guardian = Guardian(guardian); + vm.prank(adminMultisig); + guardian.scheduleRely(address(ctx.spell)); + + vm.warp(block.timestamp + 2 days); + Root rootOld = Root(ctx.spell.ROOT_OLD()); + rootOld.executeScheduledRely(address(ctx.spell)); + Root(root).executeScheduledRely(address(ctx.spell)); + + for (uint8 i; i < ctx.spell.getNumberOfMigratedMembers(); i++) { + if (ctx.spell.memberlistMembers(i) != ctx.vaultOld.escrow()) { + uint256 maxMint = IInvestmentManager(ctx.vaultOld.manager()).maxMint( + ctx.spell.VAULT_OLD(), ctx.spell.memberlistMembers(i) + ); + balancesOld[ctx.spell.memberlistMembers(i)] = + ctx.trancheTokenToMigrate.balanceOf(ctx.spell.memberlistMembers(i)) + maxMint; + } + } + } + + function verifyMigration(MigrationContext memory ctx, address root, address poolManager) internal { + ctx.totalSupplyNew = 0; + for (uint8 i; i < ctx.spell.getNumberOfMigratedMembers(); i++) { + uint256 balanceNew = ctx.trancheToken.balanceOf(ctx.spell.memberlistMembers(i)); + ctx.totalSupplyNew += balanceNew; + assertApproxEqAbs(ctx.trancheTokenToMigrate.balanceOf(ctx.spell.memberlistMembers(i)), 0, 1); + if (ctx.spell.memberlistMembers(i) != ctx.vaultOld.escrow()) { + assertApproxEqAbs(balanceNew, balancesOld[ctx.spell.memberlistMembers(i)], 1); } } - assertApproxEqAbs(trancheTokenToMigrate.balanceOf(vaultOld.escrow()), 0, 1); + assertApproxEqAbs(ctx.trancheTokenToMigrate.balanceOf(ctx.vaultOld.escrow()), 0, 1); - // check total supply - assertApproxEqAbs(trancheToken.totalSupply(), totalSupplyNew, 1); - assertApproxEqAbs(trancheToken.totalSupply(), totalSupplyOld, 1); - assertApproxEqAbs(trancheTokenToMigrate.totalSupply(), 0, 1); + assertApproxEqAbs(ctx.trancheToken.totalSupply(), ctx.totalSupplyNew, 1); + assertApproxEqAbs(ctx.trancheToken.totalSupply(), ctx.totalSupplyOld, 1); + assertApproxEqAbs(ctx.trancheTokenToMigrate.totalSupply(), 0, 1); - // check trancheToken metadata - assertEq(trancheTokenToMigrate.name(), spell.NAME_OLD()); - assertEq(trancheTokenToMigrate.symbol(), spell.SYMBOL_OLD()); - assertEq(trancheToken.name(), spell.NAME()); - assertEq(trancheToken.symbol(), spell.SYMBOL()); - assertEq(trancheToken.decimals(), trancheTokenToMigrate.decimals()); + assertEq(ctx.trancheTokenToMigrate.name(), ctx.spell.NAME_OLD()); + assertEq(ctx.trancheTokenToMigrate.symbol(), ctx.spell.SYMBOL_OLD()); + assertEq(ctx.trancheToken.name(), ctx.spell.NAME()); + assertEq(ctx.trancheToken.symbol(), ctx.spell.SYMBOL()); + assertEq(ctx.trancheToken.decimals(), ctx.trancheTokenToMigrate.decimals()); - // assert denies - assertEq(Auth(address(poolManager)).wards(address(spell)), 0); - assertEq(Auth(address(trancheToken)).wards(address(spell)), 0); - assertEq(Auth(address(trancheTokenToMigrate)).wards(address(spell)), 0); - assertEq(Auth(vaultOld.manager()).wards(address(spell)), 0); - assertEq(Auth(address(rootOld)).wards(address(spell)), 0); - assertEq(Auth(address(root)).wards(address(spell)), 0); + assertEq(Auth(address(poolManager)).wards(address(ctx.spell)), 0); + assertEq(Auth(address(ctx.trancheToken)).wards(address(ctx.spell)), 0); + assertEq(Auth(address(ctx.trancheTokenToMigrate)).wards(address(ctx.spell)), 0); + assertEq(Auth(ctx.vaultOld.manager()).wards(address(ctx.spell)), 0); + assertEq(Auth(ctx.spell.ROOT_OLD()).wards(address(ctx.spell)), 0); + assertEq(Auth(address(root)).wards(address(ctx.spell)), 0); } function deployNewContracts() internal { @@ -188,8 +480,4 @@ contract ForkTest is Deployer, Test { uint256 forkId = vm.createFork(rpcUrl); vm.selectFork(forkId); } - - function _get(uint256 id, string memory key) internal view returns (address) { - return abi.decode(deployments[id].parseRaw(key), (address)); - } } From 6d5636c2e06f9b85984060b8785c05ab4fe593d4 Mon Sep 17 00:00:00 2001 From: Adam Stox Date: Thu, 1 Aug 2024 17:23:57 -0400 Subject: [PATCH 21/21] get the allEVMSpells test working --- src/spell/MigrationSpellBase.sol | 16 +++- test/fork/ShareMigration.t.sol | 134 +++++++++++++++---------------- 2 files changed, 79 insertions(+), 71 deletions(-) diff --git a/src/spell/MigrationSpellBase.sol b/src/spell/MigrationSpellBase.sol index 4213ac5a..6553646f 100644 --- a/src/spell/MigrationSpellBase.sol +++ b/src/spell/MigrationSpellBase.sol @@ -9,6 +9,10 @@ import {InvestmentManager} from "src/InvestmentManager.sol"; import {CastLib} from "src/libraries/CastLib.sol"; import {IAuth} from "src/interfaces/IAuth.sol"; +interface IPoolManagerNew is IPoolManager { + function isPoolActive(uint64 poolId) external view returns (bool); +} + interface ITrancheOld { function authTransferFrom(address from, address to, uint256 value) external returns (bool); } @@ -36,7 +40,7 @@ contract MigrationSpellBase { address public POOLMANAGER_NEW; address public RESTRICTIONMANAGER_NEW; ITranche public trancheTokenNew; - IPoolManager poolManager; + IPoolManagerNew poolManager; address public ROOT_OLD; IRoot public rootOld; @@ -83,7 +87,7 @@ contract MigrationSpellBase { vaultOld = IVaultOld(VAULT_OLD); POOL_ID = vaultOld.poolId(); TRANCHE_ID = vaultOld.trancheId(); - poolManager = IPoolManager(address(POOLMANAGER_NEW)); + poolManager = IPoolManagerNew(address(POOLMANAGER_NEW)); trancheTokenOld = ITranche(vaultOld.share()); DECIMALS = trancheTokenOld.decimals(); investmentManagerOld = InvestmentManager(vaultOld.manager()); @@ -94,9 +98,13 @@ contract MigrationSpellBase { // deploy new tranche token rootNew.relyContract(address(POOLMANAGER_NEW), self); - poolManager.addPool(POOL_ID); + if (!poolManager.isPoolActive(POOL_ID)) { + poolManager.addPool(POOL_ID); + } poolManager.addTranche(POOL_ID, TRANCHE_ID, NAME, SYMBOL, DECIMALS, RESTRICTIONMANAGER_NEW); - poolManager.addAsset(CURRENCY_ID, vaultOld.asset()); + if (poolManager.assetToId(vaultOld.asset()) == 0) { + poolManager.addAsset(CURRENCY_ID, vaultOld.asset()); + } poolManager.allowAsset(POOL_ID, CURRENCY_ID); trancheTokenNew = ITranche(poolManager.deployTranche(POOL_ID, TRANCHE_ID)); rootNew.relyContract(address(trancheTokenNew), self); diff --git a/test/fork/ShareMigration.t.sol b/test/fork/ShareMigration.t.sol index 602838a2..387aee09 100644 --- a/test/fork/ShareMigration.t.sol +++ b/test/fork/ShareMigration.t.sol @@ -89,7 +89,7 @@ contract ForkTest is Deployer, Test { using stdJson for string; address self; - mapping(address => uint256) balancesOld; + mapping(address => mapping(address => uint256)) balancesOld; // member => token => balance string[] deployments; struct MigrationContext { @@ -293,70 +293,70 @@ contract ForkTest is Deployer, Test { migrateSharesPartTwo(ctx, address(root), address(poolManager), address(restrictionManager)); } - // function testAllEVMMigrationsAgainstRealDeployment() public { - // TestableSpell spellLTF = new TestableSpell(new LTF_EVM()); - // _loadDeployment("mainnet", spellLTF.NETWORK()); - // _loadFork(0); - // MigrationContext memory ctxLTF = migrateSharesPartOne( - // spellLTF, - // spellLTF.ROOT_NEW(), - // spellLTF.POOLMANAGER_NEW(), - // spellLTF.RESTRICTIONMANAGER_NEW(), - // spellLTF.ADMIN_MULTISIG(), - // spellLTF.GUARDIAN_NEW() - // ); - // TestableSpell spellDYF = new TestableSpell(new DYF_EVM()); - // MigrationContext memory ctxDYF = migrateSharesPartOne( - // spellDYF, - // spellDYF.ROOT_NEW(), - // spellDYF.POOLMANAGER_NEW(), - // spellDYF.RESTRICTIONMANAGER_NEW(), - // spellDYF.ADMIN_MULTISIG(), - // spellDYF.GUARDIAN_NEW() - // ); - // TestableSpell spellNS3SR = new TestableSpell(new NS3SR_EVM()); - // MigrationContext memory ctxNS3SR = migrateSharesPartOne( - // spellNS3SR, - // spellNS3SR.ROOT_NEW(), - // spellNS3SR.POOLMANAGER_NEW(), - // spellNS3SR.RESTRICTIONMANAGER_NEW(), - // spellNS3SR.ADMIN_MULTISIG(), - // spellNS3SR.GUARDIAN_NEW() - // ); - // TestableSpell spellNS3JR = new TestableSpell(new NS3JR_EVM()); - // MigrationContext memory ctxNS3JR = migrateSharesPartOne( - // spellNS3JR, - // spellNS3JR.ROOT_NEW(), - // spellNS3JR.POOLMANAGER_NEW(), - // spellNS3JR.RESTRICTIONMANAGER_NEW(), - // spellNS3JR.ADMIN_MULTISIG(), - // spellNS3JR.GUARDIAN_NEW() - // ); - // migrateSharesPartTwo( - // ctxLTF, - // spellLTF.ROOT_NEW(), - // spellLTF.POOLMANAGER_NEW(), - // spellLTF.RESTRICTIONMANAGER_NEW() - // ); - // migrateSharesPartTwo( - // ctxDYF, - // spellDYF.ROOT_NEW(), - // spellDYF.POOLMANAGER_NEW(), - // spellDYF.RESTRICTIONMANAGER_NEW() - // ); - // migrateSharesPartTwo( - // ctxNS3SR, - // spellNS3SR.ROOT_NEW(), - // spellNS3SR.POOLMANAGER_NEW(), - // spellNS3SR.RESTRICTIONMANAGER_NEW() - // ); - // migrateSharesPartTwo( - // ctxNS3JR, - // spellNS3JR.ROOT_NEW(), - // spellNS3JR.POOLMANAGER_NEW(), - // spellNS3JR.RESTRICTIONMANAGER_NEW() - // ); - // } + function testAllEVMMigrationsAgainstRealDeployment() public { + TestableSpell spellLTF = new TestableSpell(new LTF_EVM()); + _loadDeployment("mainnet", spellLTF.NETWORK()); + _loadFork(0); + MigrationContext memory ctxLTF = migrateSharesPartOne( + spellLTF, + spellLTF.ROOT_NEW(), + spellLTF.POOLMANAGER_NEW(), + spellLTF.RESTRICTIONMANAGER_NEW(), + spellLTF.ADMIN_MULTISIG(), + spellLTF.GUARDIAN_NEW() + ); + TestableSpell spellDYF = new TestableSpell(new DYF_EVM()); + MigrationContext memory ctxDYF = migrateSharesPartOne( + spellDYF, + spellDYF.ROOT_NEW(), + spellDYF.POOLMANAGER_NEW(), + spellDYF.RESTRICTIONMANAGER_NEW(), + spellDYF.ADMIN_MULTISIG(), + spellDYF.GUARDIAN_NEW() + ); + TestableSpell spellNS3SR = new TestableSpell(new NS3SR_EVM()); + MigrationContext memory ctxNS3SR = migrateSharesPartOne( + spellNS3SR, + spellNS3SR.ROOT_NEW(), + spellNS3SR.POOLMANAGER_NEW(), + spellNS3SR.RESTRICTIONMANAGER_NEW(), + spellNS3SR.ADMIN_MULTISIG(), + spellNS3SR.GUARDIAN_NEW() + ); + TestableSpell spellNS3JR = new TestableSpell(new NS3JR_EVM()); + MigrationContext memory ctxNS3JR = migrateSharesPartOne( + spellNS3JR, + spellNS3JR.ROOT_NEW(), + spellNS3JR.POOLMANAGER_NEW(), + spellNS3JR.RESTRICTIONMANAGER_NEW(), + spellNS3JR.ADMIN_MULTISIG(), + spellNS3JR.GUARDIAN_NEW() + ); + migrateSharesPartTwo( + ctxLTF, + spellLTF.ROOT_NEW(), + spellLTF.POOLMANAGER_NEW(), + spellLTF.RESTRICTIONMANAGER_NEW() + ); + migrateSharesPartTwo( + ctxDYF, + spellDYF.ROOT_NEW(), + spellDYF.POOLMANAGER_NEW(), + spellDYF.RESTRICTIONMANAGER_NEW() + ); + migrateSharesPartTwo( + ctxNS3SR, + spellNS3SR.ROOT_NEW(), + spellNS3SR.POOLMANAGER_NEW(), + spellNS3SR.RESTRICTIONMANAGER_NEW() + ); + migrateSharesPartTwo( + ctxNS3JR, + spellNS3JR.ROOT_NEW(), + spellNS3JR.POOLMANAGER_NEW(), + spellNS3JR.RESTRICTIONMANAGER_NEW() + ); + } function migrateSharesPartOne( TestableSpell spell, @@ -429,7 +429,7 @@ contract ForkTest is Deployer, Test { uint256 maxMint = IInvestmentManager(ctx.vaultOld.manager()).maxMint( ctx.spell.VAULT_OLD(), ctx.spell.memberlistMembers(i) ); - balancesOld[ctx.spell.memberlistMembers(i)] = + balancesOld[ctx.spell.memberlistMembers(i)][address(ctx.trancheTokenToMigrate)] = ctx.trancheTokenToMigrate.balanceOf(ctx.spell.memberlistMembers(i)) + maxMint; } } @@ -442,7 +442,7 @@ contract ForkTest is Deployer, Test { ctx.totalSupplyNew += balanceNew; assertApproxEqAbs(ctx.trancheTokenToMigrate.balanceOf(ctx.spell.memberlistMembers(i)), 0, 1); if (ctx.spell.memberlistMembers(i) != ctx.vaultOld.escrow()) { - assertApproxEqAbs(balanceNew, balancesOld[ctx.spell.memberlistMembers(i)], 1); + assertApproxEqAbs(balanceNew, balancesOld[ctx.spell.memberlistMembers(i)][address(ctx.trancheTokenToMigrate)], 1); } } assertApproxEqAbs(ctx.trancheTokenToMigrate.balanceOf(ctx.vaultOld.escrow()), 0, 1);