Skip to content

Commit

Permalink
setup rpc tests and spell infra (#222)
Browse files Browse the repository at this point in the history
* setup rpc tests and spell imfrastructure

* fix rpc env

* fix file names

* fix typo

* format

* add new lp deployment to spell

* fix typos
  • Loading branch information
ilinzweilin authored Dec 15, 2023
1 parent b76a159 commit 2f07d31
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 0 deletions.
23 changes: 23 additions & 0 deletions deployments/ETH_MAINNET.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.21;

contract Addresses {
address public root = address(0x498016d30Cd5f0db50d7ACE329C07313a0420502);
address public investmentManager = address(0xbBF0AB988691dB1892ADaF7F0eF560Ca4c6DD73A);
address public poolManager = address(0x78E9e622A57f70F1E0Ec652A4931E4e278e58142);
address public gateway = address(0x634F036fE66579E901c7bA34e33DF422E37A0037);
address public escrow = address(0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936);
address public userEscrow= address(0x9fc3A3bcEdc1CaB14EfC1B7ef45dFBDd3d17c9d7);
address public router = address(0x8174D5f12Ce682459864D8C081f9635012Ab51c2);
address public trancheTokenFactory = address(0x4aEFE6CeFEd5D0A30679E41C0B3Fee6cbAa6ADf6);
address public liquidityPoolFactory = address(0x77F48b2c942E6f3ac2232568d560e423c441386a);
address public restrictionManagerFactory = address(0xf4D7F6919eF0B495a2551F7299324961F29aE7aC);
address public pauseAdmin = address(0xce86472007Ea37a5d0208f8C1559A37530c8067C);
address public delayedAdmin = address(0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028);
address public messages = address(0xAf9F6Ac63C057EB7F59b6Fae2c3d447191b58Ea5);
address public deployer = address(0x7270b20603FbB3dF0921381670fbd62b9991aDa4);
address public admin = address(0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD); // multisig

// deployed LPs
address public anemoyToken = address(0x30baA3BA9D7089fD8D020a994Db75D14CF7eC83b);
}
114 changes: 114 additions & 0 deletions test/rpc/RPC.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.21;

import "forge-std/Test.sol";
import {Addresses} from "deployments/ETH_MAINNET.sol";
import {Root} from "src/Root.sol";
import {InvestmentManager} from "src/InvestmentManager.sol";
import {PoolManager} from "src/PoolManager.sol";
import {Escrow} from "src/Escrow.sol";
import {UserEscrow} from "src/UserEscrow.sol";
import {TrancheToken} from "src/token/Tranche.sol";
import {Gateway} from "src/gateway/Gateway.sol";
import {AxelarRouter} from "src/gateway/routers/axelar/Router.sol";
import {TrancheTokenFactory, LiquidityPoolFactory, RestrictionManagerFactory} from "src/util/Factory.sol";
import {DelayedAdmin} from "src/admins/DelayedAdmin.sol";
import {PauseAdmin} from "src/admins/PauseAdmin.sol";

contract RPCTest is Test, Addresses {
uint256 mainnetFork;
string MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");

function setUp() public virtual {
mainnetFork = vm.createFork(MAINNET_RPC_URL); // setup ETH mainnet fork
// use fork
vm.selectFork(mainnetFork);
}

function testContractsWiredCorrectly() public {
// investmentManager
assertEq(address(InvestmentManager(investmentManager).escrow()), escrow);
assertEq(address(InvestmentManager(investmentManager).userEscrow()), userEscrow);
assertEq(address(InvestmentManager(investmentManager).gateway()), gateway);
assertEq(address(InvestmentManager(investmentManager).poolManager()), poolManager);
assertEq(address(Gateway(gateway).investmentManager()), investmentManager);
assertEq(address(PoolManager(poolManager).investmentManager()), investmentManager);
assertEq(InvestmentManager(investmentManager).wards(poolManager), 1);
assertEq(Escrow(escrow).wards(investmentManager), 1);
assertEq(UserEscrow(userEscrow).wards(investmentManager), 1);
assertEq(InvestmentManager(investmentManager).wards(root), 1);
assertEq(InvestmentManager(investmentManager).wards(deployer), 0); // deployer has no permissions

// PoolManager
assertEq(address(PoolManager(poolManager).gateway()), gateway);
assertEq(address(PoolManager(poolManager).escrow()), escrow);
assertEq(address(PoolManager(poolManager).investmentManager()), investmentManager);
assertEq(address(PoolManager(poolManager).trancheTokenFactory()), trancheTokenFactory);
assertEq(address(PoolManager(poolManager).liquidityPoolFactory()), liquidityPoolFactory);
assertEq(address(PoolManager(poolManager).restrictionManagerFactory()), restrictionManagerFactory);
assertEq(address(Gateway(gateway).poolManager()), poolManager);
assertEq(address(InvestmentManager(investmentManager).poolManager()), poolManager);
assertEq(InvestmentManager(investmentManager).wards(poolManager), 1);
assertEq(Escrow(escrow).wards(poolManager), 1);
assertEq(InvestmentManager(investmentManager).wards(poolManager), 1);
assertEq(PoolManager(poolManager).wards(root), 1);
assertEq(PoolManager(poolManager).wards(deployer), 0); // deployer has no permissions

// Gateway
assertEq(address(Gateway(gateway).investmentManager()), investmentManager);
assertEq(address(Gateway(gateway).poolManager()), poolManager);
assertEq(address(Gateway(gateway).root()), root);
assertEq(address(InvestmentManager(investmentManager).gateway()), gateway);
assertEq(address(PoolManager(poolManager).gateway()), gateway);
assertEq(address(Gateway(gateway).outgoingRouter()), router);
assertTrue(Gateway(gateway).incomingRouters(router));
assertEq(Gateway(gateway).wards(root), 1);
assertEq(Root(root).wards(gateway), 1);
assertEq(Gateway(gateway).wards(deployer), 0); // deployer has no permissions

// Escrow
assertEq(Escrow(escrow).wards(root), 1);
assertEq(Escrow(escrow).wards(deployer), 0); // deployer has no permissions

// UserEscrow
assertEq(UserEscrow(userEscrow).wards(root), 1);
assertEq(UserEscrow(userEscrow).wards(deployer), 0); // deployer has no permissions

// router
assertEq(AxelarRouter(router).wards(root), 1);
assertEq(AxelarRouter(router).wards(deployer), 0); // deployer has no permissions

// trancheTokenFactory
assertEq(address(PoolManager(poolManager).trancheTokenFactory()), trancheTokenFactory);
assertEq(TrancheTokenFactory(trancheTokenFactory).wards(root), 1);
assertEq(TrancheTokenFactory(trancheTokenFactory).wards(deployer), 0); // deployer has no permissions

// liquidityPoolFactory
assertEq(address(PoolManager(poolManager).liquidityPoolFactory()), liquidityPoolFactory);
assertEq(LiquidityPoolFactory(liquidityPoolFactory).root(), root);
assertEq(LiquidityPoolFactory(liquidityPoolFactory).wards(root), 1);
assertEq(LiquidityPoolFactory(liquidityPoolFactory).wards(poolManager), 1);
assertEq(LiquidityPoolFactory(liquidityPoolFactory).wards(deployer), 0); // deployer has no permissions

// restrictionMangerFactory
assertEq(address(PoolManager(poolManager).restrictionManagerFactory()), restrictionManagerFactory);
assertEq(RestrictionManagerFactory(restrictionManagerFactory).wards(root), 1);
assertEq(RestrictionManagerFactory(restrictionManagerFactory).wards(deployer), 0); // deployer has no
// permissions

// delayedAdmin
assertEq(address(DelayedAdmin(delayedAdmin).root()), root);
assertEq(DelayedAdmin(delayedAdmin).wards(admin), 1);
assertEq(Root(root).wards(delayedAdmin), 1);
assertEq(DelayedAdmin(delayedAdmin).wards(root), 0);
assertEq(DelayedAdmin(delayedAdmin).wards(deployer), 0); // deployer has no permissions

// pauseAdmin
assertEq(address(PauseAdmin(pauseAdmin).root()), root);
assertEq(PauseAdmin(pauseAdmin).wards(delayedAdmin), 1);
// assertEq(PauseAdmin(pauseAdmin).wards(admin), 0); // todo: add once spell executed
assertEq(Root(root).wards(pauseAdmin), 1);
assertEq(PauseAdmin(pauseAdmin).wards(root), 0);
assertEq(PauseAdmin(pauseAdmin).wards(deployer), 0); // deployer has no permissions
}
}
87 changes: 87 additions & 0 deletions test/spells/Spell.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.21;

import "deployments/ETH_MAINNET.sol";

interface RootLike {
function relyContract(address, address) external;
}

interface FileLike {
function file(bytes32, address) external;
}

interface AuthLike {
function rely(address) external;
function deny(address) external;
}

interface PoolManagerLike {
function removeLiquidityPool(uint64 poolId, bytes16 trancheId, address currency) external;
function deployLiquidityPool(uint64 poolId, bytes16 trancheId, address currency) external returns (address);
function getLiquidityPool(uint64 poolId, bytes16 trancheId, address currency) external returns (address);
}

interface LiquidityPoolLike {
function poolId() external returns (uint64);
function trancheId() external returns (bytes16);
function asset() external returns (address);
}

// Spell to migrate the LiquidityPool factory contract
contract Spell is Addresses {
bool public done;
string public constant description = "Liquidity Pool Factory migration spell";

address public constant LIQUIDITY_POOL_FACTORY_NEW = address(0x8273E36EEcf7A8604BEdEe68FC24Af121B64f165);
address public constant DEPRECATED_LIQUIDITY_POOL = address(0xa0872E8D2975483b2Ab4Afcee729133D8666F6f5);
address public newLiquidityPool;

address self;

function cast() public {
require(!done, "spell-already-cast");
done = true;
execute();
}

function execute() internal {
self = address(this);

// give spell required permissions
RootLike root = RootLike(root);
root.relyContract(LIQUIDITY_POOL_FACTORY_NEW, self);
root.relyContract(poolManager, self);

// spell magic
migrateLiquidityPoolFactory();
migrateLiquidityPool();

// revoke all permissions from spell
AuthLike(address(root)).deny(self);
AuthLike(LIQUIDITY_POOL_FACTORY_NEW).deny(self);
AuthLike(poolManager).deny(self);
}

function migrateLiquidityPoolFactory() internal {
AuthLike(LIQUIDITY_POOL_FACTORY_NEW).rely(poolManager);
AuthLike(LIQUIDITY_POOL_FACTORY_NEW).deny(deployer);
FileLike(poolManager).file("liquidityPoolFactory", LIQUIDITY_POOL_FACTORY_NEW);
}

function migrateLiquidityPool() internal {
LiquidityPoolLike deprectaedLP = LiquidityPoolLike(DEPRECATED_LIQUIDITY_POOL);
address deprectaedLP_ = PoolManagerLike(poolManager).getLiquidityPool(
deprectaedLP.poolId(), deprectaedLP.trancheId(), deprectaedLP.asset()
);
require(deprectaedLP_ == DEPRECATED_LIQUIDITY_POOL, "SPELL - unknown Liquidity Pool");
// remove deprectaed pool
PoolManagerLike(poolManager).removeLiquidityPool(
deprectaedLP.poolId(), deprectaedLP.trancheId(), deprectaedLP.asset()
);
// add new pool
newLiquidityPool = PoolManagerLike(poolManager).deployLiquidityPool(
deprectaedLP.poolId(), deprectaedLP.trancheId(), deprectaedLP.asset()
);
}
}
57 changes: 57 additions & 0 deletions test/spells/Spell.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.21;

import "../rpc/RPC.t.sol";
import "./Spell.sol";

contract SpellTest is RPCTest {
Spell spell;

function setUp() public override {
super.setUp();
spell = new Spell();

address newLPFactory = spell.LIQUIDITY_POOL_FACTORY_NEW();

// rely root on new factory -> to be done manually before spell cast
vm.prank(deployer);
AuthLike(newLPFactory).rely(root);

liquidityPoolFactory = newLPFactory; // replace liquidityPoolFactory address in the deployment addresses to
// check for correct wiring
castSpell();
}

function castSpell() public {
// admin submits a tx to delayedAdmin in order to rely spell -> to be done manually before spell cast
vm.prank(admin);
DelayedAdmin(delayedAdmin).scheduleRely(address(spell));
// warp to the time when the spell can be cast -> current block + delay
vm.warp(block.timestamp + Root(root).delay());
Root(root).executeScheduledRely(address(spell)); // --> to be called after delay has passed
spell.cast();
}

function testCastSuccessful() public {
address newLP_ = spell.newLiquidityPool();
address deprecatedLP_ = spell.DEPRECATED_LIQUIDITY_POOL();
LiquidityPoolLike deprecatedLP = LiquidityPoolLike(deprecatedLP_);
LiquidityPoolLike newLP = LiquidityPoolLike(newLP_);

assertEq(deprecatedLP.poolId(), newLP.poolId());
assertEq(deprecatedLP.trancheId(), newLP.trancheId());
assertEq(deprecatedLP.asset(), newLP.asset());

// check if deprectaed pool removed correctly
assertEq(InvestmentManager(investmentManager).wards(deprecatedLP_), 0);
assertEq(TrancheToken(anemoyToken).wards(deprecatedLP_), 0);
assertEq(TrancheToken(anemoyToken).isTrustedForwarder(deprecatedLP_), false);
assertEq(TrancheToken(anemoyToken).allowance(address(escrow), deprecatedLP_), 0);

// check if new pool added correctly
assertEq(InvestmentManager(investmentManager).wards(newLP_), 1);
assertEq(TrancheToken(anemoyToken).wards(newLP_), 1);
assertEq(TrancheToken(anemoyToken).isTrustedForwarder(newLP_), true);
assertEq(TrancheToken(anemoyToken).allowance(address(escrow), newLP_), UINT256_MAX);
}
}

0 comments on commit 2f07d31

Please sign in to comment.