From a1c5d30f8749b968c5fe642ebb8f0a9633f84d21 Mon Sep 17 00:00:00 2001 From: katzman <84420280+stevieraykatz@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:35:07 -0700 Subject: [PATCH] Get our contracts deployed to Goerli for cross-chain testing (#210) * Add task for specifically deploying local infra * Deploy Router and Registrar to goerli, added goerli to contract-address json * Added new task for fee setting, fixed task for AP params * added infrastructure for managing strategy params * Added deployment task and deployed to Goerli * lint * Add network info updating task * Fixes to tasks * Made changes according to comments, still have some changes that are needed * Remove duped types from types, fix some small nits * lint * Use deployer address as placeholder until we have a ms on goerli * Remove unused import * Fixes and cleanup after merging master, new task for deploying all of Side Chain * Updates to dummy strategy, deployed new version * Fixes to tasks to use APTeamMS as owner of registrar, new task for updating network configs * Small fix to updateRegistrarNetworkConnections and other small changes to existing tasks * Registrar-related script fixes (#221) Good finds all around. * Add primary registrar upgrade task, upgrade registrar on mumbai * Remove debug logging * Fixed bad assumption in updateRegistrarNetworkConnections * Fixed issues in Router, adjusted tests accordingly (#229) --------- Co-authored-by: Nenad Misic --- contract-address.json | 237 +++++++++++++++--- .../accounts/facets/AccountsSwapRouter.sol | 1 - contracts/core/registrar/Registrar.sol | 4 +- contracts/core/registrar/message.sol | 3 +- contracts/core/registrar/scripts/deploy.ts | 87 ++++++- contracts/core/router/Router.sol | 12 +- contracts/integrations/dummy/GoerliDummy.sol | 28 +++ contracts/integrations/stratConfig.ts | 29 +++ .../integrations/strategy-addresses.json | 1 + contracts/test/DummyStrategy.sol | 4 +- tasks/deploy/deployAngelProtocol.ts | 18 +- tasks/deploy/deployLocalRegistrar.ts | 90 +++++++ tasks/deploy/deployRegistrar.ts | 4 +- tasks/deploy/deploySideChain.ts | 51 ++++ tasks/deploy/index.ts | 2 + tasks/deploy/integrations/dummyIntegration.ts | 98 ++++++++ tasks/deploy/integrations/index.ts | 1 + tasks/helpers/deploy/deployDummyERC20.ts | 4 - tasks/helpers/updateRegistrar.ts | 39 ++- tasks/manage/accounts/updateConfig.ts | 6 +- tasks/manage/registrar/index.ts | 2 + tasks/manage/registrar/setAPParams.ts | 55 ++-- .../registrar/setAccountsChainAndAddress.ts | 22 +- tasks/manage/registrar/setFeeSetting.ts | 70 ++++++ tasks/manage/registrar/setGasByToken.ts | 23 +- tasks/manage/registrar/setNetworkInfo.ts | 43 ++++ tasks/manage/registrar/setRebalParams.ts | 36 ++- tasks/manage/registrar/setStratApproval.ts | 38 ++- tasks/manage/registrar/setStratParams.ts | 64 ++--- tasks/manage/registrar/setTokenAccepted.ts | 23 +- tasks/upgrade/index.ts | 1 + tasks/upgrade/upgradeRegistrar.ts | 60 +++++ test/core/accounts/AccountsStrategy.ts | 6 +- test/core/router/Router.ts | 142 ++++------- test/utils/Registrar.ts | 5 +- test/utils/helpers/accounts/defaults.ts | 6 +- test/utils/helpers/types.ts | 10 - utils/constants.ts | 5 + utils/index.ts | 1 + utils/manageAddressFile/manageAddressFile.ts | 10 +- utils/manageStratParams/helpers.ts | 19 ++ utils/manageStratParams/index.ts | 3 + utils/manageStratParams/manageStratParams.ts | 33 +++ utils/manageStratParams/types.ts | 33 +++ utils/networkHelpers.ts | 28 +++ utils/twoWayMap.ts | 18 ++ 46 files changed, 1172 insertions(+), 303 deletions(-) create mode 100644 contracts/integrations/dummy/GoerliDummy.sol create mode 100644 contracts/integrations/stratConfig.ts create mode 100644 contracts/integrations/strategy-addresses.json create mode 100644 tasks/deploy/deployLocalRegistrar.ts create mode 100644 tasks/deploy/deploySideChain.ts create mode 100644 tasks/deploy/integrations/dummyIntegration.ts create mode 100644 tasks/manage/registrar/setFeeSetting.ts create mode 100644 tasks/manage/registrar/setNetworkInfo.ts create mode 100644 tasks/upgrade/upgradeRegistrar.ts create mode 100644 utils/manageStratParams/helpers.ts create mode 100644 utils/manageStratParams/index.ts create mode 100644 utils/manageStratParams/manageStratParams.ts create mode 100644 utils/manageStratParams/types.ts create mode 100644 utils/twoWayMap.ts diff --git a/contract-address.json b/contract-address.json index 7a548d486..7bd25d126 100644 --- a/contract-address.json +++ b/contract-address.json @@ -1,30 +1,187 @@ { + "5": { + "accounts": { + "diamond": "", + "facets": { + "accountsDeployContract": "", + "accountsDepositWithdrawEndowments": "", + "accountsDonationMatch": "", + "accountsAllowance": "", + "accountsCreateEndowment": "", + "accountsDaoEndowments": "", + "accountsQueryEndowments": "", + "accountsStrategy": "", + "accountsSwapRouter": "", + "accountsUpdate": "", + "accountsUpdateEndowments": "", + "accountsUpdateEndowmentSettingsController": "", + "accountsUpdateStatusEndowments": "", + "diamondCutFacet": "", + "diamondInitFacet": "", + "diamondLoupeFacet": "", + "ownershipFacet": "" + } + }, + "axelar": { + "gasService": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31" + }, + "donationMatch": { + "emitter": "", + "implementation": "" + }, + "donationMatchCharity": { + "implementation": "", + "proxy": "" + }, + "fundraising": { + "implementation": "", + "proxy": "" + }, + "gasFwd": { + "factory": "", + "implementation": "" + }, + "giftcards": { + "implementation": "", + "proxy": "" + }, + "goldfinch": { + "liquidVault": "", + "lockedVault": "" + }, + "halo": { + "airdrop": { + "implementation": "", + "proxy": "" + }, + "collector": { + "implementation": "", + "proxy": "" + }, + "community": { + "implementation": "", + "proxy": "" + }, + "distributor": { + "implementation": "", + "proxy": "" + }, + "erc20Upgrade": { + "implementation": "", + "proxy": "" + }, + "gov": { + "implementation": "", + "proxy": "" + }, + "govHodler": { + "implementation": "", + "proxy": "" + }, + "staking": { + "implementation": "", + "proxy": "" + }, + "timelock": { + "implementation": "", + "proxy": "" + }, + "token": "", + "vesting": { + "implementation": "", + "proxy": "" + }, + "votingERC20": { + "implementation": "", + "proxy": "" + } + }, + "incentivisedVotingLockup": { + "implementation": "" + }, + "indexFund": { + "implementation": "", + "proxy": "" + }, + "libraries": { + "angelCoreStruct": "", + "stringArray": "" + }, + "multiSig": { + "charityApplications": { + "implementation": "", + "proxy": "" + }, + "apTeam": { + "implementation": "0x39e698a2e9Dc5D65C42f9C0cd50904F9b46b42A3", + "proxy": "0x68E73152a3B6Fa0652d5EA5D977adEe4e168b145" + }, + "endowment": { + "emitter": { + "implementation": "", + "proxy": "" + }, + "factory": "", + "implementation": "" + } + }, + "registrar": { + "implementation": "0x24957c065471FdF299C99AA07395539a5d66B323", + "proxy": "0xD3d0B4fFF90c36e1a31d478e35d699f432428Ae5" + }, + "router": { + "implementation": "0xeaBeA4b0586CFD0263D5ebadCe2C31Ec4F03bc58", + "proxy": "0xd5018Bb152CB34B1CB0B406f4B9BbB9f03a3Db41" + }, + "subDao": { + "emitter": { + "implementation": "", + "proxy": "" + }, + "implementation": "", + "token": "", + "veBondingToken": "" + }, + "tokens": { + "dai": "", + "halo": "", + "reserveToken": "", + "seedAsset": "", + "usdc": "0x254d06f33bDc5b8ee05b2ea472107E300226659A", + "wmatic": "0xA108830A23A9a054FfF4470a8e6292da0886A4D4" + }, + "uniswap": { + "factory": "", + "swapRouter": "" + } + }, "31337": { "accounts": { - "diamond": "0x84227190685c25c4aF662EE1bD0E4cd82e57360D", + "diamond": "0x16fb8e3ab0AF1da9c6e6a589DD025E6558F496Bc", "facets": { - "accountsDeployContract": "0xA82ED5224ba72f2f776e09B11DC99E30Ee65Da8d", - "accountsDepositWithdrawEndowments": "0x1dBDba33dfA381bCC89FCe74DFF69Aa96B53b503", - "accountsDonationMatch": "0x17C8b71E5eE01A726766c99d397D619219C8CAF3", - "accountsAllowance": "0x7798A400cBe0Ca14a7D614ECa1CD15adE5055413", - "accountsCreateEndowment": "0x7B3Be2dDDdDf9A0a3fE1DC57B98980F662C3a422", - "accountsDaoEndowments": "0x8990C5DAAA40673eF8826990A6Fd8284a0a17d61", - "accountsQueryEndowments": "0xf69E1dFAc3D43F438Bae80090b8E186B0231CFeb", - "accountsStrategy": "0x650aEF4b63095e4EDe581BC79CdeA927e3ba553A", - "accountsSwapRouter": "0x90352F820342f8BE0012848bCB8aBd37877d7ec2", - "accountsUpdate": "0xE4F89Fb0dBb45378633c05ACAb071eB998F0A736", - "accountsUpdateEndowments": "0x82B642D9deDb3Ad19b8E99FF3792A49d4d9d85Bf", - "accountsUpdateEndowmentSettingsController": "0x9Fe28b717aDE38BA99E32c45BE3Ee4291f2E338B", - "accountsUpdateStatusEndowments": "0xDDEec1224034F4A68A2697eF13379a014fa60261", - "diamondCutFacet": "0x1D99a347B5EcdbAa3C5365470d461Cf66B77ECd2", - "diamondInitFacet": "0xbe241D1B7b54bF06742cefd45A3440C6562f7603", - "diamondLoupeFacet": "0x199c27B10a195ee79e02d50846e59A4aFB82CAD1", - "ownershipFacet": "0x3c705dB336C81c7FEFC5746e283aB2c0781A4B7b" + "accountsDeployContract": "0xC4A743126DCcA4DF85B8f75B6eD113bb69dD65A1", + "accountsDepositWithdrawEndowments": "0xA303374bda3A6Ce7550514E6681228Ca12020BBA", + "accountsDonationMatch": "0xB6B18cae509Fcf3542FF6975C2Da06CAAc9773c5", + "accountsAllowance": "0x7F6D5d1bDFB4b281374285510A845cb140d4367b", + "accountsCreateEndowment": "0x455A2aC2F917956c0f2664992C1DDd9Cd6562976", + "accountsDaoEndowments": "0x4060eF0D5a7F0633c5927F7E05041dd7Fcd95f42", + "accountsQueryEndowments": "0xA9526DFDd289b2C2ADa83E07c6dd293AA2C5fEe9", + "accountsStrategy": "0x32Ed2BD67238Be274E127096F42f0a4061aC0Bff", + "accountsSwapRouter": "0x4dcA4bFA0bAa0C8ce741b92B255D967599d994f0", + "accountsUpdate": "0xD7a385546a6a2355C6a1DfAdf33b55c43e2C19B0", + "accountsUpdateEndowments": "0xfAB9d4FA5c03Aa5EaccE715d02E6db648cEE91a3", + "accountsUpdateEndowmentSettingsController": "0x715214AeEf7D4C78b9c329cc4D7375cC08670843", + "accountsUpdateStatusEndowments": "0x15E1268353F6F19D9de2722bD60eC1081b45D3a6", + "diamondCutFacet": "0x8e1f69CfFd8DaD657bF18B91D75BcD26CD6F43AC", + "diamondInitFacet": "0x904df20E7d5A1D577c3763FC7bF35EFa51Df94da", + "diamondLoupeFacet": "0x9cD5998cd48385cb69AE7AaDdFaC83A5DA185FaA", + "ownershipFacet": "0x43dFD957bB91b568176E976A8d4e8ab4E94aeBfD" } }, "axelar": { - "gasService": "0x7290f72B5C67052DDE8e6E179F7803c493e90d3f", - "gateway": "0x0AFdAcD509e73115EA1654B1a770f1a807e7c9C0" + "gasService": "0x2Eb2BBAAF8D16E8BA07BD40D141a7E25C6dD9945", + "gateway": "0x4ee108458a4D97dAa2f8eF90A73942AC7B3a9209" }, "donationMatch": { "emitter": "", @@ -39,8 +196,8 @@ "proxy": "" }, "gasFwd": { - "factory": "0xB0748F8B73C53aB94b3DD1109f3427B7Bb2907F5", - "implementation": "0xDeBD0Bc00932E8b5bEfF65053989B0687c894b5F" + "factory": "0xf342D22125Eddc24c6c3D716E048388D1415C20d", + "implementation": "0x07dEF209701605580893ecd7C3cE2340f5b16875" }, "giftcards": { "implementation": "", @@ -101,8 +258,8 @@ "implementation": "" }, "indexFund": { - "implementation": "0x34E59e53Bd4f1A60ca8b6c21572509027571341d", - "proxy": "0x0165878A594ca255338adfa4d48449f69242Eb8F" + "implementation": "0x59c7E6B2c565Ff92B762523BD6B778CE66dC0302", + "proxy": "0x9A676e781A523b5d0C0e43731313A708CB607508" }, "libraries": { "angelCoreStruct": "", @@ -110,29 +267,29 @@ }, "multiSig": { "charityApplications": { - "implementation": "0x549bc7EE4B85A2Df5F74799f213483CE599F1999", - "proxy": "0xEe54514745B056F07040CaCF801f59031D801431" + "implementation": "0x9687796759CAbecC1674A4Aaf23889fC9EC2FCA2", + "proxy": "0xD63c1597435d2E16d7f216A12A3dA65B3bF12241" }, "apTeam": { - "implementation": "0xD499f5F7d3C918D0e553BA03954c4E02af16B6e4", - "proxy": "0xDadd1125B8Df98A66Abd5EB302C0d9Ca5A061dC2" + "implementation": "0x5C15f56Ee55531f011c6025B205c1750EA469f75", + "proxy": "0xb3e2d928Da7c16d53a8d6DaA14314159fa262754" }, "endowment": { "emitter": { - "implementation": "0xa115891Cae16388b84cb7a521A2032f6b354FE25", - "proxy": "0x6ad448bF2AdbF3A7Aa9BfE411eD908315566aE24" + "implementation": "0x6b07B7A11cF992B436DE5d3bf28F50eBA606649b", + "proxy": "0x05275a4799cd1B07D81319390fC62Bc7BDbDf269" }, - "factory": "0x9B4aC8FAfC44575C6963fA22D50963379e899a49", - "implementation": "0x20F43316cf784C821a65aE874c8060f30c30c7C4" + "factory": "0x086bCD73D03A5e1163A9224Fa09dC5cF70d73094", + "implementation": "0x1F570bf89d86a2C43B9b8d0867267719FC58173D" } }, "registrar": { - "implementation": "0x2572e04Caf46ba8692Bd6B4CBDc46DAA3cA9647E", - "proxy": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0" + "implementation": "0xADcb9331bfB37dC1b0db12d73c5aFeC3a6c99ce5", + "proxy": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1" }, "router": { - "implementation": "0x72F375F23BCDA00078Ac12e7e9E7f6a8CA523e7D", - "proxy": "0xf23B8c9debCdCEa2a40E81c3f6d786987069D40d" + "implementation": "0x6039565f9ff755754E9C52B6DFE4aB7bA6dB2957", + "proxy": "0x8896Dce0E60a706244553ADA1aAc5CDCc40a0428" }, "subDao": { "emitter": { @@ -147,9 +304,9 @@ "dai": "", "halo": "", "reserveToken": "", - "seedAsset": "0xc63d2a04762529edB649d7a4cC3E57A0085e8544", - "usdc": "0x093e8F4d8f267d2CeEc9eB889E2054710d187beD", - "wmatic": "0x34ee84036C47d852901b7069aBD80171D9A489a6" + "seedAsset": "0x1C3f3A797B80315faD4DB7D1a58f3AA934118e03", + "usdc": "0xb8348E945900083A270D9244614d09F9c4937d75", + "wmatic": "0x1D1aEE6D5dC35F3c15E2D11083D0e59C026b64c4" }, "uniswap": { "factory": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", @@ -284,7 +441,7 @@ } }, "registrar": { - "implementation": "0x91d385Ae51b116ac5146143F07CFF45354f5f9D7", + "implementation": "0x9956556BB0697c4cd8800e17043EDDC9D87CfC00", "proxy": "0xe1215B3e150dd298d787D41a4879959D30Dc3939" }, "router": { diff --git a/contracts/core/accounts/facets/AccountsSwapRouter.sol b/contracts/core/accounts/facets/AccountsSwapRouter.sol index d1d493058..dc0cba84c 100644 --- a/contracts/core/accounts/facets/AccountsSwapRouter.sol +++ b/contracts/core/accounts/facets/AccountsSwapRouter.sol @@ -129,7 +129,6 @@ contract AccountsSwapRouter is ReentrancyGuardFacet, IAccountsEvents, IAccountsS IERC20(tokenIn).safeApprove(address(registrar_config.uniswapRouter), amountIn); - // Who ya gonna call? Swap Function! uint256 amountOut = swap( tokenIn, diff --git a/contracts/core/registrar/Registrar.sol b/contracts/core/registrar/Registrar.sol index c35e4fa11..6c0b13421 100644 --- a/contracts/core/registrar/Registrar.sol +++ b/contracts/core/registrar/Registrar.sol @@ -63,13 +63,13 @@ contract Registrar is LocalRegistrar, Storage, ReentrancyGuard { emit ConfigUpdated(); LocalRegistrarLib.LocalRegistrarStorage storage lrs = LocalRegistrarLib.localRegistrarStorage(); - lrs.NetworkConnections["Polygon"] = IAccountsStrategy.NetworkInfo({ + lrs.NetworkConnections[details.networkName] = IAccountsStrategy.NetworkInfo({ chainId: block.chainid, router: details.router, axelarGateway: details.axelarGateway, ibcChannel: "", transferChannel: "", - gasReceiver: details.axelarGasRecv, + gasReceiver: details.axelarGasService, gasLimit: 0 }); emit NetworkConnectionPosted(block.chainid); diff --git a/contracts/core/registrar/message.sol b/contracts/core/registrar/message.sol index 315cc50ac..9338aa08b 100644 --- a/contracts/core/registrar/message.sol +++ b/contracts/core/registrar/message.sol @@ -10,7 +10,8 @@ library RegistrarMessages { LibAccounts.SplitDetails splitToLiquid; address router; address axelarGateway; - address axelarGasRecv; + address axelarGasService; + string networkName; } struct UpdateConfigRequest { diff --git a/contracts/core/registrar/scripts/deploy.ts b/contracts/core/registrar/scripts/deploy.ts index 899f56730..1457fdbd7 100644 --- a/contracts/core/registrar/scripts/deploy.ts +++ b/contracts/core/registrar/scripts/deploy.ts @@ -1,17 +1,25 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import config from "config"; import {HardhatRuntimeEnvironment} from "hardhat/types"; -import {ProxyContract__factory, Registrar__factory} from "typechain-types"; -import {Deployment, getContractName, logger, updateAddresses, validateAddress} from "utils"; +import {LocalRegistrar__factory, ProxyContract__factory, Registrar__factory} from "typechain-types"; +import { + Deployment, + getChainId, + getContractName, + getNetworkNameFromChainId, + logger, + updateAddresses, + validateAddress, +} from "utils"; -type Data = { +type RegistrarDeployData = { axelarGateway: string; axelarGasService: string; router: string; owner?: string; deployer: SignerWithAddress; proxyAdmin: SignerWithAddress; - treasuryAddress: string; + treasury: string; }; export async function deployRegistrar( @@ -22,13 +30,16 @@ export async function deployRegistrar( owner = "", deployer, proxyAdmin, - treasuryAddress, - }: Data, + treasury, + }: RegistrarDeployData, hre: HardhatRuntimeEnvironment ): Promise { logger.out("Deploying Registrar..."); try { + const chainId = await getChainId(hre); + const networkName = getNetworkNameFromChainId(chainId); + validateAddress(axelarGateway, "axelarGateway"); validateAddress(axelarGasService, "axelarGasService"); validateAddress(owner, "owner"); @@ -44,14 +55,15 @@ export async function deployRegistrar( // deploy proxy logger.out("Deploying proxy..."); const initData = registrar.interface.encodeFunctionData( - "initialize((address,(uint256,uint256,uint256),address,address,address))", + "initialize((address,(uint256,uint256,uint256),address,address,address,string))", [ { - treasury: treasuryAddress, + treasury, splitToLiquid: config.REGISTRAR_DATA.splitToLiquid, - router: router, - axelarGateway: axelarGateway, - axelarGasRecv: axelarGasService, + router, + axelarGateway, + axelarGasService, + networkName, }, ] ); @@ -82,3 +94,56 @@ export async function deployRegistrar( logger.out(error, logger.Level.Error); } } + +type LocalRegistrarDeployData = { + owner?: string; + deployer: SignerWithAddress; + proxyAdmin: SignerWithAddress; +}; + +export async function deployLocalRegistrar( + {owner = "", deployer, proxyAdmin}: LocalRegistrarDeployData, + hre: HardhatRuntimeEnvironment +): Promise { + logger.out("Deploying Local Registrar..."); + + try { + validateAddress(owner, "owner"); + // deploy implementation + logger.out("Deploying implementation..."); + const factory = new LocalRegistrar__factory(proxyAdmin); + const localRegistrar = await factory.deploy(); + await localRegistrar.deployed(); + logger.out(`Address: ${localRegistrar.address}`); + + // deploy proxy + logger.out("Deploying proxy..."); + const proxyFactory = new ProxyContract__factory(deployer); + const initData = localRegistrar.interface.encodeFunctionData("initialize"); + const proxy = await proxyFactory.deploy(localRegistrar.address, proxyAdmin.address, initData); + await proxy.deployed(); + logger.out(`Address: ${proxy.address}`); + + // update owner + logger.out(`Updating Registrar owner to '${owner}'..."`); + const proxiedRegistrar = LocalRegistrar__factory.connect(proxy.address, deployer); + logger.out(`Current owner: ${await proxiedRegistrar.owner()}`); + const tx = await proxiedRegistrar.transferOwnership(owner); + await tx.wait(); + + // update address file & verify contracts + await updateAddresses( + { + registrar: { + implementation: localRegistrar.address, + proxy: proxy.address, + }, + }, + hre + ); + + return {address: proxy.address, contractName: getContractName(factory)}; + } catch (error) { + logger.out(error, logger.Level.Error); + } +} diff --git a/contracts/core/router/Router.sol b/contracts/core/router/Router.sol index e69b0a605..677d91c1b 100644 --- a/contracts/core/router/Router.sol +++ b/contracts/core/router/Router.sol @@ -11,13 +11,12 @@ import {LocalRegistrarLib} from "../registrar/lib/LocalRegistrarLib.sol"; import {StringToAddress} from "../../lib/StringAddressUtils.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {AxelarExecutable} from "../../axelar/AxelarExecutable.sol"; import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; import {IAxelarGasService} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol"; import {IAxelarExecutable} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarExecutable.sol"; -contract Router is IRouter, OwnableUpgradeable, AxelarExecutable { +contract Router is IRouter, AxelarExecutable { using SafeERC20 for IERC20Metadata; string public chain; ILocalRegistrar public registrar; @@ -39,7 +38,6 @@ contract Router is IRouter, OwnableUpgradeable, AxelarExecutable { registrar = ILocalRegistrar(_registrar); gasReceiver = IAxelarGasService(_gasReceiver); __AxelarExecutable_init_unchained(_gateway); - __Ownable_init_unchained(); } /*/////////////////////////////////////////////// @@ -65,14 +63,12 @@ contract Router is IRouter, OwnableUpgradeable, AxelarExecutable { require(action.accountIds.length == 1, "Only one account allowed"); // deposit only require(action.selector == IVault.deposit.selector, "Only deposit accepts tokens"); - // token fwd is token expected - address tokenAddress = gateway.tokenAddresses(tokenSymbol); - require(tokenAddress == action.token, "Token mismatch"); // amt fwd equal expected amt require(amount == (action.liqAmt + action.lockAmt), "Amount mismatch"); // check that at least one vault is expected to receive a deposit require(action.lockAmt > 0 || action.liqAmt > 0, "No vault deposit specified"); // check that token is accepted by angel protocol + address tokenAddress = gateway.tokenAddresses(tokenSymbol); require(registrar.isTokenAccepted(tokenAddress), "Token not accepted"); // Get parameters from registrar if approved require( @@ -410,6 +406,10 @@ contract Router is IRouter, OwnableUpgradeable, AxelarExecutable { // decode payload IVault.VaultActionData memory action = RouterLib.unpackCalldata(payload); + // grab tokens sent cross-chain + address tokenAddress = gateway.tokenAddresses(tokenSymbol); + IERC20Metadata(tokenAddress).safeTransferFrom(address(gateway), address(this), amount); + // Leverage this.call() to enable try/catch logic try this.deposit(action, tokenSymbol, amount) { emit Deposit(action); diff --git a/contracts/integrations/dummy/GoerliDummy.sol b/contracts/integrations/dummy/GoerliDummy.sol new file mode 100644 index 000000000..c1b338531 --- /dev/null +++ b/contracts/integrations/dummy/GoerliDummy.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +// author: @stevieraykatz +pragma solidity >=0.8.0; + +import {IStrategy} from "../../core/strategy/IStrategy.sol"; +import {DummyStrategy} from "../../test/DummyStrategy.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface IDummyERC20 is IERC20 { + function mint(address account, uint256 amount) external; + + function burn(address account, uint256 amount) external; +} + +contract GoerliDummy is DummyStrategy { + constructor(StrategyConfig memory _config) DummyStrategy(_config) {} + + function deposit(uint256 amt) public payable override returns (uint256) { + IDummyERC20(config.yieldToken).mint(address(this), dummyAmt); + return super.deposit(amt); + } + + function withdraw(uint256 amt) public payable override returns (uint256) { + uint256 val = super.deposit(amt); + IDummyERC20(config.yieldToken).burn(address(this), val); + return val; + } +} diff --git a/contracts/integrations/stratConfig.ts b/contracts/integrations/stratConfig.ts new file mode 100644 index 000000000..90d00b4f8 --- /dev/null +++ b/contracts/integrations/stratConfig.ts @@ -0,0 +1,29 @@ +import { + AllStratConfigs, + StratConfig, + StrategyApprovalState, + VaultType, + getVaultAddress, +} from "utils"; + +export const dummy: StratConfig = { + name: "dummy", + id: "0x12345678", + chainId: 5, + params: { + approvalState: StrategyApprovalState.APPROVED, + network: "ethereum-2", + Locked: { + Type: VaultType.LOCKED, + vaultAddr: getVaultAddress("dummy", VaultType.LOCKED), + }, + Liquid: { + Type: VaultType.LIQUID, + vaultAddr: getVaultAddress("dummy", VaultType.LIQUID), + }, + }, +}; + +export const allStrategyConfigs: AllStratConfigs = { + dummy: dummy, +}; diff --git a/contracts/integrations/strategy-addresses.json b/contracts/integrations/strategy-addresses.json new file mode 100644 index 000000000..1b9e90ba8 --- /dev/null +++ b/contracts/integrations/strategy-addresses.json @@ -0,0 +1 @@ +{"dummy":{"strategy":"0x42f293b5D45C0a949639EE229E4c9acD51DF904D","locked":"0xf7C497157c4879A4C6ca9B66CF3911BD2b71E2da","liquid":"0x730EEB14F27B5D6132b9BF7D62eF877D89600F55"}} \ No newline at end of file diff --git a/contracts/test/DummyStrategy.sol b/contracts/test/DummyStrategy.sol index 5de478deb..40cb03ea2 100644 --- a/contracts/test/DummyStrategy.sol +++ b/contracts/test/DummyStrategy.sol @@ -33,13 +33,13 @@ contract DummyStrategy is Pausable, IStrategy { config = _newConfig; } - function deposit(uint256 amt) external payable returns (uint256) { + function deposit(uint256 amt) public payable virtual returns (uint256) { IERC20(config.baseToken).transferFrom(msg.sender, address(this), amt); IERC20(config.yieldToken).approve(msg.sender, dummyAmt); return dummyAmt; } - function withdraw(uint256 amt) external payable returns (uint256) { + function withdraw(uint256 amt) public payable virtual returns (uint256) { IERC20(config.yieldToken).transferFrom(msg.sender, address(this), amt); IERC20(config.baseToken).approve(msg.sender, dummyAmt); return dummyAmt; diff --git a/tasks/deploy/deployAngelProtocol.ts b/tasks/deploy/deployAngelProtocol.ts index 179e52c65..5e9ebda59 100644 --- a/tasks/deploy/deployAngelProtocol.ts +++ b/tasks/deploy/deployAngelProtocol.ts @@ -1,7 +1,15 @@ -import {task} from "hardhat/config"; -import {Deployment, confirmAction, isLocalNetwork, logger, verify} from "utils"; import config from "config"; -import {ADDRESS_ZERO, getSigners, resetAddresses} from "utils"; +import {task} from "hardhat/config"; +import { + ADDRESS_ZERO, + Deployment, + confirmAction, + getSigners, + isLocalNetwork, + logger, + resetAddresses, + verify, +} from "utils"; import {deployAccountsDiamond} from "contracts/core/accounts/scripts/deploy"; import {deployIndexFund} from "contracts/core/index-fund/scripts/deploy"; @@ -12,12 +20,12 @@ import {deployEndowmentMultiSig} from "contracts/normalized_endowment/endowment- // import {deployEmitters} from "contracts/normalized_endowment/scripts/deployEmitter"; // import {deployImplementation} from "contracts/normalized_endowment/scripts/deployImplementation"; +import {deployGasFwd} from "contracts/core/gasFwd/scripts/deploy"; import { getOrDeployThirdPartyContracts, updateRegistrarConfig, updateRegistrarNetworkConnections, } from "../helpers"; -import {deployGasFwd} from "contracts/core/gasFwd/scripts/deploy"; task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") .addFlag("skipVerify", "Skip contract verification") @@ -50,7 +58,7 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") owner: apTeamMultisig?.address, deployer, proxyAdmin, - treasuryAddress: treasury.address, + treasury: treasury.address, }, hre ); diff --git a/tasks/deploy/deployLocalRegistrar.ts b/tasks/deploy/deployLocalRegistrar.ts new file mode 100644 index 000000000..ace0b71f5 --- /dev/null +++ b/tasks/deploy/deployLocalRegistrar.ts @@ -0,0 +1,90 @@ +import {deployLocalRegistrar} from "contracts/core/registrar/scripts/deploy"; +import {deployRouter} from "contracts/core/router/scripts/deploy"; +import {task} from "hardhat/config"; +import { + confirmAction, + getAddresses, + getNetworkNameFromChainId, + getSigners, + isLocalNetwork, + logger, + verify, + NetworkConnectionAction, +} from "utils"; +import {Registrar__factory} from "typechain-types"; +import {IAccountsStrategy} from "typechain-types/contracts/core/registrar/interfaces/IRegistrar"; +import {updateRegistrarConfig, updateRegistrarNetworkConnections} from "../helpers"; +import {router} from "typechain-types/contracts/core"; + +type TaskArgs = { + skipVerify: boolean; + yes: boolean; + owner?: string; +}; + +task("deploy:LocalRegistrarAndRouter", "Will deploy the Local Registrar contract and Router.") + .addOptionalParam("owner", "The owner wallet for both router and registrar") + .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") + .setAction(async (taskArgs: TaskArgs, hre) => { + try { + const isConfirmed = + taskArgs.yes || (await confirmAction("Deploying Registrar and Router...")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } + + const {proxyAdmin, deployer} = await getSigners(hre); + const addresses = await getAddresses(hre); + + const owner = taskArgs.owner || addresses.multiSig.apTeam.proxy; + + const localRegistrarDeployment = await deployLocalRegistrar( + { + owner: owner, + deployer, + proxyAdmin, + }, + hre + ); + + if (!localRegistrarDeployment) { + return; + } + + const routerDeployment = await deployRouter( + addresses.axelar.gateway, + addresses.axelar.gasService, + localRegistrarDeployment.address, + hre + ); + + if (!routerDeployment) { + return; + } + + let network = await hre.ethers.provider.getNetwork(); + const networkInfo: IAccountsStrategy.NetworkInfoStruct = { + chainId: network.chainId, + router: routerDeployment.address, + axelarGateway: addresses.axelar.gateway, + ibcChannel: "", + transferChannel: "", + gasReceiver: addresses.axelar.gasService, + gasLimit: 0, + }; + await updateRegistrarNetworkConnections( + localRegistrarDeployment.address, + owner, + networkInfo, + hre + ); + + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, localRegistrarDeployment); + await verify(hre, routerDeployment); + } + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/tasks/deploy/deployRegistrar.ts b/tasks/deploy/deployRegistrar.ts index 47e9fac0e..31a451442 100644 --- a/tasks/deploy/deployRegistrar.ts +++ b/tasks/deploy/deployRegistrar.ts @@ -48,7 +48,7 @@ task( owner: apTeamMultiSig, deployer, proxyAdmin, - treasuryAddress: treasury.address, + treasury: treasury.address, }, hre ); @@ -99,7 +99,7 @@ task( } await hre.run("manage:accounts:updateConfig", { - newRegistrar: registrarDeployment.address, + registrarContract: registrarDeployment.address, yes: true, }); await hre.run("manage:IndexFund:updateRegistrar", { diff --git a/tasks/deploy/deploySideChain.ts b/tasks/deploy/deploySideChain.ts new file mode 100644 index 000000000..e8a615247 --- /dev/null +++ b/tasks/deploy/deploySideChain.ts @@ -0,0 +1,51 @@ +import {task} from "hardhat/config"; +import {Deployment, confirmAction, isLocalNetwork, logger, verify} from "utils"; +import {getSigners, resetAddresses} from "utils"; +import {deployAPTeamMultiSig} from "contracts/multisigs/scripts/deploy"; + +task("deploy:SideChain", "Will deploy complete side-chain infrastructure") + .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") + .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { + try { + const isConfirmed = + taskArgs.yes || (await confirmAction("Deploying all side chain contracts...")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } + + const verify_contracts = !isLocalNetwork(hre) && !taskArgs.skipVerify; + + const {deployer} = await getSigners(hre); + + await resetAddresses(hre); + + logger.out(`Deploying the contracts with the account: ${deployer.address}`); + + const apTeamMultisig = await deployAPTeamMultiSig(hre); + + if (!apTeamMultisig) { + return; + } + + await hre.run("deploy:LocalRegistrarAndRouter", { + skipVerify: verify_contracts, + yes: true, + owner: apTeamMultisig.address, + }); + + if (verify_contracts) { + const deployments: Array = [apTeamMultisig]; + + for (const deployment of deployments) { + if (deployment) { + await verify(hre, deployment); + } + } + } + + logger.out("Successfully deployed Side Chain contracts."); + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/tasks/deploy/index.ts b/tasks/deploy/index.ts index 8ec7df2fa..ba5f0e1a3 100644 --- a/tasks/deploy/index.ts +++ b/tasks/deploy/index.ts @@ -9,6 +9,8 @@ import "./deployGasFwd"; // import "./deployHaloImplementation"; import "./deployImplementation"; // TODO: Rename to something more clear that pertains to Normalized Endowments import "./deployIndexFund"; +import "./deployLocalRegistrar"; import "./deployRegistrar"; import "./deployRouter"; +import "./deploySideChain"; import "./integrations"; diff --git a/tasks/deploy/integrations/dummyIntegration.ts b/tasks/deploy/integrations/dummyIntegration.ts new file mode 100644 index 000000000..59362f137 --- /dev/null +++ b/tasks/deploy/integrations/dummyIntegration.ts @@ -0,0 +1,98 @@ +import {task} from "hardhat/config"; +import {APVault_V1__factory, GoerliDummy__factory, DummyERC20__factory} from "typechain-types"; +import { + logger, + getSigners, + getAddresses, + StratConfig, + writeStrategyAddresses, + VaultType, + StrategyObject, +} from "utils"; +import {allStrategyConfigs} from "../../../contracts/integrations/stratConfig"; + +type TaskArgs = { + name: string; + admin: string; + skipVerify: boolean; +}; + +task("Deploy:dummyIntegration", "Will deploy a set of vaults and a dummy strategy") + .addParam( + "name", + `The name of the strategy according to StratConfig, possible values: ${Object.keys( + allStrategyConfigs + ).join(", ")}` + ) + .addOptionalParam( + "admin", + "The wallet address that will be set as the admin for the vaults and strategy contracts, default is APTeamMultisig" + ) + .addFlag("skipVerify", "Skip contract verification") + .setAction(async (taskArgs: TaskArgs, hre) => { + try { + const config: StratConfig = allStrategyConfigs[taskArgs.name]; + const {deployer} = await getSigners(hre); + let network = await hre.ethers.provider.getNetwork(); + if (network.chainId != config.chainId) { + throw new Error( + `Deploying strategy to incorrect network. Expcted: ${config.chainId}, Actual: ${network.chainId}` + ); + } + + let addresses = await getAddresses(hre); + let admin = taskArgs.admin || addresses.multiSig.apTeam.proxy; + let YieldToken = new DummyERC20__factory(deployer); + let yieldToken = await YieldToken.deploy(0); + + let Strategy = new GoerliDummy__factory(deployer); + let strategy = await Strategy.deploy({ + strategySelector: config.id, + baseToken: addresses.tokens.usdc, + yieldToken: yieldToken.address, + admin: admin, + }); + await strategy.deployed(); + logger.pad(30, "Strategy deployed to", strategy.address); + + let Vault = new APVault_V1__factory(deployer); + + let lockedConfig = { + vaultType: VaultType.LOCKED, + strategySelector: config.id, + strategy: strategy.address, + registrar: addresses.registrar.proxy, + baseToken: addresses.tokens.usdc, + yieldToken: yieldToken.address, + apTokenName: "LockedTestVault", + apTokenSymbol: "LockTV", + admin: admin, + }; + let lockVault = await Vault.deploy(lockedConfig); + logger.pad(30, "Locked Vault deployed to", lockVault.address); + + let liquidConfig = { + vaultType: VaultType.LIQUID, + strategySelector: config.id, + strategy: strategy.address, + registrar: addresses.registrar.proxy, + baseToken: addresses.tokens.usdc, + yieldToken: yieldToken.address, + apTokenName: "LiquidTestVault", + apTokenSymbol: "LiqTV", + admin: admin, + }; + let liqVault = await Vault.deploy(liquidConfig); + logger.pad(30, "Liquid Vault deployed to", liqVault.address); + + const data: StrategyObject = { + strategy: strategy.address, + locked: lockVault.address, + liquid: liqVault.address, + }; + + writeStrategyAddresses(taskArgs.name, data); + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/tasks/deploy/integrations/index.ts b/tasks/deploy/integrations/index.ts index b7393b758..fb84d8987 100644 --- a/tasks/deploy/integrations/index.ts +++ b/tasks/deploy/integrations/index.ts @@ -1,2 +1,3 @@ +import "./dummyIntegration"; import "./goldfinch"; import "./genericVault"; diff --git a/tasks/helpers/deploy/deployDummyERC20.ts b/tasks/helpers/deploy/deployDummyERC20.ts index 663522a26..34d35d64b 100644 --- a/tasks/helpers/deploy/deployDummyERC20.ts +++ b/tasks/helpers/deploy/deployDummyERC20.ts @@ -1,6 +1,5 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {DummyERC20__factory, DummyERC20} from "typechain-types"; -import {logger} from "utils"; export async function mint(token: DummyERC20, to: string, amt: number) { await token.mint(to, amt); @@ -12,16 +11,13 @@ export async function deployDummyERC20( amounts?: number[], decimals?: number ) { - logger.out("Deploying dummy ERC20..."); const Token = new DummyERC20__factory(deployer); const decs = decimals ? decimals : 0; const token = await Token.deploy(decs); await token.deployed(); - logger.out(`Address: ${token.address}`); if (recipients && amounts) { for (var i in recipients) { - logger.out(`Minting ${amounts[i]} tokens to ${recipients[i]}...`); await mint(token, recipients[i], amounts[i]); } } diff --git a/tasks/helpers/updateRegistrar.ts b/tasks/helpers/updateRegistrar.ts index d70aec974..d4ae58e66 100644 --- a/tasks/helpers/updateRegistrar.ts +++ b/tasks/helpers/updateRegistrar.ts @@ -4,45 +4,64 @@ import { IAccountsStrategy, RegistrarMessages, } from "typechain-types/contracts/core/registrar/interfaces/IRegistrar"; -import {NetworkConnectionAction, getSigners, logger, structToObject, validateAddress} from "utils"; +import { + NetworkConnectionAction, + getChainId, + getNetworkNameFromChainId, + getSigners, + logger, + structToObject, + validateAddress, +} from "utils"; export async function updateRegistrarNetworkConnections( registrar = "", apTeamMultisig = "", - newNetworkInfo: Partial, + networkInfo: Partial, hre: HardhatRuntimeEnvironment ) { logger.divider(); - logger.out("Updating Registrar config..."); + let networkName try { + + // If we're updating info on this chain for another chain, arg info MUST specify chain id + if (Number(networkInfo.chainId) > 0) { + networkName = getNetworkNameFromChainId(Number(networkInfo.chainId)); + } + else { // we're updating this chains own network info and can safely lookup chain id + const chainId = await getChainId(hre); + networkName = getNetworkNameFromChainId(chainId); + } + + logger.out(`Updating Registrar network info for chain: ${networkName}`); + validateAddress(registrar, "registrar"); validateAddress(apTeamMultisig, "apTeamMultisig"); - const network = await hre.ethers.provider.getNetwork(); - const {apTeamMultisigOwners} = await getSigners(hre); const registrarContract = Registrar__factory.connect(registrar, apTeamMultisigOwners[0]); logger.out("Fetching current Registrar's network connection data..."); - const struct = await registrarContract.queryNetworkConnection(network.name); + + const struct = await registrarContract.queryNetworkConnection(networkName); const curNetworkConnection = structToObject(struct); logger.out(curNetworkConnection); logger.out("Network info to update:"); - logger.out(newNetworkInfo); + logger.out(networkInfo); const updateNetworkConnectionsData = registrarContract.interface.encodeFunctionData( "updateNetworkConnections", - [network.name, {...curNetworkConnection, ...newNetworkInfo}, NetworkConnectionAction.POST] + [networkName, {...curNetworkConnection, ...networkInfo}, NetworkConnectionAction.POST] ); const apTeamMultisigContract = APTeamMultiSig__factory.connect( apTeamMultisig, apTeamMultisigOwners[0] ); const tx = await apTeamMultisigContract.submitTransaction( - registrar, + registrarContract.address, 0, updateNetworkConnectionsData, "0x" @@ -51,7 +70,7 @@ export async function updateRegistrarNetworkConnections( await tx.wait(); logger.out("Updated network connection data:"); - const newStruct = await registrarContract.queryNetworkConnection(network.name); + const newStruct = await registrarContract.queryNetworkConnection(networkName); const newNetworkConnection = structToObject(newStruct); logger.out(newNetworkConnection); } catch (error) { diff --git a/tasks/manage/accounts/updateConfig.ts b/tasks/manage/accounts/updateConfig.ts index feaf71437..7c7908f5b 100644 --- a/tasks/manage/accounts/updateConfig.ts +++ b/tasks/manage/accounts/updateConfig.ts @@ -10,7 +10,7 @@ type TaskArgs = { earlyLockedWithdrawFeeBps?: number; earlyLockedWithdrawFeePayoutAddress?: string; maxGeneralCategoryId?: number; - newRegistrar?: string; + registrarContract?: string; yes: boolean; }; @@ -27,7 +27,7 @@ task("manage:accounts:updateConfig", "Will update Accounts Diamond config") ) .addOptionalParam("maxGeneralCategoryId", "The max general category id.", undefined, types.int) .addOptionalParam( - "newRegistrar", + "registrarContract", "Registrar contract address. Will do a local lookup from contract-address.json if none is provided." ) .addFlag("yes", "Automatic yes to prompt.") @@ -63,7 +63,7 @@ task("manage:accounts:updateConfig", "Will update Accounts Diamond config") apTeamMultisigOwners[0] ); const data = accountsUpdate.interface.encodeFunctionData("updateConfig", [ - newConfig.newRegistrar || curConfig.registrarContract, + newConfig.registrarContract || curConfig.registrarContract, newConfig.maxGeneralCategoryId || curConfig.maxGeneralCategoryId, { bps: newConfig.earlyLockedWithdrawFeeBps || curConfig.earlyLockedWithdrawFee.bps, diff --git a/tasks/manage/registrar/index.ts b/tasks/manage/registrar/index.ts index 9514ce8db..4b7ab4529 100644 --- a/tasks/manage/registrar/index.ts +++ b/tasks/manage/registrar/index.ts @@ -1,6 +1,8 @@ import "./setAPParams"; import "./setAccountsChainAndAddress"; import "./setGasByToken"; +import "./setFeeSetting"; +import "./setNetworkInfo"; import "./setRebalParams"; import "./setStratApproval"; import "./setStratParams"; diff --git a/tasks/manage/registrar/setAPParams.ts b/tasks/manage/registrar/setAPParams.ts index 370860d1d..184f8086a 100644 --- a/tasks/manage/registrar/setAPParams.ts +++ b/tasks/manage/registrar/setAPParams.ts @@ -1,14 +1,11 @@ import {task, types} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; +import {getAddresses, getSigners, structToObject, logger} from "utils"; const NULL_NUMBER = 0; const NULL_STRING = ""; type TaskArgs = { - protocolTaxRate: number; - protocolTaxBasis: number; - protocolTaxCollector: string; routerAddress: string; refundAddress: string; }; @@ -17,24 +14,6 @@ task( "manage:registrar:setAPParams", "Set any or all of the AP params. This task only modifies specified optional args" ) - .addOptionalParam( - "protocolTaxRate", - "The protocol tax rate as a percent (i.e. 2 => 2%)", - NULL_NUMBER, - types.int - ) - .addOptionalParam( - "protocolTaxBasis", - "The protocol tax basis for setting precision", - NULL_NUMBER, - types.int - ) - .addOptionalParam( - "protocolTaxCollector", - "Address of the protocol tax collector", - NULL_STRING, - types.string - ) .addOptionalParam("routerAddress", "The address of this chains router", NULL_STRING, types.string) .addOptionalParam( "refundAddress", @@ -47,8 +26,8 @@ task( logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -70,10 +49,28 @@ task( logger.out("Setting AP params to:"); logger.pad(50, "New router address: ", newRouterAddress); logger.pad(50, "New refund address: ", newRefundAddress); - await registrar.setAngelProtocolParams({ - routerAddr: newRouterAddress, - refundAddr: newRefundAddress, - }); + const updateData = registrar.interface.encodeFunctionData("setAngelProtocolParams", [ + { + routerAddr: newRouterAddress, + refundAddr: newRefundAddress, + }, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] + ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); + logger.out("Updated AP params:"); + const newStruct = await registrar.getAngelProtocolParams(); + const newAPParams = structToObject(newStruct); + logger.out(newAPParams); }); function checkIfDefaultAndSet(taskArg: any, currentValue: any) { diff --git a/tasks/manage/registrar/setAccountsChainAndAddress.ts b/tasks/manage/registrar/setAccountsChainAndAddress.ts index 78fa46a55..f3d66bc0f 100644 --- a/tasks/manage/registrar/setAccountsChainAndAddress.ts +++ b/tasks/manage/registrar/setAccountsChainAndAddress.ts @@ -1,5 +1,5 @@ import {task} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; import {getAddresses, getSigners, logger} from "utils"; type TaskArgs = {accountsDiamond: string; chainName: string}; @@ -12,15 +12,27 @@ task("manage:registrar:setAccountsChainAndAddress") logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); logger.pad(30, "Setting accounts contract on: ", taskArguments.chainName); logger.pad(30, "to contract at: ", taskArguments.accountsDiamond); - await registrar.setAccountsContractAddressByChain( + const updateData = registrar.interface.encodeFunctionData("setAccountsContractAddressByChain", [ taskArguments.chainName, - taskArguments.accountsDiamond + taskArguments.accountsDiamond, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); }); diff --git a/tasks/manage/registrar/setFeeSetting.ts b/tasks/manage/registrar/setFeeSetting.ts new file mode 100644 index 000000000..02cb450db --- /dev/null +++ b/tasks/manage/registrar/setFeeSetting.ts @@ -0,0 +1,70 @@ +import {task, types} from "hardhat/config"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; +import {getAddresses, getSigners, logger} from "utils"; + +type TaskArgs = {feeType: number; payoutAddress: string; bps: number}; + +task("manage:registrar:setFeeSettings") + .addParam( + "feeType", + "The enum of the fee. {0:DEFAULT, 1:HARVEST, 2:WITHDRAWCHARITY, 3:WITHDRAWNORMAL, 4:EARLYLOCKEDWITHDRAWCHARITY, 5:EARLYLOCKEDWITHDRAWNORMAL}", + 0, + types.int + ) + .addParam("payoutAddress", "Address of fee recipient", "", types.string) + .addParam("bps", "basis points to be applied for this fee", 0, types.int) + .setAction(async function (taskArguments: TaskArgs, hre) { + logger.divider(); + logger.out("Connecting to registrar on specified network..."); + const addresses = await getAddresses(hre); + const registrarAddress = addresses["registrar"]["proxy"]; + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + logger.pad(50, "Connected to Registrar at: ", registrar.address); + + logger.divider(); + logger.out("Checking current fee settings"); + let currentFeeSettings = await registrar.getFeeSettingsByFeeType(taskArguments.feeType); + if ( + currentFeeSettings.payoutAddress == taskArguments.payoutAddress && + currentFeeSettings.bps.eq(taskArguments.bps) + ) { + logger.pad(10, "Fee settings match desired settings"); + return; + } + + logger.divider(); + logger.out("Setting fees according to specification"); + const updateData = registrar.interface.encodeFunctionData("setFeeSettingsByFeesType", [ + taskArguments.feeType, + taskArguments.bps, + taskArguments.payoutAddress, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] + ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); + + const newfeeSetting = await registrar.getFeeSettingsByFeeType(taskArguments.feeType); + if ( + newfeeSetting.payoutAddress == taskArguments.payoutAddress && + newfeeSetting.bps.eq(taskArguments.bps) + ) { + logger.out("Fee settings updated successfully"); + } else { + throw new Error( + `Fee settings were not updated. Expected: ${[ + taskArguments.payoutAddress, + taskArguments.bps, + ]}, Got: ${[newfeeSetting.payoutAddress, newfeeSetting.bps]}` + ); + } + }); diff --git a/tasks/manage/registrar/setGasByToken.ts b/tasks/manage/registrar/setGasByToken.ts index 52da981d6..aa030a259 100644 --- a/tasks/manage/registrar/setGasByToken.ts +++ b/tasks/manage/registrar/setGasByToken.ts @@ -1,6 +1,6 @@ import {BigNumber} from "ethers"; import {task, types} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; import {getAddresses, getSigners, logger} from "utils"; type TaskArgs = {gas: number; tokenAddress: string}; @@ -18,8 +18,8 @@ task("manage:registrar:setGasByToken") logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -33,5 +33,20 @@ task("manage:registrar:setGasByToken") logger.divider(); logger.out("Setting gas for specified token"); - await registrar.setGasByToken(taskArguments.tokenAddress, taskArguments.gas); + const updateData = registrar.interface.encodeFunctionData("setGasByToken", [ + taskArguments.tokenAddress, + taskArguments.gas, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] + ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); }); diff --git a/tasks/manage/registrar/setNetworkInfo.ts b/tasks/manage/registrar/setNetworkInfo.ts new file mode 100644 index 000000000..da8831f0d --- /dev/null +++ b/tasks/manage/registrar/setNetworkInfo.ts @@ -0,0 +1,43 @@ +import {task, types} from "hardhat/config"; +import {IAccountsStrategy} from "typechain-types/contracts/core/registrar/interfaces/IRegistrar"; +import {updateRegistrarNetworkConnections} from "tasks/helpers"; +import { + getAddresses, + logger, + getAddressesByNetworkId, + getChainIdFromNetworkName, + DEFAULT_CONTRACT_ADDRESS_FILE_PATH, +} from "utils"; + +type TaskArgs = { + networkName: string; +}; + +task("manage:registrar:setNetworkInfo", "Set network info for a specified network") + .addParam( + "networkName", + "The name of the network using Axelars naming convention", + "", + types.string + ) + .setAction(async function (taskArguments: TaskArgs, hre) { + logger.divider(); + logger.out("Connecting to registrar on specified network..."); + + const networkId = getChainIdFromNetworkName(taskArguments.networkName); + const thisNetworkAddresses = await getAddresses(hre) + const thatNetworkAddresses = getAddressesByNetworkId(networkId, DEFAULT_CONTRACT_ADDRESS_FILE_PATH); + const newNetworkInfo: Partial = { + chainId: networkId, + router: thatNetworkAddresses.router.proxy, + axelarGateway: thatNetworkAddresses.axelar.gateway, + gasReceiver: thatNetworkAddresses.axelar.gasService, + }; + + await updateRegistrarNetworkConnections( + thisNetworkAddresses.registrar.proxy, + thisNetworkAddresses.multiSig.apTeam.proxy, + newNetworkInfo, + hre + ); + }); diff --git a/tasks/manage/registrar/setRebalParams.ts b/tasks/manage/registrar/setRebalParams.ts index 42eaa024a..44baeb8f9 100644 --- a/tasks/manage/registrar/setRebalParams.ts +++ b/tasks/manage/registrar/setRebalParams.ts @@ -1,5 +1,5 @@ import {task, types} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; import {getAddresses, getSigners, logger} from "utils"; const NULL_NUMBER = 0; @@ -47,8 +47,8 @@ task("manage:registrar:setRebalParams") logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -95,14 +95,28 @@ task("manage:registrar:setRebalParams") logger.pad(50, "New locked principle to liquid: ", newLockedPrincipleToLiquid); logger.pad(50, "New principle distribution: ", newPrincipleDistribution); logger.pad(50, "New percent basis: ", newBasis); - await registrar.setRebalanceParams({ - rebalanceLiquidProfits: newRebalanceLiquidProfits, - lockedRebalanceToLiquid: newLockedRebalanceToLiquid, - interestDistribution: newInterestDistribution, - lockedPrincipleToLiquid: newLockedPrincipleToLiquid, - principleDistribution: newPrincipleDistribution, - basis: newBasis, - }); + const updateData = registrar.interface.encodeFunctionData("setRebalanceParams", [ + { + rebalanceLiquidProfits: newRebalanceLiquidProfits, + lockedRebalanceToLiquid: newLockedRebalanceToLiquid, + interestDistribution: newInterestDistribution, + lockedPrincipleToLiquid: newLockedPrincipleToLiquid, + principleDistribution: newPrincipleDistribution, + basis: newBasis, + }, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] + ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); }); function checkIfDefaultAndSet(taskArg: any, currentValue: any) { diff --git a/tasks/manage/registrar/setStratApproval.ts b/tasks/manage/registrar/setStratApproval.ts index 0fe21792d..c5950a541 100644 --- a/tasks/manage/registrar/setStratApproval.ts +++ b/tasks/manage/registrar/setStratApproval.ts @@ -1,13 +1,16 @@ import {task, types} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; +import {getAddresses, getSigners, StratConfig, logger} from "utils"; +import {allStrategyConfigs} from "../../../contracts/integrations/stratConfig"; -type TaskArgs = {approvalState: number; strategySelector: string}; +type TaskArgs = {name: string; approvalState: number}; task("manage:registrar:setStratApproval") .addParam( - "strategySelector", - "The 4-byte unique ID of the strategy, set by bytes4(keccack256('StrategyName'))", + "name", + `The name of the strategy according to StratConfig, possible values: ${Object.keys( + allStrategyConfigs + ).join(", ")}`, "", types.string ) @@ -22,13 +25,14 @@ task("manage:registrar:setStratApproval") logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); logger.out("Checking current strategy approval state"); - let currentStratParams = await registrar.getStrategyParamsById(taskArguments.strategySelector); + const config: StratConfig = allStrategyConfigs[taskArguments.name]; + let currentStratParams = await registrar.getStrategyParamsById(config.id); if (currentStratParams.approvalState == taskArguments.approvalState) { logger.out("Strategy approval state already matches desired state"); return; @@ -37,8 +41,20 @@ task("manage:registrar:setStratApproval") logger.divider(); logger.out("Setting strategy approval state to:"); logger.pad(50, "New strategy approval state", taskArguments.approvalState); - await registrar.setStrategyApprovalState( - taskArguments.strategySelector, - taskArguments.approvalState + const updateData = registrar.interface.encodeFunctionData("setStrategyApprovalState", [ + config.id, + taskArguments.approvalState, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); }); diff --git a/tasks/manage/registrar/setStratParams.ts b/tasks/manage/registrar/setStratParams.ts index 6e7d54df8..b58408dbc 100644 --- a/tasks/manage/registrar/setStratParams.ts +++ b/tasks/manage/registrar/setStratParams.ts @@ -1,30 +1,22 @@ import {task, types} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; +import {StratConfig, getAddresses, getSigners, logger} from "utils"; +import {allStrategyConfigs} from "../../../contracts/integrations/stratConfig"; type TaskArgs = { - approvalState: number; - strategySelector: string; - lockedVaultAddress: string; - liquidVaultAddress: string; + name: string; modifyExisting: boolean; }; task("manage:registrar:setStratParams") .addParam( - "strategySelector", - "The 4-byte unique ID of the strategy, set by bytes4(keccack256('StrategyName'))", + "name", + `The name of the strategy according to StratConfig, possible values: ${Object.keys( + allStrategyConfigs + ).join(", ")}`, "", types.string ) - .addParam( - "approvalState", - "Whether the strategy is currently approved or not, enum of NOT_APPROVED, APPROVED, WITHDRAW_ONLY, or DEPRECATED", - 0, - types.int - ) - .addParam("lockedVaultAddress", "The address of the strategys locked vault", "", types.string) - .addParam("liquidVaultAddress", "The address of the strategys liquid vault", "", types.string) .addOptionalParam( "modifyExisting", "Whether to modify an existing strategy", @@ -35,14 +27,14 @@ task("manage:registrar:setStratParams") logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); - const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(addresses.registrar.proxy, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); logger.out("Checking current strategy params at specified selector"); - let currentStratParams = await registrar.getStrategyParamsById(taskArguments.strategySelector); + const config: StratConfig = allStrategyConfigs[taskArguments.name]; + let currentStratParams = await registrar.getStrategyParamsById(config.id); if ( currentStratParams.Liquid.vaultAddr == hre.ethers.constants.AddressZero && currentStratParams.Locked.vaultAddr == hre.ethers.constants.AddressZero @@ -61,15 +53,27 @@ task("manage:registrar:setStratParams") logger.divider(); logger.out("Setting strategy params to: "); - logger.pad(50, "New strategy selector", taskArguments.strategySelector); - logger.pad(50, "New approval state", taskArguments.approvalState); - logger.pad(50, "New locked vault address", taskArguments.lockedVaultAddress); - logger.pad(50, "New liquid vault address", taskArguments.liquidVaultAddress); - await registrar.setStrategyParams( - taskArguments.strategySelector, - hre.network.name, - taskArguments.lockedVaultAddress, - taskArguments.liquidVaultAddress, - taskArguments.approvalState + logger.pad(50, "New strategy selector", config.id); + logger.pad(50, "New approval state", config.params.approvalState); + logger.pad(50, "New locked vault address", config.params.Locked.vaultAddr); + logger.pad(50, "New liquid vault address", config.params.Liquid.vaultAddr); + const updateData = registrar.interface.encodeFunctionData("setStrategyParams", [ + config.id, + config.params.network, + config.params.Locked.vaultAddr, + config.params.Liquid.vaultAddr, + config.params.approvalState, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] + ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); }); diff --git a/tasks/manage/registrar/setTokenAccepted.ts b/tasks/manage/registrar/setTokenAccepted.ts index 7f532ee92..d2098673c 100644 --- a/tasks/manage/registrar/setTokenAccepted.ts +++ b/tasks/manage/registrar/setTokenAccepted.ts @@ -1,5 +1,5 @@ import {task, types} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; +import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; import {getAddresses, getSigners, logger} from "utils"; type TaskArgs = {acceptanceState: boolean; tokenAddress: string}; @@ -12,8 +12,8 @@ task("manage:registrar:setTokenAccepted") logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; - const {deployer} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, deployer); + const {apTeamMultisigOwners} = await getSigners(hre); + const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -27,5 +27,20 @@ task("manage:registrar:setTokenAccepted") logger.divider(); logger.out("Setting token acceptance"); - await registrar.setTokenAccepted(taskArguments.tokenAddress, taskArguments.acceptanceState); + const updateData = registrar.interface.encodeFunctionData("setTokenAccepted", [ + taskArguments.tokenAddress, + taskArguments.acceptanceState, + ]); + const apTeamMultisigContract = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, + apTeamMultisigOwners[0] + ); + const tx = await apTeamMultisigContract.submitTransaction( + registrar.address, + 0, + updateData, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); }); diff --git a/tasks/upgrade/index.ts b/tasks/upgrade/index.ts index 2d4ea48c2..3a2dd8893 100644 --- a/tasks/upgrade/index.ts +++ b/tasks/upgrade/index.ts @@ -3,3 +3,4 @@ import "./upgradeCharityApplications"; import "./upgradeContractsUsingAccountStorage"; import "./upgradeEndowmentMultiSig"; import "./upgradeFacets"; +import "./upgradeRegistrar"; diff --git a/tasks/upgrade/upgradeRegistrar.ts b/tasks/upgrade/upgradeRegistrar.ts new file mode 100644 index 000000000..764236469 --- /dev/null +++ b/tasks/upgrade/upgradeRegistrar.ts @@ -0,0 +1,60 @@ +import {task} from "hardhat/config"; +import {Registrar__factory, ITransparentUpgradeableProxy__factory} from "typechain-types"; +import { + confirmAction, + getAddresses, + getSigners, + isLocalNetwork, + logger, + updateAddresses, + verify, +} from "utils"; + +task("upgrade:registrar", "Will upgrade the Registrar (use only on the primary chain)") + .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") + .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { + try { + const isConfirmed = taskArgs.yes || (await confirmAction("Upgrading Registrar implementation...")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } + + const {deployer, proxyAdmin} = await getSigners(hre); + + const addresses = await getAddresses(hre); + + logger.out("Deploying a new Registrar implementation..."); + const Registrar = new Registrar__factory(deployer); + const registrar = await Registrar.deploy(); + await registrar.deployed(); + logger.out(`New impl address: ${registrar.address}`); + + logger.out("Upgrading Registrar proxy implementation..."); + const registrarProxy = ITransparentUpgradeableProxy__factory.connect( + addresses.registrar.proxy, + proxyAdmin + ); + const tx = await registrarProxy.upgradeTo(registrar.address); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); + + await updateAddresses( + { + registrar: { + implementation: registrar.address + }, + }, + hre + ); + + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, { + address: registrar.address, + contract: "contracts/core/registrar/Registrar.sol:Registrar", + }); + } + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/test/core/accounts/AccountsStrategy.ts b/test/core/accounts/AccountsStrategy.ts index 5a8039d3a..33308c95b 100644 --- a/test/core/accounts/AccountsStrategy.ts +++ b/test/core/accounts/AccountsStrategy.ts @@ -17,7 +17,6 @@ import { DEFAULT_SETTINGS_STRUCT, DEFAULT_STRATEGY_PARAMS, DEFAULT_STRATEGY_SELECTOR, - NetworkInfoStruct, StrategyApprovalState, VaultActionStatus, VaultActionStructToArray, @@ -41,6 +40,7 @@ import { Router__factory, TestFacetProxyContract, } from "typechain-types"; +import {IAccountsStrategy} from "typechain-types/contracts/core/registrar/Registrar"; import {AccountStorage} from "typechain-types/contracts/test/accounts/TestFacetProxyContract"; import {getSigners} from "utils"; import {deployFacetAsProxy} from "./utils"; @@ -77,7 +77,7 @@ describe("AccountsStrategy", function () { let state: TestFacetProxyContract; let token: DummyERC20; let gateway: DummyGateway; - let network: NetworkInfoStruct; + let network: IAccountsStrategy.NetworkInfoStruct; const ACCOUNT_ID = 1; before(async function () { @@ -461,7 +461,7 @@ describe("AccountsStrategy", function () { let state: TestFacetProxyContract; let token: DummyERC20; let gateway: DummyGateway; - let network: NetworkInfoStruct; + let network: IAccountsStrategy.NetworkInfoStruct; const ACCOUNT_ID = 1; before(async function () { diff --git a/test/core/router/Router.ts b/test/core/router/Router.ts index 4ac176e3c..9e82f6988 100644 --- a/test/core/router/Router.ts +++ b/test/core/router/Router.ts @@ -1,44 +1,35 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {expect} from "chai"; import hre from "hardhat"; -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import { - DummyERC20, - DummyGasService, - DummyGateway, - DummyVault, - IRouter, - LocalRegistrar, - LocalRegistrar__factory, - ITransparentUpgradeableProxy__factory, - Router, - Router__factory, - Registrar__factory, - Registrar, -} from "typechain-types"; import { - ArrayToVaultActionStruct, IVaultHelpers, StrategyApprovalState, - VaultActionStructToArray, deployDummyERC20, deployDummyGasService, deployDummyGateway, deployDummyVault, deployRegistrarAsProxy, packActionData, - unpackActionData, } from "test/utils"; +import { + DummyERC20, + DummyGasService, + DummyGateway, + DummyVault, + ITransparentUpgradeableProxy__factory, + Registrar, + Router, + Router__factory, +} from "typechain-types"; import {getSigners} from "utils"; import {LocalRegistrarLib} from "../../../typechain-types/contracts/core/registrar/LocalRegistrar"; describe("Router", function () { - const {ethers, upgrades} = hre; + const {ethers} = hre; let owner: SignerWithAddress; let admin: SignerWithAddress; let user: SignerWithAddress; let collector: SignerWithAddress; - let Router: Router__factory; - let Registrar: Registrar__factory; let defaultApParams = { routerAddr: ethers.constants.AddressZero, refundAddr: ethers.constants.AddressZero, @@ -109,10 +100,6 @@ describe("Router", function () { expect(await upgradeProxy(admin, router.address)); }); - it("Should set the right owner", async function () { - expect(await router.owner()).to.equal(owner.address); - }); - it("Accepts and initializes the gateway and gas receiver as part of init", async function () { const gateway = "0x4F4495243837681061C4743b74B3eEdf548D56A5"; const gasRecv = "0x2d5d7d31F671F86C782533cc367F14109a082712"; @@ -261,7 +248,6 @@ describe("Router", function () { }); gateway = await deployDummyGateway(owner); gasService = await deployDummyGasService(owner); - token = await deployDummyERC20(owner); registrar = await deployRegistrarAsProxy(owner, admin); await gateway.setTestTokenAddress(token.address); await registrar.setTokenAccepted(token.address, true); @@ -270,15 +256,12 @@ describe("Router", function () { beforeEach(async function () { router = await deployRouterAsProxy(gateway.address, gasService.address, registrar); - token.mint(router.address, 333); + await token.mint(gateway.address, 333); + await token.approveFor(gateway.address, router.address, 333) let collectorBal = await token.balanceOf(collector.address); if (collectorBal.gt(0)) { await token.connect(collector).transfer(deadAddr, collectorBal); } - let gatewayBal = await token.balanceOf(gateway.address); - if (gatewayBal.gt(0)) { - await token.connect(collector).transfer(deadAddr, gatewayBal); - } }); it("when more than one account is specified", async function () { @@ -324,27 +307,6 @@ describe("Router", function () { expect(gatewayAllowance).to.equal(333); }); - it("when the token designation doesn't match", async function () { - let actionData = getDefaultActionData(); - actionData.selector = liquidVault.interface.getSighash("deposit"); - actionData.token = token.address; - let packedData = await packActionData(actionData); - await expect( - router.executeWithToken( - ethers.utils.formatBytes32String("true"), - originatingChain, - accountsContract, - packedData, - "WRONG", - 333 - ) - ) - .to.emit(router, "ErrorLogged") - .withArgs(Array, "Token mismatch"); - let gatewayAllowance = await token.allowance(router.address, gateway.address); - expect(gatewayAllowance).to.equal(333); - }); - it("when the payload amt doesn't match the GMP amt", async function () { let actionData = getDefaultActionData(); actionData.selector = liquidVault.interface.getSighash("deposit"); @@ -473,7 +435,8 @@ describe("Router", function () { beforeEach(async function () { router = await deployRouterAsProxy(gateway.address, undefined, registrar); // set gas service to undef so that the sendTokens call fails - token.mint(router.address, 333); + await token.mint(gateway.address, 333); + await token.approveFor(gateway.address, router.address, 333) let collectorBal = await token.balanceOf(collector.address); if (collectorBal.gt(0)) { await token.connect(collector).transfer(deadAddr, collectorBal); @@ -524,27 +487,6 @@ describe("Router", function () { expect(collectorBal).to.equal(333); }); - it("when the token designation doesn't match", async function () { - let actionData = getDefaultActionData(); - actionData.selector = liquidVault.interface.getSighash("deposit"); - actionData.token = token.address; - let packedData = await packActionData(actionData); - expect( - await router.executeWithToken( - ethers.utils.formatBytes32String("true"), - originatingChain, - accountsContract, - packedData, - "WRONG", - 333 - ) - ) - .to.emit(router, "ErrorLogged") - .withArgs(Array, "Token mismatch"); - let collectorBal = await token.balanceOf(collector.address); - expect(collectorBal).to.equal(333); - }); - it("when the payload amt doesn't match the GMP amt", async function () { let actionData = getDefaultActionData(); actionData.selector = liquidVault.interface.getSighash("deposit"); @@ -659,14 +601,16 @@ describe("Router", function () { let gasService: DummyGasService; let token: DummyERC20; let router: Router; + const LOCKAMT = 111; + const LIQAMT = 222; let actionData = { destinationChain: originatingChain, strategyId: "0xffffffff", selector: "", accountIds: [1], token: "", - lockAmt: 111, - liqAmt: 222, + lockAmt: LOCKAMT, + liqAmt: LIQAMT, status: 0, } as IVaultHelpers.VaultActionDataStruct; @@ -707,8 +651,8 @@ describe("Router", function () { }); it("correctly calls depost", async function () { - await token.mint(router.address, actionData.liqAmt); - await token.mint(router.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) actionData.selector = liquidVault.interface.getSighash("deposit"); let packedData = await packActionData(actionData); await expect( @@ -725,8 +669,8 @@ describe("Router", function () { it("correctly calls redeem via execute", async function () { // Do a deposit first to update the symbol mapping - await token.mint(router.address, actionData.liqAmt); - await token.mint(router.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) actionData.selector = liquidVault.interface.getSighash("deposit"); let packedData = await packActionData(actionData); await router.executeWithToken( @@ -754,8 +698,8 @@ describe("Router", function () { it("correctly calls redeemAll via execute", async function () { // Do a deposit first to update the symbol mapping - await token.mint(router.address, actionData.liqAmt); - await token.mint(router.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) actionData.selector = liquidVault.interface.getSighash("deposit"); let packedData = await packActionData(actionData); await router.executeWithToken( @@ -771,8 +715,8 @@ describe("Router", function () { actionData.selector = liquidVault.interface.getSighash("redeemAll"); actionData.token = token.address; packedData = await packActionData(actionData); - await token.mint(liquidVault.address, actionData.liqAmt); - await token.mint(lockedVault.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) await expect( router.execute( ethers.utils.formatBytes32String("true"), @@ -805,14 +749,16 @@ describe("Router", function () { let gasService: DummyGasService; let token: DummyERC20; let router: Router; + const LOCKAMT = 111; + const LIQAMT = 222; let actionData = { destinationChain: originatingChain, strategyId: "0xffffffff", selector: "", accountIds: [1], token: "", - lockAmt: 111, - liqAmt: 222, + lockAmt: LOCKAMT, + liqAmt: LIQAMT, status: 0, } as IVaultHelpers.VaultActionDataStruct; @@ -850,8 +796,8 @@ describe("Router", function () { }); it("deposits the specified amounts to the specified vaults", async function () { - token.mint(router.address, actionData.liqAmt); - token.mint(router.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) let packedData = packActionData(actionData); await router.executeWithToken( ethers.utils.formatBytes32String("true"), @@ -874,14 +820,16 @@ describe("Router", function () { let gasService: DummyGasService; let token: DummyERC20; let router: Router; + const LOCKAMT = 111; + const LIQAMT = 222; let actionData = { destinationChain: originatingChain, strategyId: "0xffffffff", selector: "", accountIds: [1], token: "", - lockAmt: 111, - liqAmt: 222, + lockAmt: LOCKAMT, + liqAmt: LIQAMT, status: 0, } as IVaultHelpers.VaultActionDataStruct; @@ -915,8 +863,8 @@ describe("Router", function () { beforeEach(async function () { router = await deployRouterAsProxy(gateway.address, gasService.address, registrar); - await token.mint(router.address, actionData.liqAmt); - await token.mint(router.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) actionData.selector = liquidVault.interface.getSighash("deposit"); let packedData = packActionData(actionData); await router.executeWithToken( @@ -1022,14 +970,16 @@ describe("Router", function () { let gasService: DummyGasService; let token: DummyERC20; let router: Router; + const LOCKAMT = 111; + const LIQAMT = 222; let actionData = { destinationChain: originatingChain, strategyId: "0xffffffff", selector: "", accountIds: [1], token: "", - lockAmt: 111, - liqAmt: 222, + lockAmt: LOCKAMT, + liqAmt: LIQAMT, status: 0, } as IVaultHelpers.VaultActionDataStruct; @@ -1064,8 +1014,8 @@ describe("Router", function () { beforeEach(async function () { router = await deployRouterAsProxy(gateway.address, gasService.address, registrar); - await token.mint(router.address, actionData.liqAmt); - await token.mint(router.address, actionData.lockAmt); + await token.mint(gateway.address, LOCKAMT + LIQAMT); + await token.approveFor(gateway.address, router.address, LOCKAMT + LIQAMT) actionData.selector = liquidVault.interface.getSighash("deposit"); let packedData = packActionData(actionData); await router.executeWithToken( diff --git a/test/utils/Registrar.ts b/test/utils/Registrar.ts index 495d05f7a..be819f908 100644 --- a/test/utils/Registrar.ts +++ b/test/utils/Registrar.ts @@ -30,14 +30,15 @@ export async function deployRegistrarAsProxy( const registrarImpl = await Registrar.deploy(); await registrarImpl.deployed(); const data = registrarImpl.interface.encodeFunctionData( - "initialize((address,(uint256,uint256,uint256),address,address,address))", + "initialize((address,(uint256,uint256,uint256),address,address,address,string))", [ { treasury: ethers.constants.AddressZero, splitToLiquid: DEFAULT_SPLIT_STRUCT, router: ethers.constants.AddressZero, axelarGateway: ethers.constants.AddressZero, - axelarGasRecv: ethers.constants.AddressZero, + axelarGasService: ethers.constants.AddressZero, + networkName: "localhost", }, ] ); diff --git a/test/utils/helpers/accounts/defaults.ts b/test/utils/helpers/accounts/defaults.ts index a003aabdb..34db9aef2 100644 --- a/test/utils/helpers/accounts/defaults.ts +++ b/test/utils/helpers/accounts/defaults.ts @@ -2,11 +2,11 @@ import {ethers} from "hardhat"; import {AccountStorage} from "typechain-types/contracts/test/accounts/TestFacetProxyContract"; import {AccountMessages} from "typechain-types/contracts/core/accounts/facets/AccountsStrategy"; import {LibAccounts} from "typechain-types/contracts/multisigs/CharityApplications"; -import {NetworkInfoStruct} from "../types"; import {RegistrarStorage} from "typechain-types/contracts/core/registrar/Registrar"; import {BigNumber} from "ethers"; -import {DEFAULT_STRATEGY_SELECTOR, StrategyApprovalState} from "test/utils"; +import {DEFAULT_STRATEGY_SELECTOR} from "test/utils"; import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalRegistrar"; +import {IAccountsStrategy} from "typechain-types/contracts/core/registrar/interfaces/IRegistrar"; export const DEFAULT_PERMISSIONS_STRUCT: LibAccounts.SettingsPermissionStruct = { locked: false, @@ -96,7 +96,7 @@ export const DEFAULT_ACCOUNTS_CONFIG: AccountStorage.ConfigStruct = { earlyLockedWithdrawFee: DEFAULT_FEE_STRUCT, }; -export const DEFAULT_NETWORK_INFO: NetworkInfoStruct = { +export const DEFAULT_NETWORK_INFO: IAccountsStrategy.NetworkInfoStruct = { chainId: 0, router: ethers.constants.AddressZero, axelarGateway: ethers.constants.AddressZero, diff --git a/test/utils/helpers/types.ts b/test/utils/helpers/types.ts index 9957072b7..c13cc9b8d 100644 --- a/test/utils/helpers/types.ts +++ b/test/utils/helpers/types.ts @@ -1,13 +1,3 @@ -export type NetworkInfoStruct = { - chainId: number; - router: string; - axelarGateway: string; - ibcChannel: string; - transferChannel: string; - gasReceiver: string; - gasLimit: number; -}; - export enum StrategyApprovalState { NOT_APPROVED, APPROVED, diff --git a/utils/constants.ts b/utils/constants.ts index ec01611db..dfa322d1e 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -4,6 +4,11 @@ export const ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"; export const DEFAULT_CONTRACT_ADDRESS_FILE_PATH = path.join(__dirname, "../contract-address.json"); +export const DEFAULT_STRATEGY_ADDRESSES_FILE_PATH = path.join( + __dirname, + "../contracts/integrations/strategy-addresses.json" +); + export enum NetworkConnectionAction { NONE, POST, diff --git a/utils/index.ts b/utils/index.ts index c129b3db6..172013c8e 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -6,6 +6,7 @@ export * from "./getSigners"; export * from "./keygen"; export * as logger from "./logger"; export * from "./manageAddressFile"; +export * from "./manageStratParams"; export * from "./networkHelpers"; export * from "./structToObject"; export * from "./types"; diff --git a/utils/manageAddressFile/manageAddressFile.ts b/utils/manageAddressFile/manageAddressFile.ts index 6eb3d7f10..ae9bc6e54 100644 --- a/utils/manageAddressFile/manageAddressFile.ts +++ b/utils/manageAddressFile/manageAddressFile.ts @@ -1,9 +1,8 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; - -import {DEFAULT_CONTRACT_ADDRESS_FILE_PATH, isLocalNetwork} from ".."; +import {DeepPartial} from "types"; +import {DEFAULT_CONTRACT_ADDRESS_FILE_PATH, getChainId, isLocalNetwork} from ".."; import {createEmptyAddressObj, getAddressesByNetworkId, saveFrontendFiles} from "./helpers"; import {AddressObj} from "./types"; -import {DeepPartial} from "types"; /** * Removes contract address for the current network from the appropriate file. @@ -66,8 +65,3 @@ function updateInternal(original: T, partial: DeepPartial): T { return updated; } - -async function getChainId(hre: HardhatRuntimeEnvironment): Promise { - const chainId = (await hre.ethers.provider.getNetwork()).chainId; - return chainId; -} diff --git a/utils/manageStratParams/helpers.ts b/utils/manageStratParams/helpers.ts new file mode 100644 index 000000000..368150d0e --- /dev/null +++ b/utils/manageStratParams/helpers.ts @@ -0,0 +1,19 @@ +import fs from "fs"; + +import {StrategyObject} from "./types"; + +export function readStrategyAddresses(filePath: string, name: string): StrategyObject { + checkExistence(filePath); + + const jsonData = fs.readFileSync(filePath, "utf-8"); + + const allData: Record = JSON.parse(jsonData); + + return allData[name]; +} + +function checkExistence(filePath: string) { + if (!fs.existsSync(filePath)) { + throw new Error(`No such file, path: '${filePath}'.`); + } +} diff --git a/utils/manageStratParams/index.ts b/utils/manageStratParams/index.ts new file mode 100644 index 000000000..69c754388 --- /dev/null +++ b/utils/manageStratParams/index.ts @@ -0,0 +1,3 @@ +export * from "./helpers"; +export * from "./manageStratParams"; +export * from "./types"; diff --git a/utils/manageStratParams/manageStratParams.ts b/utils/manageStratParams/manageStratParams.ts new file mode 100644 index 000000000..c0a8e20ef --- /dev/null +++ b/utils/manageStratParams/manageStratParams.ts @@ -0,0 +1,33 @@ +import fs from "fs"; + +import {VaultType, StrategyObject} from "./types"; +import {readStrategyAddresses} from "./helpers"; +import {DEFAULT_STRATEGY_ADDRESSES_FILE_PATH} from ".."; + +export function getVaultAddress(name: string, type: VaultType): string { + let typeName: string; + if (type == VaultType.LOCKED) { + typeName = "locked"; + } else if (type == VaultType.LIQUID) { + typeName = "liquid"; + } else { + throw new Error(`Vault of type ${type} is not`); + } + const addresses = readStrategyAddresses(DEFAULT_STRATEGY_ADDRESSES_FILE_PATH, name); + + return addresses[typeName as keyof StrategyObject]; +} + +export function getStrategyAddress(name: string): string { + const addresses = readStrategyAddresses(DEFAULT_STRATEGY_ADDRESSES_FILE_PATH, name); + + return addresses["strategy"]; +} + +export function writeStrategyAddresses(name: string, data: StrategyObject, filepath?: string) { + const fp = filepath ? filepath : DEFAULT_STRATEGY_ADDRESSES_FILE_PATH; + const jsonData = fs.readFileSync(fp, "utf-8"); + const allData: Record = JSON.parse(jsonData); + allData[name] = data; + fs.writeFileSync(fp, JSON.stringify(allData)); +} diff --git a/utils/manageStratParams/types.ts b/utils/manageStratParams/types.ts new file mode 100644 index 000000000..41465e2d4 --- /dev/null +++ b/utils/manageStratParams/types.ts @@ -0,0 +1,33 @@ +import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalRegistrar"; + +export type StratConfig = { + name: string; + id: string; + chainId: number; + params: LocalRegistrarLib.StrategyParamsStruct; +}; + +export enum StrategyApprovalState { + NOT_APPROVED, + APPROVED, + WITHDRAW_ONLY, + DEPRECATED, +} + +export type VaultParams = { + Type: VaultType; + vaultAddr: string; +}; + +export enum VaultType { + LOCKED, + LIQUID, +} + +export type AllStratConfigs = Record; + +export type StrategyObject = { + locked: string; + liquid: string; + strategy: string; +}; diff --git a/utils/networkHelpers.ts b/utils/networkHelpers.ts index d1761fd6c..35fc62519 100644 --- a/utils/networkHelpers.ts +++ b/utils/networkHelpers.ts @@ -1,5 +1,33 @@ import {HardhatRuntimeEnvironment, Network} from "hardhat/types"; +import {TwoWayMap} from "./twoWayMap"; export function isLocalNetwork(hre: HardhatRuntimeEnvironment) { return hre.network.name === "hardhat" || hre.network.name === "localhost"; } + +export function networkNameMatchesId(id: number, name: string) { + return AxelarNetworks.get(id) == name; +} + +export function getChainIdFromNetworkName(name: string): number { + return AxelarNetworks.revGet(name); +} + +export function getNetworkNameFromChainId(id: number): string { + return AxelarNetworks.get(id); +} + +export async function getChainId(hre: HardhatRuntimeEnvironment): Promise { + const chainId = (await hre.ethers.provider.getNetwork()).chainId; + return chainId; +} + +// There are errors/mismatches in the axelar sdk jsons, so we just implement a lightweight +// version here and use this instead. +const AxelarNetworks = new TwoWayMap({ + 1: "Ethereum", + 5: "ethereum-2", + 137: "Polygon", + 31337: "localhost", + 80001: "Polygon", +}); diff --git a/utils/twoWayMap.ts b/utils/twoWayMap.ts new file mode 100644 index 000000000..12d292174 --- /dev/null +++ b/utils/twoWayMap.ts @@ -0,0 +1,18 @@ +export class TwoWayMap { + map: Record; + reverseMap: Record; + constructor(map: Record) { + this.map = map; + this.reverseMap = {}; + for (const key in map) { + const value: any = map[key]; + this.reverseMap[value] = Number(key); + } + } + get(key: any) { + return this.map[key]; + } + revGet(key: any) { + return this.reverseMap[key]; + } +}