diff --git a/CODEOWNERS b/.github/CODEOWNERS similarity index 100% rename from CODEOWNERS rename to .github/CODEOWNERS diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..3b1b4f201 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,27 @@ +# PR Type: Feature|Bug|Release + +# PR Title: A Fancy Title Here Please + +### PR Description: Replace this text with a description of the PR. It doesn't need to be a novel, but a few sentences should do. Probably about the length of this sample description; perhaps longer if there are enough details. By the way, make sure to delete the checklists not applicable below. Praise Vitalik. + +### PR Checklist - Feature (Proposal) + +- [ ] All Tests Passing +- [ ] Proposal Added to ProposalsConfig +- [ ] Fork Block Correct +- [ ] Remove Any .only's on Tests +- [ ] Update Documentation If Needed +- [ ] Update Roles Config +- [ ] Proposal Submitted + +### PR Checklist - Feature (Non-Proposal) | Bug + +- [ ] All Tests Passing +- [ ] Remove Any .only's on Tests + +### PR Checklist - Release + +- [ ] All Tests Passing +- [ ] Clean/Empty Proposals Config +- [ ] Update Fork Block +- [ ] Update Docs If Needed diff --git a/README.md b/README.md index 216e86721..7ab17c476 100644 --- a/README.md +++ b/README.md @@ -3,57 +3,71 @@ Smart contract code for Fei Protocol and the FEI stablecoin ## To get started: + 1. Git clone this repo: git clone git@github.com:fei-protocol/fei-protocol-core.git 2. Install dependencies: `npm install` 3. Set the relevant environment variables in a gitignored `.env`: `MAINNET_ALCHEMY_API_KEY` and `ETH_PRIVATE_KEY`. You can use the `.env.example` as a base 4. To run the Hardhat based unit tests, run `npm run test:hardhat` ### Setting up Forge + Fei makes use of Forge as a smart contract development framework alongside Hardhat. To set this up run: `npm run setup` ## Dependencies - Note that this has only been tested on Linux; you may encounter issues running on other operating systems. - - - Node v12 or v16 (you can manage Node versions easily with [NVM](https://github.com/nvm-sh/nvm)) + +Note that this has only been tested on Linux; you may encounter issues running on other operating systems. + +- Node v12 or v16 (you can manage Node versions easily with [NVM](https://github.com/nvm-sh/nvm)) ## Usage - - run `npm run test` to run Forge based unit tests - - run `npm run test:hardhat` to run Hardhat based unit tests - - run `npm run test:integration` to run Solidity integration tests, forked from a pinned Mainnet block - - run `npm run test:integration:latest` to run Solidity integration tests, forked from the latest block - - run `npm run test:e2e` to run end-to-end/integration tests - - run `npm run test:all` to run all tests - - run `npm run lint` to lint ts files and sol files - - run `npm lint:all` to lint ts AND js files - - run `npm run lint:sol` to lint .sol files - - run `npm run lint:fix` to fix linting errors, if fixable automatically - - run `npm run prettier:ts` to run prettier and automatically format all ts files - automatically - - run `npm run prettier:sol` to run prettier and automatically format all Solidity files - automatically - - run `npm run prettier` to run prettier and format all files - - run `npm run coverage:hardhat` to run smart-contract coverage based off of all tests - - run `npm run calldata` to generage calldata for a proposal - - run `npm run check-proposal` to run tests for a specific dao proposal - - run `npm run compile` to compile smart contracts, if needed + +- run `npm run test` to run Forge based unit tests +- run `npm run test:hardhat` to run Hardhat based unit tests +- run `npm run test:integration` to run Solidity integration tests, forked from a pinned Mainnet block +- run `npm run test:integration:latest` to run Solidity integration tests, forked from the latest block +- run `npm run test:e2e` to run end-to-end/integration tests +- run `npm run test:all` to run all tests +- run `npm run lint` to lint ts files and sol files +- run `npm lint:all` to lint ts AND js files +- run `npm run lint:sol` to lint .sol files +- run `npm run lint:fix` to fix linting errors, if fixable automatically +- run `npm run prettier:ts` to run prettier and automatically format all ts files + automatically +- run `npm run prettier:sol` to run prettier and automatically format all Solidity files + automatically +- run `npm run prettier` to run prettier and format all files +- run `npm run coverage:hardhat` to run smart-contract coverage based off of all tests +- run `npm run calldata` to generage calldata for a proposal +- run `npm run check-proposal` to run tests for a specific dao proposal +- run `npm run compile` to compile smart contracts, if needed ## Documentation + See the [docs](https://docs.fei.money) ## Release Process + Every Thursday, do the following for the weekly release: - 1) Update the current release branch's fixed hardhat block to something within the last hour - 2) Clean the release branch if necessary: +### Release Fei-Protocol-Core + +1. Update the current release branch's fixed hardhat block to something within the last hour +2. Clean the release branch if necessary: - fix any failing tests - clear out proposals-config - 3) Merge the release branch into master. Create a release via the github UI, using the version number of the release branch. - 4) Merge master back into develop to ensure that any fixes added are pulled back into develop, and so that the hardcoded fork block is set correctly for the most recent release. - 5) Create a new branch off of develop of the format release/major.minor.patch, using an incremented minor version number +3. Merge the release branch into master. Create a release via the github UI, using the version number of the release branch. +4. Merge master back into develop to ensure that any fixes added are pulled back into develop, and so that the hardcoded fork block is set correctly for the most recent release. +5. Create a new branch off of develop of the format release/major.minor.patch, using an incremented minor version number For hotfix releases or bugfixes to master, branch off of master, add in the necessary fixes, and merge back into master. Then tag that commit with a new release number (increment the patch version number here). Finally merge master back into develop. +### Release Docs (If Applicable) + +1. @Joey should update this, because I am confused about the difference between the gh-pages and the master branch. Which one should we update, + and which one should we run commands on? Also, do we need to change the default branch of this repo? + ## License + Fei Protocol is under [the AGPL v3 license](https://github.com/fei-protocol/fei-protocol-core/tree/7160dda163d45e6d6c7092ef021c365e0031a71f/LICENSE.md) diff --git a/block.txt b/block.txt new file mode 100644 index 000000000..261f961d7 --- /dev/null +++ b/block.txt @@ -0,0 +1 @@ +14939000 diff --git a/contracts/.prettierrc b/contracts/.prettierrc index 6b8854087..cbf243f3d 100644 --- a/contracts/.prettierrc +++ b/contracts/.prettierrc @@ -12,4 +12,4 @@ } } ] - } \ No newline at end of file + } \ No newline at end of file diff --git a/contracts/core/TribeRoles.sol b/contracts/core/TribeRoles.sol index 7992ef0a3..154420aca 100644 --- a/contracts/core/TribeRoles.sol +++ b/contracts/core/TribeRoles.sol @@ -90,7 +90,7 @@ library TribeRoles { bytes32 internal constant POD_METADATA_REGISTER_ROLE = keccak256("POD_METADATA_REGISTER_ROLE"); /// @notice capable of engaging with Votium for voting incentives. - bytes32 internal constant VOTIUM_ROLE = keccak256("VOTIUM_ADMIN_ROLE"); + bytes32 internal constant VOTIUM_ADMIN_ROLE = keccak256("VOTIUM_ADMIN_ROLE"); /// @notice capable of adding an address to multi rate limited bytes32 internal constant ADD_MINTER_ROLE = keccak256("ADD_MINTER_ROLE"); diff --git a/contracts/dao/nopeDAO/NopeDAO.sol b/contracts/dao/nopeDAO/NopeDAO.sol index f2b6576f1..7eb0eba6a 100644 --- a/contracts/dao/nopeDAO/NopeDAO.sol +++ b/contracts/dao/nopeDAO/NopeDAO.sol @@ -28,7 +28,7 @@ contract NopeDAO is Governor("NopeDAO") GovernorSettings( 0, /* 0 blocks */ - 4 days, + 26585, /* 4 days measured in blocks. Assumed 13s block time */ 0 ) GovernorVotesComp(_tribe) diff --git a/contracts/external/balancer/IBalancerMinter.sol b/contracts/external/balancer/IBalancerMinter.sol new file mode 100644 index 000000000..6a1587882 --- /dev/null +++ b/contracts/external/balancer/IBalancerMinter.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// See https://etherscan.io/address/0x239e55F427D44C3cc793f49bFB507ebe76638a2b + +pragma solidity ^0.8.4; + +interface IBalancerMinter { + event Minted(address indexed recipient, address gauge, uint256 minted); + + /** + * @notice Returns the address of the Balancer Governance Token + */ + function getBalancerToken() external view returns (address); + + /** + * @notice Returns the address of the Balancer Token Admin contract + */ + function getBalancerTokenAdmin() external view returns (address); + + /** + * @notice Returns the address of the Gauge Controller + */ + function getGaugeController() external view returns (address); + + /** + * @notice Mint everything which belongs to `msg.sender` and send to them + * @param gauge `LiquidityGauge` address to get mintable amount from + */ + function mint(address gauge) external returns (uint256); + + /** + * @notice Mint everything which belongs to `msg.sender` across multiple gauges + * @param gauges List of `LiquidityGauge` addresses + */ + function mintMany(address[] calldata gauges) external returns (uint256); + + /** + * @notice Mint tokens for `user` + * @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf + * @param gauge `LiquidityGauge` address to get mintable amount from + * @param user Address to mint to + */ + function mintFor(address gauge, address user) external returns (uint256); + + /** + * @notice Mint tokens for `user` across multiple gauges + * @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf + * @param gauges List of `LiquidityGauge` addresses + * @param user Address to mint to + */ + function mintManyFor(address[] calldata gauges, address user) external returns (uint256); + + /** + * @notice The total number of tokens minted for `user` from `gauge` + */ + function minted(address user, address gauge) external view returns (uint256); + + /** + * @notice Whether `minter` is approved to mint tokens for `user` + */ + function getMinterApproval(address minter, address user) external view returns (bool); + + /** + * @notice Set whether `minter` is approved to mint tokens on your behalf + */ + function setMinterApproval(address minter, bool approval) external; + + /** + * @notice Set whether `minter` is approved to mint tokens on behalf of `user`, who has signed a message authorizing + * them. + */ + function setMinterApprovalWithSignature( + address minter, + bool approval, + address user, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + // The below functions are near-duplicates of functions available above. + // They are included for ABI compatibility with snake_casing as used in vyper contracts. + // solhint-disable func-name-mixedcase + + /** + * @notice Whether `minter` is approved to mint tokens for `user` + */ + function allowed_to_mint_for(address minter, address user) external view returns (bool); + + /** + * @notice Mint everything which belongs to `msg.sender` across multiple gauges + * @dev This function is not recommended as `mintMany()` is more flexible and gas efficient + * @param gauges List of `LiquidityGauge` addresses + */ + function mint_many(address[8] calldata gauges) external; + + /** + * @notice Mint tokens for `user` + * @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf + * @param gauge `LiquidityGauge` address to get mintable amount from + * @param user Address to mint to + */ + function mint_for(address gauge, address user) external; + + /** + * @notice Toggle whether `minter` is approved to mint tokens for `user` + */ + function toggle_approve_mint(address minter) external; +} diff --git a/contracts/external/fuse/CToken.sol b/contracts/external/fuse/CToken.sol index 5122cf384..c0e8f4228 100644 --- a/contracts/external/fuse/CToken.sol +++ b/contracts/external/fuse/CToken.sol @@ -2,5 +2,29 @@ pragma solidity ^0.8.4; abstract contract CToken { - function getCash() external view returns (uint256) {} + function getCash() external view virtual returns (uint256); + + function underlying() external view virtual returns (address); + + function borrowBalanceCurrent() external virtual returns (uint256); +} + +abstract contract CTokenFuse { + function getCash() external view virtual returns (uint256); + + function underlying() external view virtual returns (address); + + function borrowBalanceCurrent(address debtor) external virtual returns (uint256); + + function repayBorrowBehalf(address borrower, uint256 repayAmount) external virtual returns (uint256); +} + +abstract contract CEtherFuse { + function getCash() external view virtual returns (uint256); + + function underlying() external view virtual returns (address); + + function borrowBalanceCurrent(address debtor) external virtual returns (uint256); + + function repayBorrowBehalf(address borrower) external payable virtual; } diff --git a/contracts/fuse/FuseGuardian.sol b/contracts/fuse/FuseGuardian.sol index 9f0603109..5a6204f5d 100644 --- a/contracts/fuse/FuseGuardian.sol +++ b/contracts/fuse/FuseGuardian.sol @@ -15,7 +15,7 @@ contract FuseGuardian is CoreRef { comptroller = _comptroller; /// @notice The reason we are reusing the tribal chief admin role is it consolidates control in the OA, /// and means we don't have to do another governance action to create this role in core - _setContractAdminRole(keccak256("TRIBAL_CHIEF_ADMIN_ROLE")); + _setContractAdminRole(keccak256("FUSE_ADMIN")); } // ************ BORROW GUARDIAN FUNCTIONS ************ diff --git a/contracts/fuse/rewards/IRewardsDistributorDelegator.sol b/contracts/fuse/rewards/IRewardsDistributorDelegator.sol new file mode 100644 index 000000000..e9a60a2f8 --- /dev/null +++ b/contracts/fuse/rewards/IRewardsDistributorDelegator.sol @@ -0,0 +1,143 @@ +pragma solidity ^0.8.0; + +import {CToken} from "../../external/fuse/CToken.sol"; + +interface IRewardsDistributorDelegator { + /// @notice The portion of compRate that each market currently receives + function compSupplySpeeds(address) external view returns (uint256); + + /// @notice The portion of compRate that each market currently receives + function compBorrowSpeeds(address) external view returns (uint256); + + /// @notice Role for AutoRewardsDistributor contracts + function AUTO_REWARDS_DISTRIBUTOR_ROLE() external view returns (bytes32); + + /*** Set Admin ***/ + + /** + * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. + * @param newPendingAdmin New pending admin. + */ + function _setPendingAdmin(address newPendingAdmin) external; + + /** + * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin + * @dev Admin function for pending admin to accept role and update admin + */ + function _acceptAdmin() external; + + /** + * @notice Keeps the flywheel moving pre-mint and pre-redeem + * @dev Called by the Comptroller + * @param cToken The relevant market + * @param supplier The minter/redeemer + */ + function flywheelPreSupplierAction(address cToken, address supplier) external; + + /** + * @notice Keeps the flywheel moving pre-borrow and pre-repay + * @dev Called by the Comptroller + * @param cToken The relevant market + * @param borrower The borrower + */ + function flywheelPreBorrowerAction(address cToken, address borrower) external; + + /** + * @notice Keeps the flywheel moving pre-transfer and pre-seize + * @dev Called by the Comptroller + * @param cToken The relevant market + * @param src The account which sources the tokens + * @param dst The account which receives the tokens + */ + function flywheelPreTransferAction( + address cToken, + address src, + address dst + ) external; + + /** + * @notice Calculate additional accrued COMP for a contributor since last accrual + * @param contributor The address to calculate contributor rewards for + */ + function updateContributorRewards(address contributor) external; + + /** + * @notice Claim all the comp accrued by holder in all markets + * @param holder The address to claim COMP for + */ + function claimRewards(address holder) external; + + /** + * @notice Claim all the comp accrued by holder in the specified markets + * @param holder The address to claim COMP for + * @param cTokens The list of markets to claim COMP in + */ + function claimRewards(address holder, CToken[] memory cTokens) external; + + /** + * @notice Claim all comp accrued by the holders + * @param holders The addresses to claim COMP for + * @param cTokens The list of markets to claim COMP in + * @param borrowers Whether or not to claim COMP earned by borrowing + * @param suppliers Whether or not to claim COMP earned by supplying + */ + function claimRewards( + address[] memory holders, + CToken[] memory cTokens, + bool borrowers, + bool suppliers + ) external; + + /*** Comp Distribution Admin ***/ + + /** + * @notice Transfer COMP to the recipient + * @dev Note: If there is not enough COMP, we do not perform the transfer all. + * @param recipient The address of the recipient to transfer COMP to + * @param amount The amount of COMP to (possibly) transfer + */ + function _grantComp(address recipient, uint256 amount) external; + + /** + * @notice Set COMP speed for a single market + * @param cToken The market whose COMP speed to update + * @param compSpeed New COMP speed for market + */ + function _setCompSupplySpeed(CToken cToken, uint256 compSpeed) external; + + /** + * @notice Set COMP speed for a single market + * @param cToken The market whose COMP speed to update + * @param compSpeed New COMP speed for market + */ + function _setCompBorrowSpeed(CToken cToken, uint256 compSpeed) external; + + /** + * @notice Set COMP borrow and supply speeds for the specified markets. + * @param cTokens The markets whose COMP speed to update. + * @param supplySpeeds New supply-side COMP speed for the corresponding market. + * @param borrowSpeeds New borrow-side COMP speed for the corresponding market. + */ + function _setCompSpeeds( + CToken[] memory cTokens, + uint256[] memory supplySpeeds, + uint256[] memory borrowSpeeds + ) external; + + /** + * @notice Set COMP speed for a single contributor + * @param contributor The contributor whose COMP speed to update + * @param compSpeed New COMP speed for contributor + */ + function _setContributorCompSpeed(address contributor, uint256 compSpeed) external; + + /*** Helper Functions */ + + function getBlockNumber() external view returns (uint256); + + /** + * @notice Returns an array of all markets. + */ + function getAllMarkets() external view returns (CToken[] memory); +} diff --git a/contracts/metagov/BalancerGaugeStaker.sol b/contracts/metagov/BalancerGaugeStaker.sol new file mode 100644 index 000000000..242539ac5 --- /dev/null +++ b/contracts/metagov/BalancerGaugeStaker.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.0; + +import "../pcv/PCVDeposit.sol"; +import "./utils/LiquidityGaugeManager.sol"; +import "../external/balancer/IBalancerMinter.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/// @title Deposit that can stake in Balancer gauges +/// @author Fei Protocol +contract BalancerGaugeStaker is PCVDeposit, LiquidityGaugeManager { + using SafeERC20 for IERC20; + + event BalancerMinterChanged(address indexed oldMinter, address indexed newMinter); + + address private constant BAL = 0xba100000625a3754423978a60c9317c58a424e3D; + + address public balancerMinter; + + /// @notice Balancer gauge staker + /// @param _core Fei Core for reference + constructor( + address _core, + address _gaugeController, + address _balancerMinter + ) CoreRef(_core) LiquidityGaugeManager(_gaugeController) { + balancerMinter = _balancerMinter; + } + + function initialize( + address _core, + address _gaugeController, + address _balancerMinter + ) external { + require(gaugeController == address(0), "BalancerGaugeStaker: initialized"); + CoreRef._initialize(_core); + gaugeController = _gaugeController; + balancerMinter = _balancerMinter; + } + + /// @notice Set the balancer minter used to mint BAL + /// @param newMinter the new minter address + function setBalancerMinter(address newMinter) public onlyTribeRole(TribeRoles.METAGOVERNANCE_GAUGE_ADMIN) { + address currentMinter = balancerMinter; // cache to save 1 sload + require(currentMinter != newMinter, "BalancerGaugeStaker: same minter"); + + emit BalancerMinterChanged(currentMinter, newMinter); + balancerMinter = newMinter; + } + + /// @notice returns total balance of PCV in the Deposit + function balance() public view override returns (uint256) { + return IERC20(BAL).balanceOf(address(this)); + } + + /// @notice gets the token address in which this deposit returns its balance + function balanceReportedIn() public view virtual override returns (address) { + return BAL; + } + + /// @notice gets the resistant token balance and protocol owned fei of this deposit + function resistantBalanceAndFei() public view virtual override returns (uint256, uint256) { + return (balance(), 0); + } + + /// @notice noop + function deposit() external override {} + + /// @notice withdraw BAL held to another address + /// the BAL rewards accrue on this PCVDeposit when Gauge rewards are claimed. + function withdraw(address to, uint256 amount) public override onlyPCVController whenNotPaused { + IERC20(BAL).safeTransfer(to, amount); + emit Withdrawal(msg.sender, to, amount); + } + + /// @notice Mint everything which belongs to this contract in the given gauge + /// @param token whose gauge should be claimed + function mintGaugeRewards(address token) external whenNotPaused returns (uint256) { + // fetch gauge address from internal mapping to avoid this permissionless + // call to mint on any arbitrary gauge. + address gaugeAddress = tokenToGauge[token]; + require(gaugeAddress != address(0), "BalancerGaugeStaker: token has no gauge configured"); + + // emit the Deposit event because accounting is performed in BAL + // and that is what is claimed from the minter. + uint256 minted = IBalancerMinter(balancerMinter).mint(gaugeAddress); + emit Deposit(msg.sender, minted); + + return minted; + } +} diff --git a/contracts/pcv/balancer/BalancerLBPSwapper.sol b/contracts/pcv/balancer/BalancerLBPSwapper.sol index f1aa3d62c..5e43166e5 100644 --- a/contracts/pcv/balancer/BalancerLBPSwapper.sol +++ b/contracts/pcv/balancer/BalancerLBPSwapper.sol @@ -5,6 +5,7 @@ import "./manager/WeightedBalancerPoolManager.sol"; import "./IVault.sol"; import "../../utils/Timed.sol"; import "../../refs/OracleRef.sol"; +import "../../core/TribeRoles.sol"; import "../IPCVSwapper.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -199,6 +200,14 @@ contract BalancerLBPSwapper is IPCVSwapper, OracleRef, Timed, WeightedBalancerPo _swap(); } + /// @notice exit LBP with all assets to this contract. The tokens can then be withdrawn via standard PCV deposit methods. + function exitPoolToSelf() + external + hasAnyOfThreeRoles(TribeRoles.GUARDIAN, TribeRoles.PCV_CONTROLLER, TribeRoles.SWAP_ADMIN_ROLE) + { + _exitPool(); + } + /// @notice redeeem all assets from LP pool /// @param to destination for withdrawn tokens function exitPool(address to) external onlyPCVController { diff --git a/contracts/pcv/balancer/BalancerPool2Lens.sol b/contracts/pcv/balancer/BalancerPool2Lens.sol index ec9d45f4a..64a356451 100644 --- a/contracts/pcv/balancer/BalancerPool2Lens.sol +++ b/contracts/pcv/balancer/BalancerPool2Lens.sol @@ -119,6 +119,7 @@ contract BalancerPool2Lens is IPCVDepositBalances { } if (feiInPair) { uint256 otherReserves = _getIdealReserves(balances, prices, weights, j); + otherReserves = (otherReserves * bptsOwned) / totalSupply; return (reserves, otherReserves); } return (reserves, 0); diff --git a/contracts/pcv/convex/VotiumBriber.sol b/contracts/pcv/convex/VotiumBriber.sol index a58b74d99..5822ac4ef 100644 --- a/contracts/pcv/convex/VotiumBriber.sol +++ b/contracts/pcv/convex/VotiumBriber.sol @@ -5,6 +5,8 @@ import "./IVotiumBribe.sol"; import "../../refs/CoreRef.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {TribeRoles} from "../../core/TribeRoles.sol"; + /// @title VotiumBriber: implementation for a contract that can use /// tokens to bribe on Votium. /// @author Fei Protocol @@ -32,8 +34,6 @@ contract VotiumBriber is CoreRef { ) CoreRef(_core) { token = _token; votiumBribe = _votiumBribe; - - _setContractAdminRole(keccak256("TRIBAL_CHIEF_ADMIN_ROLE")); } /// @notice Spend tokens on Votium to bribe for a given pool. @@ -43,7 +43,11 @@ contract VotiumBriber is CoreRef { /// the _proposal ID, if _choiceIndex is out of range, or of block.timestamp /// is after the deadline for bribing (usually 6 hours before Convex snapshot /// vote ends). - function bribe(bytes32 _proposal, uint256 _choiceIndex) public onlyGovernorOrAdmin whenNotPaused { + function bribe(bytes32 _proposal, uint256 _choiceIndex) + public + onlyTribeRole(TribeRoles.VOTIUM_ADMIN_ROLE) + whenNotPaused + { // fetch the current number of TRIBE uint256 tokenAmount = token.balanceOf(address(this)); require(tokenAmount > 0, "VotiumBriber: no tokens to bribe"); diff --git a/contracts/pcv/utils/FeiSkimmer.sol b/contracts/pcv/utils/FeiSkimmer.sol index 21bff5f64..5312c23cb 100644 --- a/contracts/pcv/utils/FeiSkimmer.sol +++ b/contracts/pcv/utils/FeiSkimmer.sol @@ -8,9 +8,10 @@ import "../../refs/CoreRef.sol"; /// @author Fei Protocol contract FeiSkimmer is CoreRef { event ThresholdUpdate(uint256 newThreshold); + event SourceUpdate(address newSource); /// @notice source PCV deposit to skim excess FEI from - IPCVDeposit public immutable source; + IPCVDeposit public source; /// @notice the threshold of FEI above which to skim uint256 public threshold; @@ -26,6 +27,7 @@ contract FeiSkimmer is CoreRef { ) CoreRef(_core) { source = _source; threshold = _threshold; + _setContractAdminRole(keccak256("PCV_MINOR_PARAM_ROLE")); emit ThresholdUpdate(threshold); } @@ -53,4 +55,11 @@ contract FeiSkimmer is CoreRef { threshold = newThreshold; emit ThresholdUpdate(newThreshold); } + + /// @notice Set the target to skim from. Only Governor + /// @param newSource the new source to skim from + function setSource(address newSource) external onlyGovernor { + source = IPCVDeposit(newSource); + emit SourceUpdate(newSource); + } } diff --git a/contracts/refs/OracleRef.sol b/contracts/refs/OracleRef.sol index 63a9757fc..64e037030 100644 --- a/contracts/refs/OracleRef.sol +++ b/contracts/refs/OracleRef.sol @@ -92,6 +92,11 @@ abstract contract OracleRef is IOracleRef, CoreRef { } require(valid, "OracleRef: oracle invalid"); + // Invert the oracle price if necessary + if (doInvert) { + _peg = invert(_peg); + } + // Scale the oracle price by token decimals delta if necessary uint256 scalingFactor; if (decimalsNormalizer < 0) { @@ -102,10 +107,6 @@ abstract contract OracleRef is IOracleRef, CoreRef { _peg = _peg.mul(scalingFactor); } - // Invert the oracle price if necessary - if (doInvert) { - _peg = invert(_peg); - } return _peg; } diff --git a/contracts/test/integration/governance/PodFactory.t.sol b/contracts/test/integration/governance/PodFactory.t.sol index d4fced083..3d83f70d8 100644 --- a/contracts/test/integration/governance/PodFactory.t.sol +++ b/contracts/test/integration/governance/PodFactory.t.sol @@ -18,8 +18,7 @@ import {DummyStorage} from "../../utils/Fixtures.sol"; import {Vm} from "../../utils/Vm.sol"; import {MainnetAddresses} from "../fixtures/MainnetAddresses.sol"; -/// @notice Validate PodFactory critical functionality such as creating pods -/// @dev PodAdmin can not also be a pod member +/// @notice Validate PodFactory functionality, such as creating pods contract PodFactoryIntegrationTest is DSTest { Vm public constant vm = Vm(HEVM_ADDRESS); @@ -276,60 +275,6 @@ contract PodFactoryIntegrationTest is DSTest { assertEq(podBAdmin, podAdmin); } - /// @notice Validate that can create a transaction in the pod and that it progresses to the timelock - function testCreateTxInOptimisticPod() public { - vm.warp(1); - vm.roll(1); - - // 1. Deploy Dummy contract to perform a transaction on - DummyStorage dummyContract = new DummyStorage(); - assertEq(dummyContract.getVariable(), 5); - - // 2. Deploy pod - IPodFactory.PodConfig memory podConfig = getPodParamsWithTimelock(podAdmin); - vm.prank(feiDAOTimelock); - (, address podTimelock, address safe) = factory.createOptimisticPod(podConfig); - - TimelockController timelockContract = TimelockController(payable(podTimelock)); - - // 3. Schedle a transaction from the Pod's safe address to timelock. Transaction sets a variable on a dummy contract - uint256 newDummyContractVar = 10; - bytes memory timelockExecutionTxData = abi.encodePacked( - bytes4(keccak256(bytes("setVariable(uint256)"))), - newDummyContractVar - ); - - vm.prank(safe); - timelockContract.schedule( - address(dummyContract), - 0, - timelockExecutionTxData, - bytes32(0), - bytes32("1"), - podConfig.minDelay - ); - - // 4. Validate that transaction is in timelock - bytes32 txHash = timelockContract.hashOperation( - address(dummyContract), - 0, - timelockExecutionTxData, - bytes32(0), - bytes32("1") - ); - assertTrue(timelockContract.isOperationPending(txHash)); - - // 5. Fast forward to execution time in timelock - vm.warp(podConfig.minDelay + 10); - vm.roll(podConfig.minDelay + 10); - - // 6. Execute transaction and validate state is updated - podExecutor.execute(podTimelock, address(dummyContract), 0, timelockExecutionTxData, bytes32(0), bytes32("1")); - - assertTrue(timelockContract.isOperationDone(txHash)); - assertEq(dummyContract.getVariable(), newDummyContractVar); - } - /// @notice Validate that the default pod controller can be updated function testUpdateDefaultPodController() public { address newDefaultPodController = address(0x123); diff --git a/contracts/test/integration/governance/PodOperation.t.sol b/contracts/test/integration/governance/PodOperation.t.sol new file mode 100644 index 000000000..524c77a9d --- /dev/null +++ b/contracts/test/integration/governance/PodOperation.t.sol @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.0; + +import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol"; +import {ControllerV1} from "@orcaprotocol/contracts/contracts/ControllerV1.sol"; +import {MemberToken} from "@orcaprotocol/contracts/contracts/MemberToken.sol"; +import {IGnosisSafe} from "../../../pods/interfaces/IGnosisSafe.sol"; +import {PodFactory} from "../../../pods/PodFactory.sol"; +import {PodExecutor} from "../../../pods/PodExecutor.sol"; +import {IPodFactory} from "../../../pods/interfaces/IPodFactory.sol"; +import {Core} from "../../../core/Core.sol"; +import {TribeRoles} from "../../../core/TribeRoles.sol"; +import {PodAdminGateway} from "../../../pods/PodAdminGateway.sol"; + +import {DSTest} from "../../utils/DSTest.sol"; +import {mintOrcaTokens, getPodParamsWithTimelock, getCouncilPodParams, getPodParamsWithNoTimelock} from "../fixtures/Orca.sol"; +import {DummyStorage} from "../../utils/Fixtures.sol"; +import {Vm} from "../../utils/Vm.sol"; +import {MainnetAddresses} from "../fixtures/MainnetAddresses.sol"; + +/// @notice Validate full pod operation including scheduling a transaction in the timelock and having the +/// podExecutor execute it +contract PodOperationIntegrationTest is DSTest { + Vm public constant vm = Vm(HEVM_ADDRESS); + + DummyStorage dummyContract; + TimelockController timelockContract; + IPodFactory.PodConfig podConfig; + PodExecutor podExecutor; + + address feiDAOTimelock = MainnetAddresses.FEI_DAO_TIMELOCK; + address core = MainnetAddresses.CORE; + address memberToken = MainnetAddresses.MEMBER_TOKEN; + address podController = MainnetAddresses.ORCA_POD_CONTROLLER_V1_2; + + address podAdmin; + address safe; + address podTimelock; + + function setUp() public { + vm.warp(1); + vm.roll(1); + + // 1. Deploy Dummy contract to perform a transaction on + dummyContract = new DummyStorage(); + assertEq(dummyContract.getVariable(), 5); + + // 2. Deploy podExecutor + podExecutor = new PodExecutor(core); + + // 3. Deploy factory + PodFactory factory = new PodFactory(core, memberToken, podController, address(podExecutor)); + PodAdminGateway podAdminGateway = new PodAdminGateway(core, memberToken, address(factory)); + podAdmin = address(podAdminGateway); + + mintOrcaTokens(address(factory), 2, vm); + + // Grant factory the PodAdmin role, to by default disable pod membership transfers + vm.startPrank(feiDAOTimelock); + Core(core).createRole(TribeRoles.POD_ADMIN, TribeRoles.GOVERNOR); + Core(core).grantRole(TribeRoles.POD_ADMIN, address(factory)); + vm.stopPrank(); + + podConfig = getPodParamsWithTimelock(podAdmin); + vm.prank(feiDAOTimelock); + (, podTimelock, safe) = factory.createOptimisticPod(podConfig); + + timelockContract = TimelockController(payable(podTimelock)); + } + + /// @notice Validate that can create a transaction in the pod and that it progresses to the timelock + function testCreateAndExecutePodTransaction() public { + // Schedule a transaction from the Pod's safe address to timelock. Transaction sets a variable on a dummy contract + uint256 newDummyContractVar = 10; + bytes memory timelockExecutionTxData = abi.encodePacked( + bytes4(keccak256(bytes("setVariable(uint256)"))), + newDummyContractVar + ); + + vm.prank(safe); + timelockContract.schedule( + address(dummyContract), + 0, + timelockExecutionTxData, + bytes32(0), + bytes32("1"), + podConfig.minDelay + ); + + // 4. Validate that transaction is in timelock + bytes32 txHash = timelockContract.hashOperation( + address(dummyContract), + 0, + timelockExecutionTxData, + bytes32(0), + bytes32("1") + ); + assertTrue(timelockContract.isOperationPending(txHash)); + + // 5. Fast forward to execution time in timelock + vm.warp(podConfig.minDelay + 10); + vm.roll(podConfig.minDelay + 10); + + // 6. Execute transaction and validate state is updated + podExecutor.execute(podTimelock, address(dummyContract), 0, timelockExecutionTxData, bytes32(0), bytes32("1")); + + assertTrue(timelockContract.isOperationDone(txHash)); + assertEq(dummyContract.getVariable(), newDummyContractVar); + } + + /// @notice Validate that can batch execute transactions from a pod + function testBatchExecutePodTransactions() public { + // Schedule a transaction from the Pod's safe address to timelock. Transaction sets a variable on a dummy contract + uint256 newDummyContractVarA = 10; + bytes memory timelockExecutionTxDataA = abi.encodePacked( + bytes4(keccak256(bytes("setVariable(uint256)"))), + newDummyContractVarA + ); + + vm.prank(safe); + timelockContract.schedule( + address(dummyContract), + 0, + timelockExecutionTxDataA, + bytes32(0), + bytes32("1"), + podConfig.minDelay + ); + + uint256 newDummyContractVarB = 20; + bytes memory timelockExecutionTxDataB = abi.encodePacked( + bytes4(keccak256(bytes("setVariable(uint256)"))), + newDummyContractVarB + ); + + vm.prank(safe); + timelockContract.schedule( + address(dummyContract), + 0, + timelockExecutionTxDataB, + bytes32(0), + bytes32("1"), + podConfig.minDelay + ); + + // 4. Validate that transaction is in timelock + bytes32 txHashA = timelockContract.hashOperation( + address(dummyContract), + 0, + timelockExecutionTxDataA, + bytes32(0), + bytes32("1") + ); + assertTrue(timelockContract.isOperationPending(txHashA)); + + bytes32 txHashB = timelockContract.hashOperation( + address(dummyContract), + 0, + timelockExecutionTxDataB, + bytes32(0), + bytes32("1") + ); + assertTrue(timelockContract.isOperationPending(txHashB)); + + // 5. Fast forward to execution time in timelock + vm.warp(podConfig.minDelay + 10); + vm.roll(podConfig.minDelay + 10); + + // 6. Execute transaction and validate state is updated + address[] memory timelocks = new address[](2); + timelocks[0] = podTimelock; + timelocks[1] = podTimelock; + + address[] memory targets = new address[](2); + targets[0] = address(dummyContract); + targets[1] = address(dummyContract); + + uint256[] memory values = new uint256[](2); + values[0] = 0; + values[1] = 0; + + bytes[] memory txDatas = new bytes[](2); + txDatas[0] = timelockExecutionTxDataA; + txDatas[1] = timelockExecutionTxDataB; + + bytes32[] memory predecessors = new bytes32[](2); + predecessors[0] = bytes32(0); + predecessors[1] = bytes32(0); + + bytes32[] memory salts = new bytes32[](2); + salts[0] = bytes32("1"); + salts[1] = bytes32("1"); + + podExecutor.executeBatch(timelocks, targets, values, txDatas, predecessors, salts); + + assertTrue(timelockContract.isOperationDone(txHashA)); + assertTrue(timelockContract.isOperationDone(txHashB)); + + // Final updated value should be dummy value B + assertEq(dummyContract.getVariable(), newDummyContractVarB); + } +} diff --git a/contracts/test/unit/governance/NopeDAO.t.sol b/contracts/test/unit/governance/NopeDAO.t.sol index 04443b976..e35d5e30c 100644 --- a/contracts/test/unit/governance/NopeDAO.t.sol +++ b/contracts/test/unit/governance/NopeDAO.t.sol @@ -77,7 +77,7 @@ contract NopeDAOTest is DSTest { assertEq(votingDelay, 0); uint256 votingPeriod = nopeDAO.votingPeriod(); - uint256 fourDays = 86400 * 4; + uint256 fourDays = 26585; // (86400 * 4) / 13 assertEq(votingPeriod, fourDays); uint256 proposalThreshold = nopeDAO.proposalThreshold(); diff --git a/contracts/test/unit/governance/PodExecutor.t.sol b/contracts/test/unit/governance/PodExecutor.t.sol index 0205cb0c5..7b37050c4 100644 --- a/contracts/test/unit/governance/PodExecutor.t.sol +++ b/contracts/test/unit/governance/PodExecutor.t.sol @@ -26,7 +26,7 @@ contract PodExecutorTest is DSTest { vm.stopPrank(); } - /// @notice Validate initial state of roleCreator + /// @notice Validate can pause execution function testCanPause() public { vm.prank(addresses.governorAddress); podExecutor.pause(); diff --git a/contracts/utils/FuseFixer.sol b/contracts/utils/FuseFixer.sol new file mode 100644 index 000000000..d46ea64bf --- /dev/null +++ b/contracts/utils/FuseFixer.sol @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.0; + +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {PCVDeposit} from "../pcv/PCVDeposit.sol"; +import {CTokenFuse, CEtherFuse} from "../external/fuse/CToken.sol"; +import {CoreRef} from "../refs/CoreRef.sol"; +import {TribeRoles} from "../core/TribeRoles.sol"; + +/// @title Utility contract for repaying the bad debt in fuse +/// @author Fei Protocol +contract FuseFixer is PCVDeposit { + address public constant DEBTOR = address(0x32075bAd9050d4767018084F0Cb87b3182D36C45); + + address[] public UNDERLYINGS = [ + address(0x0000000000000000000000000000000000000000), // ETH + address(0x956F47F50A910163D8BF957Cf5846D573E7f87CA), // FEI + address(0x853d955aCEf822Db058eb8505911ED77F175b99e), // FRAX + address(0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919), // RAI + address(0x6B175474E89094C44Da98b954EedeAC495271d0F), // DAI + address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48), // USDC + address(0x5f98805A4E8be255a32880FDeC7F6728C6568bA0), // LUSD + address(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0), // wstETH + address(0xa693B19d2931d498c5B318dF961919BB4aee87a5), // USTw + address(0xdAC17F958D2ee523a2206206994597C13D831ec7) // USDT + ]; + + address[] public CTOKENS = [ + address(0xd8553552f8868C1Ef160eEdf031cF0BCf9686945), // Pool 8: FEI + address(0xbB025D470162CC5eA24daF7d4566064EE7f5F111), // Pool 8: ETH + address(0x7e9cE3CAa9910cc048590801e64174957Ed41d43), // Pool 8: DAI + address(0x7259eE19D6B5e755e7c65cECfd2466C09E251185), // Pool 8: wstETH + address(0x647A36d421183a0a9Fa62717a64B664a24E469C7), // Pool 8: LUSD + address(0xFA1057d02A0C1a4885851e3F4fD496Ee7D38F56e), // Pool 18: ETH + address(0x8E4E0257A4759559B4B1AC087fe8d80c63f20D19), // Pool 18: DAI + address(0x6f95d4d251053483f41c8718C30F4F3C404A8cf2), // Pool 18: USDC + address(0x3E5C122Ffa75A9Fe16ec0c69F7E9149203EA1A5d), // Pool 18: FRAX + address(0x17b1A2E012cC4C31f83B90FF11d3942857664efc), // Pool 18: FEI + address(0x51fF03410a0dA915082Af444274C381bD1b4cDB1), // Pool 18: RAI + address(0xB7FE5f277058b3f9eABf6e0655991f10924BFA54), // Pool 18: USTw + address(0x9de558FCE4F289b305E38ABe2169b75C626c114e), // Pool 27: FRAX + address(0xda396c927e3e6BEf77A98f372CE431b49EdEc43D), // Pool 27: FEI + address(0xF148cDEc066b94410d403aC5fe1bb17EC75c5851), // Pool 27: ETH + address(0x0C402F06C11c6e6A6616C98868A855448d4CfE65), // Pool 27: USTw + address(0x26267e41CeCa7C8E0f143554Af707336f27Fa051), // Pool 127: ETH + address(0xEbE0d1cb6A0b8569929e062d67bfbC07608f0A47), // Pool 127: USDC + address(0x4B68ef5AB32261082DF1A6C9C6a89FFD5eF168B1), // Pool 127: DAI + address(0xe097783483D1b7527152eF8B150B99B9B2700c8d), // Pool 127: USDT + address(0x0F0d710911FB37038b3AD88FC43DDAd4Edbe16A5), // Pool 127: USTw + address(0x8922C1147E141C055fdDfc0ED5a119f3378c8ef8), // Pool 127: FRAX + address(0x7DBC3aF9251756561Ce755fcC11c754184Af71F7), // Pool 144: ETH + address(0x3a2804ec0Ff521374aF654D8D0daA1d1aE1ee900), // Pool 144: FEI + address(0xA54c548d11792b3d26aD74F5f899e12CDfD64Fd6), // Pool 144: FRAX + address(0xA6C25548dF506d84Afd237225B5B34F2Feb1aa07), // Pool 144: DAI + address(0xfbD8Aaf46Ab3C2732FA930e5B343cd67cEA5054C), // Pool 146: ETH + address(0x49dA42a1EcA4AC6cA0C6943d9E5dc64e4641e0E3), // Pool 146: wstETH + address(0xe14c2e156A3f310d41240Ce8760eB3cb8a0dDBE3), // Pool 156: USTw + address(0x001E407f497e024B9fb1CB93ef841F43D645CA4F), // Pool 156: FEI + address(0x5CaDc2a04921213DE60B237688776e0F1A7155E6), // Pool 156: FRAX + address(0x9CD060A4855290bf0c5aeD266aBe119FF3b01966), // Pool 156: DAI + address(0x74897C0061ADeec84D292e8900c7BDD00b3388e4), // Pool 156: LUSD + address(0x88d3557eB6280CC084cA36e425d6BC52d0A04429), // Pool 156: USDC + address(0xe92a3db67e4b6AC86114149F522644b34264f858) // Pool 156: ETH + ]; + + mapping(address => address[]) public underlyingsToCTokens; + + constructor(address core) CoreRef(core) { + _buildCTokenMapping(); + + // check mappings lengths - hand calculated + assert(underlyingsToCTokens[UNDERLYINGS[0]].length == 7); + assert(underlyingsToCTokens[UNDERLYINGS[1]].length == 5); + assert(underlyingsToCTokens[UNDERLYINGS[2]].length == 5); + assert(underlyingsToCTokens[UNDERLYINGS[3]].length == 1); + assert(underlyingsToCTokens[UNDERLYINGS[4]].length == 5); + assert(underlyingsToCTokens[UNDERLYINGS[5]].length == 3); + assert(underlyingsToCTokens[UNDERLYINGS[6]].length == 2); + assert(underlyingsToCTokens[UNDERLYINGS[7]].length == 2); + assert(underlyingsToCTokens[UNDERLYINGS[8]].length == 4); + assert(underlyingsToCTokens[UNDERLYINGS[9]].length == 1); + + // send out token approvals + _approveCTokens(); + } + + /// @dev Repay all debt + function repayAll() public hasAnyOfTwoRoles(TribeRoles.PCV_SAFE_MOVER_ROLE, TribeRoles.GUARDIAN) { + _repayETH(); + + // we skip index 0 because that's ETH + for (uint256 i = 1; i < UNDERLYINGS.length; i++) { + _repayERC20(UNDERLYINGS[i]); + } + } + + /// @dev Repay the underlying asset on all ctokens up to the maximum provide + /// @notice reverts if the total bad debt is beyond the provided maximum + /// @param underlying the asset to repay in + /// @param maximum the maximum amount of underlying asset to repay + function repay(address underlying, uint256 maximum) + public + hasAnyOfTwoRoles(TribeRoles.PCV_SAFE_MOVER_ROLE, TribeRoles.GUARDIAN) + { + require(getTotalDebt(underlying) < maximum, "Total debt is greater than maximum"); + + if (underlying == address(0)) { + _repayETH(); + } else { + _repayERC20(underlying); + } + } + + /// @dev Gets the total debt for the provided underlying asset + /// @notice This is not a view function! Use .staticcall in ethers to get the return value + /// @param underlying the asset to get the debt for; pass in 0x0 for ETH + /// @return debt the total debt for the asset + function getTotalDebt(address underlying) public returns (uint256 debt) { + for (uint256 i = 0; i < CTOKENS.length; i++) { + CTokenFuse token = CTokenFuse(CTOKENS[i]); + if (token.underlying() == underlying) { + debt += CTokenFuse(CTOKENS[i]).borrowBalanceCurrent(DEBTOR); + } + } + } + + /* Helper Functions */ + + // Creates mappings of underlyings to all applicable ctokens + function _buildCTokenMapping() internal { + for (uint256 i = 0; i < CTOKENS.length; i++) { + address token = CTOKENS[i]; + address underlying = CTokenFuse(token).underlying(); + underlyingsToCTokens[underlying].push(token); + } + } + + // Approves all underlyings to their respective ctokens + function _approveCTokens() internal { + for (uint256 i = 0; i < UNDERLYINGS.length; i++) { + address underlying = UNDERLYINGS[i]; + + // Don't approve to the 0x0 address + if (underlying == address(0)) continue; + + address[] memory ctokens = underlyingsToCTokens[underlying]; + + for (uint256 j = 0; j < ctokens.length; j++) { + address ctoken = ctokens[j]; + SafeERC20.safeApprove(IERC20(underlying), ctoken, type(uint256).max); + } + } + } + + // Repays ETH to all cether-tokens + function _repayETH() internal { + address[] memory cEtherTokens = underlyingsToCTokens[address(0)]; + + for (uint256 i = 0; i < cEtherTokens.length; i++) { + CEtherFuse token = CEtherFuse(cEtherTokens[i]); + uint256 debtAmount = token.borrowBalanceCurrent(DEBTOR); + if (debtAmount > 0) { + token.repayBorrowBehalf{value: debtAmount}(DEBTOR); + } + } + } + + // Repays the provided erc20 to the applicable ctokens + function _repayERC20(address underlying) internal { + address[] memory cERC20Tokens = underlyingsToCTokens[underlying]; + + for (uint256 i = 0; i < cERC20Tokens.length; i++) { + CTokenFuse token = CTokenFuse(cERC20Tokens[i]); + uint256 debtAmount = token.borrowBalanceCurrent(DEBTOR); + token.repayBorrowBehalf(DEBTOR, debtAmount); + } + } + + /* Required Functions from PCVDeposit */ + + function deposit() external override { + // no-op + } + + function withdraw(address to, uint256 amount) external override { + // no-op, use withdrawERC20 or withdrawETH + } + + function balance() public view virtual override returns (uint256) { + return 0; + } + + function balanceReportedIn() public view virtual override returns (address) { + return address(0); + } + + /* Make this contract able to receive ETH */ + + receive() external payable {} + + fallback() external payable {} +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 4790ea15f..c6941afe0 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -22,11 +22,12 @@ const mainnetAlchemyApiKey = process.env.MAINNET_ALCHEMY_API_KEY; const runAllTests = process.env.RUN_ALL_TESTS; const useJSONTestReporter = process.env.REPORT_TEST_RESULTS_AS_JSON; const etherscanKey = process.env.ETHERSCAN_API_KEY; +const forkBlock = process.env.FORK_BLOCK; +const logging = process.env.LOGGING; if (!(process.env.NODE_OPTIONS && process.env.NODE_OPTIONS.includes('max-old-space-size'))) { - throw new Error( - `Please export node env var max-old-space-size before running hardhat. "export NODE_OPTIONS=--max-old-space-size=4096"` - ); + console.warn(`Node option 'max-old-space-size' is not set. This *might* cause hardhat to run out of memory.`); + console.warn('To fix: export NODE_OPTIONS=--max-old-space-size=4096'); } if (enableMainnetForking) { @@ -34,9 +35,9 @@ if (enableMainnetForking) { throw new Error('Cannot fork mainnet without mainnet alchemy api key.'); } - console.log('Mainnet forking enabled.'); + logging && console.log('Mainnet forking enabled.'); } else { - console.log('Mainnet forking disabled.'); + logging && console.log('Mainnet forking disabled.'); } if (useJSONTestReporter) { @@ -57,7 +58,7 @@ export default { forking: enableMainnetForking ? { url: `https://eth-mainnet.alchemyapi.io/v2/${mainnetAlchemyApiKey}`, - blockNumber: 14807700 // Thursday, May 19th + blockNumber: forkBlock ? parseInt(forkBlock) : undefined } : undefined }, diff --git a/package-lock.json b/package-lock.json index 6f9040ba1..34b9cd138 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,20 +12,20 @@ "@balancer-labs/v2-pool-weighted": "^2.0.1", "@chainlink/contracts": "^0.1.7", "@gnosis.pm/safe-core-sdk": "^2.1.0", - "@gnosis.pm/safe-deployments": "^1.12.0", + "@gnosis.pm/safe-deployments": "^1.15.0", "@gnosis.pm/safe-ethers-lib": "^1.1.0", "@nomiclabs/hardhat-waffle": "^2.0.3", "@openzeppelin/contracts": "4.6.0", "@openzeppelin/test-environment": "^0.1.7", "@openzeppelin/test-helpers": "^0.5.15", "@orcaprotocol/contracts": "^5.0.1", - "@rari-capital/solmate": "^6.2.0", + "@rari-capital/solmate": "^6.4.0", "@uniswap/lib": "^1.1.2", "@uniswap/v2-core": "^1.0.1", "@uniswap/v2-periphery": "^1.1.0-beta.0", "chai": "^4.3.6", - "dotenv": "^16.0.0", - "hardhat": "^2.9.3", + "dotenv": "^16.0.1", + "hardhat": "^2.9.7", "hardhat-contract-sizer": "^2.5.1", "hardhat-gas-reporter": "^1.0.8", "merkletreejs": "^0.2.31", @@ -33,13 +33,13 @@ }, "devDependencies": { "@idle-finance/hardhat-proposals-plugin": "^0.2.3", - "@nomiclabs/hardhat-ethers": "^2.0.5", - "@nomiclabs/hardhat-etherscan": "^3.0.3", + "@nomiclabs/hardhat-ethers": "^2.0.6", + "@nomiclabs/hardhat-etherscan": "^3.0.4", "@typechain/ethers-v5": "^7.1.2", "@typechain/hardhat": "^2.3.0", "@types/chai": "^4.3.1", "@types/mocha": "^9.1.1", - "@types/node": "^17.0.31", + "@types/node": "^17.0.41", "@typescript-eslint/eslint-plugin": "^4.31.2", "@typescript-eslint/parser": "^4.31.2", "chai-bn": "^0.3.1", @@ -49,9 +49,9 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.0.0", "ethereum-waffle": "^3.4.4", - "ethers": "^5.6.5", - "husky": "^7.0.4", - "lint-staged": "^12.4.1", + "ethers": "^5.6.8", + "husky": "^8.0.1", + "lint-staged": "^13.0.0", "mocha": "^10.0.0", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", @@ -60,10 +60,10 @@ "solhint": "^3.3.7", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.7.21", - "ts-node": "^10.7.0", + "ts-node": "^10.8.1", "tsconfig-paths": "^4.0.0", "typechain": "^5.2.0", - "typescript": "^4.6.4" + "typescript": "^4.7.3" }, "engines": { "node": ">=16.0.0", @@ -237,22 +237,13 @@ "node": ">=0.1.90" } }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" @@ -844,9 +835,9 @@ } }, "node_modules/@ethersproject/abi": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.1.tgz", - "integrity": "sha512-0cqssYh6FXjlwKWBmLm3+zH2BNARoS5u/hxbz+LpQmcDB3w0W553h2btWui1/uZp2GBM/SI3KniTuMcYyHpA5w==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.3.tgz", + "integrity": "sha512-CxKTdoZY4zDJLWXG6HzNH6znWK0M79WzzxHegDoecE3+K32pzfHOzuXg2/oGSTecZynFgpkjYXNPOqXVJlqClw==", "funding": [ { "type": "individual", @@ -858,21 +849,21 @@ } ], "dependencies": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "node_modules/@ethersproject/abstract-provider": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", - "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz", + "integrity": "sha512-BxlIgogYJtp1FS8Muvj8YfdClk3unZH0vRMVX791Z9INBNT/kuACZ9GzaY1Y4yFq+YSy6/w4gzj3HCRKrK9hsQ==", "funding": [ { "type": "individual", @@ -884,19 +875,19 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", + "@ethersproject/networks": "^5.6.3", "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0" + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/web": "^5.6.1" } }, "node_modules/@ethersproject/abstract-signer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", - "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz", + "integrity": "sha512-n1r6lttFBG0t2vNiI3HoWaS/KdOt8xyDjzlP2cuevlWLG6EX0OwcKLyG/Kp/cuwNxdy/ous+R/DEMdTUwWQIjQ==", "funding": [ { "type": "individual", @@ -908,17 +899,17 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0" } }, "node_modules/@ethersproject/address": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", - "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz", + "integrity": "sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==", "funding": [ { "type": "individual", @@ -930,17 +921,17 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.0" + "@ethersproject/rlp": "^5.6.1" } }, "node_modules/@ethersproject/base64": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", - "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.1.tgz", + "integrity": "sha512-qB76rjop6a0RIYYMiB4Eh/8n+Hxu2NIZm8S/Q7kNo5pmZfXhHGHmS4MinUainiBC54SCyRnwzL+KZjj8zbsSsw==", "funding": [ { "type": "individual", @@ -952,13 +943,13 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0" + "@ethersproject/bytes": "^5.6.1" } }, "node_modules/@ethersproject/basex": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz", - "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.1.tgz", + "integrity": "sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA==", "funding": [ { "type": "individual", @@ -970,14 +961,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/properties": "^5.6.0" } }, "node_modules/@ethersproject/bignumber": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", - "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.2.tgz", + "integrity": "sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw==", "funding": [ { "type": "individual", @@ -989,16 +980,11 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "bn.js": "^4.11.9" + "bn.js": "^5.2.1" } }, - "node_modules/@ethersproject/bignumber/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/@ethersproject/bytes": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.1.tgz", @@ -1018,9 +1004,9 @@ } }, "node_modules/@ethersproject/constants": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", - "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.1.tgz", + "integrity": "sha512-QSq9WVnZbxXYFftrjSjZDUshp6/eKp6qrtdBtUCm0QxCV5z1fG/w3kdlcsjMCQuQHUnAclKoK7XpXMezhRDOLg==", "funding": [ { "type": "individual", @@ -1032,13 +1018,13 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.6.0" + "@ethersproject/bignumber": "^5.6.2" } }, "node_modules/@ethersproject/contracts": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz", - "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.2.tgz", + "integrity": "sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g==", "funding": [ { "type": "individual", @@ -1050,16 +1036,16 @@ } ], "dependencies": { - "@ethersproject/abi": "^5.6.0", - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", + "@ethersproject/abi": "^5.6.3", + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0" + "@ethersproject/transactions": "^5.6.2" } }, "node_modules/@ethersproject/hardware-wallets": { @@ -1088,9 +1074,9 @@ } }, "node_modules/@ethersproject/hash": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", - "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.1.tgz", + "integrity": "sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA==", "funding": [ { "type": "individual", @@ -1102,20 +1088,20 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "node_modules/@ethersproject/hdnode": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz", - "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.2.tgz", + "integrity": "sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q==", "funding": [ { "type": "individual", @@ -1127,24 +1113,24 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/basex": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.1", "@ethersproject/properties": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" + "@ethersproject/sha2": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/wordlists": "^5.6.1" } }, "node_modules/@ethersproject/json-wallets": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz", - "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz", + "integrity": "sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ==", "funding": [ { "type": "individual", @@ -1156,17 +1142,17 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/hdnode": "^5.6.2", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.1", "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", + "@ethersproject/random": "^5.6.1", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/transactions": "^5.6.2", "aes-js": "3.0.0", "scrypt-js": "3.0.1" } @@ -1177,9 +1163,9 @@ "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" }, "node_modules/@ethersproject/keccak256": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", - "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.1.tgz", + "integrity": "sha512-bB7DQHCTRDooZZdL3lk9wpL0+XuG3XLGHLh3cePnybsO3V0rdCAOQGpn/0R3aODmnTOOkCATJiD2hnL+5bwthA==", "funding": [ { "type": "individual", @@ -1191,7 +1177,7 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "js-sha3": "0.8.0" } }, @@ -1211,9 +1197,9 @@ ] }, "node_modules/@ethersproject/networks": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.2.tgz", - "integrity": "sha512-9uEzaJY7j5wpYGTojGp8U89mSsgQLc40PCMJLMCnFXTs7nhBveZ0t7dbqWUNrepWTszDbFkYD6WlL8DKx5huHA==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.3.tgz", + "integrity": "sha512-QZxRH7cA5Ut9TbXwZFiCyuPchdWi87ZtVNHWZd0R6YFgYtes2jQ3+bsslJ0WdyDe0i6QumqtoYqvY3rrQFRZOQ==", "funding": [ { "type": "individual", @@ -1229,9 +1215,9 @@ } }, "node_modules/@ethersproject/pbkdf2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz", - "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz", + "integrity": "sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ==", "funding": [ { "type": "individual", @@ -1243,8 +1229,8 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/sha2": "^5.6.0" + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/sha2": "^5.6.1" } }, "node_modules/@ethersproject/properties": { @@ -1266,9 +1252,9 @@ } }, "node_modules/@ethersproject/providers": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.5.tgz", - "integrity": "sha512-TRS+c2Ud+cMpWodmGAc9xbnYRPWzRNYt2zkCSnj58nJoamBQ6x4cUbBeo0lTC3y+6RDVIBeJv18OqsDbSktLVg==", + "version": "5.6.8", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.8.tgz", + "integrity": "sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w==", "funding": [ { "type": "individual", @@ -1280,31 +1266,32 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/base64": "^5.6.1", + "@ethersproject/basex": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", + "@ethersproject/hash": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", + "@ethersproject/networks": "^5.6.3", "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0", + "@ethersproject/random": "^5.6.1", + "@ethersproject/rlp": "^5.6.1", + "@ethersproject/sha2": "^5.6.1", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/web": "^5.6.1", "bech32": "1.1.4", "ws": "7.4.6" } }, "node_modules/@ethersproject/random": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz", - "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.1.tgz", + "integrity": "sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA==", "funding": [ { "type": "individual", @@ -1316,14 +1303,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/rlp": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", - "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.1.tgz", + "integrity": "sha512-uYjmcZx+DKlFUk7a5/W9aQVaoEC7+1MOBgNtvNg13+RnuUwT4F0zTovC0tmay5SmRslb29V1B7Y5KCri46WhuQ==", "funding": [ { "type": "individual", @@ -1335,14 +1322,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/sha2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", - "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.1.tgz", + "integrity": "sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g==", "funding": [ { "type": "individual", @@ -1354,15 +1341,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "hash.js": "1.1.7" } }, "node_modules/@ethersproject/signing-key": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.1.tgz", - "integrity": "sha512-XvqQ20DH0D+bS3qlrrgh+axRMth5kD1xuvqUQUTeezxUTXBOeR6hWz2/C6FBEu39FRytyybIWrYf7YLSAKr1LQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.2.tgz", + "integrity": "sha512-jVbu0RuP7EFpw82vHcL+GP35+KaNruVAZM90GxgQnGqB6crhBqW/ozBfFvdeImtmb4qPko0uxXjn8l9jpn0cwQ==", "funding": [ { "type": "individual", @@ -1374,23 +1361,18 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "bn.js": "^4.11.9", + "bn.js": "^5.2.1", "elliptic": "6.5.4", "hash.js": "1.1.7" } }, - "node_modules/@ethersproject/signing-key/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/@ethersproject/solidity": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz", - "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.1.tgz", + "integrity": "sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g==", "funding": [ { "type": "individual", @@ -1402,18 +1384,18 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/sha2": "^5.6.1", + "@ethersproject/strings": "^5.6.1" } }, "node_modules/@ethersproject/strings": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", - "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.1.tgz", + "integrity": "sha512-2X1Lgk6Jyfg26MUnsHiT456U9ijxKUybz8IM1Vih+NJxYtXhmvKBcHOmvGqpFSVJ0nQ4ZCoIViR8XlRw1v/+Cw==", "funding": [ { "type": "individual", @@ -1425,15 +1407,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/transactions": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", - "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.2.tgz", + "integrity": "sha512-BuV63IRPHmJvthNkkt9G70Ullx6AcM+SDc+a8Aw/8Yew6YwT51TcBKEp1P4oOQ/bP25I18JJr7rcFRgFtU9B2Q==", "funding": [ { "type": "individual", @@ -1445,21 +1427,21 @@ } ], "dependencies": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0" + "@ethersproject/rlp": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2" } }, "node_modules/@ethersproject/units": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz", - "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.1.tgz", + "integrity": "sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw==", "funding": [ { "type": "individual", @@ -1471,15 +1453,15 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/constants": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/constants": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/wallet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz", - "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.2.tgz", + "integrity": "sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg==", "funding": [ { "type": "individual", @@ -1491,27 +1473,27 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/json-wallets": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/hdnode": "^5.6.2", + "@ethersproject/json-wallets": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" + "@ethersproject/random": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2", + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/wordlists": "^5.6.1" } }, "node_modules/@ethersproject/web": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", - "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.1.tgz", + "integrity": "sha512-/vSyzaQlNXkO1WV+RneYKqCJwualcUdx/Z3gseVovZP0wIlOFcCE1hkRhKBH8ImKbGQbMl9EAAyJFrJu7V0aqA==", "funding": [ { "type": "individual", @@ -1523,17 +1505,17 @@ } ], "dependencies": { - "@ethersproject/base64": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/base64": "^5.6.1", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "node_modules/@ethersproject/wordlists": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz", - "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.1.tgz", + "integrity": "sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw==", "funding": [ { "type": "individual", @@ -1545,11 +1527,11 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/hash": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "node_modules/@gnosis.pm/mock-contract": { @@ -1599,9 +1581,12 @@ } }, "node_modules/@gnosis.pm/safe-deployments": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@gnosis.pm/safe-deployments/-/safe-deployments-1.12.0.tgz", - "integrity": "sha512-fNwQqTdBushxlkqp8WpgXVP9HTePa/VFWM9VYPzbSsdqYqSUnXYDDOMyHH3H6eNltwRV8RVp/cxqUZLrvQ3YPg==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@gnosis.pm/safe-deployments/-/safe-deployments-1.15.0.tgz", + "integrity": "sha512-twfC5HNuj+TKS2gOowf6A1FGZfOLBHAV2JhYpmOCf2MKsfcG+Fe4TrSRgQg605MhWdwFiaGVpNkcwjvpxhGuew==", + "dependencies": { + "semver": "^7.3.7" + } }, "node_modules/@gnosis.pm/safe-ethers-lib": { "version": "1.1.0", @@ -1670,6 +1655,31 @@ "hardhat": "^2.0.0" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@ledgerhq/cryptoassets": { "version": "5.53.0", "resolved": "https://registry.npmjs.org/@ledgerhq/cryptoassets/-/cryptoassets-5.53.0.tgz", @@ -1936,18 +1946,18 @@ } }, "node_modules/@nomiclabs/hardhat-ethers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.5.tgz", - "integrity": "sha512-A2gZAGB6kUvLx+kzM92HKuUF33F1FSe90L0TmkXkT2Hh0OKRpvWZURUSU2nghD2yC4DzfEZ3DftfeHGvZ2JTUw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.6.tgz", + "integrity": "sha512-q2Cjp20IB48rEn2NPjR1qxsIQBvFVYW9rFRCFq+bC4RUrn1Ljz3g4wM8uSlgIBZYBi2JMXxmOzFqHraczxq4Ng==", "peerDependencies": { "ethers": "^5.0.0", "hardhat": "^2.0.0" } }, "node_modules/@nomiclabs/hardhat-etherscan": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.0.3.tgz", - "integrity": "sha512-OfNtUKc/ZwzivmZnnpwWREfaYncXteKHskn3yDnz+fPBZ6wfM4GR+d5RwjREzYFWE+o5iR9ruXhWw/8fejWM9g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.0.4.tgz", + "integrity": "sha512-AZPlnyCYp3YObmhtsFo6RWgY/81fQKRF5h42iV22H4jz9MwP+SWeoB99YVPLnxId2fmAYu3VgCNeE9QpApv06g==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", @@ -2324,9 +2334,9 @@ } }, "node_modules/@rari-capital/solmate": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.2.0.tgz", - "integrity": "sha512-g94F+Ra9ixyJyNgvnOIufNjUz488uEG0nxIEEtJ7+g+tA1XGUupRB2kB5b+VO7WYO26RNOVD2fW6xE4e14iWpg==" + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.4.0.tgz", + "integrity": "sha512-BXWIHHbG5Zbgrxi0qVYe0Zs+bfx+XgOciVUACjuIApV0KzC0kY8XdO1higusIei/ZKCC+GUKdcdQZflxYPUTKQ==" }, "node_modules/@resolver-engine/core": { "version": "0.3.3", @@ -4471,9 +4481,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.31.tgz", - "integrity": "sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==" + "version": "17.0.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.41.tgz", + "integrity": "sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==" }, "node_modules/@types/node-fetch": { "version": "2.6.1", @@ -5474,9 +5484,9 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "node_modules/body-parser": { "version": "1.20.0", @@ -7124,9 +7134,9 @@ } }, "node_modules/dotenv": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", - "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", "engines": { "node": ">=12" } @@ -8923,9 +8933,9 @@ } }, "node_modules/ethers": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.5.tgz", - "integrity": "sha512-9CTmplO9bv0s/aPw3HB3txGzKz3tUSI2EfO4dJo0W2WvaEq1ArgsEX6obV+bj5X3yY+Zgb1kAux8TDtJKe1FaA==", + "version": "5.6.8", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.8.tgz", + "integrity": "sha512-YxIGaltAOdvBFPZwIkyHnXbW40f1r8mHUgapW6dxkO+6t7H6wY8POUn0Kbxrd/N7I4hHxyi7YCddMAH/wmho2w==", "funding": [ { "type": "individual", @@ -8937,36 +8947,36 @@ } ], "dependencies": { - "@ethersproject/abi": "5.6.1", - "@ethersproject/abstract-provider": "5.6.0", - "@ethersproject/abstract-signer": "5.6.0", - "@ethersproject/address": "5.6.0", - "@ethersproject/base64": "5.6.0", - "@ethersproject/basex": "5.6.0", - "@ethersproject/bignumber": "5.6.0", + "@ethersproject/abi": "5.6.3", + "@ethersproject/abstract-provider": "5.6.1", + "@ethersproject/abstract-signer": "5.6.2", + "@ethersproject/address": "5.6.1", + "@ethersproject/base64": "5.6.1", + "@ethersproject/basex": "5.6.1", + "@ethersproject/bignumber": "5.6.2", "@ethersproject/bytes": "5.6.1", - "@ethersproject/constants": "5.6.0", - "@ethersproject/contracts": "5.6.0", - "@ethersproject/hash": "5.6.0", - "@ethersproject/hdnode": "5.6.0", - "@ethersproject/json-wallets": "5.6.0", - "@ethersproject/keccak256": "5.6.0", + "@ethersproject/constants": "5.6.1", + "@ethersproject/contracts": "5.6.2", + "@ethersproject/hash": "5.6.1", + "@ethersproject/hdnode": "5.6.2", + "@ethersproject/json-wallets": "5.6.1", + "@ethersproject/keccak256": "5.6.1", "@ethersproject/logger": "5.6.0", - "@ethersproject/networks": "5.6.2", - "@ethersproject/pbkdf2": "5.6.0", + "@ethersproject/networks": "5.6.3", + "@ethersproject/pbkdf2": "5.6.1", "@ethersproject/properties": "5.6.0", - "@ethersproject/providers": "5.6.5", - "@ethersproject/random": "5.6.0", - "@ethersproject/rlp": "5.6.0", - "@ethersproject/sha2": "5.6.0", - "@ethersproject/signing-key": "5.6.1", - "@ethersproject/solidity": "5.6.0", - "@ethersproject/strings": "5.6.0", - "@ethersproject/transactions": "5.6.0", - "@ethersproject/units": "5.6.0", - "@ethersproject/wallet": "5.6.0", - "@ethersproject/web": "5.6.0", - "@ethersproject/wordlists": "5.6.0" + "@ethersproject/providers": "5.6.8", + "@ethersproject/random": "5.6.1", + "@ethersproject/rlp": "5.6.1", + "@ethersproject/sha2": "5.6.1", + "@ethersproject/signing-key": "5.6.2", + "@ethersproject/solidity": "5.6.1", + "@ethersproject/strings": "5.6.1", + "@ethersproject/transactions": "5.6.2", + "@ethersproject/units": "5.6.1", + "@ethersproject/wallet": "5.6.2", + "@ethersproject/web": "5.6.1", + "@ethersproject/wordlists": "5.6.1" } }, "node_modules/ethjs-abi": { @@ -9056,28 +9066,55 @@ } }, "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/exit-hook": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", @@ -18396,15 +18433,15 @@ } }, "node_modules/hardhat": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.9.3.tgz", - "integrity": "sha512-7Vw99RbYbMZ15UzegOR/nqIYIqddZXvLwJGaX5sX4G5bydILnbjmDU6g3jMKJSiArEixS3vHAEaOs5CW1JQ3hg==", - "dependencies": { - "@ethereumjs/block": "^3.6.0", - "@ethereumjs/blockchain": "^5.5.0", - "@ethereumjs/common": "^2.6.0", - "@ethereumjs/tx": "^3.4.0", - "@ethereumjs/vm": "^5.6.0", + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.9.7.tgz", + "integrity": "sha512-PVSgTlM4Mtc4HNEoISpcM6rRNAK3ngqhxUaTmSw9eCtuVmtxTK86Tqnuq4zNPmlrtcuReXry9k3LGEnk2gJgbA==", + "dependencies": { + "@ethereumjs/block": "^3.6.2", + "@ethereumjs/blockchain": "^5.5.2", + "@ethereumjs/common": "^2.6.4", + "@ethereumjs/tx": "^3.5.1", + "@ethereumjs/vm": "^5.9.0", "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", "@sentry/node": "^5.18.1", @@ -18423,15 +18460,15 @@ "env-paths": "^2.2.0", "ethereum-cryptography": "^0.1.2", "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^7.1.3", + "ethereumjs-util": "^7.1.4", "find-up": "^2.1.0", "fp-ts": "1.19.3", "fs-extra": "^7.0.1", - "glob": "^7.1.3", + "glob": "7.2.0", "immutable": "^4.0.0-rc.12", "io-ts": "1.10.4", "lodash": "^4.17.11", - "merkle-patricia-tree": "^4.2.2", + "merkle-patricia-tree": "^4.2.4", "mnemonist": "^0.38.0", "mocha": "^9.2.0", "p-map": "^4.0.0", @@ -18454,6 +18491,9 @@ }, "engines": { "node": "^12.0.0 || ^14.0.0 || ^16.0.0" + }, + "peerDependencies": { + "chai": "^4.2.0" } }, "node_modules/hardhat-contract-sizer": { @@ -19389,24 +19429,24 @@ } }, "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">=12.20.0" } }, "node_modules/husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", "dev": true, "bin": { "husky": "lib/bin.js" }, "engines": { - "node": ">=12" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/typicode" @@ -20102,12 +20142,12 @@ } }, "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -20568,64 +20608,51 @@ } }, "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/lint-staged": { - "version": "12.4.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.4.1.tgz", - "integrity": "sha512-PTXgzpflrQ+pODQTG116QNB+Q6uUTDg5B5HqGvNhoQSGt8Qy+MA/6zSnR8n38+sxP5TapzeQGTvoKni0KRS8Vg==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.0.tgz", + "integrity": "sha512-vWban5utFt78VZohbosUxNIa46KKJ+KOQTDWTQ8oSl1DLEEVl9zhUtaQbiiydAmx+h2wKJK2d0+iMaRmknuWRQ==", "dev": true, "dependencies": { "cli-truncate": "^3.1.0", "colorette": "^2.0.16", - "commander": "^8.3.0", - "debug": "^4.3.3", - "execa": "^5.1.1", - "lilconfig": "2.0.4", - "listr2": "^4.0.1", - "micromatch": "^4.0.4", + "commander": "^9.3.0", + "debug": "^4.3.4", + "execa": "^6.1.0", + "lilconfig": "2.0.5", + "listr2": "^4.0.5", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "pidtree": "^0.5.0", "string-argv": "^0.3.1", - "supports-color": "^9.2.1", - "yaml": "^1.10.2" + "yaml": "^2.1.1" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^14.13.1 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/lint-staged" } }, "node_modules/lint-staged/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", + "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", "dev": true, "engines": { - "node": ">= 12" - } - }, - "node_modules/lint-staged/node_modules/supports-color": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", - "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": "^12.20.0 || >=14" } }, "node_modules/listr2": { @@ -22179,15 +22206,30 @@ } }, "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npmlog": { @@ -22335,9 +22377,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -26587,12 +26629,15 @@ } }, "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-hex-prefix": { @@ -27253,12 +27298,12 @@ "integrity": "sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==" }, "node_modules/ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", "dev": true, "dependencies": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -27269,7 +27314,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { @@ -27510,9 +27555,9 @@ } }, "node_modules/typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -28628,12 +28673,12 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", + "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { @@ -28864,19 +28909,13 @@ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "optional": true }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true - }, "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "requires": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" } }, "@ensdomains/address-encoder": { @@ -29394,91 +29433,84 @@ } }, "@ethersproject/abi": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.1.tgz", - "integrity": "sha512-0cqssYh6FXjlwKWBmLm3+zH2BNARoS5u/hxbz+LpQmcDB3w0W553h2btWui1/uZp2GBM/SI3KniTuMcYyHpA5w==", - "requires": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.3.tgz", + "integrity": "sha512-CxKTdoZY4zDJLWXG6HzNH6znWK0M79WzzxHegDoecE3+K32pzfHOzuXg2/oGSTecZynFgpkjYXNPOqXVJlqClw==", + "requires": { + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "@ethersproject/abstract-provider": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", - "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz", + "integrity": "sha512-BxlIgogYJtp1FS8Muvj8YfdClk3unZH0vRMVX791Z9INBNT/kuACZ9GzaY1Y4yFq+YSy6/w4gzj3HCRKrK9hsQ==", "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", + "@ethersproject/networks": "^5.6.3", "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0" + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/web": "^5.6.1" } }, "@ethersproject/abstract-signer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", - "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz", + "integrity": "sha512-n1r6lttFBG0t2vNiI3HoWaS/KdOt8xyDjzlP2cuevlWLG6EX0OwcKLyG/Kp/cuwNxdy/ous+R/DEMdTUwWQIjQ==", "requires": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0" } }, "@ethersproject/address": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", - "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz", + "integrity": "sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==", "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.0" + "@ethersproject/rlp": "^5.6.1" } }, "@ethersproject/base64": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", - "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.1.tgz", + "integrity": "sha512-qB76rjop6a0RIYYMiB4Eh/8n+Hxu2NIZm8S/Q7kNo5pmZfXhHGHmS4MinUainiBC54SCyRnwzL+KZjj8zbsSsw==", "requires": { - "@ethersproject/bytes": "^5.6.0" + "@ethersproject/bytes": "^5.6.1" } }, "@ethersproject/basex": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz", - "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.1.tgz", + "integrity": "sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/properties": "^5.6.0" } }, "@ethersproject/bignumber": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", - "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.2.tgz", + "integrity": "sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "bn.js": "^4.11.9" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } + "bn.js": "^5.2.1" } }, "@ethersproject/bytes": { @@ -29490,28 +29522,28 @@ } }, "@ethersproject/constants": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", - "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.1.tgz", + "integrity": "sha512-QSq9WVnZbxXYFftrjSjZDUshp6/eKp6qrtdBtUCm0QxCV5z1fG/w3kdlcsjMCQuQHUnAclKoK7XpXMezhRDOLg==", "requires": { - "@ethersproject/bignumber": "^5.6.0" + "@ethersproject/bignumber": "^5.6.2" } }, "@ethersproject/contracts": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz", - "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==", - "requires": { - "@ethersproject/abi": "^5.6.0", - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.2.tgz", + "integrity": "sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g==", + "requires": { + "@ethersproject/abi": "^5.6.3", + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0" + "@ethersproject/transactions": "^5.6.2" } }, "@ethersproject/hardware-wallets": { @@ -29528,55 +29560,55 @@ } }, "@ethersproject/hash": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", - "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", - "requires": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.1.tgz", + "integrity": "sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA==", + "requires": { + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "@ethersproject/hdnode": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz", - "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.2.tgz", + "integrity": "sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q==", "requires": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/basex": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.1", "@ethersproject/properties": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" + "@ethersproject/sha2": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/wordlists": "^5.6.1" } }, "@ethersproject/json-wallets": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz", - "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==", - "requires": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz", + "integrity": "sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ==", + "requires": { + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/hdnode": "^5.6.2", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.1", "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", + "@ethersproject/random": "^5.6.1", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/transactions": "^5.6.2", "aes-js": "3.0.0", "scrypt-js": "3.0.1" }, @@ -29589,11 +29621,11 @@ } }, "@ethersproject/keccak256": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", - "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.1.tgz", + "integrity": "sha512-bB7DQHCTRDooZZdL3lk9wpL0+XuG3XLGHLh3cePnybsO3V0rdCAOQGpn/0R3aODmnTOOkCATJiD2hnL+5bwthA==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "js-sha3": "0.8.0" } }, @@ -29603,20 +29635,20 @@ "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==" }, "@ethersproject/networks": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.2.tgz", - "integrity": "sha512-9uEzaJY7j5wpYGTojGp8U89mSsgQLc40PCMJLMCnFXTs7nhBveZ0t7dbqWUNrepWTszDbFkYD6WlL8DKx5huHA==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.3.tgz", + "integrity": "sha512-QZxRH7cA5Ut9TbXwZFiCyuPchdWi87ZtVNHWZd0R6YFgYtes2jQ3+bsslJ0WdyDe0i6QumqtoYqvY3rrQFRZOQ==", "requires": { "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/pbkdf2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz", - "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz", + "integrity": "sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ==", "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/sha2": "^5.6.0" + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/sha2": "^5.6.1" } }, "@ethersproject/properties": { @@ -29628,172 +29660,166 @@ } }, "@ethersproject/providers": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.5.tgz", - "integrity": "sha512-TRS+c2Ud+cMpWodmGAc9xbnYRPWzRNYt2zkCSnj58nJoamBQ6x4cUbBeo0lTC3y+6RDVIBeJv18OqsDbSktLVg==", - "requires": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", + "version": "5.6.8", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.8.tgz", + "integrity": "sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w==", + "requires": { + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/base64": "^5.6.1", + "@ethersproject/basex": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", + "@ethersproject/hash": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", + "@ethersproject/networks": "^5.6.3", "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0", + "@ethersproject/random": "^5.6.1", + "@ethersproject/rlp": "^5.6.1", + "@ethersproject/sha2": "^5.6.1", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/web": "^5.6.1", "bech32": "1.1.4", "ws": "7.4.6" } }, "@ethersproject/random": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz", - "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.1.tgz", + "integrity": "sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/rlp": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", - "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.1.tgz", + "integrity": "sha512-uYjmcZx+DKlFUk7a5/W9aQVaoEC7+1MOBgNtvNg13+RnuUwT4F0zTovC0tmay5SmRslb29V1B7Y5KCri46WhuQ==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/sha2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", - "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.1.tgz", + "integrity": "sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "hash.js": "1.1.7" } }, "@ethersproject/signing-key": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.1.tgz", - "integrity": "sha512-XvqQ20DH0D+bS3qlrrgh+axRMth5kD1xuvqUQUTeezxUTXBOeR6hWz2/C6FBEu39FRytyybIWrYf7YLSAKr1LQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.2.tgz", + "integrity": "sha512-jVbu0RuP7EFpw82vHcL+GP35+KaNruVAZM90GxgQnGqB6crhBqW/ozBfFvdeImtmb4qPko0uxXjn8l9jpn0cwQ==", "requires": { - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "bn.js": "^4.11.9", + "bn.js": "^5.2.1", "elliptic": "6.5.4", "hash.js": "1.1.7" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } } }, "@ethersproject/solidity": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz", - "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.1.tgz", + "integrity": "sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g==", "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/sha2": "^5.6.1", + "@ethersproject/strings": "^5.6.1" } }, "@ethersproject/strings": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", - "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.1.tgz", + "integrity": "sha512-2X1Lgk6Jyfg26MUnsHiT456U9ijxKUybz8IM1Vih+NJxYtXhmvKBcHOmvGqpFSVJ0nQ4ZCoIViR8XlRw1v/+Cw==", "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/transactions": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", - "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", - "requires": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.2.tgz", + "integrity": "sha512-BuV63IRPHmJvthNkkt9G70Ullx6AcM+SDc+a8Aw/8Yew6YwT51TcBKEp1P4oOQ/bP25I18JJr7rcFRgFtU9B2Q==", + "requires": { + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/constants": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0" + "@ethersproject/rlp": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2" } }, "@ethersproject/units": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz", - "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.1.tgz", + "integrity": "sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw==", "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/constants": "^5.6.0", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/constants": "^5.6.1", "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/wallet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz", - "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==", - "requires": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/json-wallets": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.2.tgz", + "integrity": "sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg==", + "requires": { + "@ethersproject/abstract-provider": "^5.6.1", + "@ethersproject/abstract-signer": "^5.6.2", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/hdnode": "^5.6.2", + "@ethersproject/json-wallets": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" + "@ethersproject/random": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2", + "@ethersproject/transactions": "^5.6.2", + "@ethersproject/wordlists": "^5.6.1" } }, "@ethersproject/web": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", - "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.1.tgz", + "integrity": "sha512-/vSyzaQlNXkO1WV+RneYKqCJwualcUdx/Z3gseVovZP0wIlOFcCE1hkRhKBH8ImKbGQbMl9EAAyJFrJu7V0aqA==", "requires": { - "@ethersproject/base64": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", + "@ethersproject/base64": "^5.6.1", + "@ethersproject/bytes": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "@ethersproject/wordlists": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz", - "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.1.tgz", + "integrity": "sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw==", "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/hash": "^5.6.1", "@ethersproject/logger": "^5.6.0", "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@ethersproject/strings": "^5.6.1" } }, "@gnosis.pm/mock-contract": { @@ -29841,9 +29867,12 @@ } }, "@gnosis.pm/safe-deployments": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@gnosis.pm/safe-deployments/-/safe-deployments-1.12.0.tgz", - "integrity": "sha512-fNwQqTdBushxlkqp8WpgXVP9HTePa/VFWM9VYPzbSsdqYqSUnXYDDOMyHH3H6eNltwRV8RVp/cxqUZLrvQ3YPg==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@gnosis.pm/safe-deployments/-/safe-deployments-1.15.0.tgz", + "integrity": "sha512-twfC5HNuj+TKS2gOowf6A1FGZfOLBHAV2JhYpmOCf2MKsfcG+Fe4TrSRgQg605MhWdwFiaGVpNkcwjvpxhGuew==", + "requires": { + "semver": "^7.3.7" + } }, "@gnosis.pm/safe-ethers-lib": { "version": "1.1.0", @@ -29901,6 +29930,28 @@ "dev": true, "requires": {} }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@ledgerhq/cryptoassets": { "version": "5.53.0", "resolved": "https://registry.npmjs.org/@ledgerhq/cryptoassets/-/cryptoassets-5.53.0.tgz", @@ -30139,15 +30190,15 @@ } }, "@nomiclabs/hardhat-ethers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.5.tgz", - "integrity": "sha512-A2gZAGB6kUvLx+kzM92HKuUF33F1FSe90L0TmkXkT2Hh0OKRpvWZURUSU2nghD2yC4DzfEZ3DftfeHGvZ2JTUw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.6.tgz", + "integrity": "sha512-q2Cjp20IB48rEn2NPjR1qxsIQBvFVYW9rFRCFq+bC4RUrn1Ljz3g4wM8uSlgIBZYBi2JMXxmOzFqHraczxq4Ng==", "requires": {} }, "@nomiclabs/hardhat-etherscan": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.0.3.tgz", - "integrity": "sha512-OfNtUKc/ZwzivmZnnpwWREfaYncXteKHskn3yDnz+fPBZ6wfM4GR+d5RwjREzYFWE+o5iR9ruXhWw/8fejWM9g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.0.4.tgz", + "integrity": "sha512-AZPlnyCYp3YObmhtsFo6RWgY/81fQKRF5h42iV22H4jz9MwP+SWeoB99YVPLnxId2fmAYu3VgCNeE9QpApv06g==", "dev": true, "requires": { "@ethersproject/abi": "^5.1.2", @@ -30474,9 +30525,9 @@ } }, "@rari-capital/solmate": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.2.0.tgz", - "integrity": "sha512-g94F+Ra9ixyJyNgvnOIufNjUz488uEG0nxIEEtJ7+g+tA1XGUupRB2kB5b+VO7WYO26RNOVD2fW6xE4e14iWpg==" + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@rari-capital/solmate/-/solmate-6.4.0.tgz", + "integrity": "sha512-BXWIHHbG5Zbgrxi0qVYe0Zs+bfx+XgOciVUACjuIApV0KzC0kY8XdO1higusIei/ZKCC+GUKdcdQZflxYPUTKQ==" }, "@resolver-engine/core": { "version": "0.3.3", @@ -32390,9 +32441,9 @@ "dev": true }, "@types/node": { - "version": "17.0.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.31.tgz", - "integrity": "sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==" + "version": "17.0.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.41.tgz", + "integrity": "sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==" }, "@types/node-fetch": { "version": "2.6.1", @@ -33152,9 +33203,9 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" }, "body-parser": { "version": "1.20.0", @@ -34478,9 +34529,9 @@ } }, "dotenv": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", - "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" }, "duplexer3": { "version": "0.1.4", @@ -35925,40 +35976,40 @@ } }, "ethers": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.5.tgz", - "integrity": "sha512-9CTmplO9bv0s/aPw3HB3txGzKz3tUSI2EfO4dJo0W2WvaEq1ArgsEX6obV+bj5X3yY+Zgb1kAux8TDtJKe1FaA==", - "requires": { - "@ethersproject/abi": "5.6.1", - "@ethersproject/abstract-provider": "5.6.0", - "@ethersproject/abstract-signer": "5.6.0", - "@ethersproject/address": "5.6.0", - "@ethersproject/base64": "5.6.0", - "@ethersproject/basex": "5.6.0", - "@ethersproject/bignumber": "5.6.0", + "version": "5.6.8", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.8.tgz", + "integrity": "sha512-YxIGaltAOdvBFPZwIkyHnXbW40f1r8mHUgapW6dxkO+6t7H6wY8POUn0Kbxrd/N7I4hHxyi7YCddMAH/wmho2w==", + "requires": { + "@ethersproject/abi": "5.6.3", + "@ethersproject/abstract-provider": "5.6.1", + "@ethersproject/abstract-signer": "5.6.2", + "@ethersproject/address": "5.6.1", + "@ethersproject/base64": "5.6.1", + "@ethersproject/basex": "5.6.1", + "@ethersproject/bignumber": "5.6.2", "@ethersproject/bytes": "5.6.1", - "@ethersproject/constants": "5.6.0", - "@ethersproject/contracts": "5.6.0", - "@ethersproject/hash": "5.6.0", - "@ethersproject/hdnode": "5.6.0", - "@ethersproject/json-wallets": "5.6.0", - "@ethersproject/keccak256": "5.6.0", + "@ethersproject/constants": "5.6.1", + "@ethersproject/contracts": "5.6.2", + "@ethersproject/hash": "5.6.1", + "@ethersproject/hdnode": "5.6.2", + "@ethersproject/json-wallets": "5.6.1", + "@ethersproject/keccak256": "5.6.1", "@ethersproject/logger": "5.6.0", - "@ethersproject/networks": "5.6.2", - "@ethersproject/pbkdf2": "5.6.0", + "@ethersproject/networks": "5.6.3", + "@ethersproject/pbkdf2": "5.6.1", "@ethersproject/properties": "5.6.0", - "@ethersproject/providers": "5.6.5", - "@ethersproject/random": "5.6.0", - "@ethersproject/rlp": "5.6.0", - "@ethersproject/sha2": "5.6.0", - "@ethersproject/signing-key": "5.6.1", - "@ethersproject/solidity": "5.6.0", - "@ethersproject/strings": "5.6.0", - "@ethersproject/transactions": "5.6.0", - "@ethersproject/units": "5.6.0", - "@ethersproject/wallet": "5.6.0", - "@ethersproject/web": "5.6.0", - "@ethersproject/wordlists": "5.6.0" + "@ethersproject/providers": "5.6.8", + "@ethersproject/random": "5.6.1", + "@ethersproject/rlp": "5.6.1", + "@ethersproject/sha2": "5.6.1", + "@ethersproject/signing-key": "5.6.2", + "@ethersproject/solidity": "5.6.1", + "@ethersproject/strings": "5.6.1", + "@ethersproject/transactions": "5.6.2", + "@ethersproject/units": "5.6.1", + "@ethersproject/wallet": "5.6.2", + "@ethersproject/web": "5.6.1", + "@ethersproject/wordlists": "5.6.1" } }, "ethjs-abi": { @@ -36034,20 +36085,37 @@ } }, "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", "dev": true, "requires": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + } } }, "exit-hook": { @@ -43018,15 +43086,15 @@ } }, "hardhat": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.9.3.tgz", - "integrity": "sha512-7Vw99RbYbMZ15UzegOR/nqIYIqddZXvLwJGaX5sX4G5bydILnbjmDU6g3jMKJSiArEixS3vHAEaOs5CW1JQ3hg==", - "requires": { - "@ethereumjs/block": "^3.6.0", - "@ethereumjs/blockchain": "^5.5.0", - "@ethereumjs/common": "^2.6.0", - "@ethereumjs/tx": "^3.4.0", - "@ethereumjs/vm": "^5.6.0", + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.9.7.tgz", + "integrity": "sha512-PVSgTlM4Mtc4HNEoISpcM6rRNAK3ngqhxUaTmSw9eCtuVmtxTK86Tqnuq4zNPmlrtcuReXry9k3LGEnk2gJgbA==", + "requires": { + "@ethereumjs/block": "^3.6.2", + "@ethereumjs/blockchain": "^5.5.2", + "@ethereumjs/common": "^2.6.4", + "@ethereumjs/tx": "^3.5.1", + "@ethereumjs/vm": "^5.9.0", "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", "@sentry/node": "^5.18.1", @@ -43045,15 +43113,15 @@ "env-paths": "^2.2.0", "ethereum-cryptography": "^0.1.2", "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^7.1.3", + "ethereumjs-util": "^7.1.4", "find-up": "^2.1.0", "fp-ts": "1.19.3", "fs-extra": "^7.0.1", - "glob": "^7.1.3", + "glob": "7.2.0", "immutable": "^4.0.0-rc.12", "io-ts": "1.10.4", "lodash": "^4.17.11", - "merkle-patricia-tree": "^4.2.2", + "merkle-patricia-tree": "^4.2.4", "mnemonist": "^0.38.0", "mocha": "^9.2.0", "p-map": "^4.0.0", @@ -43765,15 +43833,15 @@ } }, "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", "dev": true }, "husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", + "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", "dev": true }, "iconv-lite": { @@ -44258,9 +44326,9 @@ } }, "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true }, "is-string": { @@ -44616,43 +44684,36 @@ } }, "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", + "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", "dev": true }, "lint-staged": { - "version": "12.4.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.4.1.tgz", - "integrity": "sha512-PTXgzpflrQ+pODQTG116QNB+Q6uUTDg5B5HqGvNhoQSGt8Qy+MA/6zSnR8n38+sxP5TapzeQGTvoKni0KRS8Vg==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.0.tgz", + "integrity": "sha512-vWban5utFt78VZohbosUxNIa46KKJ+KOQTDWTQ8oSl1DLEEVl9zhUtaQbiiydAmx+h2wKJK2d0+iMaRmknuWRQ==", "dev": true, "requires": { "cli-truncate": "^3.1.0", "colorette": "^2.0.16", - "commander": "^8.3.0", - "debug": "^4.3.3", - "execa": "^5.1.1", - "lilconfig": "2.0.4", - "listr2": "^4.0.1", - "micromatch": "^4.0.4", + "commander": "^9.3.0", + "debug": "^4.3.4", + "execa": "^6.1.0", + "lilconfig": "2.0.5", + "listr2": "^4.0.5", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "pidtree": "^0.5.0", "string-argv": "^0.3.1", - "supports-color": "^9.2.1", - "yaml": "^1.10.2" + "yaml": "^2.1.1" }, "dependencies": { "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, - "supports-color": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", - "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", + "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", "dev": true } } @@ -45885,12 +45946,20 @@ "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" }, "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "requires": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } } }, "npmlog": { @@ -46007,9 +46076,9 @@ } }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "object-keys": { "version": "1.1.1", @@ -49289,9 +49358,9 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true }, "strip-hex-prefix": { @@ -49817,12 +49886,12 @@ } }, "ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "version": "10.8.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.1.tgz", + "integrity": "sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==", "dev": true, "requires": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -49833,7 +49902,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "dependencies": { @@ -50007,9 +50076,9 @@ } }, "typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==" + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", + "integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==" }, "typical": { "version": "2.6.1", @@ -50931,9 +51000,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz", + "integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==", "dev": true }, "yargs": { diff --git a/package.json b/package.json index 08350784e..9f39df26f 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,11 @@ "console:ropsten": "npx hardhat console --network ropsten", "clean": "forge clean && rm -rf artifacts", "test": "forge test --no-match-contract IntegrationTest", - "test:integration": "FORK_BLOCK=14810964; forge test --fork-url https://eth-mainnet.alchemyapi.io/v2/$MAINNET_ALCHEMY_API_KEY --fork-block-number $FORK_BLOCK --match-contract IntegrationTest", + "test:integration": "FORK_BLOCK=`cat block.txt` forge test --fork-url https://eth-mainnet.alchemyapi.io/v2/$MAINNET_ALCHEMY_API_KEY --fork-block-number $FORK_BLOCK --match-contract IntegrationTest", "test:integration:latest": "forge test --fork-url https://eth-mainnet.alchemyapi.io/v2/$MAINNET_ALCHEMY_API_KEY --match-contract IntegrationTest", "test:hardhat": "npx hardhat test", "test:hardhat:dependencies": "LOGGING=true NO_RESET=true npx hardhat test test/integration/tests/dependencies.ts", - "test:e2e": "ENABLE_MAINNET_FORKING=true RUN_E2E_TESTS=true npx hardhat test", + "test:e2e": "FORK_BLOCK=`cat block.txt` ENABLE_MAINNET_FORKING=true RUN_E2E_TESTS=true npx hardhat test", "test:gas": "REPORT_GAS=true npx hardhat test", "test:all": "RUN_ALL_TESTS=true npx hardhat test", "lint": "npm run lint:ts && npm run lint:sol", @@ -52,20 +52,20 @@ "@balancer-labs/v2-pool-weighted": "^2.0.1", "@chainlink/contracts": "^0.1.7", "@gnosis.pm/safe-core-sdk": "^2.1.0", - "@gnosis.pm/safe-deployments": "^1.12.0", + "@gnosis.pm/safe-deployments": "^1.15.0", "@gnosis.pm/safe-ethers-lib": "^1.1.0", "@nomiclabs/hardhat-waffle": "^2.0.3", "@openzeppelin/contracts": "4.6.0", "@openzeppelin/test-environment": "^0.1.7", "@openzeppelin/test-helpers": "^0.5.15", "@orcaprotocol/contracts": "^5.0.1", - "@rari-capital/solmate": "^6.2.0", + "@rari-capital/solmate": "^6.4.0", "@uniswap/lib": "^1.1.2", "@uniswap/v2-core": "^1.0.1", "@uniswap/v2-periphery": "^1.1.0-beta.0", "chai": "^4.3.6", - "dotenv": "^16.0.0", - "hardhat": "^2.9.3", + "dotenv": "^16.0.1", + "hardhat": "^2.9.7", "hardhat-contract-sizer": "^2.5.1", "hardhat-gas-reporter": "^1.0.8", "merkletreejs": "^0.2.31", @@ -73,13 +73,13 @@ }, "devDependencies": { "@idle-finance/hardhat-proposals-plugin": "^0.2.3", - "@nomiclabs/hardhat-ethers": "^2.0.5", - "@nomiclabs/hardhat-etherscan": "^3.0.3", + "@nomiclabs/hardhat-ethers": "^2.0.6", + "@nomiclabs/hardhat-etherscan": "^3.0.4", "@typechain/ethers-v5": "^7.1.2", "@typechain/hardhat": "^2.3.0", "@types/chai": "^4.3.1", "@types/mocha": "^9.1.1", - "@types/node": "^17.0.31", + "@types/node": "^17.0.41", "@typescript-eslint/eslint-plugin": "^4.31.2", "@typescript-eslint/parser": "^4.31.2", "chai-bn": "^0.3.1", @@ -89,9 +89,9 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.0.0", "ethereum-waffle": "^3.4.4", - "ethers": "^5.6.5", - "husky": "^7.0.4", - "lint-staged": "^12.4.1", + "ethers": "^5.6.8", + "husky": "^8.0.1", + "lint-staged": "^13.0.0", "mocha": "^10.0.0", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", @@ -100,10 +100,10 @@ "solhint": "^3.3.7", "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.7.21", - "ts-node": "^10.7.0", + "ts-node": "^10.8.1", "tsconfig-paths": "^4.0.0", "typechain": "^5.2.0", - "typescript": "^4.6.4" + "typescript": "^4.7.3" }, "lint-staged": { "*.{ts,tsx}": [ diff --git a/proposals/README.md b/proposals/README.md index 3cf176541..105b152bb 100644 --- a/proposals/README.md +++ b/proposals/README.md @@ -23,7 +23,7 @@ These permissiones are validated against on-chain state in the last e2e test ## Step 3: Proposal Mocking and Integration Test Write a script following the template of `proposals/dao/fip_x.js`. See below for descriptions of each of the `deploy`, `setup`,`teardown`, and `validate` functions. Only `validate` is required. -Add an object with the key `fip_x` to `end-to-end/proposals_config.ts`, +Add an object with the key `fip_x` to `end-to-end/proposalsConfig.ts`, Your proposal will be run before any integration tests via `npm run test:e2e`. Fill in the following parameters: * deploy - set to true only if you added a deploy script for your proposal in the optional step, otherwise false. This will run your deploy script before the integration tests and add the contract objects as keys in `contracts` parameter of each of the hooks. @@ -32,7 +32,7 @@ Your proposal will be run before any integration tests via `npm run test:e2e`. F ### Step 3a (Optional): deploy() - Contract Deployments: Whether a deployment of a new instance of a pre-exisiting or new contract, if your proposal requires a new contract deployment you'll need to write a deploy script. -The deploy script is automatically run before any e2e tests if the deploy flag is set to true in the `end-to-end/proposals_config.ts`. The contract objects will be present in the setup, run, teardown and validate hooks as keys in the `contracts` parameter. +The deploy script is automatically run before any e2e tests if the deploy flag is set to true in the `end-to-end/proposalsConfig.ts`. The contract objects will be present in the setup, run, teardown and validate hooks as keys in the `contracts` parameter. This is useful for fully testing the deploy script against a mainnet fork before deploying to mainnet. @@ -65,7 +65,7 @@ Run `DEPLOY_FILE=fip_x npm run deploy:fip` Run your deploy script if you had one from step 2. Update `/protocol-configuration/mainnetAddresses.ts` with the new contract addresses. -Update the fork block inside the hardhat config and set the deploy flag to false in the config entry for `fip_x` in `end-to-end/proposals_config.ts` +Update the fork block inside the hardhat config and set the deploy flag to false in the config entry for `fip_x` in `end-to-end/proposalsConfig.ts` Finally rerun `npm run test:e2e` and make sure everything passes as expected. diff --git a/proposals/dao/end_tribe_incentives.ts b/proposals/dao/end_tribe_incentives.ts new file mode 100644 index 000000000..ff6337b6e --- /dev/null +++ b/proposals/dao/end_tribe_incentives.ts @@ -0,0 +1,157 @@ +import hre, { ethers } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { getImpersonatedSigner, time } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; + +/* + +TIP-109: Discontinue Tribe Incentives + +Ends all Tribe Incentives being distributed. + +Specifically: +- Set AP rewards of all pools to 0, and set one pool AP reward to 1 +- Effectively set Tribe block reward to 0 +- Remove CREAM deposit from CR +*/ + +const NEW_TRIBE_BLOCK_REWARD = 100000; +const NEW_TOTAL_ALLOC_POINTS = 1; + +const fipNumber = 'TIP-109: Discontinue Tribe Incentives'; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + console.log(`No deploy actions for fip${fipNumber}`); + return { + // put returned contract objects here + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const stakeAmount = ethers.constants.WeiPerEther.mul(40_000); + const curve3Metapool = '0x06cb22615BA53E60D67Bf6C341a0fD5E718E1655'; + const curvePoolId = 1; + const curve3LPWhale = '0xdc69d4cb5b86388fff0b51885677e258883534ae'; + const curveLPStaker = await getImpersonatedSigner(curve3LPWhale); + const curveLPToken = await ethers.getContractAt('ERC20', curve3Metapool); + + await forceEth(curve3LPWhale); + await curveLPToken.connect(curveLPStaker).approve(contracts.tribalChief.address, stakeAmount); + await contracts.tribalChief.connect(curveLPStaker).deposit(curvePoolId, stakeAmount, 0); + + // Set the pool to have a non-zero AP, so can test can claim rewards + const daoSigner = await getImpersonatedSigner(addresses.feiDAOTimelock); + await contracts.tribalChief.connect(daoSigner).set(curvePoolId, 500, ethers.constants.AddressZero, false); + await time.increase(86400 * 7); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const tribe = contracts.tribe; + const tribalChief = contracts.tribalChief; + + // 0. Validate TC timelock has TRIBAL_CHIEF_ADMIN_ROLE role + expect( + await contracts.core.hasRole(ethers.utils.id('TRIBAL_CHIEF_ADMIN_ROLE'), addresses.tribalCouncilTimelock) + ).to.equal(true); + + expect( + await contracts.core.hasRole(ethers.utils.id('TRIBAL_CHIEF_ADMIN_ROLE'), addresses.tribalChiefSyncV2) + ).to.equal(false); + + expect(await contracts.core.hasRole(ethers.utils.id('FUSE_ADMIN'), addresses.tribalChiefSyncV2)).to.equal(false); + expect(await contracts.core.hasRole(ethers.utils.id('VOTIUM_ADMIN_ROLE'), addresses.opsOptimisticTimelock)).to.equal( + false + ); + + // 1. Verify TribalChief block rewards are effectively 0 + expect(await tribalChief.tribePerBlock()).to.equal(NEW_TRIBE_BLOCK_REWARD); + + // 2. Validate number of pools is as expected + const poolIds = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]; + const numPools = await tribalChief.numPools(); + expect(numPools).to.equal(poolIds.length); + + // 3. Validate that all pool AP points are set to zero, apart from Fei-Tribe Uniswap V2 + const feiRariPoolId = '0'; + for (const pid in poolIds) { + const poolInfo = await tribalChief.poolInfo(pid); + + if (pid == feiRariPoolId) { + expect(poolInfo.allocPoint).to.be.equal(NEW_TOTAL_ALLOC_POINTS.toString()); + } else { + expect(poolInfo.allocPoint).to.be.equal('0'); + } + } + + // 4. Verify rewardsDistributorAdmin internal ACL revoked + const rewardsDistributorAdmin = contracts.rewardsDistributorAdmin; + expect( + await rewardsDistributorAdmin.hasRole( + ethers.utils.id('AUTO_REWARDS_DISTRIBUTOR_ROLE'), + addresses.feiDaiAutoRewardsDistributor + ) + ).to.equal(false); + + expect( + await rewardsDistributorAdmin.hasRole( + ethers.utils.id('AUTO_REWARDS_DISTRIBUTOR_ROLE'), + addresses.feiUsdcAutoRewardsDistributor + ) + ).to.equal(false); + + expect( + await rewardsDistributorAdmin.hasRole( + ethers.utils.id('AUTO_REWARDS_DISTRIBUTOR_ROLE'), + addresses.autoRewardsDistributor + ) + ).to.equal(false); + + expect( + await rewardsDistributorAdmin.hasRole( + ethers.utils.id('AUTO_REWARDS_DISTRIBUTOR_ROLE'), + addresses.d3AutoRewardsDistributor + ) + ).to.equal(false); + + expect( + await rewardsDistributorAdmin.hasRole( + ethers.utils.id('AUTO_REWARDS_DISTRIBUTOR_ROLE'), + addresses.fei3CrvAutoRewardsDistributor + ) + ).to.equal(false); + + // 5. Verify total AP points is 1 + expect(await tribalChief.totalAllocPoint()).to.be.equal(NEW_TOTAL_ALLOC_POINTS.toString()); + + // 6. Verify an AutoRewardDistributor speed is set correctly + const d3Ctoken = await contracts.rariPool8Comptroller.cTokensByUnderlying(addresses.curveD3pool); + + const d3RewardSpeed = await contracts.d3AutoRewardsDistributor.getNewRewardSpeed(); + expect(d3RewardSpeed[1]).to.equal(false); // updateNeeded + expect(d3RewardSpeed[0]).to.equal(0); // newSpeed + + const delegatorReportedSpeed = await contracts.rariRewardsDistributorDelegator.compSupplySpeeds(d3Ctoken); + expect(delegatorReportedSpeed).to.equal(0); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/eth_lbp.ts b/proposals/dao/eth_lbp.ts new file mode 100644 index 000000000..80e2d3980 --- /dev/null +++ b/proposals/dao/eth_lbp.ts @@ -0,0 +1,285 @@ +import { ethers } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + NamedContracts, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { forceEth } from '@test/integration/setup/utils'; +import { TransactionResponse } from '@ethersproject/providers'; +import { expectApprox, getImpersonatedSigner, overwriteChainlinkAggregator, time } from '@test/helpers'; +import { BigNumber } from 'ethers'; + +const toBN = ethers.BigNumber.from; + +/* + +DAO Proposal #110 + +1. Set ethToDaiLBPSwapper to be guardian Safe addresses +2. Deploy Balancer LBP and initialise auction of ETH for DAI +3. forceSwap() +4. tighten ETH redemption spread +*/ + +// LBP Swapper config +const LBP_FREQUENCY = 86400 * 2; // 2 days in seconds +const MIN_LBP_SIZE = ethers.constants.WeiPerEther.mul(500); // 500 ETH +let poolId; // auction pool id + +const fipNumber = '110'; + +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + /////////// 1. Deploy the Balancer LBP swapper + const BalancerLBPSwapperFactory = await ethers.getContractFactory('BalancerLBPSwapper'); + + // Oracle reports WETH price in terms of USD, so should not be inverted + const ethToDaiLBPSwapper = await BalancerLBPSwapperFactory.deploy( + addresses.core, + { + _oracle: addresses.chainlinkEthUsdOracleWrapper, + _backupOracle: ethers.constants.AddressZero, + _invertOraclePrice: false, + _decimalsNormalizer: 0 + }, + LBP_FREQUENCY, + '50000000000000000', // small weight 5% + '950000000000000000', // large weight 95% + addresses.weth, + addresses.dai, + addresses.compoundDaiPCVDeposit, // send DAI to Compound DAI deposit, where it can then be dripped to PSM + MIN_LBP_SIZE // minimum size of a pool which the swapper is used against + ); + + await ethToDaiLBPSwapper.deployed(); + logging && console.log('WETH to DAI swapper deployed to: ', ethToDaiLBPSwapper.address); + + // 2. Create a liquidity bootstrapping pool between WETH and DAI + const lbpFactory = await ethers.getContractAt( + 'ILiquidityBootstrappingPoolFactory', + addresses.balancerLBPoolFactoryNoFee + ); + + const tx: TransactionResponse = await lbpFactory.create( + 'WETH->DAI Auction Pool', // pool name + 'apWETH-DAI', // lbp token symbol + [addresses.dai, addresses.weth], // pool contains [DAI, WETH] + [ethers.constants.WeiPerEther.mul(5).div(100), ethers.constants.WeiPerEther.mul(95).div(100)], // initial weights 5%/95% + ethers.constants.WeiPerEther.mul(30).div(10_000), // 0.3% swap fees + ethToDaiLBPSwapper.address, // pool owner = fei protocol swapper + true + ); + + const txReceipt = await tx.wait(); + const { logs: rawLogs } = txReceipt; + const noFeeEthDaiLBPAddress = `0x${rawLogs[rawLogs.length - 1].topics[1].slice(-40)}`; + poolId = rawLogs[1].topics[1]; + + logging && console.log('LBP Pool deployed to: ', noFeeEthDaiLBPAddress); + logging && console.log('LBP Pool Id: ', poolId); + + // 3. Initialise the LBP swapper with the pool address + const tx2 = await ethToDaiLBPSwapper.init(noFeeEthDaiLBPAddress); + await tx2.wait(); + + // 4. Deploy a lens to report the swapper value + const BPTLensFactory = await ethers.getContractFactory('BPTLens'); + const ethToDaiLensDai = await BPTLensFactory.deploy( + addresses.dai, // token reported in + noFeeEthDaiLBPAddress, // pool address + addresses.chainlinkDaiUsdOracleWrapper, // reportedOracle - DAI + addresses.chainlinkEthUsdOracleWrapper, // otherOracle - WETH + false, // feiIsReportedIn + false // feiIsOther + ); + await ethToDaiLensDai.deployTransaction.wait(); + + logging && console.log('BPTLens for DAI in swapper pool: ', ethToDaiLensDai.address); + + const ethToDaiLensEth = await BPTLensFactory.deploy( + addresses.weth, // token reported in + noFeeEthDaiLBPAddress, // pool address + addresses.chainlinkEthUsdOracleWrapper, // reportedOracle - WETH + addresses.chainlinkDaiUsdOracleWrapper, // otherOracle - DAI + false, // feiIsReportedIn + false // feiIsOther + ); + await ethToDaiLensEth.deployTransaction.wait(); + + logging && console.log('BPTLens for WETH in swapper pool: ', ethToDaiLensEth.address); + return { + ethToDaiLBPSwapper, + ethToDaiLensDai, + ethToDaiLensEth + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + // check PSM redeem fee + const psm = contracts.ethPSM; + expect(await psm.redeemFeeBasisPoints()).to.be.equal('75'); + + // overwrite chainlink ETH/USD oracle + const ethToDaiLBPSwapper = contracts.ethToDaiLBPSwapper; + poolId = await ethToDaiLBPSwapper.pid(); + + await overwriteChainlinkAggregator(addresses.chainlinkEthUsdOracle, '200000000000', '8'); // $2000 ETH + + // invariant checks + expect(await ethToDaiLBPSwapper.tokenSpent()).to.be.equal(addresses.weth); + expect(await ethToDaiLBPSwapper.tokenReceived()).to.be.equal(addresses.dai); + expect(await ethToDaiLBPSwapper.tokenReceivingAddress()).to.be.equal(addresses.compoundDaiPCVDeposit); + + const poolTokens = await contracts.balancerVault.getPoolTokens(poolId); + expect(poolTokens.tokens[0]).to.be.equal(addresses.dai); + expect(poolTokens.tokens[1]).to.be.equal(addresses.weth); + + // LBP swapper should be empty + expect(poolTokens.balances[0]).to.be.equal('0'); + expect(poolTokens.balances[1]).to.be.equal('0'); + + // Lenses should report 0 because LBP is empty + expect(await contracts.ethToDaiLensDai.balance()).to.be.equal('0'); + expect(await contracts.ethToDaiLensEth.balance()).to.be.equal('0'); + + // Swapper should hold no tokens + expect(await contracts.weth.balanceOf(ethToDaiLBPSwapper.address)).to.be.equal('0'); + expect(await contracts.dai.balanceOf(ethToDaiLBPSwapper.address)).to.be.equal('0'); + + console.log('Starting DAI PSM dai balance [M]', (await contracts.compoundDaiPCVDeposit.balance()) / 1e24); + + console.log('DAI needed', await ethToDaiLBPSwapper.getTokensIn(ethers.constants.WeiPerEther.mul(20_000))); + await forceEth(addresses.tribalCouncilTimelock); + + await time.increase(LBP_FREQUENCY); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const core = contracts.core; + const ethToDaiLBPSwapper = contracts.ethToDaiLBPSwapper; + poolId = await ethToDaiLBPSwapper.pid(); + + console.log('Final DAI PSM dai balance [M]', (await contracts.compoundDaiPCVDeposit.balance()) / 1e24); + + //////////// 1. New Safe adddresses ////////////// + expect(await contracts.pcvGuardianNew.isSafeAddress(addresses.ethToDaiLBPSwapper)).to.be.true; + + ///////////// 2. WETH LBP //////////////// + await validateLBPSetup(contracts, addresses, poolId); + + ///////////// 3. PSM Redeem //////////////// + + // check PSM redeem fee + const psm = contracts.ethPSM; + expect(await psm.redeemFeeBasisPoints()).to.be.equal('60'); + + // Validate PSM_ADMIN_ROLE is under ROLE_ADMIN and that TribalCouncilTimelock has the role + expect(await core.hasRole(ethers.utils.id('PSM_ADMIN_ROLE'), addresses.tribalCouncilTimelock)).to.be.true; + expect(await core.getRoleAdmin(ethers.utils.id('PSM_ADMIN_ROLE'))).to.be.equal(ethers.utils.id('ROLE_ADMIN')); +}; + +const validateLBPSetup = async (contracts: NamedContracts, addresses: NamedAddresses, poolId: string) => { + const ethToDaiLBPSwapper = contracts.ethToDaiLBPSwapper; + + expect(await ethToDaiLBPSwapper.doInvert()).to.be.equal(false); + expect(await ethToDaiLBPSwapper.isTimeStarted()).to.be.true; + expect(await ethToDaiLBPSwapper.tokenSpent()).to.equal(addresses.weth); + expect(await ethToDaiLBPSwapper.tokenReceived()).to.equal(addresses.dai); + + // tokenSpent = WETH + // tokenReceived = DAI + // On BalancerVault, token[0] = WETH, token[1] = DAI + // Therefore, on LBPSwapper, assets[0] = WETH, assets[1] = DAI + + // 2.1 Check oracle price + const price = (await ethToDaiLBPSwapper.readOracle())[0]; // DAI price in units of WETH + console.log('price: ', price); + expect(price).to.be.bignumber.at.least(ethers.constants.WeiPerEther.mul(1600)); // 1600e18 + expect(price).to.be.bignumber.at.most(ethers.constants.WeiPerEther.mul(2200)); // 2200e18 + + // 2.2 Check relative price in pool + + // Putting in 20,000 tokens of WETH, getting an amount of DAI back + const response = await ethToDaiLBPSwapper.getTokensIn(20000); // input is spent token balance, 100,000 WETH tokens + const amounts = response[1]; + + // DAI/WETH price * DAI amount * 5% ~= amount + expectApprox(price.mul(20000).mul(5).div(ethers.constants.WeiPerEther).div(100), amounts[1]); // DAI + expect(amounts[0]).to.be.bignumber.at.least(toBN(2_000_000)); // Make sure orcacle inversion is correct (i.e. not inverted) + + expect(amounts[1]).to.be.bignumber.equal(ethers.BigNumber.from(20000)); // WETH + + // 2.3 Check pool info + const poolTokens = await contracts.balancerVault.getPoolTokens(poolId); + // there should be 2.1M DAI in the pool + expect(poolTokens.tokens[0]).to.be.equal(contracts.dai.address); // this is DAI + expect(poolTokens.balances[0]).to.be.bignumber.at.least(ethers.constants.WeiPerEther.mul(2_000_000)); + expect(poolTokens.balances[0]).to.be.bignumber.at.most(ethers.constants.WeiPerEther.mul(2_200_000)); + // there should be 20k WETH in the pool + expect(poolTokens.tokens[1]).to.be.equal(contracts.weth.address); // this is WETH + expect(poolTokens.balances[1]).to.be.equal('20000000000000000000000'); + + // Validate that a swap can occur + const daiWhale = '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643'; + const daiWhaleSigner = await getImpersonatedSigner(daiWhale); + await forceEth(daiWhale); + + const initialUserEthBalance = await contracts.weth.balanceOf(daiWhale); + const initialUserDaiBalance = await contracts.dai.balanceOf(daiWhale); + + const amountIn = ethers.constants.WeiPerEther.mul(10_000); + await contracts.dai.connect(daiWhaleSigner).approve(addresses.balancerVault, amountIn); + await contracts.balancerVault.connect(daiWhaleSigner).swap( + { + poolId: poolId, + kind: 0, + assetIn: addresses.dai, + assetOut: addresses.weth, + amount: amountIn, + userData: '0x' + }, + { + sender: daiWhale, + fromInternalBalance: false, + recipient: daiWhale, + toInternalBalance: false + }, + 0, + '10000000000000000000000' + ); + + const postUserEthBalance = await contracts.weth.balanceOf(daiWhale); + const postUserDaiBalance = await contracts.dai.balanceOf(daiWhale); + + const daiSpent = initialUserDaiBalance.sub(postUserDaiBalance); + expect(daiSpent).to.be.bignumber.equal(amountIn); + + const ethGained = postUserEthBalance.sub(initialUserEthBalance); + expect(ethGained).to.be.bignumber.at.least(ethers.constants.WeiPerEther.mul(4)); + expect(ethGained).to.be.bignumber.at.most(ethers.constants.WeiPerEther.mul(6)); + + // Put in 10k DAI, got out ~5 WETH + // Implies price of $2000 per WETH + console.log('DAI spent: ', daiSpent); + console.log('WETH gained: ', ethGained); + + // Accelerate time and check ended + await time.increase(LBP_FREQUENCY); + expect(await ethToDaiLBPSwapper.isTimeEnded()).to.be.true; +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/fip_104b.ts b/proposals/dao/fip_104b.ts new file mode 100644 index 000000000..f02b01a33 --- /dev/null +++ b/proposals/dao/fip_104b.ts @@ -0,0 +1,67 @@ +import { ethers } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { time } from '@test/helpers'; +import { BigNumber } from 'ethers'; + +/* +Withdraw liquidity from the LBP once it has finished +*/ + +const fipNumber = 'fip_104b'; + +let initialDaiPCVBalance: BigNumber; +let initialTCDpiBalance: BigNumber; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + console.log(`No deploy actions for fip${fipNumber}`); + return { + // put returned contract objects here + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const dpi = contracts.dpi; + initialTCDpiBalance = await dpi.balanceOf(addresses.tribalCouncilSafe); + initialDaiPCVBalance = await contracts.compoundDaiPCVDeposit.balance(); + logging && console.log('Initial dai balance: ', initialDaiPCVBalance.toString()); + + // Fast forward to end of LPB + const timeRemaining = await contracts.dpiToDaiLBPSwapper.remainingTime(); + await time.increase(timeRemaining); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + // 1. Validate withdrawn liquidity destinations + const sanityCheckDAIAmount = ethers.constants.WeiPerEther.mul(3_200_000); + const finalDAIDepositBalance = await contracts.compoundDaiPCVDeposit.balance(); + const daiGained = finalDAIDepositBalance.sub(initialDaiPCVBalance); + expect(daiGained).to.be.bignumber.at.least(sanityCheckDAIAmount); + + const dpi = contracts.dpi; + const sanityCheckDPIAmount = ethers.constants.WeiPerEther.mul(1500); + const finalTCDpiBalance = await dpi.balanceOf(addresses.tribalCouncilSafe); + const dpiGained = finalTCDpiBalance.sub(initialTCDpiBalance); + expect(dpiGained).to.be.bignumber.at.least(sanityCheckDPIAmount); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/old/balancer_gauge_fix.ts b/proposals/dao/old/balancer_gauge_fix.ts new file mode 100644 index 000000000..78a381fc4 --- /dev/null +++ b/proposals/dao/old/balancer_gauge_fix.ts @@ -0,0 +1,162 @@ +import hre, { ethers, artifacts } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { getImpersonatedSigner, overwriteChainlinkAggregator, time } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; + +const e18 = '000000000000000000'; +const fipNumber = 'balancer_gauge_fix'; +let pcvStatsBefore; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + // Deploy balancer gauge staker implementation + const balancerGaugeStakerFactory = await ethers.getContractFactory('BalancerGaugeStaker'); + const balancerGaugeStakerImplementation = await balancerGaugeStakerFactory.deploy( + addresses.core, // address _core + addresses.balancerGaugeController, // address _gaugeController + addresses.balancerMinter // address _balancerMinter + ); + await balancerGaugeStakerImplementation.deployTransaction.wait(); + logging && console.log('balancerGaugeStakerImplementation: ', balancerGaugeStakerImplementation.address); + + // Deploy balancer gauge staker proxy + const ProxyFactory = await ethers.getContractFactory('TransparentUpgradeableProxy'); + const balancerGaugeStakerProxy = await ProxyFactory.deploy( + balancerGaugeStakerImplementation.address, + addresses.proxyAdmin, + '0x' // empty calldata + ); + await balancerGaugeStakerProxy.deployTransaction.wait(); + const balancerGaugeStaker = await ethers.getContractAt('BalancerGaugeStaker', balancerGaugeStakerProxy.address); + logging && console.log('balancerGaugeStaker: ', balancerGaugeStaker.address); + + // initialize proxy state + await balancerGaugeStaker.initialize( + addresses.core, // address _core + addresses.balancerGaugeController, // address _gaugeController + addresses.balancerMinter // address _balancerMinter + ); + + // Deploy lens to report the B-30FEI-70WETH staked in gauge + const gaugeLensFactory = await ethers.getContractFactory('CurveGaugeLens'); + const gaugeLensBpt30Fei70WethGauge = await gaugeLensFactory.deploy( + addresses.balancerGaugeBpt30Fei70Weth, + balancerGaugeStaker.address + ); + await gaugeLensBpt30Fei70WethGauge.deployTransaction.wait(); + logging && console.log('gaugeLensBpt30Fei70WethGauge:', gaugeLensBpt30Fei70WethGauge.address); + + // Deploy lens to report B-30FEI-70WETH as WETH and protocol-owned FEI + const balancerPool2LensFactory = await ethers.getContractFactory('BalancerPool2Lens'); + const balancerLensBpt30Fei70Weth = await balancerPool2LensFactory.deploy( + gaugeLensBpt30Fei70WethGauge.address, // address _depositAddress + addresses.weth, // address _token + '0x90291319f1d4ea3ad4db0dd8fe9e12baf749e845', // IWeightedPool _pool + addresses.chainlinkEthUsdOracleWrapper, // IOracle _reportedOracle + addresses.oneConstantOracle, // IOracle _otherOracle + false, // bool _feiIsReportedIn + true // bool _feiIsOther + ); + await balancerLensBpt30Fei70Weth.deployTransaction.wait(); + logging && console.log('balancerLensBpt30Fei70Weth: ', balancerLensBpt30Fei70Weth.address); + + return { + balancerGaugeStakerImplementation, + balancerGaugeStaker, + gaugeLensBpt30Fei70WethGauge, + balancerLensBpt30Fei70Weth + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`Setup of ${fipNumber} : reading CR oracle...`); + + // make sure TC has enough ETH to run + await forceEth(addresses.tribalCouncilSafe); + await forceEth(addresses.tribalCouncilTimelock); + + // make sure ETH oracle is fresh (for B.AMM not to revert, etc) + // Read Chainlink ETHUSD price & override chainlink storage to make it a fresh value + const ethPrice = (await contracts.chainlinkEthUsdOracleWrapper.read())[0].toString() / 1e10; + await overwriteChainlinkAggregator(addresses.chainlinkEthUsdOracle, Math.round(ethPrice), '8'); + + // read pcvStats before proposal execution + pcvStatsBefore = await contracts.collateralizationOracle.pcvStats(); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + // check the new staking contract has staked in gauge + expect(await contracts.balancerGaugeBpt30Fei70Weth.balanceOf(addresses.balancerGaugeStaker)).to.be.equal( + '252865858892972812879565' + ); + + // check rewards can be claimed + await time.increase('86400'); + const balBalanceBefore = await contracts.bal.balanceOf(addresses.balancerGaugeStaker); + await contracts.balancerGaugeStaker.mintGaugeRewards(addresses.bpt30Fei70Weth); + const balBalanceAfter = await contracts.bal.balanceOf(addresses.balancerGaugeStaker); + expect(balBalanceAfter.sub(balBalanceBefore)).to.be.at.least(`1${e18}`); + + // check collateralization oracle reports the LP tokens staked + expect(await contracts.collateralizationOracle.depositToToken(addresses.balancerLensBpt30Fei70Weth)).to.be.equal( + addresses.weth + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.balancerLensBpt30Fei70WethOld)).to.be.equal( + ethers.constants.AddressZero + ); + const resistantBalanceAndFei = await contracts.balancerLensBpt30Fei70Weth.resistantBalanceAndFei(); + expect(resistantBalanceAndFei[0]).to.be.at.least(`14000${e18}`); + expect(resistantBalanceAndFei[0]).to.be.at.most(`18000${e18}`); + expect(resistantBalanceAndFei[1]).to.be.at.least(`13000000${e18}`); + expect(resistantBalanceAndFei[1]).to.be.at.most(`19000000${e18}`); + + // check withdraw() can move BAL + const withdrawAmount = `1${e18}`; + const sourceBalanceBefore = await contracts.bal.balanceOf(addresses.balancerGaugeStaker); + const targetBalanceBefore = await contracts.bal.balanceOf(addresses.feiDAOTimelock); + await contracts.balancerGaugeStaker.withdraw(addresses.feiDAOTimelock, withdrawAmount); + const sourceBalanceAfter = await contracts.bal.balanceOf(addresses.balancerGaugeStaker); + const targetBalanceAfter = await contracts.bal.balanceOf(addresses.feiDAOTimelock); + expect(sourceBalanceBefore.sub(sourceBalanceAfter)).to.be.equal(withdrawAmount); + expect(targetBalanceAfter.sub(targetBalanceBefore)).to.be.equal(withdrawAmount); + + // display pcvStats + console.log('----------------------------------------------------'); + console.log(' pcvStatsBefore.protocolControlledValue [M]e18 ', pcvStatsBefore.protocolControlledValue / 1e24); + console.log(' pcvStatsBefore.userCirculatingFei [M]e18 ', pcvStatsBefore.userCirculatingFei / 1e24); + console.log(' pcvStatsBefore.protocolEquity [M]e18 ', pcvStatsBefore.protocolEquity / 1e24); + const pcvStatsAfter = await contracts.collateralizationOracle.pcvStats(); + console.log('----------------------------------------------------'); + console.log(' pcvStatsAfter.protocolControlledValue [M]e18 ', pcvStatsAfter.protocolControlledValue / 1e24); + console.log(' pcvStatsAfter.userCirculatingFei [M]e18 ', pcvStatsAfter.userCirculatingFei / 1e24); + console.log(' pcvStatsAfter.protocolEquity [M]e18 ', pcvStatsAfter.protocolEquity / 1e24); + console.log('----------------------------------------------------'); + const pcvDiff = pcvStatsAfter.protocolControlledValue.sub(pcvStatsBefore.protocolControlledValue); + const cFeiDiff = pcvStatsAfter.userCirculatingFei.sub(pcvStatsBefore.userCirculatingFei); + const eqDiff = pcvStatsAfter.protocolEquity.sub(pcvStatsBefore.protocolEquity); + console.log(' PCV diff [M]e18 ', pcvDiff / 1e24); + console.log(' Circ FEI diff [M]e18 ', cFeiDiff / 1e24); + console.log(' Equity diff [M]e18 ', eqDiff / 1e24); + console.log('----------------------------------------------------'); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/old/fip_104.ts b/proposals/dao/old/fip_104.ts new file mode 100644 index 000000000..4b38608b4 --- /dev/null +++ b/proposals/dao/old/fip_104.ts @@ -0,0 +1,352 @@ +import { ethers } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + NamedContracts, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { forceEth } from '@test/integration/setup/utils'; +import { TransactionResponse } from '@ethersproject/providers'; +import { expectApprox, getImpersonatedSigner, overwriteChainlinkAggregator, time } from '@test/helpers'; +import { BigNumber } from 'ethers'; + +const toBN = ethers.BigNumber.from; + +/* + +DAO Proposal #105 + +1. Set uniswapPCVDeposit and dpiToDaiLBPSwapper to be guardian Safe addresses +2. Deploy Balancer LBP and initialise auction of DPI for DAI +3. Fix NopeDAO voting period +4. Transfer CREAM to TribalCouncil multisig, where it will then be sold to ETH +5. Withdraw 15,000 WETH from DAO timelock to the aaveETHPCVDeposit +6. Fund TC with 10 eth +7. Invert oracle price on LBP swapper and forceSwap() +*/ + +// LBP Swapper config +const LBP_FREQUENCY = 86400 * 14; // 2 weeks in seconds +const MIN_LBP_SIZE = ethers.constants.WeiPerEther.mul(10_000); // 10k +let poolId; // auction pool id + +const fipNumber = '105'; +const skimThreshold = ethers.constants.WeiPerEther.mul(20_000_000); + +let initialAavePCVBalance: BigNumber; +const aaveWETHTransferAmount = '14999999999999999992057'; // almost 15,000 WETH + +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + ///////// 1. Deploy a Fei Skimmer for the DAI PSM + const daiPSMFeiSkimmerFactory = await ethers.getContractFactory('FeiSkimmer'); + const daiFixedPricePSMFeiSkimmer = await daiPSMFeiSkimmerFactory.deploy( + addresses.core, + addresses.daiFixedPricePSM, + skimThreshold + ); + await daiFixedPricePSMFeiSkimmer.deployed(); + logging && console.log('DAI PSM Fei Skimmer deployed at', daiFixedPricePSMFeiSkimmer.address); + + /////////// 2. Deploy the Balancer LBP swapper + // // Amounts: + // DPI: 37888449801955370645659 (95%), 37k DPI, $3,587,445 + // DAI: 187947000000000000000000 (5%), 187k DAI, $179,372.05, overfunding by ~$9k and transferring $187,947 + const BalancerLBPSwapperFactory = await ethers.getContractFactory('BalancerLBPSwapper'); + + // Oracle reports DPI price in terms of USD, so should not be inverted + // Specifically reports: 101258471470000000000, which is $101. As expected + const dpiToDaiSwapper = await BalancerLBPSwapperFactory.deploy( + addresses.core, + { + _oracle: addresses.chainlinkDpiUsdOracleWrapper, + _backupOracle: ethers.constants.AddressZero, + _invertOraclePrice: true, + _decimalsNormalizer: 0 + }, + LBP_FREQUENCY, + '50000000000000000', // small weight 5% + '950000000000000000', // large weight 95% + addresses.dpi, + addresses.dai, + addresses.compoundDaiPCVDeposit, // send DAI to Compound DAI deposit, where it can then be dripped to PSM + MIN_LBP_SIZE // minimum size of a pool which the swapper is used against + ); + + await dpiToDaiSwapper.deployed(); + logging && console.log('DPI to DAI swapper deployed to: ', dpiToDaiSwapper.address); + + // 2. Create a liquidity bootstrapping pool between DPI and DAI + const lbpFactory = await ethers.getContractAt( + 'ILiquidityBootstrappingPoolFactory', + addresses.balancerLBPoolFactoryNoFee + ); + + const tx: TransactionResponse = await lbpFactory.create( + 'DPI->DAI Auction Pool', // pool name + 'apDPI-DAI', // lbp token symbol + [addresses.dpi, addresses.dai], // pool contains [DPI, DAI] + [ethers.constants.WeiPerEther.mul(95).div(100), ethers.constants.WeiPerEther.mul(5).div(100)], // initial weights 5%/95% + ethers.constants.WeiPerEther.mul(30).div(10_000), // 0.3% swap fees + dpiToDaiSwapper.address, // pool owner = fei protocol swapper + true + ); + + const txReceipt = await tx.wait(); + const { logs: rawLogs } = txReceipt; + const noFeeDpiDaiLBPAddress = `0x${rawLogs[rawLogs.length - 1].topics[1].slice(-40)}`; + poolId = rawLogs[1].topics[1]; + + logging && console.log('LBP Pool deployed to: ', noFeeDpiDaiLBPAddress); + logging && console.log('LBP Pool Id: ', poolId); + + // 3. Initialise the LBP swapper with the pool address + const tx2 = await dpiToDaiSwapper.init(noFeeDpiDaiLBPAddress); + await tx2.wait(); + + // 4. Deploy a lens to report the swapper value + const BPTLensFactory = await ethers.getContractFactory('BPTLens'); + const dpiToDaiLensDai = await BPTLensFactory.deploy( + addresses.dai, // token reported in + noFeeDpiDaiLBPAddress, // pool address + addresses.chainlinkDaiUsdOracleWrapper, // reportedOracle - DAI + addresses.chainlinkDpiUsdOracleWrapper, // otherOracle - DPI + false, // feiIsReportedIn + false // feiIsOther + ); + await dpiToDaiLensDai.deployTransaction.wait(); + + logging && console.log('BPTLens for DAI in swapper pool: ', dpiToDaiLensDai.address); + + const dpiToDaiLensDpi = await BPTLensFactory.deploy( + addresses.dpi, // token reported in + noFeeDpiDaiLBPAddress, // pool address + addresses.chainlinkDpiUsdOracleWrapper, // reportedOracle - DPI + addresses.chainlinkDaiUsdOracleWrapper, // otherOracle - DAI + false, // feiIsReportedIn + false // feiIsOther + ); + await dpiToDaiLensDpi.deployTransaction.wait(); + + logging && console.log('BPTLens for DPI in swapper pool: ', dpiToDaiLensDpi.address); + return { + daiFixedPricePSMFeiSkimmer, + dpiToDaiSwapper, + dpiToDaiLensDai, + dpiToDaiLensDpi + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + poolId = '0xd10386804959a121a8a487e49f45aa9f5a2eb2a00002000000000000000001f1'; + // overwrite chainlink ETH/USD oracle + const dpiToDaiLBPSwapper = contracts.dpiToDaiLBPSwapper; + await overwriteChainlinkAggregator(addresses.chainlinkEthUsdOracle, '250000000000', '8'); + + // invariant checks + expect(await dpiToDaiLBPSwapper.tokenSpent()).to.be.equal(addresses.dpi); + expect(await dpiToDaiLBPSwapper.tokenReceived()).to.be.equal(addresses.dai); + expect(await dpiToDaiLBPSwapper.tokenReceivingAddress()).to.be.equal(addresses.compoundDaiPCVDeposit); + + const poolTokens = await contracts.balancerVault.getPoolTokens(poolId); + expect(poolTokens.tokens[0]).to.be.equal(addresses.dpi); + expect(poolTokens.tokens[1]).to.be.equal(addresses.dai); + + // LBP swapper should be empty + expect(poolTokens.balances[0]).to.be.equal('0'); + expect(poolTokens.balances[1]).to.be.equal('0'); + + // Lenses should report 0 because LBP is empty + expect(await contracts.dpiToDaiLensDai.balance()).to.be.equal('0'); + expect(await contracts.dpiToDaiLensDpi.balance()).to.be.equal('0'); + + // Swapper should hold no tokens + expect(await contracts.dpi.balanceOf(dpiToDaiLBPSwapper.address)).to.be.equal('0'); + expect(await contracts.dai.balanceOf(dpiToDaiLBPSwapper.address)).to.be.equal('0'); + + console.log('Starting DAI PSM dai balance [M]', (await contracts.compoundDaiPCVDeposit.balance()) / 1e24); + + await forceEth(addresses.tribalCouncilTimelock); + + initialAavePCVBalance = await contracts.aaveEthPCVDepositWrapper.balance(); + logging && console.log('Initial Aave Eth PCV Balance: ', initialAavePCVBalance.toString()); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const core = contracts.core; + poolId = '0xd10386804959a121a8a487e49f45aa9f5a2eb2a00002000000000000000001f1'; + console.log('Final DAI PSM dai balance [M]', (await contracts.compoundDaiPCVDeposit.balance()) / 1e24); + + //////////// 1. New Safe adddresses ////////////// + expect(await contracts.pcvGuardianNew.isSafeAddress(addresses.uniswapPCVDeposit)).to.be.true; + expect(await contracts.pcvGuardianNew.isSafeAddress(addresses.dpiToDaiLBPSwapper)).to.be.true; + + ///////////// 2. DPI LBP //////////////// + await validateLBPSetup(contracts, addresses, poolId); + + // Validate SWAP_ADMIN_ROLE is under ROLE_ADMIN and that TribalCouncilTimelock has the role + expect(await core.hasRole(ethers.utils.id('SWAP_ADMIN_ROLE'), addresses.tribalCouncilTimelock)).to.be.true; + expect(await core.getRoleAdmin(ethers.utils.id('SWAP_ADMIN_ROLE'))).to.be.equal(ethers.utils.id('ROLE_ADMIN')); + + //////// 3. Nope DAO Voting Period fix ///////////// + expect(await contracts.nopeDAO.votingPeriod()).to.be.equal(26585); + + /////// 4. CREAM transferred to TribalCouncil multisig //////// + const creamAmount = '31780370000000000000000'; + expect(await contracts.cream.balanceOf(addresses.tribalCouncilSafe)).to.be.equal(toBN(creamAmount)); + + /////// 5. Fund TribalCouncil with 10 Eth ////////// + const ethersSigner = (await ethers.getSigners())[0]; + expect(await ethersSigner.provider.getBalance(addresses.tribalCouncilSafe)).to.be.equal( + ethers.utils.parseEther('10') + ); + + /////// 6. Transfer WETH to the aaveETHPCVDeposit ////// + const finalAavePCVBalance = await contracts.aaveEthPCVDepositWrapper.balance(); + expect(finalAavePCVBalance).to.be.bignumber.at.least(initialAavePCVBalance.add(aaveWETHTransferAmount)); + logging && console.log('Final Aave Eth PCV Balance: ', finalAavePCVBalance.toString()); +}; + +const validateLBPSetup = async (contracts: NamedContracts, addresses: NamedAddresses, poolId: string) => { + const dpiToDaiLBPSwapper = contracts.dpiToDaiLBPSwapper; + const dpiToDaiLBPPool = contracts.dpiToDaiLBPPool; + + const retrievedPoolId = await dpiToDaiLBPPool.getPoolId(); + expect(retrievedPoolId).to.equal(poolId); + + // expect(await dpiToDaiLBPSwapper.doInvert()).to.be.equal(true); + expect(await dpiToDaiLBPSwapper.isTimeStarted()).to.be.true; + expect(await dpiToDaiLBPSwapper.tokenSpent()).to.equal(addresses.dpi); + expect(await dpiToDaiLBPSwapper.tokenReceived()).to.equal(addresses.dai); + expect(await dpiToDaiLBPPool.getSwapEnabled()).to.equal(true); + // tokenSpent = DPI + // tokenReceived = DAI + // On BalancerVault, token[0] = DPI, token[1] = DAI + // Therefore, on LBPSwapper, assets[0] = DPI, assets[1] = DAI + + // 2.1 Check oracle price + const price = (await dpiToDaiLBPSwapper.readOracle())[0]; // DAI price in units of DPI + console.log('price: ', price); + expect(price).to.be.bignumber.at.least(ethers.constants.WeiPerEther.mul(90)); // 90e18 + expect(price).to.be.bignumber.at.most(ethers.constants.WeiPerEther.mul(100)); // 100e18 + + // 2.2 Check relative price in pool + // Putting in 100,000 tokens of DPI, getting an amount of DAI back + const response = await dpiToDaiLBPSwapper.getTokensIn(100000); // input is spent token balance, 100,000 DPI tokens + const amounts = response[1]; + expect(amounts[0]).to.be.bignumber.equal(ethers.BigNumber.from(100000)); // DPI + + // DAI/DPI price * DAI amount * 5% ~= amount + expectApprox(price.mul(100000).mul(5).div(ethers.constants.WeiPerEther).div(100), amounts[1]); // DAI + expect(amounts[1]).to.be.bignumber.at.least(toBN(1000)); // Make sure orcacle inversion is correct (i.e. not inverted) + + // 2.3 Check pool weights + const weights = await dpiToDaiLBPPool.getNormalizedWeights(); + expectApprox(weights[0], ethers.constants.WeiPerEther.mul(5).div(100)); // 5% DAI + expectApprox(weights[1], ethers.constants.WeiPerEther.mul(95).div(100)); // 95% DPI + + // 2.4 Check pool info + const poolTokens = await contracts.balancerVault.getPoolTokens(poolId); + // there should be 188k DAI in the pool + expect(poolTokens.tokens[1]).to.be.equal(contracts.dai.address); // this is DAI + expect(poolTokens.balances[1]).to.be.bignumber.at.least(ethers.constants.WeiPerEther.mul(185_000)); + expect(poolTokens.balances[1]).to.be.bignumber.at.most(ethers.constants.WeiPerEther.mul(200_000)); + // there should be 37k DPI in the pool + expect(poolTokens.tokens[0]).to.be.equal(contracts.dpi.address); // this is DPI + expect(poolTokens.balances[0]).to.be.equal('37888449801955370645659'); + + // Pool balances Maths: + // Total value of pool = (188k DAI * $1) + (37k DPI * $93) = $3.63M + // DAI share = 5% + // DPI share = 95% + // Expected DAI amount = $3.63M * 0.05 = ~$181k + // Expected DPI amount = $3.63M * 0.95 = ~$3.5M -> ~ ($3500k / 93) 37k DPI + + // Validate that a swap can occur + const daiWhale = '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643'; + const daiWhaleSigner = await getImpersonatedSigner(daiWhale); + await forceEth(daiWhale); + + const initialUserDpiBalance = await contracts.dpi.balanceOf(daiWhale); + const initialUserDaiBalance = await contracts.dai.balanceOf(daiWhale); + + const amountIn = ethers.constants.WeiPerEther.mul(10_000); + await contracts.dai.connect(daiWhaleSigner).approve(addresses.balancerVault, amountIn); + await contracts.balancerVault.connect(daiWhaleSigner).swap( + { + poolId: poolId, + kind: 0, + assetIn: addresses.dai, + assetOut: addresses.dpi, + amount: amountIn, + userData: '0x' + }, + { + sender: daiWhale, + fromInternalBalance: false, + recipient: daiWhale, + toInternalBalance: false + }, + 0, + '10000000000000000000000' + ); + + const postUserDpiBalance = await contracts.dpi.balanceOf(daiWhale); + const postUserDaiBalance = await contracts.dai.balanceOf(daiWhale); + + const daiSpent = initialUserDaiBalance.sub(postUserDaiBalance); + expect(daiSpent).to.be.bignumber.equal(amountIn); + + const dpiGained = postUserDpiBalance.sub(initialUserDpiBalance); + expect(dpiGained).to.be.bignumber.at.least(ethers.constants.WeiPerEther.mul(80)); + expect(dpiGained).to.be.bignumber.at.most(ethers.constants.WeiPerEther.mul(120)); + + // Put in 10k DAI, got out 101 DPI + // Implies price of $98.5 per DPI, compared to an oracle price of $95.6 + console.log('DAI spent: ', daiSpent); + console.log('DPI gained: ', dpiGained); + + await time.increase(86400 * 7); + // Perform second swap, check price goes down + await contracts.dai.connect(daiWhaleSigner).approve(addresses.balancerVault, amountIn); + await contracts.balancerVault.connect(daiWhaleSigner).swap( + { + poolId: poolId, + kind: 0, + assetIn: addresses.dai, + assetOut: addresses.dpi, + amount: amountIn, + userData: '0x' + }, + { + sender: daiWhale, + fromInternalBalance: false, + recipient: daiWhale, + toInternalBalance: false + }, + 0, + '10000000000000000000000' + ); + const secondSwapDPIAmount = (await contracts.dpi.balanceOf(daiWhale)).sub(postUserDpiBalance); + // If price has dropped, then for the same DAI the user gets more DPI + expect(secondSwapDPIAmount).to.be.bignumber.greaterThan(dpiGained); + + // Accelerate time and check ended + await time.increase(LBP_FREQUENCY); + expect(await dpiToDaiLBPSwapper.isTimeEnded()).to.be.true; +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/fip_82b.ts b/proposals/dao/old/fip_82b.ts similarity index 100% rename from proposals/dao/fip_82b.ts rename to proposals/dao/old/fip_82b.ts diff --git a/proposals/dao/old/oa_cr_fix.ts b/proposals/dao/old/oa_cr_fix.ts new file mode 100644 index 000000000..d9a966e47 --- /dev/null +++ b/proposals/dao/old/oa_cr_fix.ts @@ -0,0 +1,129 @@ +import hre, { ethers, artifacts } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { ZERO_ADDRESS, overwriteChainlinkAggregator } from '@test/helpers'; + +const fipNumber = 'oa_cr_fix'; +let pcvStatsBefore; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + // Deploy lens to report B-30FEI-70WETH as WETH and protocol-owned FEI + // (The new contract contains a fix) + const balancerPool2LensFactory = await ethers.getContractFactory('BalancerPool2Lens'); + const balancerLensBpt30Fei70Weth = await balancerPool2LensFactory.deploy( + addresses.gaugeLensBpt30Fei70WethGauge, // address _depositAddress + addresses.weth, // address _token + addresses.bpt30Fei70Weth, // IWeightedPool _pool + addresses.chainlinkEthUsdOracleWrapper, // IOracle _reportedOracle + addresses.oneConstantOracle, // IOracle _otherOracle + false, // bool _feiIsReportedIn + true // bool _feiIsOther + ); + await balancerLensBpt30Fei70Weth.deployTransaction.wait(); + logging && console.log('balancerLensBpt30Fei70Weth: ', balancerLensBpt30Fei70Weth.address); + + return { + balancerLensBpt30Fei70Weth + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`Setup of ${fipNumber} : reading CR oracle...`); + + // make sure ETH oracle is fresh (for B.AMM not to revert, etc) + // Read Chainlink ETHUSD price & override chainlink storage to make it a fresh value + const ethPrice = (await contracts.chainlinkEthUsdOracleWrapper.read())[0].toString() / 1e10; + await overwriteChainlinkAggregator(addresses.chainlinkEthUsdOracle, Math.round(ethPrice), '8'); + + // read pcvStats + pcvStatsBefore = await contracts.collateralizationOracle.pcvStats(); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + // Check the removed PCV Deposits + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool8FeiPCVDepositWrapper)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool8DaiPCVDeposit)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool8LusdPCVDeposit)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool18FeiPCVDepositWrapper)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool27FeiPCVDepositWrapper)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool90FeiPCVDepositWrapper)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.rariPool146EthPCVDeposit)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.convexPoolPCVDepositWrapper)).to.be.equal( + ZERO_ADDRESS + ); + + // Check the lens swap + expect(await contracts.collateralizationOracle.depositToToken(addresses.balancerLensBpt30Fei70WethOld)).to.be.equal( + ZERO_ADDRESS + ); + expect(await contracts.collateralizationOracle.depositToToken(addresses.balancerLensBpt30Fei70Weth)).to.be.equal( + addresses.weth + ); + + // Check the new lens returned values + const balance = (await contracts.balancerLensBpt30Fei70Weth.balance()) / 1e18; + const resistantBalanceAndFei = await contracts.balancerLensBpt30Fei70Weth.resistantBalanceAndFei(); + const resistantBalance = resistantBalanceAndFei[0] / 1e18; + const resistantFei = resistantBalanceAndFei[1] / 1e18; + // 15.86k ETH, 16.3M FEI on 2022-05-10 + expect(balance).to.be.at.least(14000); + expect(balance).to.be.at.most(18000); + expect(resistantBalance).to.be.at.least(14000); + expect(resistantBalance).to.be.at.most(18000); + expect(resistantFei).to.be.at.least(10e6); + expect(resistantFei).to.be.at.most(25e6); + + // display pcvStats + console.log('----------------------------------------------------'); + console.log(' pcvStatsBefore.protocolControlledValue [M]e18 ', pcvStatsBefore.protocolControlledValue / 1e24); + console.log(' pcvStatsBefore.userCirculatingFei [M]e18 ', pcvStatsBefore.userCirculatingFei / 1e24); + console.log(' pcvStatsBefore.protocolEquity [M]e18 ', pcvStatsBefore.protocolEquity / 1e24); + const pcvStatsAfter = await contracts.collateralizationOracle.pcvStats(); + console.log('----------------------------------------------------'); + console.log(' pcvStatsAfter.protocolControlledValue [M]e18 ', pcvStatsAfter.protocolControlledValue / 1e24); + console.log(' pcvStatsAfter.userCirculatingFei [M]e18 ', pcvStatsAfter.userCirculatingFei / 1e24); + console.log(' pcvStatsAfter.protocolEquity [M]e18 ', pcvStatsAfter.protocolEquity / 1e24); + console.log('----------------------------------------------------'); + const pcvDiff = pcvStatsAfter.protocolControlledValue.sub(pcvStatsBefore.protocolControlledValue); + const cFeiDiff = pcvStatsAfter.userCirculatingFei.sub(pcvStatsBefore.userCirculatingFei); + const eqDiff = pcvStatsAfter.protocolEquity.sub(pcvStatsBefore.protocolEquity); + console.log(' PCV diff [M]e18 ', pcvDiff / 1e24); + console.log(' Circ FEI diff [M]e18 ', cFeiDiff / 1e24); + console.log(' Equity diff [M]e18 ', eqDiff / 1e24); + console.log('----------------------------------------------------'); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/old/register_proposal.ts b/proposals/dao/old/register_proposal.ts new file mode 100644 index 000000000..8eb70081a --- /dev/null +++ b/proposals/dao/old/register_proposal.ts @@ -0,0 +1,59 @@ +import hre, { ethers, artifacts } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { Core } from '@custom-types/contracts'; + +/* + +TC Proposal: Register Balance Metadata and grant POD_METADATA_ROLES + +*/ + +const fipNumber = 'register_pod_metadata'; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + console.log(`No deploy actions for fip${fipNumber}`); + return { + // put returned contract objects here + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in setup for fip${fipNumber}`); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const core = contracts.core; + const podMetadataRole = ethers.utils.id('POD_METADATA_REGISTER_ROLE'); + + const deployer1 = '0x5346b4ff3e924508d33d93f352d11e392a7a9d3b'; // Caleb + const deployer2 = '0x64c4Bffb220818F0f2ee6DAe7A2F17D92b359c5d'; // Tom + const deployer3 = '0xE2388f22cf5e328C197D6530663809cc0408a510'; // Joey + const deployer4 = '0xcE96fE7Eb7186E9F894DE7703B4DF8ea60E2dD77'; // Erwan + + expect(await core.hasRole(podMetadataRole, deployer1)); + expect(await core.hasRole(podMetadataRole, deployer2)); + expect(await core.hasRole(podMetadataRole, deployer3)); + expect(await core.hasRole(podMetadataRole, deployer4)); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/old/withdraw_aave_comp_fei.ts b/proposals/dao/old/withdraw_aave_comp_fei.ts new file mode 100644 index 000000000..813a293dd --- /dev/null +++ b/proposals/dao/old/withdraw_aave_comp_fei.ts @@ -0,0 +1,78 @@ +import hre, { ethers, artifacts } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { BigNumber } from 'ethers'; +import { forceEth } from '@test/integration/setup/utils'; + +/* +Withdraw FEI from Aave and Compound +*/ + +const fipNumber = '9001'; // Change me! + +let aavePCVBalanceBefore: BigNumber; +let compoundPCVBalanceBefore: BigNumber; +let daiInitialPSMFeiBalance: BigNumber; +const totalFeiWithdraw = ethers.constants.WeiPerEther.mul(9_400_000); + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + console.log(`No deploy actions for fip${fipNumber}`); + return {}; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in setup for fip${fipNumber}`); + aavePCVBalanceBefore = await contracts.aaveFeiPCVDeposit.balance(); + compoundPCVBalanceBefore = await contracts.compoundFeiPCVDepositWrapper.balance(); + daiInitialPSMFeiBalance = await contracts.daiFixedPricePSM.feiBalance(); + + await forceEth(addresses.tribalCouncilTimelock); + await forceEth(addresses.tribalCouncilSafe); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + // 1. Validate Aave PCV deposit + const aavePCVBalanceAfter = await contracts.aaveFeiPCVDeposit.balance(); + expect(aavePCVBalanceAfter).to.bignumber.at.least( + aavePCVBalanceBefore.sub(ethers.constants.WeiPerEther.mul(6_500_000)) + ); + + expect(aavePCVBalanceAfter).to.bignumber.at.most( + aavePCVBalanceBefore.sub(ethers.constants.WeiPerEther.mul(6_300_000)) + ); + + // 2. Validate Compound PCV deposit + const compoundPCVBalanceAfter = await contracts.compoundFeiPCVDepositWrapper.balance(); + expect(compoundPCVBalanceAfter).to.bignumber.at.least( + compoundPCVBalanceBefore.sub(ethers.constants.WeiPerEther.mul(3_100_000)) + ); + + expect(compoundPCVBalanceAfter).to.bignumber.at.most( + compoundPCVBalanceBefore.sub(ethers.constants.WeiPerEther.mul(2_900_000)) + ); + + // 3. Validate funds received by DAI PSM + const daiFixedPricePSMBalance = await contracts.daiFixedPricePSM.feiBalance(); + expect(daiFixedPricePSMBalance).to.be.equal(daiInitialPSMFeiBalance.add(totalFeiWithdraw)); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/old/withdraw_d3_pool.ts b/proposals/dao/old/withdraw_d3_pool.ts new file mode 100644 index 000000000..a4e6350f5 --- /dev/null +++ b/proposals/dao/old/withdraw_d3_pool.ts @@ -0,0 +1,101 @@ +import { ethers } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { forceEth } from '@test/integration/setup/utils'; +import { BigNumber } from 'ethers'; + +const fipNumber = 'withdraw_from_d3Pool'; + +let convexResistantBalanceBefore: BigNumber; +let convexFeiBalanceBefore: BigNumber; +let curveResistantBalanceBefore: BigNumber; +let curveFeiBalanceBefore: BigNumber; +let daiInitialPSMFeiBalance: BigNumber; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + return {}; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const convexPCVDeposit = contracts.d3poolConvexPCVDeposit; + const curvePCVdeposit = contracts.d3poolCurvePCVDeposit; + const daiFixedPricePSM = contracts.daiFixedPricePSM; + + [convexResistantBalanceBefore, convexFeiBalanceBefore] = await convexPCVDeposit.resistantBalanceAndFei(); + [curveResistantBalanceBefore, curveFeiBalanceBefore] = await curvePCVdeposit.resistantBalanceAndFei(); + + daiInitialPSMFeiBalance = await daiFixedPricePSM.feiBalance(); + + await forceEth(addresses.tribalCouncilTimelock); + await forceEth(addresses.tribalCouncilSafe); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + const convexPCVDeposit = contracts.d3poolConvexPCVDeposit; + const curvePCVDeposit = contracts.d3poolCurvePCVDeposit; + const daiFixedPricePSM = contracts.daiFixedPricePSM; + const feiWithdrawAmount = ethers.constants.WeiPerEther.mul(10_000_000); + + // 2. Validate withdraw convexPCVDeposit - have pulled 30M LP tokens from Convex + const [convexResistantBalanceAfter, convexFeiBalanceAfter] = await convexPCVDeposit.resistantBalanceAndFei(); + + // ~20M in resistantBalance (value of LP tokens?) has been withdrawn + expect(convexResistantBalanceAfter).to.bignumber.at.least( + convexResistantBalanceBefore.sub(ethers.constants.WeiPerEther.mul(20_100_000)) + ); + expect(convexResistantBalanceAfter).to.bignumber.at.most( + convexResistantBalanceBefore.sub(ethers.constants.WeiPerEther.mul(19_900_000)) + ); + + // ~10M Fei has been withdrawn - would only expect LP tokens to be withdrawn? + expect(convexFeiBalanceAfter).to.bignumber.at.least( + convexFeiBalanceBefore.sub(ethers.constants.WeiPerEther.mul(10_100_000)) + ); + expect(convexFeiBalanceAfter).to.bignumber.at.most( + convexFeiBalanceBefore.sub(ethers.constants.WeiPerEther.mul(9_900_000)) + ); + + // 3. Validate curvePCVDeposit - have transferred 30M LP tokens here, but then withdrawn 10M. Net 20M inflow + const [curveResistantBalanceAfter, curveFeiBalanceAfter] = await curvePCVDeposit.resistantBalanceAndFei(); + + // ~13.6M in resistantBalance net inflow + expect(curveResistantBalanceAfter).to.bignumber.at.most( + curveResistantBalanceBefore.add(ethers.constants.WeiPerEther.mul(13_400_000)) + ); + expect(curveResistantBalanceAfter).to.bignumber.at.least( + curveResistantBalanceBefore.add(ethers.constants.WeiPerEther.mul(13_200_000)) + ); + + // ~6.3M Fei net inflow + expect(curveFeiBalanceAfter).to.bignumber.at.most( + curveFeiBalanceBefore.add(ethers.constants.WeiPerEther.mul(6_700_000)) + ); + expect(curveFeiBalanceAfter).to.bignumber.at.least( + curveFeiBalanceBefore.add(ethers.constants.WeiPerEther.mul(6_500_000)) + ); + + // 10M net flow into DAI PSM + const daiPSMFeiBalance = await daiFixedPricePSM.feiBalance(); + expect(daiPSMFeiBalance).to.be.equal(daiInitialPSMFeiBalance.add(feiWithdrawAmount)); +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/repay_fuse_bad_debt.ts b/proposals/dao/repay_fuse_bad_debt.ts new file mode 100644 index 000000000..186367496 --- /dev/null +++ b/proposals/dao/repay_fuse_bad_debt.ts @@ -0,0 +1,206 @@ +import { CToken, CTokenFuse, FuseFixer__factory, FuseFixer, PCVGuardian } from '@custom-types/contracts'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { getImpersonatedSigner } from '@test/helpers'; +import { forceEth, forceEthMultiple, forceSpecificEth } from '@test/integration/setup/utils'; +import { BigNumber, utils } from 'ethers'; +import hre from 'hardhat'; + +/* +Withdraw FEI from Aave and Compound +*/ + +const fipNumber = 'repay_fuse_bad_debt'; // Change me! + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + const fuseFixerFactory = (await hre.ethers.getContractFactory('FuseFixer')) as FuseFixer__factory; + const fuseFixer = await fuseFixerFactory.deploy(addresses.core); + await fuseFixer.deployTransaction.wait(); + + return { fuseFixer }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + // acquire assets for repayment + // + // where to get (testing only): + // amount token erc20 address where to get + // 6114 eth --> 0x0000000000000000000000000000000000000000 // 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5 (ceth) + // 20,325,623 fei --> 0x956F47F50A910163D8BF957Cf5846D573E7f87CA // 0xbC9C084a12678ef5B516561df902fdc426d95483 (optimistic timelock) + // 13,200,967 frax --> 0x853d955aCEf822Db058eb8505911ED77F175b99e // 0xd632f22692fac7611d2aa1c0d552930d43caed3b (frax-3crv-f) + // 31,688 rai --> 0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919 // 0xc9BC48c72154ef3e5425641a3c747242112a46AF (arai) + // 14,312,434 dai --> 0x6B175474E89094C44Da98b954EedeAC495271d0F // 0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643 (cdai) + // 10,073,986 usdc --> 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 // 0x0A59649758aa4d66E25f08Dd01271e891fe52199 (psm-usdc-a) + // 1,955,846 lusd --> 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0 // 0x66017d22b0f8556afdd19fc67041899eb65a21bb (liquidity stability pool) + // 2,793,119 ustw --> 0xa47c8bf37f92aBed4A126BDA807A7b7498661acD // 0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2 (ftx exchange) + // 133,178 usdt --> 0xdAC17F958D2ee523a2206206994597C13D831ec7 // 0x5754284f345afc66a98fbb0a0afe71e0f007b949 (tether treasury) + /* + // give eth to each of the signers + await forceEthMultiple([ + '0xbC9C084a12678ef5B516561df902fdc426d95483', + '0xd632f22692fac7611d2aa1c0d552930d43caed3b', + '0xc9BC48c72154ef3e5425641a3c747242112a46AF', + '0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643', + '0x0A59649758aa4d66E25f08Dd01271e891fe52199', + '0x66017d22b0f8556afdd19fc67041899eb65a21bb', + '0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2', + '0x5754284f345afc66a98fbb0a0afe71e0f007b949' + ]); + + const fei = await hre.ethers.getContractAt( + 'ERC20', + '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', + await getImpersonatedSigner('0xbC9C084a12678ef5B516561df902fdc426d95483') + ); + const frax = await hre.ethers.getContractAt( + 'ERC20', + '0x853d955aCEf822Db058eb8505911ED77F175b99e', + await getImpersonatedSigner('0xd632f22692fac7611d2aa1c0d552930d43caed3b') + ); + const rai = await hre.ethers.getContractAt( + 'ERC20', + '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', + await getImpersonatedSigner('0xc9BC48c72154ef3e5425641a3c747242112a46AF') + ); + const dai = await hre.ethers.getContractAt( + 'ERC20', + '0x6B175474E89094C44Da98b954EedeAC495271d0F', + await getImpersonatedSigner('0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643') + ); + const usdc = await hre.ethers.getContractAt( + 'ERC20', + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + await getImpersonatedSigner('0x0A59649758aa4d66E25f08Dd01271e891fe52199') + ); + const lusd = await hre.ethers.getContractAt( + 'ERC20', + '0x5f98805A4E8be255a32880FDeC7F6728C6568bA0', + await getImpersonatedSigner('0x66017d22b0f8556afdd19fc67041899eb65a21bb') + ); + const ustw = await hre.ethers.getContractAt( + 'ERC20', + '0xa693B19d2931d498c5B318dF961919BB4aee87a5', + await getImpersonatedSigner('0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2') + ); + const usdt = await hre.ethers.getContractAt( + 'ERC20', + '0xdAC17F958D2ee523a2206206994597C13D831ec7', + await getImpersonatedSigner('0x5754284f345afc66a98fbb0a0afe71e0f007b949') + ); + + await fei.transfer(addresses.fuseFixer, utils.parseEther('21000000')); + await frax.transfer(addresses.fuseFixer, utils.parseEther('14000000')); + await rai.transfer(addresses.fuseFixer, utils.parseEther('32000')); + await dai.transfer(addresses.fuseFixer, utils.parseEther('15000000')); + await usdc.transfer(addresses.fuseFixer, utils.parseEther('11000000').div(1e12)); + await lusd.transfer(addresses.fuseFixer, utils.parseEther('2000000')); + await ustw.transfer(addresses.fuseFixer, utils.parseEther('3000000').div(1e12)); + await usdt.transfer(addresses.fuseFixer, utils.parseEther('150000').div(1e12)); + + await forceSpecificEth(addresses.fuseFixer, utils.parseEther('6500').toString()); + // contract should now have enough to repayBorrowBehalf everything + */ +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + /*const debtor = '0x32075bAd9050d4767018084F0Cb87b3182D36C45'; + + const ctokens = [ + '0xd8553552f8868C1Ef160eEdf031cF0BCf9686945', // Pool 8: FEI + '0xbB025D470162CC5eA24daF7d4566064EE7f5F111', // Pool 8: ETH + '0x7e9cE3CAa9910cc048590801e64174957Ed41d43', // Pool 8: DAI + '0x7259eE19D6B5e755e7c65cECfd2466C09E251185', // Pool 8: wstETH + '0x647A36d421183a0a9Fa62717a64B664a24E469C7', // Pool 8: LUSD + '0xFA1057d02A0C1a4885851e3F4fD496Ee7D38F56e', // Pool 18: ETH + '0x8E4E0257A4759559B4B1AC087fe8d80c63f20D19', // Pool 18: DAI + '0x6f95d4d251053483f41c8718C30F4F3C404A8cf2', // Pool 18: USDC + '0x3E5C122Ffa75A9Fe16ec0c69F7E9149203EA1A5d', // Pool 18: FRAX + '0x17b1A2E012cC4C31f83B90FF11d3942857664efc', // Pool 18: FEI + '0x51fF03410a0dA915082Af444274C381bD1b4cDB1', // Pool 18: RAI + '0xB7FE5f277058b3f9eABf6e0655991f10924BFA54', // Pool 18: USTw + '0x9de558FCE4F289b305E38ABe2169b75C626c114e', // Pool 27: FRAX + '0xda396c927e3e6BEf77A98f372CE431b49EdEc43D', // Pool 27: FEI + '0xF148cDEc066b94410d403aC5fe1bb17EC75c5851', // Pool 27: ETH + '0x0C402F06C11c6e6A6616C98868A855448d4CfE65', // Pool 27: USTw + '0x26267e41CeCa7C8E0f143554Af707336f27Fa051', // Pool 127: ETH + '0xEbE0d1cb6A0b8569929e062d67bfbC07608f0A47', // Pool 127: USDC + '0x4B68ef5AB32261082DF1A6C9C6a89FFD5eF168B1', // Pool 127: DAI + '0xe097783483D1b7527152eF8B150B99B9B2700c8d', // Pool 127: USDT + '0x0F0d710911FB37038b3AD88FC43DDAd4Edbe16A5', // Pool 127: USTw + '0x8922C1147E141C055fdDfc0ED5a119f3378c8ef8', // Pool 127: FRAX + '0x7DBC3aF9251756561Ce755fcC11c754184Af71F7', // Pool 144: ETH + '0x3a2804ec0Ff521374aF654D8D0daA1d1aE1ee900', // Pool 144: FEI + '0xA54c548d11792b3d26aD74F5f899e12CDfD64Fd6', // Pool 144: FRAX + '0xA6C25548dF506d84Afd237225B5B34F2Feb1aa07', // Pool 144: DAI + '0xfbD8Aaf46Ab3C2732FA930e5B343cd67cEA5054C', // Pool 146: ETH + '0x49dA42a1EcA4AC6cA0C6943d9E5dc64e4641e0E3', // Pool 146: wstETH + '0xe14c2e156A3f310d41240Ce8760eB3cb8a0dDBE3', // Pool 156: USTw + '0x001E407f497e024B9fb1CB93ef841F43D645CA4F', // Pool 156: FEI + '0x5CaDc2a04921213DE60B237688776e0F1A7155E6', // Pool 156: FRAX + '0x9CD060A4855290bf0c5aeD266aBe119FF3b01966', // Pool 156: DAI + '0x74897C0061ADeec84D292e8900c7BDD00b3388e4', // Pool 156: LUSD + '0x88d3557eB6280CC084cA36e425d6BC52d0A04429', // Pool 156: USDC + '0xe92a3db67e4b6AC86114149F522644b34264f858' // Pool 156: ETH + ]; + + // Verify that the borrowBalanceCurrent for the debtor is zero for each ctoken + for (const ctokenAddress of ctokens) { + const ctoken = await hre.ethers.getContractAt('CTokenFuse', ctokenAddress); + const debt = await ctoken.callStatic.borrowBalanceCurrent(debtor); + + if (debt.gt(0)) { + throw new Error(`Debt for ctoken ${ctokenAddress} is greater than 0: ${debt}`); + } + } + + const fuseFixer = contracts.fuseFixer as FuseFixer; + + // Copied from smart contract + const underlyings = [ + '0x0000000000000000000000000000000000000000', // ETH + '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', // FEI + '0x853d955aCEf822Db058eb8505911ED77F175b99e', // FRAX + '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', // RAI + '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC + '0x5f98805A4E8be255a32880FDeC7F6728C6568bA0', // LUSD + '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', // wstETH + '0xa693B19d2931d498c5B318dF961919BB4aee87a5', // USTw + '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT + ]; + + for (const underlying of underlyings) { + const debt = await fuseFixer.callStatic.getTotalDebt(underlying); + if (!debt.eq(BigNumber.from(0))) { + throw new Error('Debt for ' + underlying + ' is not zero: ' + debt.toString()); + } + }*/ + + // Ensure that the fuse fixer is a safe address + const pcvGuardian = contracts.pcvGuardianNew as PCVGuardian; + const isSafeAddress = await pcvGuardian.isSafeAddress(contracts.fuseFixer.address); + + if (!isSafeAddress) { + throw new Error(`Fuse fixer (${contracts.fuseFixer.address}) is not a safe address`); + } +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/dao/tokemak_withdraw.ts b/proposals/dao/tokemak_withdraw.ts new file mode 100644 index 000000000..15466feda --- /dev/null +++ b/proposals/dao/tokemak_withdraw.ts @@ -0,0 +1,50 @@ +import hre, { ethers, artifacts } from 'hardhat'; +import { expect } from 'chai'; +import { + DeployUpgradeFunc, + NamedAddresses, + SetupUpgradeFunc, + TeardownUpgradeFunc, + ValidateUpgradeFunc +} from '@custom-types/types'; +import { forceEth } from '@test/integration/setup/utils'; +import { getImpersonatedSigner, time } from '@test/helpers'; + +/* + +FIP 111: Withdraw from Tokemak + +*/ + +const fipNumber = 'fip_111_tokemak_withdraw'; + +// Do any deployments +// This should exclusively include new contract deployments +const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses: NamedAddresses, logging: boolean) => { + console.log(`No deploy actions for fip${fipNumber}`); + return { + // put returned contract objects here + }; +}; + +// Do any setup necessary for running the test. +// This could include setting up Hardhat to impersonate accounts, +// ensuring contracts have a specific state, etc. +const setup: SetupUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in setup for fip${fipNumber}`); +}; + +// Tears down any changes made in setup() that need to be +// cleaned up before doing any validation checks. +const teardown: TeardownUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in teardown for fip${fipNumber}`); +}; + +// Run any validations required on the fip using mocha or console logging +// IE check balances, check state of contracts, etc. +const validate: ValidateUpgradeFunc = async (addresses, oldContracts, contracts, logging) => { + console.log(`No actions to complete in validate for fip${fipNumber}`); + // Validation performed in e2e test +}; + +export { deploy, setup, teardown, validate }; diff --git a/proposals/data/ragequit_data.json b/proposals/data/old/ragequit_data.json similarity index 100% rename from proposals/data/ragequit_data.json rename to proposals/data/old/ragequit_data.json diff --git a/proposals/description/end_tribe_incentives.ts b/proposals/description/end_tribe_incentives.ts new file mode 100644 index 000000000..3dc84d236 --- /dev/null +++ b/proposals/description/end_tribe_incentives.ts @@ -0,0 +1,312 @@ +import { ProposalDescription, TemplatedProposalDescription } from '@custom-types/types'; + +const end_tribe_incentives: TemplatedProposalDescription = { + title: 'TIP-109: Discontinue Tribe Incentives', + commands: [ + /////// TC grants itself TRIBAL_CHIEF_ADMIN_ROLE + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: (addresses) => [ + '0x23970cab3799b6876df4319661e6c03cc45bd59628799d92e988dd8cbdc90e31', + addresses.tribalCouncilTimelock + ], + description: 'Grant TRIBAL_CHIEF_ADMIN_ROLE to Tribal Council timelock' + }, + + ///////////// Replicate onlyGovernor behaviour or resetRewards() + //////// Set Pool allocation points to 0. This also updates reward variables + + // FEI-TRIBE LP has a single AP point + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['0', '1', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 0 rewards to 1 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['1', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 1 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['2', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 2 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['3', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 3 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['4', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 4 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['5', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 5 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['6', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 6 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['7', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 7 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['8', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 8 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['9', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 9 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['10', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 10 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['11', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 11 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['12', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 12 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['13', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 13 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['14', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 14 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['15', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 15 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['16', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 16 rewards to 0 and do not overwrite or change the rewarder' + }, + { + target: 'tribalChief', + values: '0', + method: 'set(uint256,uint120,address,bool)', + arguments: (addresses) => ['17', '0', '0x0000000000000000000000000000000000000000', false], + description: 'Set Pool 17 rewards to 0 and do not overwrite or change the rewarder' + }, + + //// Set block rewards to effectively 0 + { + target: 'tribalChief', + values: '0', + method: 'updateBlockReward(uint256)', + arguments: (addresses) => ['100000'], + description: 'Set Tribal Chief block reward effectively to zero. Setting to 100000' + }, + + //// Sync new reward speeds on all AutoRewardDistributors + { + target: 'autoRewardsDistributor', + values: '0', + method: 'setAutoRewardsDistribution()', + arguments: (addresses) => [], + description: 'Sync the reward speed of the AutoRewardsDistributor' + }, + { + target: 'd3AutoRewardsDistributor', + values: '0', + method: 'setAutoRewardsDistribution()', + arguments: (addresses) => [], + description: 'Sync the reward speed of the d3AutoRewardsDistributor' + }, + { + target: 'fei3CrvAutoRewardsDistributor', + values: '0', + method: 'setAutoRewardsDistribution()', + arguments: (addresses) => [], + description: 'Sync the reward speed of the fei3CrvAutoRewardsDistributor' + }, + { + target: 'feiDaiAutoRewardsDistributor', + values: '0', + method: 'setAutoRewardsDistribution()', + arguments: (addresses) => [], + description: 'Sync the reward speed of the feiDaiAutoRewardsDistributor' + }, + { + target: 'feiUsdcAutoRewardsDistributor', + values: '0', + method: 'setAutoRewardsDistribution()', + arguments: (addresses) => [], + description: 'Sync the reward speed of the feiUsdcAutoRewardsDistributor' + }, + ///// Deprecate roles of Incentives system + { + target: 'core', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x7f85477db6c0857f19179a2b3846a7ddbc64caeeb3a02ef34771b82f5ab926e4', // FUSE_ADMIN + addresses.tribalChiefSyncV2 + ], + description: 'Revoke FUSE_ADMIN from tribalChiefSyncV2' + }, + { + target: 'core', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x23970cab3799b6876df4319661e6c03cc45bd59628799d92e988dd8cbdc90e31', // TRIBAL_CHIEF_ADMIN_ROLE + addresses.tribalChiefSyncV2 + ], + description: 'Revoke TRIBAL_CHIEF_ADMIN_ROLE from tribalChiefSyncV2' + }, + + // Deprecate RewardDistributorAdmin internal roles + { + target: 'rewardsDistributorAdmin', + values: '0', + method: 'becomeAdmin()', + arguments: (addresses) => [], + description: + 'Grant the TC timelock the DEFAULT_ADMIN_ROLE, to it can dismantle the RewardDistributorAdmin permissions' + }, + { + target: 'rewardsDistributorAdmin', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x19cca239eaee0f28c6ba4c8c860332b8a23b35008b89b0507b96138ca5691cbb', // AUTO_REWARDS_DISTRIBUTOR_ROLE + addresses.feiDaiAutoRewardsDistributor + ], + description: 'Revoke AUTO_REWARDS_DISTRIBUTOR_ROLE from feiDaiAutoRewardsDistributor' + }, + { + target: 'rewardsDistributorAdmin', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x19cca239eaee0f28c6ba4c8c860332b8a23b35008b89b0507b96138ca5691cbb', // AUTO_REWARDS_DISTRIBUTOR_ROLE + addresses.feiUsdcAutoRewardsDistributor + ], + description: 'Revoke AUTO_REWARDS_DISTRIBUTOR_ROLE from feiUsdcAutoRewardsDistributor' + }, + { + target: 'rewardsDistributorAdmin', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x19cca239eaee0f28c6ba4c8c860332b8a23b35008b89b0507b96138ca5691cbb', // AUTO_REWARDS_DISTRIBUTOR_ROLE + addresses.autoRewardsDistributor + ], + description: 'Revoke AUTO_REWARDS_DISTRIBUTOR_ROLE from autoRewardsDistributor' + }, + { + target: 'rewardsDistributorAdmin', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x19cca239eaee0f28c6ba4c8c860332b8a23b35008b89b0507b96138ca5691cbb', // AUTO_REWARDS_DISTRIBUTOR_ROLE + addresses.d3AutoRewardsDistributor + ], + description: 'Revoke AUTO_REWARDS_DISTRIBUTOR_ROLE from d3AutoRewardsDistributor' + }, + { + target: 'rewardsDistributorAdmin', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x19cca239eaee0f28c6ba4c8c860332b8a23b35008b89b0507b96138ca5691cbb', // AUTO_REWARDS_DISTRIBUTOR_ROLE + addresses.fei3CrvAutoRewardsDistributor + ], + description: 'Revoke AUTO_REWARDS_DISTRIBUTOR_ROLE from fei3CrvAutoRewardsDistributor' + }, + + //// Revoke VOTIUM_ROLE, no longer needed + { + target: 'core', + values: '0', + method: 'revokeRole(bytes32,address)', + arguments: (addresses) => [ + '0x2d46c62aa6fbc9b550f22e00476aebb90f4ea69cd492a68db4d444217763330d', // VOTIUM_ADMIN_ROLE + addresses.opsOptimisticTimelock + ], + description: 'Revoke VOTIUM_ROLE from opsOptimisticTimelock as no longer required' + }, + + ////// Remove CREAM from CR + { + target: 'collateralizationOracle', + values: '0', + method: 'removeDeposit(address)', + arguments: (addresses) => [addresses.creamDepositWrapper], + description: 'Remove empty CREAM deposit from the CR oracle' + } + ], + description: ` + TIP-109: Discontinue Tribe Incentives + + This proposal will disable all Tribe incentives. Specifically it: + - Sets the allocation points of all pools effectively to 0 + - Updates the reward variables of incentivised pools + - Sets the amount of Tribe issued per block by the Tribal Chief to effectively zero + - Dismantle internal ACL/permission mapping of the rewardsDistributorAdmin + - Sync all AutoRewardDistributors + - Revoke TribeRoles from incentives system + + It also removes CREAM from the Collaterisation Oracle + ` +}; + +export default end_tribe_incentives; diff --git a/proposals/description/eth_lbp.ts b/proposals/description/eth_lbp.ts new file mode 100644 index 000000000..52164ff18 --- /dev/null +++ b/proposals/description/eth_lbp.ts @@ -0,0 +1,79 @@ +import { TemplatedProposalDescription } from '@custom-types/types'; + +const eth_lbp: TemplatedProposalDescription = { + title: 'FIP-111: Reinforce PCV via ETH LBP and tighter spread', + commands: [ + { + target: 'pcvGuardianNew', + values: '0', + method: 'setSafeAddresses(address[])', + arguments: (addresses) => [[addresses.ethToDaiLBPSwapper]], + description: 'Set the ethToDai LBP swapper to be guardian Safe addresses' + }, + //////// ETH LBP //////// + { + target: 'pcvGuardianNew', + values: '0', + method: 'withdrawToSafeAddress(address,address,uint256,bool,bool)', + arguments: (addresses) => [ + addresses.aaveEthPCVDeposit, + addresses.ethToDaiLBPSwapper, + '20000000000000000000000', + false, + false + ], + description: 'Transfer WETH from Aave to the LBP swapper' + }, + { + target: 'pcvGuardianNew', + values: '0', + method: 'withdrawToSafeAddress(address,address,uint256,bool,bool)', + arguments: (addresses) => [ + addresses.compoundDaiPCVDeposit, + addresses.ethToDaiLBPSwapper, + '3000000000000000000000000', + false, + false + ], + description: 'Withdraw 3M DAI from the CompoundPCVDeposit and transfer to the LBP pool' + }, + // Swap and update CR oracle + { + target: 'ethToDaiLBPSwapper', + values: '0', + method: 'swap()', + arguments: (addresses) => [], + description: 'Start the auction and override the current no-op auction' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'addDeposit(address)', + arguments: (addresses) => [addresses.ethToDaiLensDai], + description: 'Add DAI swapper lens to the CR oracle' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'addDeposit(address)', + arguments: (addresses) => [addresses.ethToDaiLensEth], + description: 'Add ETH swapper lens to the CR oracle' + }, + ////// Tighten ETH PSM ////////// + { + target: 'ethPSM', + values: '0', + method: 'setRedeemFee(uint256)', + arguments: (addresses) => ['60'], + description: 'set PSM spread to 60' + } + ], + description: ` + FIP-111: Reinforce PCV via ETH LBP and tighter spread. + + This proposal uses a balancer liquidity bootstrapping pool to sell 20k ETH for DAI over 2 days. + It also tightens the spread on the ETH psm by allowing redemptions for a 60bps fee. + ` +}; + +export default eth_lbp; diff --git a/proposals/description/fip_104b.ts b/proposals/description/fip_104b.ts new file mode 100644 index 000000000..40772787e --- /dev/null +++ b/proposals/description/fip_104b.ts @@ -0,0 +1,48 @@ +import { TemplatedProposalDescription } from '@custom-types/types'; + +const fip_104b: TemplatedProposalDescription = { + title: 'FIP_104b: Withdraw LBP liquidity', + commands: [ + { + target: 'dpiToDaiLBPSwapper', + values: '0', + method: 'exitPool(address)', + arguments: (addresses) => [addresses.compoundDaiPCVDeposit], + description: 'Withdraw all DAI and DPI from LBP pool to the compoundDAIPCVDeposit (~$3.8m)' + }, + { + target: 'ratioPCVControllerV2', + values: '0', + method: 'withdrawRatioERC20(address,address,address,uint256)', + arguments: (addresses) => [ + addresses.compoundDaiPCVDeposit, // pcvDeposit + addresses.dpi, // token + addresses.tribalCouncilSafe, // to + '10000' // basisPoints, 100% + ], + description: + 'Withdraw all DPI from the Compound DAI PCV deposit (~$200k) to the TribalCouncil multisig, where it will be liquidated' + }, + { + target: 'compoundDaiPCVDeposit', + values: '0', + method: 'deposit()', + arguments: (addresses) => [], + description: 'Deposit DAI on compoundDAIPCVdeposit into Compound' + } + ], + description: ` + FIP_104b: Withdraw all liquidity from the DPI LBP. + + This FIP cleans up and finishes elements of the PCV reinforcement process snapshotted here: + https://snapshot.fei.money/#/proposal/0x2fd5bdda0067098f6c0520fe309dfe90ca403758f0ce98c1854a00bf38999674 + and discussed here: https://tribe.fei.money/t/fip-104-fei-pcv-reinforcement-proposal/4162 . + + Specifically it: + - Exits the LBP pool and withdraws all liquidity to the compound DAI deposit + - Withdraws the DPI from the deposit to the TribalCouncil multisig, using the ratioPCVController + - Deposits the DAI on the deposit into Compound + ` +}; + +export default fip_104b; diff --git a/proposals/description/old/balancer_gauge_fix.ts b/proposals/description/old/balancer_gauge_fix.ts new file mode 100644 index 000000000..fa1ec7ece --- /dev/null +++ b/proposals/description/old/balancer_gauge_fix.ts @@ -0,0 +1,75 @@ +import { ProposalDescription } from '@custom-types/types'; + +const fip_x: ProposalDescription = { + title: 'Balancer Gauge Staker', + commands: [ + { + target: 'pcvGuardianNew', + values: '0', + method: 'setSafeAddress(address)', + arguments: ['{balancerGaugeStaker}'], + description: 'Set balancerGaugeStaker as safe address' + }, + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: [ + '0x3bee38c33241595abfefa470fd75bfa1cc9cb01eff02cf6732fd2baea4ea4241', // METAGOVERNANCE_GAUGE_ADMIN + '{tribalCouncilTimelock}' + ], + description: 'Grant TC Timelock the METAGOVERNANCE_GAUGE_ADMIN role' + }, + { + target: 'balancerGaugeStaker', + values: '0', + method: 'setTokenToGauge(address,address)', + arguments: [ + '{bpt30Fei70Weth}', // token address + '{balancerGaugeBpt30Fei70Weth}' // gauge address + ], + description: 'Set Balancer B-30FEI-70WETH pool tokens gauge address' + }, + { + target: 'pcvGuardianNew', + values: '0', + method: 'withdrawERC20ToSafeAddress(address,address,address,uint256,bool,bool)', + arguments: [ + '{balancerDepositFeiWeth}', // address pcvDeposit + '{balancerGaugeStaker}', // address safeAddress + '{bpt30Fei70Weth}', // address token + '252865858892972812879565', // uint256 amount + false, // bool pauseAfter + false // bool depositAfter + ], + description: 'Move all LP tokens to the new gauge staker' + }, + { + target: 'balancerGaugeStaker', + values: '0', + method: 'stakeInGauge(address,uint256)', + arguments: [ + '{bpt30Fei70Weth}', // token + '252865858892972812879565' // amount + ], + description: 'Stake all B-30FEI-70WETH in gauge' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'swapDeposit(address,address)', + arguments: ['{balancerLensBpt30Fei70WethOld}', '{balancerLensBpt30Fei70Weth}'], + description: 'Add new FEI/WETH Lens to CR oracle & swap out the old one' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'addDeposit(address)', + arguments: ['{balancerGaugeStaker}'], + description: 'Count farmed BAL in the CR Oracle' + } + ], + description: 'Migrate liquidity to a new Balancer Gauge Staker which is able to claim BAL rewards.' +}; + +export default fip_x; diff --git a/proposals/description/old/fip_104.ts b/proposals/description/old/fip_104.ts new file mode 100644 index 000000000..36e31e66a --- /dev/null +++ b/proposals/description/old/fip_104.ts @@ -0,0 +1,147 @@ +import { ProposalDescription } from '@custom-types/types'; + +const fip_104: ProposalDescription = { + title: 'FIP-104: Reinforce PCV by consolidating assets and perform technical maintenance', + commands: [ + { + target: 'pcvGuardianNew', + values: '0', + method: 'setSafeAddresses(address[])', + arguments: [['{uniswapPCVDeposit}', '{dpiToDaiLBPSwapper}']], + description: 'Set the uniswapPCVDeposit and dpiToDai LBP swapper to be guardian Safe addresses' + }, + //////// DPI LBP //////// + { + target: 'dpi', + values: '0', + method: 'transfer(address,uint256)', + arguments: ['{dpiToDaiLBPSwapper}', '37888449801955370645659'], + description: 'Transfer DPI from DAO timelock to the LBP swapper' + }, + { + target: 'compoundDaiPCVDeposit', + values: '0', + method: 'withdraw(address,uint256)', + arguments: ['{dpiToDaiLBPSwapper}', '230000000000000000000000'], + description: 'Withdraw DAI from the CompoundPCVDeposit and transfer to the LBP pool' + }, + // Correcting the oracle needs to happen before forceSwap() + { + target: 'dpiToDaiLBPSwapper', + values: '0', + method: 'setDoInvert(bool)', + arguments: [false], + description: 'Set the dpiToDai LBP swapper to not invert' + }, + { + target: 'dpiToDaiLBPSwapper', + values: '0', + method: 'forceSwap()', + arguments: [], + description: 'Start the auction and override the current no-op auction' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'addDeposit(address)', + arguments: ['{dpiToDaiLensDai}'], + description: 'Add DAI swapper lens to the CR oracle' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'addDeposit(address)', + arguments: ['{dpiToDaiLensDpi}'], + description: 'Add DPI swapper lens to the CR oracle' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'removeDeposits(address[])', + arguments: [ + [ + '{rariPool31FeiPCVDepositWrapper}', + '{rariPool25FeiPCVDepositWrapper}', + '{rariPool9RaiPCVDepositWrapper}', + '{aaveRaiPCVDepositWrapper}', + '{rariPool19DpiPCVDepositWrapper}', + '{liquityFusePoolLusdPCVDeposit}', + '{rariPool72FeiPCVDepositWrapper}', + '{raiDepositWrapper}', + '{dpiDepositWrapper}' + ] + ], + description: 'Remove various empty PCV deposits from CR oracle' + }, + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: ['0x471cfe1a44bf1b786db7d7104d51e6728ed7b90a35394ad7cc424adf8ed16816', '{tribalCouncilTimelock}'], + description: 'Grant TribalCouncilTimelock SWAP_ADMIN_ROLE so it can initiate the LBP swap' + }, + /////////// Nope DAO ///////// + { + target: 'nopeDAO', + values: '0', + method: 'setVotingPeriod(uint256)', + arguments: ['26585'], // (86400 * 4) / 13 seconds (assumed 13s block time) + description: 'Set the voting period for the NopeDAO to 4 days' + }, + //////// Transfer CREAM to TribalCouncil Multisig ///////// + { + target: 'cream', + values: '0', + method: 'transfer(address,uint256)', + arguments: ['{tribalCouncilSafe}', '31780370000000000000000'], + description: 'Transfer CREAM to TribalCouncil multisig where it will then be swapped' + }, + /////// Transfer WETH from feiDAOTimelock to aaveETHPCVDeposit and deposit //////// + { + target: 'weth', + values: '0', + method: 'transfer(address,uint256)', + arguments: ['{aaveEthPCVDeposit}', '14999999999999999992057'], + description: 'Transfer WETH from the DAO timelock to the aaveETHPCVDeposit' + }, + { + target: 'aaveEthPCVDeposit', + values: '0', + method: 'deposit()', + arguments: [], + description: 'Deposit WETH transferred to aaveETHPCVDeposit into the deposit' + }, + //////// Fund Council ////////// + { + target: 'compoundEthPCVDeposit', + values: '0', + method: 'withdraw(address,uint256)', + arguments: ['{tribalCouncilSafe}', '10000000000000000000'], + description: 'Fund TribalCouncil with 10 Eth' + } + ], + description: ` + FIP-104: Reinforce PCV by consolidating assets and perform technical maintenance. + + This FIP implements parts of the PCV reinforcement proposal that was approved in this snapshot: + https://snapshot.fei.money/#/proposal/0x2fd5bdda0067098f6c0520fe309dfe90ca403758f0ce98c1854a00bf38999674 + and discussed in this forum post: https://tribe.fei.money/t/fip-104-fei-pcv-reinforcement-proposal/4162?page=2 + + Specifically, it: + - Liquidates the protocol's DPI holdings to DAI using a Balancer LBP + - Transfers the protocol's CREAM holdings from the DAO timelock to the TribalCouncil multisig. The TribalCouncil will + then liquidate the position on a DEX before returning the funds to PCV reserves + + In addition, the FIP performs several technical maintenance tasks: + - Add and remove the relevant PCV deposits from the Collaterization Oracle + - Grant the TribalCouncil the role required to initiate the DPI LBP auction + - Add the uniswapPCVDeposit and dpiToDai LBP swapper as Safe addresses so PCV can be moved there + - Fix a bug in the NopeDAO configuration that previously set the voting period to 22 months rather than the + expected 4 days + - Fund the TribalCouncil with 10 Eth + - Transfer 15,000 WETH from the DAO timelock to the aaveETHPCVDeposit + - Invert oracle price on LBP swapper and initiate auction + ` +}; + +export default fip_104; diff --git a/proposals/description/fip_82b.ts b/proposals/description/old/fip_82b.ts similarity index 99% rename from proposals/description/fip_82b.ts rename to proposals/description/old/fip_82b.ts index d118b4a3b..bedf13d76 100644 --- a/proposals/description/fip_82b.ts +++ b/proposals/description/old/fip_82b.ts @@ -109,10 +109,10 @@ const fip_82b: ProposalDescription = { values: '0', method: 'createRole(bytes32,bytes32)', arguments: [ - '0x2d46c62aa6fbc9b550f22e00476aebb90f4ea69cd492a68db4d444217763330d', // VOTIUM_ROLE + '0x2d46c62aa6fbc9b550f22e00476aebb90f4ea69cd492a68db4d444217763330d', // VOTIUM_ADMIN_ROLE '0x2172861495e7b85edac73e3cd5fbb42dd675baadf627720e687bcfdaca025096' // ROLE_ADMIN ], - description: 'Transfer VOTIUM_ROLE role admin from GOVERNOR to ROLE_ADMIN' + description: 'Transfer VOTIUM_ADMIN_ROLE role admin from GOVERNOR to ROLE_ADMIN' }, //////// Create new roles for the Tribal Council to manage ///////// { diff --git a/proposals/description/old/oa_cr_fix.ts b/proposals/description/old/oa_cr_fix.ts new file mode 100644 index 000000000..302941f97 --- /dev/null +++ b/proposals/description/old/oa_cr_fix.ts @@ -0,0 +1,35 @@ +import { ProposalDescription } from '@custom-types/types'; + +const fip_x: ProposalDescription = { + title: 'OA CR Fixes', + commands: [ + { + target: 'collateralizationOracle', + values: '0', + method: 'swapDeposit(address,address)', + arguments: ['{balancerLensBpt30Fei70WethOld}', '{balancerLensBpt30Fei70Weth}'], + description: 'Update B-70WETH-30FEI Lens' + }, + { + target: 'collateralizationOracle', + values: '0', + method: 'removeDeposits(address[])', + arguments: [ + [ + '{rariPool8FeiPCVDepositWrapper}', // Fuse Pool 8 FEI + '{rariPool8DaiPCVDeposit}', // Fuse Pool 8 DAI + '{rariPool8LusdPCVDeposit}', // Fuse Pool 8 LUSD + '{rariPool18FeiPCVDepositWrapper}', // Fuse Pool 18 FEI + '{rariPool27FeiPCVDepositWrapper}', // Fuse Pool 27 FEI + '{rariPool90FeiPCVDepositWrapper}', // Fuse Pool 90 FEI + '{rariPool146EthPCVDeposit}', // Fuse Pool 146 ETH + '{convexPoolPCVDepositWrapper}' // Fuse Pool 156 FEI + ] + ], + description: 'Remove PCV Deposits with bad debt' + } + ], + description: 'Fix Collateralization Oracle config after the Fuse May 2022 hack.' +}; + +export default fip_x; diff --git a/proposals/description/old/register_proposal.ts b/proposals/description/old/register_proposal.ts new file mode 100644 index 000000000..3dc36672d --- /dev/null +++ b/proposals/description/old/register_proposal.ts @@ -0,0 +1,52 @@ +import { ProposalDescription } from '@custom-types/types'; + +const register_proposal: ProposalDescription = { + title: 'Register TC Proposal and grant pod metadata roles', + commands: [ + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: [ + '0xf62a46a499242191aaab61084d4912c2c0a8c48e3d70edfb5a9be2bc9e92622f', // POD_METADATA_REGISTER_ROLE + '0x64c4Bffb220818F0f2ee6DAe7A2F17D92b359c5d' + ], + description: 'Grant Tribe dev, Tom, POD_METADATA_REGISTER_ROLE to register proposal metadata' + }, + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: [ + '0xf62a46a499242191aaab61084d4912c2c0a8c48e3d70edfb5a9be2bc9e92622f', // POD_METADATA_REGISTER_ROLE + '0x5346b4ff3e924508d33d93f352d11e392a7a9d3b' + ], + description: 'Grant Tribe dev, Caleb, POD_METADATA_REGISTER_ROLE to register proposal metadata' + }, + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: [ + '0xf62a46a499242191aaab61084d4912c2c0a8c48e3d70edfb5a9be2bc9e92622f', // POD_METADATA_REGISTER_ROLE + '0xcE96fE7Eb7186E9F894DE7703B4DF8ea60E2dD77' + ], + description: 'Grant Tribe dev, Erwan, POD_METADATA_REGISTER_ROLE to register proposal metadata' + }, + { + target: 'core', + values: '0', + method: 'grantRole(bytes32,address)', + arguments: [ + '0xf62a46a499242191aaab61084d4912c2c0a8c48e3d70edfb5a9be2bc9e92622f', // POD_METADATA_REGISTER_ROLE + '0xE2388f22cf5e328C197D6530663809cc0408a510' + ], + description: 'Grant Tribe dev, Joey, POD_METADATA_REGISTER_ROLE to register proposal metadata' + } + ], + description: ` + Grant Tribe engineers the POD_METADATA_REGISTER_ROLE so they are able to register pod proposal metadata + ` +}; + +export default register_proposal; diff --git a/proposals/description/old/withdraw_d3_pool.ts b/proposals/description/old/withdraw_d3_pool.ts new file mode 100644 index 000000000..d803d9b53 --- /dev/null +++ b/proposals/description/old/withdraw_d3_pool.ts @@ -0,0 +1,29 @@ +import { ProposalDescription } from '@custom-types/types'; + +const fip_x: ProposalDescription = { + // Curve/Convex reports balance in USD + title: 'Withdraw from the D3Pool', + commands: [ + { + target: 'pcvGuardianNew', + values: '0', + method: 'withdrawToSafeAddress(address,address,uint256,bool,bool)', + arguments: ['{d3poolConvexPCVDeposit}', '{d3poolCurvePCVDeposit}', '30000000000000000000000000', false, false], + description: 'Withdraw 30M USD worth of LP tokens to the d3PoolCurvePCVDeposit' + }, + { + target: 'pcvGuardianNew', + values: '0', + method: 'withdrawToSafeAddress(address,address,uint256,bool,bool)', + arguments: ['{d3poolCurvePCVDeposit}', '{daiFixedPricePSM}', '10000000000000000000000000', false, false], + description: 'Withdraw 10M worth of Fei from the Curve D3 pool to the DAI PSM' + } + ], + description: ` + Withdraw 30M USD worth of LP tokens from the d3 pool on Curve. + + Send the LP tokens to the d3PoolCurvePCVDeposit and then withdraw 10M FEI from the pool to the DAI PSM. + ` +}; + +export default fip_x; diff --git a/proposals/description/repay_fuse_bad_debt.ts b/proposals/description/repay_fuse_bad_debt.ts new file mode 100644 index 000000000..782f438bd --- /dev/null +++ b/proposals/description/repay_fuse_bad_debt.ts @@ -0,0 +1,97 @@ +import { MainnetAddresses } from '@custom-types/contracts'; +import { ProposalDescription, TemplatedProposalDescription } from '@custom-types/types'; + +const fip_x: TemplatedProposalDescription = { + title: 'Repay Fuse Bad Debt', + commands: [ + { + target: 'pcvGuardianNew', + values: '0', + method: 'setSafeAddress(address)', + arguments: (addresses) => [addresses.fuseFixer], + description: 'Set FuseFixer as a safe address' + } + ], + description: 'Set FuseFixer as a safe address' +}; + +export default fip_x; + +/*const fip_x: ProposalDescription = { + title: 'Repay Fuse Bad Debt', + commands: [ + { + target: 'fuseFixer', + values: '0', + method: 'repayAll()', + arguments: [], + description: 'Repay all bad debt in Fuse pools 8, 18, 27, 127, 144, 146, 156' + } + ], + description: 'Repay all bad debt in Fuse pools 8, 18, 27, 127, 144, 146, 156' +}; + + /* + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0x0000000000000000000000000000000000000000', '6500000000000000000000'], + description: 'Repay ETH' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0x956F47F50A910163D8BF957Cf5846D573E7f87CA', '21000000000000000000000000'], + description: 'Repay FEI' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0x853d955aCEf822Db058eb8505911ED77F175b99e', '14000000000000000000000000'], + description: 'Repay FRAX' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', '32000000000000000000000'], + description: 'Repay RAI' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0x6B175474E89094C44Da98b954EedeAC495271d0F', '15000000000000000000000000'], + description: 'Repay DAI' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', '11000000000000'], + description: 'Repay USDC' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0x5f98805A4E8be255a32880FDeC7F6728C6568bA0', '2000000000000000000000000'], + description: 'Repay LUSD' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0xa693B19d2931d498c5B318dF961919BB4aee87a5', '3000000000000'], + description: 'Repay USTw' + }, + { + target: 'fuseFixer', + values: '0', + method: 'repay(address,uint256)', + arguments: ['0xdAC17F958D2ee523a2206206994597C13D831ec7', '150000000000'], + description: 'Repay USDT' + }*/ diff --git a/proposals/description/tokemak_withdraw.ts b/proposals/description/tokemak_withdraw.ts new file mode 100644 index 000000000..0a8640f55 --- /dev/null +++ b/proposals/description/tokemak_withdraw.ts @@ -0,0 +1,21 @@ +import { TemplatedProposalDescription } from '@custom-types/types'; + +const tokemak_withdraw: TemplatedProposalDescription = { + title: 'Withdraw from Tokemak', + commands: [ + { + target: 'ethTokemakPCVDeposit', + values: '0', + method: 'requestWithdrawal(uint256)', + arguments: (addresses) => ['10000000000000000000000'], + description: 'Request to withdraw 10K WETH from Tokemak in the next cycle' + } + ], + description: ` + FIP 111: Request withdrawal from Tokemak + + Request a withdrawal of 10k ETH from Tokemak in the next cycle. + ` +}; + +export default tokemak_withdraw; diff --git a/protocol-configuration/collateralizationOracle.ts b/protocol-configuration/collateralizationOracle.ts index e748be1be..1f1ac50e3 100644 --- a/protocol-configuration/collateralizationOracle.ts +++ b/protocol-configuration/collateralizationOracle.ts @@ -1,25 +1,21 @@ -const collateralizationAddresses = { +const collateralizationAddresses: CollateralizationAddressType = { fei: [ 'feiOATimelockWrapper', 'rariPool6FeiPCVDepositWrapper', 'rariPool19FeiPCVDepositWrapper', 'rariPool24FeiPCVDepositWrapper', - 'rariPool25FeiPCVDepositWrapper', 'aaveFeiPCVDepositWrapper', 'rariPool79FeiPCVDepositWrapper', - 'rariPool31FeiPCVDepositWrapper', - 'rariPool72FeiPCVDepositWrapper', 'rariPool128FeiPCVDepositWrapper', 'rariPool22FeiPCVDepositWrapper', 'feiBuybackLensNoFee', 'compoundFeiPCVDepositWrapper', 'turboFusePCVDeposit' ], - lusd: ['liquityFusePoolLusdPCVDeposit', 'rariPool7LusdPCVDeposit', 'bammDeposit', 'lusdPSM'], - dai: ['compoundDaiPCVDepositWrapper', 'daiFixedPricePSM'], + lusd: ['rariPool7LusdPCVDeposit', 'bammDeposit', 'lusdPSM'], + dai: ['compoundDaiPCVDepositWrapper', 'daiFixedPricePSM', 'dpiToDaiLensDai'], usd: ['namedStaticPCVDepositWrapper', 'd3poolCurvePCVDeposit', 'd3poolConvexPCVDeposit'], - bal: ['balancerDepositBalWeth', 'balancerLensVeBalBal'], - cream: ['creamDepositWrapper'], + bal: ['balancerDepositBalWeth', 'balancerLensVeBalBal', 'balancerGaugeStaker'], weth: [ 'ethLidoPCVDepositWrapper', 'compoundEthPCVDepositWrapper', @@ -32,10 +28,12 @@ const collateralizationAddresses = { 'balancerLensBpt30Fei70Weth', 'balancerLensVeBalWeth' ], - dpi: ['rariPool19DpiPCVDepositWrapper', 'dpiDepositWrapper'], - rai: ['rariPool9RaiPCVDepositWrapper', 'aaveRaiPCVDepositWrapper', 'raiDepositWrapper', 'raiPriceBoundPSM'], + dpi: ['dpiToDaiLensDpi'], + rai: ['raiPriceBoundPSM'], agEUR: ['agEurDepositWrapper', 'uniswapLensAgEurUniswapGauge', 'agEurUniswapPCVDeposit'], volt: ['voltDepositWrapper'] }; +export type CollateralizationAddressType = { [key: string]: string[] }; + export default collateralizationAddresses; diff --git a/protocol-configuration/dependencies.ts b/protocol-configuration/dependencies.ts deleted file mode 100644 index 95e70277b..000000000 --- a/protocol-configuration/dependencies.ts +++ /dev/null @@ -1,1079 +0,0 @@ -import { DependencyMap } from '../types/types'; - -const dependencies: DependencyMap = { - angleDelegatorPCVDeposit: { - contractDependencies: ['core', 'gaugeLensAgEurUniswapGauge'] - }, - gaugeLensAgEurUniswapGauge: { - contractDependencies: ['angleDelegatorPCVDeposit', 'uniswapLensAgEurUniswapGauge'] - }, - uniswapLensAgEurUniswapGauge: { - contractDependencies: ['core', 'gaugeLensAgEurUniswapGauge', 'chainlinkEurUsdOracleWrapper'] - }, - collateralizationOracleGuardian: { - contractDependencies: ['core', 'guardian', 'collateralizationOracleWrapper'] - }, - restrictedPermissions: { - contractDependencies: ['fei', 'core'] - }, - rariInfraTribeTimelock: { - contractDependencies: ['tribe'] - }, - rariInfraFeiTimelock: { - contractDependencies: ['fei'] - }, - laTribuFeiTimelock: { - contractDependencies: ['fei'] - }, - laTribuTribeTimelock: { - contractDependencies: ['tribe'] - }, - core: { - contractDependencies: [ - 'raiPriceBoundPSM', - 'raiPCVDripController', - 'collateralizationOracleGuardian', - 'fei', - 'feiTribeLBPSwapper', - 'optimisticMinter', - 'pcvEquityMinter', - 'pcvGuardianNew', - 'ratioPCVControllerV2', - 'tribe', - 'tribeMinter', - 'feiDAOTimelock', - 'guardian', - 'optimisticTimelock', - 'aaveEthPCVDripController', - 'bammDeposit', - 'daiPCVDripController', - 'ethPSM', - 'lusdPSM', - 'daiFixedPricePSM', - 'lusdPCVDripController', - 'lusdPSMFeiSkimmer', - 'ethPSMFeiSkimmer', - 'tribeReserveStabilizer', - 'aaveEthPCVDeposit', - 'aaveFeiPCVDeposit', - 'aaveRaiPCVDeposit', - 'agEurAngleUniswapPCVDeposit', - 'agEurUniswapPCVDeposit', - 'balancerDepositBalWeth', - 'compoundDaiPCVDeposit', - 'compoundEthPCVDeposit', - 'd3poolConvexPCVDeposit', - 'd3poolCurvePCVDeposit', - 'ethLidoPCVDeposit', - 'ethTokemakPCVDeposit', - 'feiLusdLBPSwapper', - 'indexCoopFusePoolDpiPCVDeposit', - 'indexCoopFusePoolFeiPCVDeposit', - 'indexDelegator', - 'liquityFusePoolLusdPCVDeposit', - 'poolPartyFeiPCVDeposit', - 'rariTimelock', - 'rariPool146EthPCVDeposit', - 'rariPool18FeiPCVDeposit', - 'rariPool19DpiPCVDeposit', - 'rariPool19FeiPCVDeposit', - 'rariPool22FeiPCVDeposit', - 'rariPool24FeiPCVDeposit', - 'rariPool25FeiPCVDeposit', - 'rariPool26FeiPCVDeposit', - 'rariPool27FeiPCVDeposit', - 'rariPool31FeiPCVDeposit', - 'rariPool54FeiPCVDeposit', - 'rariPool6FeiPCVDeposit', - 'rariPool72FeiPCVDeposit', - 'rariPool79FeiPCVDeposit', - 'rariPool7FeiPCVDeposit', - 'rariPool7LusdPCVDeposit', - 'rariPool8FeiPCVDeposit', - 'rariPool90FeiPCVDeposit', - 'rariPool91FeiPCVDeposit', - 'rariPool9FeiPCVDeposit', - 'rariPool9RaiPCVDeposit', - 'reflexerStableAssetFusePoolRaiPCVDeposit', - 'tokeTokemakPCVDeposit', - 'uniswapPCVDeposit', - 'collateralizationOracle', - 'collateralizationOracleWrapper', - 'namedStaticPCVDepositWrapper', - 'balUsdCompositeOracle', - 'chainlinkBALEthOracle', - 'chainlinkCREAMEthOracle', - 'chainlinkDaiUsdOracleWrapper', - 'chainlinkDpiUsdOracleWrapper', - 'chainlinkEthUsdOracleWrapper', - 'chainlinkEurUsdOracleWrapper', - 'chainlinkFeiEthOracleWrapper', - 'chainlinkLUSDOracleWrapper', - 'chainlinkRaiEthOracleWrapper', - 'chainlinkRaiUsdCompositeOracle', - 'chainlinkTribeEthOracleWrapper', - 'compositeOracle', - 'creamUsdCompositeOracle', - 'oneConstantOracle', - 'tribeUsdCompositeOracle', - 'zeroConstantOracle', - 'collateralizationOracleKeeper', - 'autoRewardsDistributor', - 'erc20Dripper', - 'tribalChief', - 'fuseAdmin', - 'fuseGuardian', - 'restrictedPermissions', - 'balancerDepositFeiWeth', - 'delayedPCVMoverWethUniToBal', - 'angleDelegatorPCVDeposit', - 'uniswapLensAgEurUniswapGauge', - 'veBalDelegatorPCVDeposit', - 'uniswapLensAgEurUniswapGauge', - 'governanceMetadataRegistry', - 'nopeDAO', - 'podAdminGateway', - 'podFactory', - 'roleBastion' - ] - }, - fei: { - contractDependencies: [ - 'raiPriceBoundPSM', - 'raiPCVDripController', - 'core', - 'rariPool8Fei', - 'feiDAOTimelock', - 'collateralizationOracleKeeper', - 'aaveEthPCVDripController', - 'ethPSM', - 'lusdPSM', - 'daiFixedPricePSM', - 'daiPCVDripController', - 'lusdPSMFeiSkimmer', - 'aaveFeiPCVDeposit', - 'agEurAngleUniswapPCVDeposit', - 'indexCoopFusePoolFeiPCVDeposit', - 'poolPartyFeiPCVDeposit', - 'rariPool18FeiPCVDeposit', - 'rariPool19FeiPCVDeposit', - 'rariPool22FeiPCVDeposit', - 'rariPool24FeiPCVDeposit', - 'rariPool25FeiPCVDeposit', - 'rariPool26FeiPCVDeposit', - 'rariPool27FeiPCVDeposit', - 'rariPool31FeiPCVDeposit', - 'rariPool54FeiPCVDeposit', - 'rariPool6FeiPCVDeposit', - 'rariPool72FeiPCVDeposit', - 'rariPool79FeiPCVDeposit', - 'rariPool7FeiPCVDeposit', - 'rariPool8FeiPCVDeposit', - 'rariPool90FeiPCVDeposit', - 'rariPool91FeiPCVDeposit', - 'rariPool9FeiPCVDeposit', - 'restrictedPermissions', - 'ethPSMFeiSkimmer', - 'rariInfraFeiTimelock', - 'reptbRedeemer', - 'laTribuFeiTimelock', - 'voltFeiSwapContract' - ] - }, - ethPSMFeiSkimmer: { - contractDependencies: ['fei', 'ethPSM', 'core'] - }, - lusdPSMFeiSkimmer: { - contractDependencies: ['fei', 'lusdPSM', 'core'] - }, - feiTribeLBPSwapper: { - contractDependencies: ['core', 'pcvEquityMinter'] - }, - optimisticMinter: { - contractDependencies: ['core', 'optimisticTimelock'] - }, - pcvEquityMinter: { - contractDependencies: ['core', 'collateralizationOracleWrapper', 'feiTribeLBPSwapper'] - }, - pcvGuardianNew: { - contractDependencies: [ - 'core', - 'guardian', - 'feiDAOTimelock', - 'ethPSM', - 'lusdPSM', - 'daiFixedPricePSM', - 'compoundEthPCVDeposit', - 'aaveEthPCVDeposit', - 'aaveRaiPCVDeposit', - 'raiPriceBoundPSM' - ] - }, - raiPriceBoundPSM: { - contractDependencies: ['core', 'fei', 'raiPCVDripController', 'pcvGuardianNew'] - }, - proxyAdmin: { - contractDependencies: [ - 'feiDAOTimelock', - 'aaveTribeIncentivesController', - 'tribalChief', - 'collateralizationOracleWrapper' - ] - }, - ratioPCVControllerV2: { - contractDependencies: ['core', 'delayedPCVMoverWethUniToBal'] - }, - tribe: { - contractDependencies: [ - 'core', - 'rariPool8Tribe', - 'feiDAO', - 'tribeRariDAO', - 'erc20Dripper', - 'aaveTribeIncentivesController', - 'tribeMinter', - 'tribeReserveStabilizer', - 'rariPool8Fei3Crv', - 'rariPool8d3', - 'rariInfraTribeTimelock', - 'pegExchanger', - 'laTribuTribeTimelock', - 'nopeDAO' - ] - }, - tribeMinter: { - contractDependencies: ['core', 'tribeReserveStabilizer', 'tribe', 'erc20Dripper', 'feiDAOTimelock' /* Owner */] - }, - feiDAO: { - contractDependencies: ['feiDAOTimelock', 'tribe'] - }, - feiDAOTimelock: { - contractDependencies: [ - 'core', - 'feiDAO', - 'fei', - 'proxyAdmin', - 'creamDepositWrapper', - 'wethDepositWrapper', - 'dpiDepositWrapper', - 'raiDepositWrapper', - 'agEurDepositWrapper', - 'aaveTribeIncentivesController', - 'tribeMinter', - 'timelock', - 'pcvGuardianNew', - 'pegExchanger', - 'voltFeiSwapContract', - 'voltDepositWrapper' - ] - }, - guardian: { - contractDependencies: ['core', 'collateralizationOracleGuardian', 'pcvGuardianNew', 'fuseGuardian', 'fuseAdmin'] - }, - optimisticMultisig: { - contractDependencies: ['optimisticTimelock'] - }, - opsOptimisticTimelock: { - contractDependencies: ['votiumBriberD3pool', 'votiumBriber3Crvpool'] - }, - optimisticTimelock: { - contractDependencies: [ - 'core', - 'rewardsDistributorAdmin', - 'tribalChiefSyncV2', - 'rariPool8Comptroller', - 'optimisticMultisig', - 'optimisticMinter', - 'tribalChief', - 'collateralizationOracle', - 'collateralizationOracleWrapper', - 'namedStaticPCVDepositWrapper', - 'rariPool8MasterOracle' - ] - }, - rariTimelock: { - contractDependencies: ['tribeRariDAO', 'core'] - }, - tribeRariDAO: { - contractDependencies: ['rariTimelock', 'tribe'] - }, - aaveEthPCVDripController: { - contractDependencies: ['core', 'fei', 'aaveEthPCVDeposit', 'ethPSM'] - }, - daiPCVDripController: { - contractDependencies: ['core', 'fei', 'daiFixedPricePSM', 'compoundDaiPCVDeposit'] - }, - raiPCVDripController: { - contractDependencies: ['core', 'fei', 'aaveRaiPCVDeposit', 'raiPriceBoundPSM'] - }, - daiFixedPricePSM: { - contractDependencies: [ - 'core', - 'fei', - 'compoundDaiPCVDeposit', - 'daiPCVDripController', - 'chainlinkDaiUsdOracleWrapper', - 'pcvGuardianNew' - ] - }, - lusdPSM: { - contractDependencies: [ - 'core', - 'fei', - 'bammDeposit', - 'chainlinkLUSDOracleWrapper', - 'pcvGuardianNew', - 'lusdPCVDripController', - 'lusdPSMFeiSkimmer' - ] - }, - lusdPCVDripController: { - contractDependencies: ['lusdPSM', 'core', 'bammDeposit'] - }, - bammDeposit: { - contractDependencies: ['lusdPSM', 'core', 'lusdPCVDripController'] - }, - ethPSM: { - contractDependencies: [ - 'core', - 'fei', - 'aaveEthPCVDeposit', - 'chainlinkEthUsdOracleWrapper', - 'pcvGuardianNew', - 'aaveEthPCVDripController', - 'ethPSMRouter', - 'ethPSMFeiSkimmer' - ] - }, - ethPSMRouter: { - contractDependencies: ['ethPSM'] - }, - tribeReserveStabilizer: { - contractDependencies: ['core', 'tribeUsdCompositeOracle', 'tribeMinter', 'collateralizationOracleWrapper', 'tribe'] - }, - aaveEthPCVDeposit: { - contractDependencies: ['core', 'aaveEthPCVDripController', 'pcvGuardianNew', 'ethPSM'] - }, - aaveFeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - aaveRaiPCVDeposit: { - contractDependencies: ['core', 'pcvGuardianNew', 'raiPCVDripController'] - }, - agEurAngleUniswapPCVDeposit: { - contractDependencies: ['core', 'fei', 'chainlinkEurUsdOracleWrapper'] - }, - agEurUniswapPCVDeposit: { - contractDependencies: ['core', 'chainlinkEurUsdOracleWrapper'] - }, - balancerDepositBalWeth: { - contractDependencies: ['core', 'balUsdCompositeOracle', 'chainlinkEthUsdOracleWrapper'] - }, - compoundDaiPCVDeposit: { - contractDependencies: ['core', 'daiPCVDripController', 'daiFixedPricePSM'] - }, - compoundEthPCVDeposit: { - contractDependencies: ['core', 'pcvGuardianNew'] - }, - d3poolConvexPCVDeposit: { - contractDependencies: ['core'] - }, - d3poolCurvePCVDeposit: { - contractDependencies: ['core'] - }, - ethLidoPCVDeposit: { - contractDependencies: ['core'] - }, - ethTokemakPCVDeposit: { - contractDependencies: ['core'] - }, - feiLusdLBPSwapper: { - contractDependencies: ['core', 'chainlinkLUSDOracleWrapper'] - }, - indexCoopFusePoolDpiPCVDeposit: { - contractDependencies: ['core'] - }, - indexCoopFusePoolFeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - indexDelegator: { - contractDependencies: ['core'] - }, - liquityFusePoolLusdPCVDeposit: { - contractDependencies: ['core'] - }, - poolPartyFeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool146EthPCVDeposit: { - contractDependencies: ['core', 'rariPool146Eth'] - }, - rariPool146Comptroller: { - contractDependencies: ['rariPool146FuseAdmin', 'rariPool146Eth'] - }, - rariPool146FuseAdmin: { - contractDependencies: ['rariPool146Comptroller'] - }, - rariPool146Eth: { - contractDependencies: ['rariPool146Comptroller', 'rariPool146EthPCVDeposit'] - }, - rariPool18FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool19DpiPCVDeposit: { - contractDependencies: ['core'] - }, - rariPool19FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool22FeiPCVDeposit: { - contractDependencies: ['core', 'fei', 'rariPool22FeiPCVDepositWrapper'] - }, - rariPool24FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool25FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool26FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool27FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool31FeiPCVDeposit: { - contractDependencies: ['core', 'fei', 'rariPool31FeiPCVDepositWrapper'] - }, - rariPool54FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool6FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool72FeiPCVDeposit: { - contractDependencies: ['core', 'fei', 'rariPool72FeiPCVDepositWrapper'] - }, - rariPool79FeiPCVDeposit: { - contractDependencies: ['core', 'fei', 'rariPool79FeiPCVDepositWrapper'] - }, - rariPool7FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool7LusdPCVDeposit: { - contractDependencies: ['core'] - }, - rariPool8FeiPCVDeposit: { - contractDependencies: ['core', 'rariPool8Fei', 'fei'] - }, - rariPool90FeiPCVDeposit: { - contractDependencies: ['core', 'fei', 'rariPool90FeiPCVDepositWrapper'] - }, - rariPool91FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool9FeiPCVDeposit: { - contractDependencies: ['core', 'fei'] - }, - rariPool9RaiPCVDeposit: { - contractDependencies: ['core'] - }, - reflexerStableAssetFusePoolRaiPCVDeposit: { - contractDependencies: ['core'] - }, - tokeTokemakPCVDeposit: { - contractDependencies: ['core'] - }, - uniswapPCVDeposit: { - contractDependencies: ['core', 'chainlinkEthUsdOracleWrapper'] - }, - aaveEthPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - aaveFeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - aaveRaiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - collateralizationOracle: { - contractDependencies: [ - 'core', - 'optimisticTimelock', - 'balUsdCompositeOracle', - 'chainlinkDaiUsdOracleWrapper', - 'chainlinkDpiUsdOracleWrapper', - 'chainlinkEthUsdOracleWrapper', - 'chainlinkEurUsdOracleWrapper', - 'chainlinkLUSDOracleWrapper', - 'chainlinkRaiUsdCompositeOracle', - 'creamUsdCompositeOracle', - 'oneConstantOracle', - 'zeroConstantOracle', - 'aaveEthPCVDepositWrapper', - 'aaveFeiPCVDepositWrapper', - 'aaveRaiPCVDepositWrapper', - 'compoundDaiPCVDepositWrapper', - 'compoundEthPCVDepositWrapper', - 'creamDepositWrapper', - 'wethDepositWrapper', - 'dpiDepositWrapper', - 'raiDepositWrapper', - 'agEurDepositWrapper', - 'ethLidoPCVDepositWrapper', - 'feiBuybackLens', - 'feiLusdLens', - 'feiOATimelockWrapper', - 'rariPool18FeiPCVDepositWrapper', - 'rariPool19DpiPCVDepositWrapper', - 'rariPool19FeiPCVDepositWrapper', - 'rariPool24FeiPCVDepositWrapper', - 'rariPool25FeiPCVDepositWrapper', - 'rariPool27FeiPCVDepositWrapper', - 'rariPool31FeiPCVDepositWrapper', - 'rariPool6FeiPCVDepositWrapper', - 'rariPool8FeiPCVDepositWrapper', - 'rariPool9RaiPCVDepositWrapper', - 'rariPool90FeiPCVDepositWrapper', - 'rariPool79FeiPCVDepositWrapper', - 'rariPool72FeiPCVDepositWrapper', - 'rariPool128FeiPCVDepositWrapper', - 'rariPool22FeiPCVDepositWrapper', - 'rariPool8LusdPCVDeposit', - 'rariPool8DaiPCVDeposit', - 'voltFusePCVDeposit', - 'voltOracle', - 'turboFusePCVDeposit', - 'voltDepositWrapper' - ] - }, - collateralizationOracleWrapper: { - contractDependencies: [ - 'core', - 'optimisticTimelock', - 'collateralizationOracleKeeper', - 'collateralizationOracleGuardian', - 'collateralizationOracleWrapperImpl', - 'tribeReserveStabilizer', - 'pcvEquityMinter', - 'proxyAdmin' - ] - }, - collateralizationOracleWrapperImpl: { - contractDependencies: ['collateralizationOracleWrapper'] - }, - compoundDaiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - compoundEthPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - creamDepositWrapper: { - contractDependencies: ['feiDAOTimelock', 'collateralizationOracle'] - }, - wethDepositWrapper: { - contractDependencies: ['feiDAOTimelock', 'collateralizationOracle'] - }, - dpiDepositWrapper: { - contractDependencies: ['feiDAOTimelock', 'collateralizationOracle'] - }, - raiDepositWrapper: { - contractDependencies: ['feiDAOTimelock', 'collateralizationOracle'] - }, - agEurDepositWrapper: { - contractDependencies: ['feiDAOTimelock', 'collateralizationOracle'] - }, - ethLidoPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - feiBuybackLens: { - contractDependencies: ['collateralizationOracle'] - }, - feiLusdLens: { - contractDependencies: ['collateralizationOracle'] - }, - feiOATimelockWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool18FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool19DpiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool19FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool24FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool25FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool27FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool31FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle', 'rariPool31FeiPCVDeposit'] - }, - rariPool6FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool90FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle', 'rariPool90FeiPCVDeposit'] - }, - rariPool79FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle', 'rariPool79FeiPCVDeposit'] - }, - rariPool72FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle', 'rariPool72FeiPCVDeposit'] - }, - rariPool128FeiPCVDeposit: { - contractDependencies: ['rariPool128FeiPCVDepositWrapper'] - }, - rariPool128FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle', 'rariPool128FeiPCVDeposit'] - }, - rariPool22FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle', 'rariPool22FeiPCVDeposit'] - }, - rariPool8FeiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - rariPool9RaiPCVDepositWrapper: { - contractDependencies: ['collateralizationOracle'] - }, - namedStaticPCVDepositWrapper: { - contractDependencies: ['core', 'optimisticTimelock'] - }, - balUsdCompositeOracle: { - contractDependencies: [ - 'core', - 'chainlinkBALEthOracle', - 'chainlinkEthUsdOracleWrapper', - 'collateralizationOracle', - 'balancerDepositBalWeth', - 'balancerLensVeBalBal', - 'balancerLensVeBalWeth' - ] - }, - balancerLensVeBalBal: { - contractDependencies: ['balUsdCompositeOracle', 'chainlinkEthUsdOracleWrapper'] - }, - chainlinkBALEthOracle: { - contractDependencies: ['core', 'balUsdCompositeOracle'] - }, - chainlinkCREAMEthOracle: { - contractDependencies: ['core', 'creamUsdCompositeOracle'] - }, - chainlinkDaiUsdOracleWrapper: { - contractDependencies: ['core', 'collateralizationOracle', 'daiFixedPricePSM'] - }, - chainlinkDpiUsdOracleWrapper: { - contractDependencies: ['core', 'collateralizationOracle'] - }, - chainlinkEthUsdOracleWrapper: { - contractDependencies: [ - 'core', - 'ethPSM', - 'compositeOracle', - 'tribeUsdCompositeOracle', - 'chainlinkRaiUsdCompositeOracle', - 'creamUsdCompositeOracle', - 'balUsdCompositeOracle', - 'collateralizationOracle', - 'uniswapPCVDeposit', - 'balancerDepositBalWeth', - 'balancerDepositFeiWeth', - 'balancerLensBpt30Fei70Weth', - 'balancerLensVeBalBal', - 'balancerLensVeBalWeth' - ] - }, - chainlinkEurUsdOracleWrapper: { - contractDependencies: [ - 'core', - 'collateralizationOracle', - 'agEurAngleUniswapPCVDeposit', - 'agEurUniswapPCVDeposit', - 'uniswapLensAgEurUniswapGauge' - ] - }, - chainlinkFeiEthOracleWrapper: { - contractDependencies: ['core'] - }, - chainlinkLUSDOracleWrapper: { - contractDependencies: ['core', 'collateralizationOracle', 'feiLusdLBPSwapper', 'lusdPSM'] - }, - chainlinkRaiEthOracleWrapper: { - contractDependencies: ['core', 'chainlinkRaiUsdCompositeOracle'] - }, - chainlinkRaiUsdCompositeOracle: { - contractDependencies: [ - 'core', - 'chainlinkEthUsdOracleWrapper', - 'chainlinkRaiEthOracleWrapper', - 'collateralizationOracle' - ] - }, - chainlinkTribeEthOracleWrapper: { - contractDependencies: ['core', 'tribeUsdCompositeOracle', 'compositeOracle'] - }, - compositeOracle: { - contractDependencies: ['core', 'chainlinkEthUsdOracleWrapper', 'chainlinkTribeEthOracleWrapper'] - }, - creamUsdCompositeOracle: { - contractDependencies: ['core', 'chainlinkEthUsdOracleWrapper', 'chainlinkCREAMEthOracle', 'collateralizationOracle'] - }, - oneConstantOracle: { - contractDependencies: ['core', 'collateralizationOracle', 'balancerDepositFeiWeth', 'balancerLensBpt30Fei70Weth'] - }, - tribeUsdCompositeOracle: { - contractDependencies: [ - 'core', - 'chainlinkTribeEthOracleWrapper', - 'chainlinkEthUsdOracleWrapper', - 'tribeReserveStabilizer' - ] - }, - zeroConstantOracle: { - contractDependencies: ['core', 'collateralizationOracle'] - }, - collateralizationOracleKeeper: { - contractDependencies: ['core', 'collateralizationOracleWrapper', 'fei'] - }, - aaveTribeIncentivesController: { - contractDependencies: ['aaveTribeIncentivesControllerImpl', 'tribe', 'feiDAOTimelock', 'proxyAdmin'] // NOTE uses old timelock - }, - aaveTribeIncentivesControllerImpl: { - contractDependencies: ['aaveTribeIncentivesController'] - }, - autoRewardsDistributor: { - contractDependencies: ['core', 'rewardsDistributorAdmin', 'tribalChiefSyncV2', 'tribalChief', 'rariPool8Tribe'] - }, - erc20Dripper: { - contractDependencies: ['core', 'tribe', 'tribalChief', 'tribeMinter'] - }, - rariRewardsDistributorDelegate: { - contractDependencies: [ - 'rariRewardsDistributorDelegator' // proxy - ] - }, - rariRewardsDistributorDelegator: { - contractDependencies: [ - 'rariPool8Tribe', - 'rariRewardsDistributorDelegate', // impl - 'rewardsDistributorAdmin', //admin - 'rariPool8Comptroller', - 'fei3CrvStakingtokenWrapper', - 'd3StakingTokenWrapper', - 'rariPool8Fei3Crv', - 'rariPool8d3', - 'feiDaiStakingTokenWrapper', - 'feiUsdcStakingTokenWrapper' - ] - }, - fei3CrvAutoRewardsDistributor: { - contractDependencies: ['fei3CrvStakingtokenWrapper', 'tribalChief', 'rewardsDistributorAdmin', 'rariPool8Fei3Crv'] - }, - d3AutoRewardsDistributor: { - contractDependencies: ['d3StakingTokenWrapper', 'tribalChief', 'rewardsDistributorAdmin', 'rariPool8d3'] - }, - feiDaiAutoRewardsDistributor: { - contractDependencies: ['feiDaiStakingTokenWrapper', 'tribalChief', 'rewardsDistributorAdmin'] - }, - feiUsdcAutoRewardsDistributor: { - contractDependencies: ['feiUsdcStakingTokenWrapper', 'tribalChief', 'rewardsDistributorAdmin'] - }, - fei3CrvStakingtokenWrapper: { - contractDependencies: ['fei3CrvAutoRewardsDistributor', 'tribalChief', 'rariRewardsDistributorDelegator'] - }, - feiDaiStakingTokenWrapper: { - contractDependencies: ['feiDaiAutoRewardsDistributor', 'tribalChief', 'rariRewardsDistributorDelegator'] - }, - feiUsdcStakingTokenWrapper: { - contractDependencies: ['feiUsdcAutoRewardsDistributor', 'tribalChief', 'rariRewardsDistributorDelegator'] - }, - d3StakingTokenWrapper: { - contractDependencies: ['d3AutoRewardsDistributor', 'tribalChief', 'rariRewardsDistributorDelegator'] - }, - rewardsDistributorAdmin: { - contractDependencies: [ - 'rariRewardsDistributorDelegator', - 'optimisticTimelock', - 'autoRewardsDistributor', // rewards dripper role - 'fei3CrvAutoRewardsDistributor', - 'd3AutoRewardsDistributor', - 'feiDaiAutoRewardsDistributor', - 'feiUsdcAutoRewardsDistributor' - ] - }, - stwBulkHarvest: { - contractDependencies: [ - 'stakingTokenWrapperFOXLaaS', - 'stakingTokenWrapperBribeD3pool', - 'stakingTokenWrapperGROLaaS', - 'stakingTokenWrapperKYLINLaaS', - 'stakingTokenWrapperMStableLaaS', - 'stakingTokenWrapperNEARLaaS', - 'stakingTokenWrapperPoolTogetherLaaS', - 'stakingTokenWrapperRari', - 'stakingTokenWrapperSYNLaaS', - 'stakingTokenWrapperUMALaaS' - ] - }, - stakingTokenWrapperFOXLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperBribeD3pool: { - contractDependencies: ['tribalChief', 'votiumBriberD3pool', 'stwBulkHarvest'] - }, - stakingTokenWrapperGROLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperKYLINLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperMStableLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperNEARLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperPoolTogetherLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperRari: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperSYNLaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - stakingTokenWrapperUMALaaS: { - contractDependencies: ['tribalChief', 'stwBulkHarvest'] - }, - tribalChief: { - contractDependencies: [ - 'core', - 'autoRewardsDistributor', - 'tribalChiefSyncV2', - 'optimisticTimelock', - 'erc20Dripper', - 'stakingTokenWrapperBribeD3pool', - 'stakingTokenWrapperFOXLaaS', - 'stakingTokenWrapperGROLaaS', - 'stakingTokenWrapperKYLINLaaS', - 'stakingTokenWrapperMStableLaaS', - 'stakingTokenWrapperNEARLaaS', - 'stakingTokenWrapperPoolTogetherLaaS', - 'stakingTokenWrapperRari', - 'stakingTokenWrapperSYNLaaS', - 'stakingTokenWrapperUMALaaS', - 'tribalChiefImpl', - 'proxyAdmin', - 'fei3CrvAutoRewardsDistributor', - 'd3AutoRewardsDistributor', - 'fei3CrvStakingtokenWrapper', - 'd3StakingTokenWrapper', - 'feiDaiStakingTokenWrapper', - 'feiUsdcStakingTokenWrapper', - 'feiDaiAutoRewardsDistributor', - 'feiUsdcAutoRewardsDistributor' - ] - }, - tribalChiefImpl: { - contractDependencies: ['tribalChief'] - }, - tribalChiefSyncV2: { - contractDependencies: [ - 'autoRewardsDistributor', // triggers autoRewardsDistributor after updates - 'optimisticTimelock', // executes atomic updates - 'tribalChief' // mass updates pools - ] - }, - votiumBriberD3pool: { - contractDependencies: ['stakingTokenWrapperBribeD3pool', 'opsOptimisticTimelock'] - }, - votiumBriber3Crvpool: { - contractDependencies: ['opsOptimisticTimelock'] - }, - rariPool8Comptroller: { - contractDependencies: [ - 'rariPool8Dai', - 'rariPool8Eth', - 'rariPool8Fei', - 'rariPool8Tribe', - 'rariPool8Lusd', - 'rariRewardsDistributorDelegator', // registered rewards distributor - 'optimisticTimelock', // admin - 'rariPool8MasterOracle', - 'fuseGuardian', - 'fuseAdmin', - 'rariPool8Fei3Crv', - 'rariPool8d3' - ] - }, - fuseAdmin: { - contractDependencies: ['core', 'rariPool8Comptroller', 'guardian'] - }, - fuseGuardian: { - contractDependencies: ['core', 'rariPool8Comptroller', 'guardian'] - }, - rariPool8MasterOracle: { - contractDependencies: ['gUniFuseOracle', 'optimisticTimelock', 'rariPool8Comptroller', 'curveLPTokenOracle'] - }, - gUniFuseOracle: { - contractDependencies: ['rariPool8MasterOracle'] - }, - curveLPTokenOracle: { - contractDependencies: ['rariPool8MasterOracle'] - }, - rariPool8Dai: { - contractDependencies: ['rariPool8Comptroller', 'rariPool8DaiIrm', 'rariPool8DaiPCVDeposit'] - }, - rariPool8DaiIrm: { - contractDependencies: ['rariPool8Dai'] - }, - rariPool8Eth: { - contractDependencies: ['rariPool8Comptroller', 'rariPool8EthIrm'] - }, - rariPool8EthIrm: { - contractDependencies: ['rariPool8Eth'] - }, - rariPool8Fei: { - contractDependencies: ['fei', 'rariPool8Comptroller', 'rariPool8FeiIrm', 'rariPool8FeiPCVDeposit'] - }, - rariPool8FeiIrm: { - contractDependencies: ['rariPool8Fei'] - }, - rariPool8CTokenImpl: { - contractDependencies: ['rariPool8Fei3Crv', 'rariPool8d3'] - }, - rariPool8Fei3Crv: { - contractDependencies: [ - 'rariPool8CTokenImpl', - 'tribe', - 'rariPool8Comptroller', - 'rariRewardsDistributorDelegator', - 'fei3CrvAutoRewardsDistributor' - ] - }, - rariPool8d3: { - contractDependencies: [ - 'rariPool8CTokenImpl', - 'tribe', - 'rariPool8Comptroller', - 'rariRewardsDistributorDelegator', - 'd3AutoRewardsDistributor' - ] - }, - rariPool8Tribe: { - contractDependencies: [ - 'tribe', - 'rariPool8Comptroller', - 'rariPool8TribeIrm', - 'rariRewardsDistributorDelegator', // Drips TRIBE rewards - 'autoRewardsDistributor' - ] - }, - rariPool8TribeIrm: { - contractDependencies: ['rariPool8Tribe'] - }, - reptbRedeemer: { - contractDependencies: ['fei'] - }, - pegExchanger: { - contractDependencies: ['tribe', 'feiDAOTimelock'] - }, - bbRedeemer: { - contractDependencies: [] - }, - idleRedeemer: { - contractDependencies: [] - }, - idleTranchesRedeemer: { - contractDependencies: [] - }, - kashiRedeemer: { - contractDependencies: [] - }, - weightedBalancerPoolManagerBase: { - contractDependencies: [] - }, - rariChainlinkPriceOracleV3: { - contractDependencies: [] - }, - balancerDepositFeiWeth: { - contractDependencies: ['core', 'oneConstantOracle', 'chainlinkEthUsdOracleWrapper'] - }, - delayedPCVMoverWethUniToBal: { - contractDependencies: ['core', 'ratioPCVControllerV2'] - }, - rariPool8DaiPCVDeposit: { - contractDependencies: ['rariPool8Dai', 'collateralizationOracle'] - }, - rariPool8LusdPCVDeposit: { - contractDependencies: ['rariPool8Lusd', 'collateralizationOracle'] - }, - rariPool8Lusd: { - contractDependencies: ['rariPool8LusdPCVDeposit', 'rariPool8Comptroller'] - }, - timelock: { - contractDependencies: ['feiDAOTimelock'] - }, - roleBastion: { - contractDependencies: ['core'] - }, - podFactory: { - contractDependencies: ['core', 'podExecutor', 'podAdminGateway'] - }, - podAdminGateway: { - contractDependencies: ['core', 'podFactory', 'tribalCouncilTimelock'] - }, - podExecutor: { - contractDependencies: ['podFactory', 'tribalCouncilTimelock'] - }, - nopeDAO: { - contractDependencies: ['core', 'tribe'] - }, - governanceMetadataRegistry: { - contractDependencies: ['core'] - }, - turboFusePCVDeposit: { - contractDependencies: ['collateralizationOracle'] - }, - voltFeiSwapContract: { - contractDependencies: ['fei', 'feiDAOTimelock'] - }, - voltDepositWrapper: { - contractDependencies: ['volt', 'feiDAOTimelock', 'collateralizationOracle', 'voltOracle'] - }, - volt: { - contractDependencies: ['voltDepositWrapper', 'voltOracle'] - }, - voltFusePCVDeposit: { - contractDependencies: ['collateralizationOracle'] - }, - voltOracle: { - contractDependencies: ['volt', 'voltDepositWrapper', 'collateralizationOracle'] - }, - tribalCouncilTimelock: { - contractDependencies: ['podExecutor', 'tribalCouncilSafe', 'podAdminGateway'] - }, - tribalCouncilSafe: { - contractDependencies: ['tribalCouncilTimelock'] - }, - veBalDelegatorPCVDeposit: { - contractDependencies: ['core'] - }, - balancerLensVeBalWeth: { - contractDependencies: ['balUsdCompositeOracle', 'chainlinkEthUsdOracleWrapper'] - }, - balancerLensBpt30Fei70Weth: { - contractDependencies: ['oneConstantOracle', 'chainlinkEthUsdOracleWrapper'] - }, - pcvGuardian: { - contractDependencies: [] - } -}; - -export default dependencies; diff --git a/protocol-configuration/mainnetAddresses.ts b/protocol-configuration/mainnetAddresses.ts index 5c3f82269..d82877d98 100644 --- a/protocol-configuration/mainnetAddresses.ts +++ b/protocol-configuration/mainnetAddresses.ts @@ -1,8 +1,8 @@ -import { MainnetAddresses, AddressCategory } from '../types/types'; // imported without custom path to allow docs to autogen without ts errors +import { MainnetContractsConfig, AddressCategory } from '../types/types'; // imported without custom path to allow docs to autogen without ts errors -const MainnetAddresses: MainnetAddresses = { +const MainnetContractsConfig: MainnetContractsConfig = { core: { - artifactName: AddressCategory.Core, + artifactName: 'Core', address: '0x8d5ED43dCa8C2F7dFB20CF7b53CC7E593635d7b9', category: AddressCategory.Core }, @@ -81,7 +81,7 @@ const MainnetAddresses: MainnetAddresses = { address: '0xd51dbA7a94e1adEa403553A8235C302cEbF41a3c', category: AddressCategory.Governance }, - guardian: { + guardianMultisig: { artifactName: 'unknown', address: '0xB8f482539F2d3Ae2C9ea6076894df36D1f632775', category: AddressCategory.Governance @@ -176,6 +176,46 @@ const MainnetAddresses: MainnetAddresses = { address: '0x2A188F9EB761F70ECEa083bA6c2A40145078dfc2', category: AddressCategory.Peg }, + dpiToDaiLBPSwapper: { + artifactName: 'BalancerLBPSwapper', + address: '0x05FD907528cf725C6F6d1D28E14619A313513Ba8', + category: AddressCategory.Core + }, + dpiToDaiLensDai: { + artifactName: 'BPTLens', + address: '0x3AA57FAf7114a9ebEbda73a997A35eAE06008A7B', + category: AddressCategory.PCV + }, + dpiToDaiLensDpi: { + artifactName: 'BPTLens', + address: '0xaDdB7eBdCA3fa3b72D2e57c8e660C90ec00af7Cc', + category: AddressCategory.PCV + }, + dpiToDaiLBPPool: { + artifactName: 'IWeightedPool', + address: '0xd10386804959a121a8a487e49f45aa9f5a2eb2a0', + category: AddressCategory.External + }, + ethToDaiLBPSwapper: { + artifactName: 'BalancerLBPSwapper', + address: '0xf7991f4698ffb6716982aec7f78964dd731c4a54', + category: AddressCategory.Core + }, + ethToDaiLensDai: { + artifactName: 'BPTLens', + address: '0xdF9Ff5c077d9F3427ade67AC2d27a864Be6F3187', + category: AddressCategory.TBD + }, + ethToDaiLensEth: { + artifactName: 'BPTLens', + address: '0xf24401F6992FaEAcbc5d6C6991db15B5F8364A1B', + category: AddressCategory.TBD + }, + ethToDaiLBPPool: { + artifactName: 'IWeightedPool', + address: '0x34809aEDF93066b49F638562c42A9751eDb36DF5', + category: AddressCategory.External + }, aaveEthPCVDeposit: { artifactName: 'AavePCVDeposit', address: '0x5B86887e171bAE0C2C826e87E34Df8D558C079B9', @@ -189,7 +229,7 @@ const MainnetAddresses: MainnetAddresses = { aaveRaiPCVDeposit: { artifactName: 'AavePCVDeposit', address: '0xd2174d78637a40448112aa6B30F9B19e6CF9d1F9', - category: AddressCategory.PCV_V1 + category: AddressCategory.Deprecated }, compoundDaiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', @@ -206,16 +246,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0xac38ee05c0204a1e119c625d0a560d6731478880', category: AddressCategory.PCV_V1 }, - indexCoopFusePoolDpiPCVDeposit: { - artifactName: 'ERC20CompoundPCVDeposit', - address: '0x3dD3d945C4253bAc5B4Cc326a001B7d3f9C4DD66', - category: AddressCategory.PCV_V1 - }, - indexCoopFusePoolFeiPCVDeposit: { - artifactName: 'ERC20CompoundPCVDeposit', - address: '0xD6960adba53212bBE96E54a7AFeDA2066437D000', - category: AddressCategory.PCV_V1 - }, indexDelegator: { artifactName: 'SnapshotDelegatorPCVDeposit', address: '0x0ee81df08B20e4f9E0F534e50da437D24491c4ee', @@ -239,7 +269,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool25FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', address: '0xe1662531aA5de1DAD8ab5B5756b8F6c8F3C759Ca', - category: AddressCategory.PCV_V1 + category: AddressCategory.Deprecated }, rariPool26FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', @@ -259,7 +289,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool19DpiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', address: '0x3dD3d945C4253bAc5B4Cc326a001B7d3f9C4DD66', - category: AddressCategory.PCV_V1 + category: AddressCategory.Deprecated }, rariPool19FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', @@ -289,7 +319,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool9RaiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', address: '0x9aAdFfe00eAe6d8e59bB4F7787C6b99388A6960D', - category: AddressCategory.PCV_V1 + category: AddressCategory.Deprecated }, rariPool28FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', @@ -299,12 +329,12 @@ const MainnetAddresses: MainnetAddresses = { rariPool31FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', address: '0x81DCB06eA4db474D1506Ca6275Ff7D870bA3A1Be', - category: AddressCategory.PCV_V1 + category: AddressCategory.Deprecated }, rariPool72FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', address: '0x4A5Af5A124E672C156241b76CAd4E41D09dd4883', - category: AddressCategory.PCV_V1 + category: AddressCategory.Deprecated }, rariPool79FeiPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', @@ -336,11 +366,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x374628EBE7Ef6AcA0574e750B618097531A26Ff8', category: AddressCategory.PCV }, - balancerFeiWethPool: { - artifactName: 'IWeightedPool', - address: '0x90291319F1D4eA3ad4dB0Dd8fe9E12BAF749E845', - category: AddressCategory.External - }, delayedPCVMoverWethUniToBal: { artifactName: 'DelayedPCVMover', address: '0x52B1D5BE5005002afD76193ADd3a827c18e2db99', @@ -376,6 +401,11 @@ const MainnetAddresses: MainnetAddresses = { address: '0x90291319F1D4eA3ad4dB0Dd8fe9E12BAF749E845', category: AddressCategory.External }, + balancerMinter: { + artifactName: 'IBalancerMinter', + address: '0x239e55F427D44C3cc793f49bFB507ebe76638a2b', + category: AddressCategory.External + }, balancerGaugeController: { artifactName: 'ILiquidityGaugeController', address: '0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD', @@ -391,19 +421,34 @@ const MainnetAddresses: MainnetAddresses = { address: '0xc4EAc760C2C631eE0b064E39888b89158ff808B2', category: AddressCategory.Governance }, - gaugeLensBpt30Fei70WethGauge: { + balancerGaugeStaker: { + artifactName: 'BalancerGaugeStaker', // actually a TransparentUpgradeableProxy + address: '0x66977Ce30049CD0e443216Bf26377966c3A109E2', + category: AddressCategory.Governance + }, + balancerGaugeStakerImpl: { + artifactName: 'BalancerGaugeStaker', + address: '0xF53E251352683155898295569d77B8506bA00d80', + category: AddressCategory.Governance + }, + gaugeLensBpt30Fei70WethGaugeOld: { artifactName: 'CurveGaugeLens', address: '0xa8E388a1f19f2b33Be8bf2cCeC43641C10b4D1e5', - category: AddressCategory.External // not really External, but not PCV + category: AddressCategory.Deprecated + }, + gaugeLensBpt30Fei70WethGauge: { + artifactName: 'CurveGaugeLens', + address: '0xd9fc482E0Af8fd509699f1074d72D137cAC94D5B', + category: AddressCategory.PCV_V1 }, balancerLensBpt30Fei70WethOld: { artifactName: 'BalancerPool2Lens', - address: '0xb31F75550e97A2C4c7AC8d4355032B8AE8b9584D', + address: '0x673f7DFA863b611dE657759aEDE629b260F4E682', category: AddressCategory.Deprecated }, balancerLensBpt30Fei70Weth: { artifactName: 'BalancerPool2Lens', - address: '0x673f7DFA863b611dE657759aEDE629b260F4E682', + address: '0x8465E7CFA63Aa6682531C7a34141966318aC5178', category: AddressCategory.PCV }, balancerLensVeBalBal: { @@ -436,10 +481,20 @@ const MainnetAddresses: MainnetAddresses = { address: '0x0961d2a545e0c1201B313d14C57023682a546b9D', category: AddressCategory.PCV }, + tokemakManagerRollover: { + artifactName: 'unknown', + address: '0x90b6C61B102eA260131aB48377E143D6EB3A9d4B', + category: AddressCategory.External + }, + tokemakManager: { + artifactName: 'unknown', + address: '0xa86e412109f77c45a3bc1c5870b880492fb86a14', + category: AddressCategory.External + }, liquityFusePoolLusdPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', address: '0x8C51E4532CC745cF3DFec5CEBd835D07E7BA1002', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, rariPool7LusdPCVDeposit: { artifactName: 'ERC20CompoundPCVDeposit', @@ -464,7 +519,7 @@ const MainnetAddresses: MainnetAddresses = { aaveRaiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', address: '0x1267B39c93711Dd374DEAB15e0127e4adB259BE0', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, compoundDaiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', @@ -479,7 +534,7 @@ const MainnetAddresses: MainnetAddresses = { creamDepositWrapper: { artifactName: 'ERC20PCVDepositWrapper', address: '0x3a1838Ac9EcA864054bebB82C32455Dd7d7Fc89c', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, ethLidoPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', @@ -496,6 +551,11 @@ const MainnetAddresses: MainnetAddresses = { address: '0x89DfBC12001b41985eFAbd7dFCae6a77B22E4Ec3', category: AddressCategory.PCV }, + fuseFixer: { + artifactName: 'FuseFixer', + address: '0xFE7547F583aAe1212e72e063Aac25057C06c4797', + category: AddressCategory.Governance + }, feiOATimelockWrapper: { artifactName: 'PCVDepositWrapper', address: '0x7Eb88140af813294aEDce981b6aC08fcd139d408', @@ -524,7 +584,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool19DpiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', address: '0x9a774a1B1208C323EDeD05E6Daf592E6E59cAa55', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, rariPool19FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', @@ -539,7 +599,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool25FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', address: '0xB4FFD10C4C290Dc13E8e30BF186F1509001515fD', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, rariPool26FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', @@ -579,7 +639,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool31FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', address: '0x05E2e93CFb0B53D36A3151ee727Bb581D4B918Ce', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, rariPool90FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', @@ -599,7 +659,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool72FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', address: '0x395B1Bc1800fa0ad48ae3876E66d4C10d297650c', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, rariPool128FeiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', @@ -614,7 +674,7 @@ const MainnetAddresses: MainnetAddresses = { rariPool9RaiPCVDepositWrapper: { artifactName: 'PCVDepositWrapper', address: '0xCCe230c087F31032fc17621a2CF5E425A0b80C96', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, wethDepositWrapper: { artifactName: 'ERC20PCVDepositWrapper', @@ -624,12 +684,12 @@ const MainnetAddresses: MainnetAddresses = { dpiDepositWrapper: { artifactName: 'ERC20PCVDepositWrapper', address: '0xB250926E75b1CC6c53E77bb9426Baac14aB1e24c', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, raiDepositWrapper: { artifactName: 'ERC20PCVDepositWrapper', address: '0x7339cA4Ac94020b83A34f5edFA6e0F26986c434b', - category: AddressCategory.PCV + category: AddressCategory.Deprecated }, agEurDepositWrapper: { artifactName: 'ERC20PCVDepositWrapper', @@ -774,17 +834,17 @@ const MainnetAddresses: MainnetAddresses = { autoRewardsDistributor: { artifactName: 'AutoRewardsDistributor', address: '0x61be49dfbd869a601fea076e1a1379903e61a895', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, d3AutoRewardsDistributor: { artifactName: 'AutoRewardsDistributorV2', address: '0x9Fd318C3F8f8583Fd40a0C2fba058fB7097E11d4', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, fei3CrvAutoRewardsDistributor: { artifactName: 'AutoRewardsDistributorV2', address: '0x15f6D0d95aceCD7570e8Ff6128D953BC6aA3573C', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, erc20Dripper: { artifactName: 'ERC20Dripper', @@ -796,100 +856,101 @@ const MainnetAddresses: MainnetAddresses = { address: '0x220f93183a69d1598e8405310cB361CFF504146F', category: AddressCategory.Rewards }, + // TODO: This has ~$1.5M TRIBE on it rariRewardsDistributorDelegator: { - artifactName: 'IRewardsDistributorAdmin', + artifactName: 'IRewardsDistributorDelegator', address: '0x73F16f0c0Cd1A078A54894974C5C054D8dC1A3d7', category: AddressCategory.Rewards }, rewardsDistributorAdmin: { artifactName: 'RewardsDistributorAdmin', address: '0x4e979E8b136Cd7BdEBB83ea50a599C3BED1e15c0', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperBribeD3pool: { artifactName: 'StakingTokenWrapper', address: '0x462515dC7c21C728C8b7A777fDC89EEdAcF74537', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperFOXLaaS: { artifactName: 'StakingTokenWrapper', address: '0x3CD384ff1Fa1cbA8f06DF326AF4cbDA634aF94e8', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperGROLaaS: { artifactName: 'StakingTokenWrapper', address: '0x508629e8E0B96986Df4D0F1F60aadeF1d0FbaE96', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperKYLINLaaS: { artifactName: 'StakingTokenWrapper', address: '0xFe266d143dB42a9835e2B1AB43B64a46278398cc', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperMStableLaaS: { artifactName: 'StakingTokenWrapper', address: '0x9B9ad20Cd99Cac3B536b94497A18346d66db0379', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperNEARLaaS: { artifactName: 'StakingTokenWrapper', address: '0x3b3591a4f7FD386E9987Eb48d898e29b57c30c47', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperPoolTogetherLaaS: { artifactName: 'StakingTokenWrapper', address: '0x6b018170311F3DA23c3fA62AFe1b2D0638522CCD', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperRari: { artifactName: 'StakingTokenWrapper', address: '0xd81Be1B9A7895C996704A8DDa794BbA4454EeB90', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperSYNLaaS: { artifactName: 'StakingTokenWrapper', address: '0x5Db85e395735Bb42eEB720Fe2EE69627d246e300', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperUMALaaS: { artifactName: 'StakingTokenWrapper', address: '0x90B336dFF819b9e4b3D9A32cabdcAB0E92836065', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, fei3CrvStakingtokenWrapper: { artifactName: 'StakingTokenWrapper', address: '0x7013dc2e3c0D5ca3c0a6a66F6B5883eD203ac49c', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, feiDaiStakingTokenWrapper: { artifactName: 'StakingTokenWrapper', address: '0x601FFddACcAF7F05600D7E7561a51C745B8A2A3e', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, feiUsdcStakingTokenWrapper: { artifactName: 'StakingTokenWrapper', address: '0x0A0542Adf2fA8e85DD797697da537448b2e7c3EE', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, feiDaiAutoRewardsDistributor: { artifactName: 'AutoRewardsDistributorV2', address: '0xE6Fef62A834D9b0BA1Da832769D6E99135dD2E0e', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, feiUsdcAutoRewardsDistributor: { artifactName: 'AutoRewardsDistributorV2', address: '0x1126f1fA7Da556F8F82846223E3C2176B5631707', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, d3StakingTokenWrapper: { artifactName: 'StakingTokenWrapper', address: '0xAa267d0A5A0A56Ef0F17bB4A28f85a5C4e0394F6', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stwBulkHarvest: { artifactName: 'STWBulkHarvest', address: '0x83433D925048d7e9D2D7Eec2A0Efbb4456Af2F93', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, tribalChief: { artifactName: 'TribalChief', @@ -904,18 +965,19 @@ const MainnetAddresses: MainnetAddresses = { tribalChiefSyncV2: { artifactName: 'TribalChiefSyncV2', address: '0xb41c594f9a6a2E0882212598337AF8145f63731b', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, tribalChiefSyncExtension: { artifactName: 'TribalChiefSyncExtension', address: '0x7b834cA07f81d52bB52d98DaE560D1442b2d7dBa', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, stakingTokenWrapperBribe3Crvpool: { artifactName: 'StakingTokenWrapper', address: '0xaC98807E5CC43f134b00E87349e4ea3eDf927961', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, + // TODO: This has $50k TRIBE on it, should withdraw votiumBriber3Crvpool: { artifactName: 'VotiumBriber', address: '0x8B6A295a35171E2F05B1579E485017B999810dcb', @@ -924,7 +986,7 @@ const MainnetAddresses: MainnetAddresses = { votiumBriberD3pool: { artifactName: 'VotiumBriber', address: '0x0BEC570466B466aB689Ad33F1Ce5238CA43C8003', - category: AddressCategory.Rewards + category: AddressCategory.Deprecated }, rariPool8ConvexD3Plugin: { artifactName: 'IConvexERC4626', @@ -1296,11 +1358,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490', category: AddressCategory.External }, - curve3Metapool: { - artifactName: 'IERC20', - address: '0x06cb22615BA53E60D67Bf6C341a0fD5E718E1655', - category: AddressCategory.External - }, curve3pool: { artifactName: 'unknown', address: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7', @@ -1311,9 +1368,9 @@ const MainnetAddresses: MainnetAddresses = { address: '0xBaaa1F5DbA42C3389bDbc2c9D2dE134F5cD0Dc89', category: AddressCategory.External }, - curveMetapool: { - artifactName: 'unknown', - address: '0x06cb22615ba53e60d67bf6c341a0fd5e718e1655', + curveFei3crvMetapool: { + artifactName: 'IERC20', + address: '0x06cb22615BA53E60D67Bf6C341a0fD5E718E1655', category: AddressCategory.External }, cvx: { @@ -1331,11 +1388,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x1494CA1F11D487c2bBe4543E90080AeBa4BA3C2b', category: AddressCategory.External }, - fAAVE: { - artifactName: 'IERC20', - address: '0x4da27a545c0c5b758a6ba100e3a049001de870f5', - category: AddressCategory.External - }, feiEthPair: { artifactName: 'IUniswapV2Pair', address: '0x94B0A3d511b6EcDb17eBF877278Ab030acb0A878', @@ -1411,16 +1463,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x0954906da0Bf32d5479e25f46056d22f08464cab', category: AddressCategory.External }, - indexCoopFusePoolDpi: { - artifactName: 'CErc20Delegator', - address: '0xf06f65a6b7d2c401fcb8b3273d036d21fe2a5963', - category: AddressCategory.External - }, - indexCoopFusePoolFei: { - artifactName: 'CErc20Delegator', - address: '0x04281F6715Dea6A8EbBCE143D86ea506FF326531', - category: AddressCategory.External - }, kashiFeiDPI: { artifactName: 'IKashiPair', address: '0xf352773f1d4d69deb4de8d0578e43b993ee76e5d', @@ -1466,11 +1508,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x0B36b0F351ea8383506F596743a2DA7DCa204cc3', category: AddressCategory.External }, - poolPartyFei: { - artifactName: 'CErc20Delegator', - address: '0x17b1A2E012cC4C31f83B90FF11d3942857664efc', - category: AddressCategory.External - }, rai: { artifactName: 'IERC20', address: '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', @@ -1541,11 +1578,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x6c806eDDAd78A5505Fce27B18C6f859fc9739BEc', category: AddressCategory.External }, - reflexerStableAssetFusePoolRai: { - artifactName: 'CErc20Delegator', - address: '0x752F119bD4Ee2342CE35E2351648d21962c7CAfE', - category: AddressCategory.External - }, rgt: { artifactName: 'ERC20VotesComp', address: '0xD291E7a03283640FDc51b121aC401383A46cC623', @@ -1616,21 +1648,11 @@ const MainnetAddresses: MainnetAddresses = { address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', category: AddressCategory.External }, - wethERC20: { - artifactName: 'IERC20', - address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - category: AddressCategory.External - }, aavePassthroughETH: { artifactName: 'unknown', // AavePassthroughETH address: '0x126AD2B5341A30D8115C443B3158E7661e4faD26', category: AddressCategory.Deprecated }, - aaveTribeIncentivesControllerProxy: { - artifactName: 'TransparentUpgradeableProxy', - address: '0xDee5c1662bBfF8f80f7c572D8091BF251b3B0dAB', - category: AddressCategory.Deprecated - }, balDepositWrapper: { artifactName: 'ERC20PCVDepositWrapper', address: '0x7E28BA7a2D52Af88242E588d868E927119BA45dB', @@ -1641,11 +1663,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0xF56B0B80ea6E986364c50177d396b988C3e41094', category: AddressCategory.Deprecated }, - coreV1: { - artifactName: 'ICoreV1', - address: '0x8d5ED43dCa8C2F7dFB20CF7b53CC7E593635d7b9', - category: AddressCategory.Deprecated - }, daiBondingCurve: { artifactName: 'unknown', // BondingCurve address: '0xC0afe0E649e32528666F993ce63822c3840e941a', @@ -1681,6 +1698,11 @@ const MainnetAddresses: MainnetAddresses = { address: '0xFf419Bc27483edb94b7Ad5c97b7FaB5DB323c7E0', category: AddressCategory.Deprecated }, + daiFixedPricePSMFeiSkimmer: { + artifactName: 'FeiSkimmer', + address: '0xe49B608663EeB89f1E3AbBe75744e5318F85029C', + category: AddressCategory.Peg + }, daiPSMFeiSkimmer: { artifactName: 'FeiSkimmer', address: '0xf8Ca6c10a794C867497541F5b7A7f96ca2bCd1E8', @@ -1756,11 +1778,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x4C895973334Af8E06fd6dA4f723Ac24A5f259e6B', category: AddressCategory.Deprecated }, - multisig: { - artifactName: 'unknown', - address: '0xB8f482539F2d3Ae2C9ea6076894df36D1f632775', - category: AddressCategory.Deprecated - }, oldEthBondingCurve: { artifactName: 'unknown', // EthBondingCurve address: '0xe1578B4a32Eaefcd563a9E6d0dc02a4213f673B7', @@ -1771,11 +1788,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0xa08A721dFB595753FFf335636674D76C455B275C', category: AddressCategory.Deprecated }, - poolPartyFeiPCVDeposit: { - artifactName: 'ERC20CompoundPCVDeposit', - address: '0x5A8CB4556e5D5935Af06beab8292905f48131479', - category: AddressCategory.Deprecated - }, ratioPCVController: { artifactName: 'unknown', // RatioPCVController address: '0xB1410aeCe2c65fE9e107c58b5aa32e91B18f0BC7', @@ -1796,11 +1808,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0xc42e155788f9f599Fd437C7455F63810A395a81f', category: AddressCategory.Deprecated }, - reflexerStableAssetFusePoolRaiPCVDeposit: { - artifactName: 'ERC20CompoundPCVDeposit', - address: '0x9aAdFfe00eAe6d8e59bB4F7787C6b99388A6960D', - category: AddressCategory.Deprecated - }, staticPcvDepositWrapper: { artifactName: 'unknown', // StaticPCVDepositWrapper address: '0x8B41DcEfAe6064E6bc2A9B3ae20141d23EFD6cbd', @@ -1816,11 +1823,6 @@ const MainnetAddresses: MainnetAddresses = { address: '0x639572471f2f318464dc01066a56867130e45E25', category: AddressCategory.TBD }, - tribalChiefOptimisticMultisig: { - artifactName: 'unknown', - address: '0x35ED000468f397AA943009bD60cc6d2d9a7d32fF', - category: AddressCategory.Deprecated - }, tribalChiefOptimisticTimelock: { artifactName: 'Timelock', address: '0x27Fae9E49AD955A24bB578B66Cdc962b5029fbA9', @@ -2070,7 +2072,27 @@ const MainnetAddresses: MainnetAddresses = { artifactName: 'RoleBastion', address: '0x8096314D9014EbB69Fc777ED3791DDE6FFbaFAed', category: AddressCategory.Governance + }, + tribeDev1Deployer: { + artifactName: 'unknown', + address: '0x64c4Bffb220818F0f2ee6DAe7A2F17D92b359c5d', + category: AddressCategory.External + }, + tribeDev2Deployer: { + artifactName: 'unknown', + address: '0xcE96fE7Eb7186E9F894DE7703B4DF8ea60E2dD77', + category: AddressCategory.External + }, + tribeDev3Deployer: { + artifactName: 'unknown', + address: '0xE2388f22cf5e328C197D6530663809cc0408a510', + category: AddressCategory.External + }, + tribeDev4Deployer: { + artifactName: 'unknown', + address: '0x5346b4ff3e924508d33d93f352d11e392a7a9d3b', + category: AddressCategory.External } }; -export default MainnetAddresses; +export default MainnetContractsConfig; diff --git a/protocol-configuration/permissions.ts b/protocol-configuration/permissions.ts index ca1aaae8c..588e0fe69 100644 --- a/protocol-configuration/permissions.ts +++ b/protocol-configuration/permissions.ts @@ -24,31 +24,39 @@ export const permissions = { 'lusdPSMFeiSkimmer', 'raiPCVDripController' ], - GUARDIAN_ROLE: ['multisig', 'pcvGuardianNew', 'pcvSentinel'], + GUARDIAN_ROLE: ['guardianMultisig', 'pcvGuardianNew', 'pcvSentinel'], ORACLE_ADMIN_ROLE: [ 'collateralizationOracleGuardian', 'optimisticTimelock', 'opsOptimisticTimelock', 'tribalCouncilTimelock' ], - SWAP_ADMIN_ROLE: ['pcvEquityMinter', 'optimisticTimelock'], + SWAP_ADMIN_ROLE: ['pcvEquityMinter', 'optimisticTimelock', 'tribalCouncilTimelock'], BALANCER_MANAGER_ADMIN_ROLE: [], RATE_LIMITED_MINTER_ADMIN: [], PARAMETER_ADMIN: [], PSM_ADMIN_ROLE: ['tribalCouncilTimelock'], - TRIBAL_CHIEF_ADMIN_ROLE: ['optimisticTimelock', 'tribalChiefSyncV2'], - FUSE_ADMIN: ['optimisticTimelock', 'tribalChiefSyncV2', 'tribalCouncilTimelock'], - VOTIUM_ADMIN_ROLE: ['opsOptimisticTimelock'], + TRIBAL_CHIEF_ADMIN_ROLE: ['optimisticTimelock', 'tribalCouncilTimelock'], + FUSE_ADMIN: ['optimisticTimelock', 'tribalCouncilTimelock'], + VOTIUM_ADMIN_ROLE: [], PCV_GUARDIAN_ADMIN_ROLE: ['optimisticTimelock', 'tribalCouncilTimelock'], PCV_SAFE_MOVER_ROLE: ['tribalCouncilTimelock'], METAGOVERNANCE_VOTE_ADMIN: ['feiDAOTimelock', 'opsOptimisticTimelock', 'tribalCouncilTimelock'], METAGOVERNANCE_TOKEN_STAKING: ['feiDAOTimelock', 'opsOptimisticTimelock'], - METAGOVERNANCE_GAUGE_ADMIN: ['feiDAOTimelock', 'optimisticTimelock'], + METAGOVERNANCE_GAUGE_ADMIN: ['feiDAOTimelock', 'optimisticTimelock', 'tribalCouncilTimelock'], ROLE_ADMIN: ['feiDAOTimelock', 'tribalCouncilTimelock'], - POD_METADATA_REGISTER_ROLE: ['tribalCouncilSafe'], + POD_METADATA_REGISTER_ROLE: [ + 'tribalCouncilSafe', + 'tribeDev1Deployer', + 'tribeDev2Deployer', + 'tribeDev3Deployer', + 'tribeDev4Deployer' + ], FEI_MINT_ADMIN: ['feiDAOTimelock', 'tribalCouncilTimelock'], POD_VETO_ADMIN: ['nopeDAO'], POD_ADMIN: ['tribalCouncilTimelock', 'podFactory'], PCV_MINOR_PARAM_ROLE: ['feiDAOTimelock', 'optimisticTimelock', 'tribalCouncilTimelock'], TOKEMAK_DEPOSIT_ADMIN_ROLE: ['optimisticTimelock', 'feiDAOTimelock', 'tribalCouncilTimelock'] }; + +export type PermissionsType = keyof typeof permissions; diff --git a/protocol-configuration/proposalsConfig.ts b/protocol-configuration/proposalsConfig.ts new file mode 100644 index 000000000..595a785d4 --- /dev/null +++ b/protocol-configuration/proposalsConfig.ts @@ -0,0 +1,5 @@ +import { TemplatedProposalsConfigMap } from '@custom-types/types'; + +const proposals: TemplatedProposalsConfigMap = {}; + +export default proposals; diff --git a/protocol-configuration/tribalchief.ts b/protocol-configuration/tribalchief.ts index 64dbc7278..5351372bb 100644 --- a/protocol-configuration/tribalchief.ts +++ b/protocol-configuration/tribalchief.ts @@ -1,24 +1,24 @@ import { TribalChiefConfig } from '../types/types'; const config: TribalChiefConfig = { - feiTribePair: { allocPoint: 0, unlocked: false }, // Uniswap-v2 FEI/TRIBE LP - curve3Metapool: { allocPoint: 0, unlocked: false }, // Curve 3crv-FEI metapool LP - gUniFeiDaiLP: { allocPoint: 0, unlocked: true }, // G-UNI DAI/FEI 0.05% fee tier - stakingTokenWrapperRari: { allocPoint: 1000, unlocked: false }, // FeiRari: TRIBE - stakingTokenWrapperGROLaaS: { allocPoint: 0, unlocked: false }, // LaaS: GRO - stakingTokenWrapperFOXLaaS: { allocPoint: 0, unlocked: false }, // LaaS: FOX - stakingTokenWrapperUMALaaS: { allocPoint: 0, unlocked: false }, // LaaS: UMA - stakingTokenWrapperSYNLaaS: { allocPoint: 0, unlocked: false }, // LaaS: SYN - stakingTokenWrapperNEARLaaS: { allocPoint: 0, unlocked: false }, // LaaS: NEAR - stakingTokenWrapperKYLINLaaS: { allocPoint: 0, unlocked: false }, // LaaS: KYLIN - stakingTokenWrapperMStableLaaS: { allocPoint: 0, unlocked: false }, // LaaS: MStable - stakingTokenWrapperPoolTogetherLaaS: { allocPoint: 0, unlocked: false }, // LaaS: PoolTogether - stakingTokenWrapperBribeD3pool: { allocPoint: 250, unlocked: false }, // Votium bribes: d3pool - d3StakingTokenWrapper: { allocPoint: 250, unlocked: false }, // FeiRari: d3pool LP - fei3CrvStakingtokenWrapper: { allocPoint: 1000, unlocked: false }, // FeiRari: 3crv-FEI metapool LP - feiDaiStakingTokenWrapper: { allocPoint: 100, unlocked: false }, // FeiRari: G-UNI DAI/FEI 0.05% fee tier - feiUsdcStakingTokenWrapper: { allocPoint: 500, unlocked: false }, // FeiRari: G-UNI USDC/FEI 0.01% fee tier - stakingTokenWrapperBribe3Crvpool: { allocPoint: 250, unlocked: false } // Votium bribes: 3crv-FEI metapool + feiTribePair: { allocPoint: 1, unlocked: false }, // Uniswap-v2 FEI/TRIBE LP, 0 (poolId) + curveFei3crvMetapool: { allocPoint: 0, unlocked: false }, // Curve 3crv-FEI metapool LP, 1 + gUniFeiDaiLP: { allocPoint: 0, unlocked: true }, // G-UNI DAI/FEI 0.05% fee tier, 2 + stakingTokenWrapperRari: { allocPoint: 0, unlocked: false }, // FeiRari: TRIBE, 3 + stakingTokenWrapperGROLaaS: { allocPoint: 0, unlocked: false }, // LaaS: GRO, 4 + stakingTokenWrapperFOXLaaS: { allocPoint: 0, unlocked: false }, // LaaS: FOX, 5 + stakingTokenWrapperUMALaaS: { allocPoint: 0, unlocked: false }, // LaaS: UMA, 6 + stakingTokenWrapperSYNLaaS: { allocPoint: 0, unlocked: false }, // LaaS: SYN, 7 + stakingTokenWrapperNEARLaaS: { allocPoint: 0, unlocked: false }, // LaaS: NEAR, 8 + stakingTokenWrapperKYLINLaaS: { allocPoint: 0, unlocked: false }, // LaaS: KYLIN, 9 + stakingTokenWrapperMStableLaaS: { allocPoint: 0, unlocked: false }, // LaaS: MStable, 10 + stakingTokenWrapperPoolTogetherLaaS: { allocPoint: 0, unlocked: false }, // LaaS: PoolTogether, 11 + stakingTokenWrapperBribeD3pool: { allocPoint: 0, unlocked: false }, // Votium bribes: d3pool, 12 + d3StakingTokenWrapper: { allocPoint: 0, unlocked: false }, // FeiRari: d3pool LP, 13 + fei3CrvStakingtokenWrapper: { allocPoint: 0, unlocked: false }, // FeiRari: 3crv-FEI metapool LP, 14 + feiDaiStakingTokenWrapper: { allocPoint: 0, unlocked: false }, // FeiRari: G-UNI DAI/FEI 0.05% fee tier, 15 + feiUsdcStakingTokenWrapper: { allocPoint: 0, unlocked: false }, // FeiRari: G-UNI USDC/FEI 0.01% fee tier, 16 + stakingTokenWrapperBribe3Crvpool: { allocPoint: 0, unlocked: false } // Votium bribes: 3crv-FEI metapool, 17 }; export default config; diff --git a/scripts/deploy/fuseFixer.ts b/scripts/deploy/fuseFixer.ts new file mode 100644 index 000000000..40ca526c4 --- /dev/null +++ b/scripts/deploy/fuseFixer.ts @@ -0,0 +1,39 @@ +import { DeployUpgradeFunc } from '@custom-types/types'; +import { ethers } from 'hardhat'; + +export const deploy: DeployUpgradeFunc = async (deployAddress: string, addresses, logging = false) => { + const core = '0x8d5ED43dCa8C2F7dFB20CF7b53CC7E593635d7b9'; + + if (!core) { + throw new Error('An environment variable contract address is not set'); + } + + const fuseFixerFactory = await ethers.getContractFactory('FuseFixer'); + const fuseFixer = await fuseFixerFactory.deploy(core); + await fuseFixer.deployTransaction.wait(); + + console.log('FuseFixer deployed to: ', fuseFixer.address); + + // Copied from smart contract + const underlyings = [ + '0x0000000000000000000000000000000000000000', // ETH + '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', // FEI + '0x853d955aCEf822Db058eb8505911ED77F175b99e', // FRAX + '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', // RAI + '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC + '0x5f98805A4E8be255a32880FDeC7F6728C6568bA0', // LUSD + '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', // wstETH + '0xa693B19d2931d498c5B318dF961919BB4aee87a5', // USTw + '0xdAC17F958D2ee523a2206206994597C13D831ec7' // USDT + ]; + + for (const underlying of underlyings) { + const debt = await fuseFixer.callStatic.getTotalDebt(underlying); + console.log(`Total debt for ${underlying} is ${debt.toString()}`); + } + + return { fuseFixer }; +}; + +deploy('', {}, true); diff --git a/scripts/deploy/old/optimisticTimelock.ts b/scripts/deploy/old/optimisticTimelock.ts index e693d0437..7d6300f26 100644 --- a/scripts/deploy/old/optimisticTimelock.ts +++ b/scripts/deploy/old/optimisticTimelock.ts @@ -4,15 +4,15 @@ import { ethers } from 'hardhat'; const fourDays = 4 * 24 * 60 * 60; const deploy: DeployUpgradeFunc = async (deployAddress, addresses, logging = false) => { - const { tribalChiefOptimisticMultisig, core } = addresses; + const { optimisticMultisig, core } = addresses; - if (!tribalChiefOptimisticMultisig || !core) { + if (!optimisticMultisig || !core) { throw new Error('An environment variable contract address is not set'); } const optimisticTimelock = await ( await ethers.getContractFactory('OptimisticTimelock') - ).deploy(core, fourDays, [tribalChiefOptimisticMultisig], [tribalChiefOptimisticMultisig]); + ).deploy(core, fourDays, [optimisticMultisig], [optimisticMultisig]); logging && console.log('Optimistic Timelock deployed to: ', optimisticTimelock.address); return { diff --git a/scripts/utils/checkProposal.ts b/scripts/utils/checkProposal.ts index 750296c59..c2601823b 100644 --- a/scripts/utils/checkProposal.ts +++ b/scripts/utils/checkProposal.ts @@ -1,6 +1,6 @@ import { getAllContracts, getAllContractAddresses } from '@test/integration/setup/loadContracts'; import { NamedContracts, UpgradeFuncs } from '@custom-types/types'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import * as dotenv from 'dotenv'; import { execProposal } from './exec'; @@ -30,19 +30,14 @@ async function checkProposal(proposalName: string, doSetup?: string) { if (doSetup) { console.log('Setup'); - await proposalFuncs.setup( - contractAddresses, - contracts as unknown as NamedContracts, - contracts as unknown as NamedContracts, - true - ); + await proposalFuncs.setup(contractAddresses, contracts, contracts, true); } const { feiDAO } = contracts; const proposalNo = proposals[proposalName].proposalId; - await execProposal(voterAddress, feiDAO.address, proposals[proposalName].totalValue, proposalNo); + await execProposal(voterAddress, feiDAO.address, proposals[proposalName].totalValue.toString(), proposalNo); console.log('Teardown'); await proposalFuncs.teardown( diff --git a/scripts/utils/constructProposal.ts b/scripts/utils/constructProposal.ts index 26bc1b218..b87bbc491 100644 --- a/scripts/utils/constructProposal.ts +++ b/scripts/utils/constructProposal.ts @@ -1,16 +1,20 @@ -import hre, { proposals } from 'hardhat'; -import { MainnetContracts, NamedAddresses, ProposalDescription } from '@custom-types/types'; -import format from 'string-template'; +import { + MainnetContracts, + NamedAddresses, + ProposalDescription, + TemplatedProposalDescription +} from '@custom-types/types'; +import { errors, PACKAGE_NAME } from '@idle-finance/hardhat-proposals-plugin/dist/src/constants'; import { AlphaProposal, AlphaProposalBuilder } from '@idle-finance/hardhat-proposals-plugin/dist/src/proposals/compound-alpha'; -import { BigNumber, utils } from 'ethers'; import { InternalProposalState } from '@idle-finance/hardhat-proposals-plugin/dist/src/proposals/proposal'; +import { time } from '@test/helpers'; +import { BigNumber, utils } from 'ethers'; +import hre from 'hardhat'; import { HardhatPluginError } from 'hardhat/plugins'; -import { PACKAGE_NAME, errors } from '@idle-finance/hardhat-proposals-plugin/dist/src/constants'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; -import { time } from '@test/helpers'; export class SigmaProposal extends AlphaProposal { protected async mineBlocks(blocks: any) { @@ -64,7 +68,7 @@ export class SigmaProposalBuilder extends AlphaProposalBuilder { * */ export default async function constructProposal( - proposalInfo: ProposalDescription, + proposalInfo: TemplatedProposalDescription, contracts: MainnetContracts, contractAddresses: NamedAddresses, logging = false @@ -82,9 +86,14 @@ export default async function constructProposal( for (let i = 0; i < proposalInfo.commands.length; i += 1) { const command = proposalInfo.commands[i]; - const ethersContract = contracts[command.target]; + const ethersContract = contracts[command.target as keyof MainnetContracts]; + + const generateArgsFunc = command.arguments; + if (typeof generateArgsFunc !== 'function') { + throw new Error(`Command ${command.target} has no arguments function (cannot use direct assignments)`); + } + const args = generateArgsFunc(contractAddresses); - const args = replaceArgs(command.arguments, contractAddresses); proposalBuilder.addContractAction(ethersContract, command.method, args, command.values); logging && console.log(`Adding proposal step: ${command.description}`); @@ -95,20 +104,3 @@ export default async function constructProposal( logging && console.log(await proposal.printProposalInfo()); return proposal; } - -// Recursively interpolate strings in the argument array -const replaceArgs = (args: any[], contractNames: NamedAddresses) => { - const result = []; - for (let i = 0; i < args.length; i++) { - const element = args[i]; - if (typeof element === typeof '') { - const formatted = format(element, contractNames); - result.push(formatted); - } else if (typeof element === typeof []) { - result.push(replaceArgs(element, contractNames)); - } else { - result.push(element); - } - } - return result; -}; diff --git a/scripts/utils/constructProposalCalldata.ts b/scripts/utils/constructProposalCalldata.ts index 79c6bf9fd..a78bff35c 100644 --- a/scripts/utils/constructProposalCalldata.ts +++ b/scripts/utils/constructProposalCalldata.ts @@ -1,8 +1,11 @@ import constructProposal from './constructProposal'; import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; import { Interface } from '@ethersproject/abi'; import { utils } from 'ethers'; import { getAllContractAddresses, getAllContracts } from '@test/integration/setup/loadContracts'; +import { ProposalCategory, ProposalDescription, TemplatedProposalDescription } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; type ExtendedAlphaProposal = { targets: string[]; @@ -17,17 +20,25 @@ type ExtendedAlphaProposal = { * See `proposals/utils/getProposalCalldata.js` on how to construct the proposal calldata */ export async function constructProposalCalldata(proposalName: string): Promise { - const proposalInfo = await import(`@proposals/description/${proposalName}`); + const proposalInfo = (await import(`@proposals/description/${proposalName}`)).default as TemplatedProposalDescription; const contracts = await getAllContracts(); - const contractAddresses = await getAllContractAddresses(); + const contractAddresses = getAllContractAddresses(); - const proposal = (await constructProposal( - proposalInfo.default, - contracts, - contractAddresses - )) as ExtendedAlphaProposal; + const proposal = (await constructProposal(proposalInfo, contracts, contractAddresses)) as ExtendedAlphaProposal; + console.log(proposals[proposalName].category); + if ( + proposals[proposalName].category === ProposalCategory.OA || + proposals[proposalName].category === ProposalCategory.TC + ) { + return getTimelockCalldata(proposal, proposalInfo); + } + + return getDAOCalldata(proposal); +} + +function getDAOCalldata(proposal: ExtendedAlphaProposal): string { const proposeFuncFrag = new Interface([ 'function propose(address[] memory targets,uint256[] memory values,bytes[] memory calldatas,string memory description) public returns (uint256)' ]); @@ -47,3 +58,38 @@ export async function constructProposalCalldata(proposalName: string): Promise process.exit(0)) + .catch((err) => { + console.log(err); + process.exit(1); + }); diff --git a/scripts/utils/simulateDEBUGProposal.ts b/scripts/utils/simulateDEBUGProposal.ts new file mode 100644 index 000000000..aedfa3860 --- /dev/null +++ b/scripts/utils/simulateDEBUGProposal.ts @@ -0,0 +1,31 @@ +import { MainnetContracts, NamedAddresses, ProposalConfig, TemplatedProposalConfig } from '@custom-types/types'; +import { Contract, Signer } from 'ethers'; + +export async function simulateDEBUGProposal( + signer: Signer, + contractAddresses: NamedAddresses, + contracts: MainnetContracts, + config: TemplatedProposalConfig +) { + let totalGasUsed = 0; + for (let i = 0; i < config.proposal.commands.length; i++) { + const cmd = config.proposal.commands[i]; + // build tx & print details + console.log(' Step' + (config.proposal.commands.length >= 10 && i < 10 ? ' ' : ''), i, ':', cmd.description); + const to = contractAddresses[cmd.target] || cmd.target; + const value = cmd.values; + + const args = cmd.arguments(contractAddresses); + const ethersContract: Contract = contracts[cmd.target as keyof MainnetContracts] as Contract; + const calldata = ethersContract.interface.encodeFunctionData(cmd.method, args); + console.log(' Target:', cmd.target, '[' + to + ']'); + console.log(' Method:', cmd.method, '- Calling...'); + + // send tx + const tx = await signer.sendTransaction({ data: calldata, to, value: Number(value) }); + const d = await tx.wait(); + console.log(' Done. Used ' + d.cumulativeGasUsed.toString() + ' gas.'); + totalGasUsed += Number(d.cumulativeGasUsed.toString()); + } + console.log(' Done. Used', totalGasUsed, 'gas in total.'); +} diff --git a/scripts/utils/simulateOAProposal.ts b/scripts/utils/simulateOAProposal.ts deleted file mode 100644 index b4c92abac..000000000 --- a/scripts/utils/simulateOAProposal.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { ethers } from 'hardhat'; -import { MainnetContracts, NamedAddresses, ProposalDescription } from '@custom-types/types'; -import format from 'string-template'; -import { OptimisticTimelock } from '@custom-types/contracts'; -import { getImpersonatedSigner, time } from '@test/helpers'; -import { Contract } from '@ethersproject/contracts'; - -export default async function simulateOAProposal( - proposalInfo: ProposalDescription, - contracts: MainnetContracts, - contractAddresses: NamedAddresses, - logging = false -) { - const timelock: OptimisticTimelock = contracts.optimisticTimelock as OptimisticTimelock; - const signer = await getImpersonatedSigner(contractAddresses.optimisticMultisig); - - logging && console.log(`Constructing proposal ${proposalInfo.title}`); - - const salt = ethers.utils.id(proposalInfo.title); - const predecessor = ethers.constants.HashZero; - const targets = []; - const values = []; - const datas = []; - const delay = await timelock.getMinDelay(); - - for (let i = 0; i < proposalInfo.commands.length; i += 1) { - const command = proposalInfo.commands[i]; - - const ethersContract: Contract = contracts[command.target] as Contract; - - const target = contractAddresses[command.target]; - targets.push(target); - values.push(command.values); - - const args = replaceArgs(command.arguments, contractAddresses); - const data = ethersContract.interface.encodeFunctionData(command.method, args); - datas.push(data); - - logging && console.log(`Adding proposal step: ${command.description}`); - } - - logging && console.log(`Scheduling proposal ${proposalInfo.title}`); - - const proposalId = await timelock.hashOperationBatch(targets, values, datas, predecessor, salt); - - console.log('proposalId: ', proposalId); - if (!proposalId || !(await timelock.isOperation(proposalId))) { - const schedule = await timelock.connect(signer).scheduleBatch(targets, values, datas, predecessor, salt, delay); - console.log('Calldata:', schedule.data); - } else { - console.log('Already scheduled proposal'); - } - - await time.increase(delay); - - if ((await timelock.isOperationReady(proposalId)) && !(await timelock.isOperationDone(proposalId))) { - logging && console.log(`Executing proposal ${proposalInfo.title}`); - const execute = await timelock.connect(signer).executeBatch(targets, values, datas, predecessor, salt); - console.log('Execute Calldata:', execute.data); - } else { - console.log('Operation not ready for execution'); - } -} - -// Recursively interpolate strings in the argument array -const replaceArgs = (args: any[], contractNames: NamedAddresses) => { - const result = []; - for (let i = 0; i < args.length; i++) { - const element = args[i]; - if (typeof element === typeof '') { - const formatted = format(element, contractNames); - result.push(formatted); - } else if (typeof element === typeof []) { - result.push(replaceArgs(element, contractNames)); - } else { - result.push(element); - } - } - return result; -}; diff --git a/scripts/utils/simulateTimelockProposal.ts b/scripts/utils/simulateTimelockProposal.ts new file mode 100644 index 000000000..3aeb9b7f4 --- /dev/null +++ b/scripts/utils/simulateTimelockProposal.ts @@ -0,0 +1,105 @@ +import { ethers } from 'hardhat'; +import { + MainnetContracts, + NamedAddresses, + ProposalDescription, + TemplatedProposalDescription +} from '@custom-types/types'; +import { OptimisticTimelock } from '@custom-types/contracts'; +import { getImpersonatedSigner, time } from '@test/helpers'; +import { Contract } from '@ethersproject/contracts'; +import { forceEth } from '@test/integration/setup/utils'; + +export async function simulateOAProposal( + proposalInfo: TemplatedProposalDescription, + contracts: MainnetContracts, + contractAddresses: NamedAddresses, + logging = false +) { + const timelockOA = contracts.optimisticTimelock as OptimisticTimelock; + const multisigAddressOA = contractAddresses.optimisticMultisig as string; + await simulateTimelockProposal(timelockOA, multisigAddressOA, proposalInfo, contracts, contractAddresses, logging); +} + +export async function simulateTCProposal( + proposalInfo: TemplatedProposalDescription, + contracts: MainnetContracts, + contractAddresses: NamedAddresses, + logging = false +) { + const timelockTC = contracts.tribalCouncilTimelock as OptimisticTimelock; + const multisigAddressTC = contractAddresses.tribalCouncilSafe as string; + await simulateTimelockProposal(timelockTC, multisigAddressTC, proposalInfo, contracts, contractAddresses, logging); +} + +export async function simulateTimelockProposal( + timelock: OptimisticTimelock, + multisigAddress: string, + proposalInfo: TemplatedProposalDescription, + contracts: MainnetContracts, + contractAddresses: NamedAddresses, + logging = false +) { + await forceEth(multisigAddress); + const signer = await getImpersonatedSigner(multisigAddress); + logging && console.log(`Constructing proposal ${proposalInfo.title}`); + + const salt = ethers.utils.id(proposalInfo.title); + const predecessor = ethers.constants.HashZero; + const targets = []; + const values = []; + const datas = []; + const delay = await timelock.getMinDelay(); + + for (let i = 0; i < proposalInfo.commands.length; i += 1) { + const command = proposalInfo.commands[i]; + + if (contracts[command.target as keyof MainnetContracts] === undefined) { + throw new Error(`Unknown contract ${command.target}, cannot parse (from MainnetContracts)`); + } + + if (contractAddresses[command.target] === undefined) { + throw new Error(`Unknown contract ${command.target}, cannot parse (from NamedAddresses)`); + } + + const ethersContract: Contract = contracts[command.target as keyof MainnetContracts] as Contract; + const target = contractAddresses[command.target]; + + targets.push(target); + values.push(command.values); + + const generateArgsFunc = command.arguments; + if (typeof generateArgsFunc !== 'function') { + throw new Error(`Command ${command.target} has no arguments function (cannot use direct assignments)`); + } + const args = generateArgsFunc(contractAddresses); + + const data = ethersContract.interface.encodeFunctionData(command.method, args); + datas.push(data); + + logging && console.log(`Adding proposal step: ${command.description}`); + } + + logging && console.log(`Scheduling proposal ${proposalInfo.title}`); + + const proposalId = await timelock.hashOperationBatch(targets, values, datas, predecessor, salt); + + console.log('proposalId: ', proposalId); + if (!proposalId || !(await timelock.isOperation(proposalId))) { + const schedule = await timelock.connect(signer).scheduleBatch(targets, values, datas, predecessor, salt, delay); + console.log('Calldata:', schedule.data); + } else { + console.log('Already scheduled proposal'); + } + + await time.increase(delay); + + if ((await timelock.isOperationReady(proposalId)) && !(await timelock.isOperationDone(proposalId))) { + logging && console.log(`Executing proposal ${proposalInfo.title}`); + const execute = await timelock.connect(signer).executeBatch(targets, values, datas, predecessor, salt); + + console.log('Execute Calldata:', execute.data); + } else { + console.log('Operation not ready for execution'); + } +} diff --git a/tc.json b/tc.json deleted file mode 100644 index 00047af89..000000000 --- a/tc.json +++ /dev/null @@ -1,1119 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "coreAddress", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "oldContractAdminRole", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "newContractAdminRole", - "type": "bytes32" - } - ], - "name": "ContractAdminRoleUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "oldCore", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newCore", - "type": "address" - } - ], - "name": "CoreUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "depositID", - "type": "uint256" - } - ], - "name": "Deposit", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "EmergencyWithdraw", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "Harvest", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "allocPoint", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "contract IERC20", - "name": "stakedToken", - "type": "address" - }, - { - "indexed": true, - "internalType": "contract IRewarder", - "name": "rewarder", - "type": "address" - } - ], - "name": "LogPoolAddition", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint128", - "name": "lockLength", - "type": "uint128" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - } - ], - "name": "LogPoolMultiplier", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "allocPoint", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "contract IRewarder", - "name": "rewarder", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "overwrite", - "type": "bool" - } - ], - "name": "LogSetPool", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "uint128", - "name": "lastRewardBlock", - "type": "uint128" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "lpSupply", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "accTribePerShare", - "type": "uint256" - } - ], - "name": "LogUpdatePool", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "NewTribePerBlock", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bool", - "name": "locked", - "type": "bool" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - } - ], - "name": "PoolLocked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "TribeWithdraw", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "Withdraw", - "type": "event" - }, - { - "inputs": [], - "name": "CONTRACT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "SCALE_FACTOR", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "TRIBE", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint120", - "name": "allocPoint", - "type": "uint120" - }, - { - "internalType": "contract IERC20", - "name": "_stakedToken", - "type": "address" - }, - { - "internalType": "contract IRewarder", - "name": "_rewarder", - "type": "address" - }, - { - "components": [ - { - "internalType": "uint128", - "name": "lockLength", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "rewardMultiplier", - "type": "uint128" - } - ], - "internalType": "struct TribalChief.RewardData[]", - "name": "rewardData", - "type": "tuple[]" - } - ], - "name": "add", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "core", - "outputs": [ - { - "internalType": "contract ICore", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "lockLength", - "type": "uint64" - } - ], - "name": "deposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "depositInfo", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint128", - "name": "unlockBlock", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "multiplier", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "emergencyWithdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "fei", - "outputs": [ - { - "internalType": "contract IFei", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feiBalance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "getTotalStakedInPool", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pid", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "lockLength", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "newRewardsMultiplier", - "type": "uint64" - } - ], - "name": "governorAddPoolMultiplier", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "governorWithdrawTribe", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "harvest", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_core", - "type": "address" - }, - { - "internalType": "contract IERC20", - "name": "_tribe", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_admin", - "type": "address" - } - ], - "name": "isContractAdmin", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pid", - "type": "uint256" - } - ], - "name": "lockPool", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "pids", - "type": "uint256[]" - } - ], - "name": "massUpdatePools", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "numPools", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "address", - "name": "user", - "type": "address" - } - ], - "name": "openUserDeposits", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pid", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_user", - "type": "address" - } - ], - "name": "pendingRewards", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "poolInfo", - "outputs": [ - { - "internalType": "uint256", - "name": "virtualTotalSupply", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "accTribePerShare", - "type": "uint256" - }, - { - "internalType": "uint128", - "name": "lastRewardBlock", - "type": "uint128" - }, - { - "internalType": "uint120", - "name": "allocPoint", - "type": "uint120" - }, - { - "internalType": "bool", - "name": "unlocked", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pid", - "type": "uint256" - } - ], - "name": "resetRewards", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "name": "rewardMultipliers", - "outputs": [ - { - "internalType": "uint128", - "name": "", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "rewarder", - "outputs": [ - { - "internalType": "contract IRewarder", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pid", - "type": "uint256" - }, - { - "internalType": "uint120", - "name": "_allocPoint", - "type": "uint120" - }, - { - "internalType": "contract IRewarder", - "name": "_rewarder", - "type": "address" - }, - { - "internalType": "bool", - "name": "overwrite", - "type": "bool" - } - ], - "name": "set", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "newContractAdminRole", - "type": "bytes32" - } - ], - "name": "setContractAdminRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newCore", - "type": "address" - } - ], - "name": "setCore", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "stakedToken", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalAllocPoint", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "tribe", - "outputs": [ - { - "internalType": "contract IERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "tribeBalance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "tribePerBlock", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_pid", - "type": "uint256" - } - ], - "name": "unlockPool", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "newBlockReward", - "type": "uint256" - } - ], - "name": "updateBlockReward", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - } - ], - "name": "updatePool", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "userInfo", - "outputs": [ - { - "internalType": "int256", - "name": "rewardDebt", - "type": "int256" - }, - { - "internalType": "uint256", - "name": "virtualAmount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "withdrawAllAndHarvest", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "pid", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "withdrawFromDeposit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] \ No newline at end of file diff --git a/test/helpers.ts b/test/helpers.ts index 40f7abccc..686ceeda7 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -2,12 +2,12 @@ import hre, { ethers, artifacts, network } from 'hardhat'; import chai from 'chai'; import CBN from 'chai-bn'; import { Core, Core__factory } from '@custom-types/contracts'; -import { BigNumber, BigNumberish, Contract, Signer } from 'ethers'; +import { BigNumber, BigNumberish, Contract, ContractTransaction, Signer } from 'ethers'; import { NamedAddresses } from '@custom-types/types'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import EthersAdapter from '@gnosis.pm/safe-ethers-lib'; -import { BN } from 'ethereumjs-util'; import Safe from '@gnosis.pm/safe-core-sdk'; +import { TransactionDescription } from 'ethers/lib/utils'; // use default BigNumber chai.use(CBN(ethers.BigNumber)); @@ -176,17 +176,17 @@ async function expectApproxAbs( expect(actualBN).to.be.lte(upperBound); } -async function expectEvent(tx, contract: any, event: string, args: any[]): Promise { +async function expectEvent(tx: any, contract: any, event: string, args: any[]): Promise { await expect(tx) .to.emit(contract, event) .withArgs(...args); } -async function expectRevert(tx, errorMessage: string): Promise { +async function expectRevert(tx: Promise, errorMessage: string): Promise { await expect(tx).to.be.revertedWith(errorMessage); } -async function expectUnspecifiedRevert(tx): Promise { +async function expectUnspecifiedRevert(tx: Promise): Promise { await expect(tx).to.be.reverted; } @@ -200,7 +200,7 @@ const balance = { } }; -async function overwriteChainlinkAggregator(chainlink, value, decimals) { +async function overwriteChainlinkAggregator(aggregatorAddress: string, value: string, decimals: string) { // Deploy new mock aggregator const factory = await ethers.getContractFactory('MockChainlinkOracle'); const mockAggregator = await factory.deploy(value, decimals); @@ -209,7 +209,7 @@ async function overwriteChainlinkAggregator(chainlink, value, decimals) { // Overwrite storage at chainlink address to use mock aggregator for updates const address = `0x00000000000000000000${mockAggregator.address.slice(2)}0005`; - await hre.network.provider.send('hardhat_setStorageAt', [chainlink, '0x2', address]); + await hre.network.provider.send('hardhat_setStorageAt', [aggregatorAddress, '0x2', address]); } const time = { @@ -262,7 +262,7 @@ async function performDAOAction( targets: string[], values: number[] ): Promise { - const description = []; + const description = ''; await hre.network.provider.request({ method: 'hardhat_impersonateAccount', @@ -310,7 +310,7 @@ async function initialiseGnosisSDK(safeOwner: Signer, safeAddress: string): Prom ethers, signer: safeOwner }); - const { chainId } = await safeOwner.provider.getNetwork(); + const { chainId } = await safeOwner.provider!.getNetwork(); const contractNetworks = { [chainId]: { multiSendAddress: '0x8D29bE29923b68abfDD21e541b9374737B49cdAD', diff --git a/test/integration/proposals_config.ts b/test/integration/proposals_config.ts deleted file mode 100644 index e825c3957..000000000 --- a/test/integration/proposals_config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ProposalCategory, ProposalsConfigMap } from '@custom-types/types'; - -// import fip_xx_proposal from '@proposals/description/fip_xx'; - -const proposals: ProposalsConfigMap = { - /* - fip_xx: { - deploy: true, // deploy flag for whether to run deploy action during e2e tests or use mainnet state - totalValue: 0, // amount of ETH to send to DAO execution - proposal: fip_xx, // full proposal file, imported from '@proposals/description/fip_xx.ts' - proposalId: '', - affectedContractSignoff: [''], - deprecatedContractSignoff: [''], - category: ProposalCategory.DAO - } - */ -}; - -export default proposals; diff --git a/test/integration/setup/index.ts b/test/integration/setup/index.ts index ee1e8bb31..6ad05629f 100644 --- a/test/integration/setup/index.ts +++ b/test/integration/setup/index.ts @@ -1,12 +1,12 @@ -import { ethers } from 'hardhat'; -import { permissions } from '@protocol/permissions'; +import { permissions, PermissionsType } from '@protocol/permissions'; import { getAllContractAddresses, getAllContracts } from './loadContracts'; import { Config, ContractAccessRights, TestCoordinator, - Env, + ContractsAndAddresses, ProposalConfig, + TemplatedProposalConfig, namedContractsToNamedAddresses, NamedAddresses, NamedContracts, @@ -21,7 +21,9 @@ import { sudo } from '@scripts/utils/sudo'; import constructProposal from '@scripts/utils/constructProposal'; import '@nomiclabs/hardhat-ethers'; import { resetFork } from '@test/helpers'; -import simulateOAProposal from '@scripts/utils/simulateOAProposal'; +import { simulateOAProposal } from '@scripts/utils/simulateTimelockProposal'; +import { simulateTCProposal } from '@scripts/utils/simulateTimelockProposal'; +import { simulateDEBUGProposal } from '@scripts/utils/simulateDEBUGProposal'; import { forceEth } from '@test/integration/setup/utils'; import { getImpersonatedSigner } from '@test/helpers'; @@ -38,6 +40,10 @@ export class TestEndtoEndCoordinator implements TestCoordinator { constructor(private config: Config, proposals?: any) { this.proposals = proposals; + + this.mainnetContracts = {}; + this.afterUpgradeAddresses = {}; + this.afterUpgradeContracts = {}; } public async initMainnetContracts(): Promise { @@ -54,7 +60,7 @@ export class TestEndtoEndCoordinator implements TestCoordinator { * 3) Apply appropriate permissions to the contracts e.g. minter, burner priviledges * */ - public async loadEnvironment(): Promise { + public async loadEnvironment(): Promise { await resetFork(); await this.initMainnetContracts(); let existingContracts = this.mainnetContracts; @@ -94,7 +100,7 @@ export class TestEndtoEndCoordinator implements TestCoordinator { async applyUpgrade( existingContracts: NamedContracts, proposalName: string, - config: ProposalConfig + config: TemplatedProposalConfig ): Promise { let deployedUpgradedContracts = {}; @@ -159,51 +165,14 @@ export class TestEndtoEndCoordinator implements TestCoordinator { await proposal.simulate(); } - if (config.category === ProposalCategory.DEBUG) { - console.log('Simulating DAO proposal in DEBUG mode (step by step)...'); - console.log(' Title: ', config.proposal.title); - - const signer = await getImpersonatedSigner(contracts.feiDAOTimelock.address); - await forceEth(contracts.feiDAOTimelock.address); - - let totalGasUsed = 0; - for (let i = 0; i < config.proposal.commands.length; i++) { - const cmd = config.proposal.commands[i]; - // build tx & print details - console.log(' Step' + (config.proposal.commands.length >= 10 && i < 10 ? ' ' : ''), i, ':', cmd.description); - let types = []; - if (cmd.method.indexOf('(') !== -1 && cmd.method.indexOf('()') === -1) { - // e.g. ['address', 'bytes32', 'uint256'], or empty array [] - types = cmd.method.split('(')[1].split(')')[0].split(','); - } - const cmdArguments = cmd.arguments.map((arg) => { - if (arg.indexOf('{') == 0) { - arg = contractAddresses[arg.replace('{', '').replace('}', '')] || arg; - } - return arg; - }); - const functionSig = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(cmd.method)); - const calldata = ethers.utils.defaultAbiCoder - .encode(types, cmdArguments) - .replace('0x', functionSig.substring(0, 10)); // prepend function signature - const to = contractAddresses[cmd.target] || cmd.target; - const value = cmd.values; - console.log(' Target:', cmd.target, '[' + to + ']'); - console.log(' Method:', cmd.method); - types.forEach((type, i) => { - console.log(' Argument', i, '[' + type + ']', cmdArguments[i]); - }); - //console.log(' Value:', value); - //console.log(' Calldata:', calldata); - console.log(' Calling... '); - - // send tx - const tx = await signer.sendTransaction({ data: calldata, to, value: Number(value) }); - const d = await tx.wait(); - console.log(' Done. Used ' + d.cumulativeGasUsed.toString() + ' gas.'); - totalGasUsed += Number(d.cumulativeGasUsed.toString()); - } - console.log(' Done. Used', totalGasUsed, 'gas in total.'); + if (config.category === ProposalCategory.TC) { + this.config.logging && console.log(`Simulating Tribal Council proposal...`); + await simulateTCProposal( + config.proposal, + contracts as unknown as MainnetContracts, + contractAddresses, + this.config.logging + ); } if (config.category === ProposalCategory.OA) { @@ -216,6 +185,26 @@ export class TestEndtoEndCoordinator implements TestCoordinator { ); } + if (config.category === ProposalCategory.DEBUG) { + console.log('Simulating DAO proposal in DEBUG mode (step by step)...'); + console.log(' Title: ', config.proposal.title); + + const signer = await getImpersonatedSigner(contracts.feiDAOTimelock.address); + await forceEth(contracts.feiDAOTimelock.address); + + await simulateDEBUGProposal(signer, contractAddresses, contracts as unknown as MainnetContracts, config); + } + + if (config.category === ProposalCategory.DEBUG_TC) { + console.log('Simulating TC proposal in DEBUG mode (step by step)...'); + console.log(' Title: ', config.proposal.title); + + const signer = await getImpersonatedSigner(contracts.tribalCouncilTimelock.address); + await forceEth(contracts.tribalCouncilTimelock.address); + + await simulateDEBUGProposal(signer, contractAddresses, contracts as unknown as MainnetContracts, config); + } + // teardown the DAO proposal this.config.logging && console.log(`Running proposal teardown...`); const teardownTyped = teardown as TeardownUpgradeFunc; @@ -259,16 +248,22 @@ export class TestEndtoEndCoordinator implements TestCoordinator { * permissions contract */ getAccessControlMapping(): ContractAccessRights { - const accessControlRoles = {}; + const accessControlRoles: ContractAccessRights = { + minter: [], + burner: [], + pcvController: [], + governor: [], + guardian: [] + }; // Array of all deployed contracts Object.keys(permissions).map((role) => { - const contracts = permissions[role]; + const contracts = permissions[role as PermissionsType]; const addresses = contracts.map((contractName) => { return this.afterUpgradeAddresses[contractName]; }); - accessControlRoles[role] = addresses; + accessControlRoles[role as keyof ContractAccessRights] = addresses; }); return accessControlRoles as ContractAccessRights; diff --git a/test/integration/setup/loadContracts.ts b/test/integration/setup/loadContracts.ts index c2dae32dc..ab2eab3a5 100644 --- a/test/integration/setup/loadContracts.ts +++ b/test/integration/setup/loadContracts.ts @@ -1,18 +1,9 @@ import mainnetAddresses from '@protocol/mainnetAddresses'; -import { artifacts, ethers } from 'hardhat'; -import { MainnetContracts, NamedAddresses } from '@custom-types/types'; - -interface MainnetContractJSONEntry { - artifactName: string; - address: string; -} - -interface MainnetContractsJSON { - [key: string]: MainnetContractJSONEntry; -} +import { ethers } from 'hardhat'; +import { MainnetContracts, MainnetContractsConfig, NamedAddresses } from '@custom-types/types'; export async function getAllContracts(): Promise { - const addresses = mainnetAddresses as MainnetContractsJSON; + const addresses = mainnetAddresses as MainnetContractsConfig; const contractsAsArrayEntries = await Promise.all( Object.entries(addresses) .filter((entry) => entry[1].artifactName != 'unknown') @@ -26,7 +17,7 @@ export async function getAllContracts(): Promise { export function getAllContractAddresses(): NamedAddresses { const contracts: NamedAddresses = {}; - const addresses = mainnetAddresses as MainnetContractsJSON; + const addresses = mainnetAddresses as MainnetContractsConfig; for (const mainnetAddressEntryName in addresses) { const mainnetAddressEntry = addresses[mainnetAddressEntryName]; diff --git a/test/integration/setup/utils.ts b/test/integration/setup/utils.ts index 48eba475c..175ac879b 100644 --- a/test/integration/setup/utils.ts +++ b/test/integration/setup/utils.ts @@ -15,3 +15,9 @@ export async function forceSpecificEth(target: string, amount: string): Promise< const forceETHContract = await forceETHContractFactory.deploy({ value: ethers.BigNumber.from(amount) }); await forceETHContract.forceEth(target); } + +export async function forceEthMultiple(targets: string[]): Promise { + for (const target of targets) { + await forceEth(target); + } +} diff --git a/test/integration/tests/backstop.ts b/test/integration/tests/backstop.ts index 9988b00cd..84deb5eed 100644 --- a/test/integration/tests/backstop.ts +++ b/test/integration/tests/backstop.ts @@ -4,7 +4,7 @@ import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; import { NamedAddresses, NamedContracts } from '@custom-types/types'; import { resetFork, time, overwriteChainlinkAggregator } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; const toBN = ethers.BigNumber.from; diff --git a/test/integration/tests/balancer-weightedpool.ts b/test/integration/tests/balancer-weightedpool.ts index 8c10e6fd7..be1e9b41c 100644 --- a/test/integration/tests/balancer-weightedpool.ts +++ b/test/integration/tests/balancer-weightedpool.ts @@ -1,14 +1,14 @@ +import { NamedContracts } from '@custom-types/types'; +import { TransactionResponse } from '@ethersproject/providers'; +import proposals from '@protocol/proposalsConfig'; +import { balance, expectApproxAbs, expectRevert, getImpersonatedSigner } from '@test/helpers'; +import { TestEndtoEndCoordinator } from '@test/integration/setup'; +import { forceEth } from '@test/integration/setup/utils'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; -import { NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, expectRevert, expectApproxAbs, balance, resetFork } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import { forceEth } from '@test/integration/setup/utils'; const toBN = ethers.BigNumber.from; -import { TransactionResponse } from '@ethersproject/providers'; const BNe18 = (x: any) => ethers.constants.WeiPerEther.mul(toBN(x)); describe('balancer-weightedpool', function () { @@ -137,7 +137,7 @@ describe('balancer-weightedpool', function () { expect(await balancerDepositTribeWeth.balance()).to.be.equal('0'); expect((await balancerDepositTribeWeth.resistantBalanceAndFei())[0]).to.be.equal('0'); expect((await balancerDepositTribeWeth.resistantBalanceAndFei())[1]).to.be.equal('0'); - expect(await contracts.wethERC20.balanceOf(balancerDepositTribeWeth.address)).to.be.equal('0'); + expect(await contracts.weth.balanceOf(balancerDepositTribeWeth.address)).to.be.equal('0'); expect(await contracts.tribe.balanceOf(balancerDepositTribeWeth.address)).to.be.equal('0'); }); @@ -149,12 +149,12 @@ describe('balancer-weightedpool', function () { const tribeToAllocate = BNe18(Math.round(4 * tribePerEth * 10000)).div(10000); // rounding error < slippage tolerance await contracts.aaveEthPCVDeposit.connect(daoSigner).withdraw(balancerDepositTribeWeth.address, BNe18('1')); await contracts.core.connect(daoSigner).allocateTribe(balancerDepositTribeWeth.address, tribeToAllocate); - expect(await contracts.wethERC20.balanceOf(balancerDepositTribeWeth.address)).to.be.equal(BNe18('1')); + expect(await contracts.weth.balanceOf(balancerDepositTribeWeth.address)).to.be.equal(BNe18('1')); expect(await contracts.tribe.balanceOf(balancerDepositTribeWeth.address)).to.be.equal(tribeToAllocate); // deposit funds in the pool await balancerDepositTribeWeth.deposit(); - expect(await contracts.wethERC20.balanceOf(balancerDepositTribeWeth.address)).to.be.equal('0'); + expect(await contracts.weth.balanceOf(balancerDepositTribeWeth.address)).to.be.equal('0'); expect(await contracts.tribe.balanceOf(balancerDepositTribeWeth.address)).to.be.equal('0'); const poolTokens = await contracts.balancerVault.getPoolTokens(await balancerDepositTribeWeth.poolId()); @@ -226,7 +226,7 @@ describe('balancer-weightedpool', function () { // check the amount of tokens out after exitPool const tribeBalanceAfterExit = (await contracts.tribe.balanceOf(balancerDepositTribeWeth.address)) / 1e18; - const wethBalanceAfterExit = (await contracts.wethERC20.balanceOf(balancerDepositTribeWeth.address)) / 1e18; + const wethBalanceAfterExit = (await contracts.weth.balanceOf(balancerDepositTribeWeth.address)) / 1e18; expect(tribeBalanceAfterExit).to.be.at.least(4 * tribePerEth * 0.99); expect(wethBalanceAfterExit).to.be.at.least(0.99); }); @@ -358,24 +358,24 @@ describe('balancer-weightedpool', function () { }); it('should be able to wrap and unwrap ETH', async function () { - expect(await contracts.wethERC20.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); + expect(await contracts.weth.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); expect((await balance.current(balancerDepositFeiWeth.address)).toString()).to.be.equal('0'); await ( await ethers.getSigner(deployAddress) ).sendTransaction({ to: balancerDepositFeiWeth.address, value: toBN('1000') }); - expect(await contracts.wethERC20.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); + expect(await contracts.weth.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); expect((await balance.current(balancerDepositFeiWeth.address)).toString()).to.be.equal(toBN('1000')); await balancerDepositFeiWeth.wrapETH(); - expect(await contracts.wethERC20.balanceOf(balancerDepositFeiWeth.address)).to.be.equal(toBN('1000')); + expect(await contracts.weth.balanceOf(balancerDepositFeiWeth.address)).to.be.equal(toBN('1000')); expect((await balance.current(balancerDepositFeiWeth.address)).toString()).to.be.equal('0'); await balancerDepositFeiWeth.connect(daoSigner).unwrapETH(); - expect(await contracts.wethERC20.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); + expect(await contracts.weth.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); expect((await balance.current(balancerDepositFeiWeth.address)).toString()).to.be.equal(toBN('1000')); }); @@ -385,10 +385,10 @@ describe('balancer-weightedpool', function () { const signer = await getImpersonatedSigner(WETH_HOLDER); await forceEth(WETH_HOLDER); const amount = '10000000000000000000000'; // 10k WETH (18 decimals) - await contracts.wethERC20.connect(signer).transfer(balancerDepositFeiWeth.address, amount); + await contracts.weth.connect(signer).transfer(balancerDepositFeiWeth.address, amount); // check initial amounts and deposit - expect(await contracts.wethERC20.balanceOf(balancerDepositFeiWeth.address)).to.be.equal(amount); + expect(await contracts.weth.balanceOf(balancerDepositFeiWeth.address)).to.be.equal(amount); expect(await contracts.fei.balanceOf(balancerDepositFeiWeth.address)).to.be.equal('0'); await balancerDepositFeiWeth.deposit(); diff --git a/test/integration/tests/buybacks.ts b/test/integration/tests/buybacks.ts index 974ffac88..9e0102185 100644 --- a/test/integration/tests/buybacks.ts +++ b/test/integration/tests/buybacks.ts @@ -1,19 +1,18 @@ -import chai, { expect } from 'chai'; -import CBN from 'chai-bn'; -import { solidity } from 'ethereum-waffle'; -import { ethers } from 'hardhat'; +import { CollateralizationOracle } from '@custom-types/contracts'; import { NamedAddresses, NamedContracts } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; import { expectApprox, getImpersonatedSigner, increaseTime, latestTime, - resetFork, overwriteChainlinkAggregator } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import { CollateralizationOracle } from '@custom-types/contracts'; +import chai, { expect } from 'chai'; +import CBN from 'chai-bn'; +import { solidity } from 'ethereum-waffle'; +import { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('e2e-buybacks', function () { diff --git a/test/integration/tests/collateralizationOracle.ts b/test/integration/tests/collateralizationOracle.ts index 1ddfe467a..73feafc2e 100644 --- a/test/integration/tests/collateralizationOracle.ts +++ b/test/integration/tests/collateralizationOracle.ts @@ -1,18 +1,18 @@ -import chai, { expect } from 'chai'; -import CBN from 'chai-bn'; -import { solidity } from 'ethereum-waffle'; -import { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { expectApprox, overwriteChainlinkAggregator } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import collateralizationAddresses from '@protocol/collateralizationOracle'; -import { TestEndtoEndCoordinator } from '@test/integration/setup'; import { CollateralizationOracle, - CollateralizationOracleWrapper, CollateralizationOracleGuardian, + CollateralizationOracleWrapper, NamedStaticPCVDepositWrapper } from '@custom-types/contracts'; +import { NamedAddresses, NamedContracts } from '@custom-types/types'; +import collateralizationAddresses from '@protocol/collateralizationOracle'; +import proposals from '@protocol/proposalsConfig'; +import { expectApprox, overwriteChainlinkAggregator } from '@test/helpers'; +import { TestEndtoEndCoordinator } from '@test/integration/setup'; +import chai, { expect } from 'chai'; +import CBN from 'chai-bn'; +import { solidity } from 'ethereum-waffle'; +import { ethers } from 'hardhat'; describe('e2e-collateralization', function () { let contracts: NamedContracts; diff --git a/test/integration/tests/daiFixedPricePSM.ts b/test/integration/tests/daiFixedPricePSM.ts index 551b0fcf3..1fdf0f7a2 100644 --- a/test/integration/tests/daiFixedPricePSM.ts +++ b/test/integration/tests/daiFixedPricePSM.ts @@ -1,15 +1,14 @@ -import chai, { expect } from 'chai'; -import CBN from 'chai-bn'; -import { solidity } from 'ethereum-waffle'; -import { ethers } from 'hardhat'; +import { FixedPricePSM } from '@custom-types/contracts'; import { NamedContracts } from '@custom-types/types'; -import { expectRevert, getAddresses, getImpersonatedSigner, resetFork, time } from '@test/helpers'; +import proposals from '@protocol/proposalsConfig'; +import { expectApprox, expectRevert, getAddresses, getImpersonatedSigner, time } from '@test/helpers'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import proposals from '@test/integration/proposals_config'; import { forceEth } from '@test/integration/setup/utils'; +import chai, { expect } from 'chai'; +import CBN from 'chai-bn'; +import { solidity } from 'ethereum-waffle'; import { Contract, Signer } from 'ethers'; -import { expectApprox } from '@test/helpers'; -import { FixedPricePSM } from '@custom-types/contracts'; +import { ethers } from 'hardhat'; before(async () => { chai.use(CBN(ethers.BigNumber)); @@ -23,8 +22,9 @@ describe('e2e-peg-stability-module', function () { let e2eCoord: TestEndtoEndCoordinator; let daiPCVDripController: Contract; let doLogging: boolean; - let userAddress; - let minterAddress; + let userAddress: string; + let minterAddress: string; + let governorAddress; let dai: Contract; let daiPSM: Contract; let fei: Contract; diff --git a/test/integration/tests/dao.ts b/test/integration/tests/dao.ts index 2257af38f..6be9f0c7d 100644 --- a/test/integration/tests/dao.ts +++ b/test/integration/tests/dao.ts @@ -1,13 +1,13 @@ +import { Core } from '@custom-types/contracts'; +import { ContractAccessRights, NamedAddresses, NamedContracts } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; +import { getImpersonatedSigner, increaseTime, latestTime, time } from '@test/helpers'; +import { TestEndtoEndCoordinator } from '@test/integration/setup'; +import { forceEth } from '@test/integration/setup/utils'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import hre, { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, increaseTime, latestTime, resetFork, time } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import { forceEth } from '@test/integration/setup/utils'; -import { Core } from '@custom-types/contracts'; const toBN = ethers.BigNumber.from; describe('e2e-dao', function () { @@ -71,14 +71,14 @@ describe('e2e-dao', function () { const calldatas = [ '0x70b0f660000000000000000000000000000000000000000000000000000000000000000a' // set voting delay 10 ]; - const description = []; + const description: any[] = []; await hre.network.provider.request({ method: 'hardhat_impersonateAccount', - params: [contractAddresses.multisig] + params: [contractAddresses.guardianMultisig] }); - const signer = await ethers.getSigner(contractAddresses.multisig); + const signer = await ethers.getSigner(contractAddresses.guardianMultisig); // Propose // note ethers.js requires using this notation when two overloaded methods exist) @@ -122,11 +122,11 @@ describe('e2e-dao', function () { describe('Optimistic Approval', async () => { beforeEach(async function () { - const { tribalChiefOptimisticMultisig, timelock } = contractAddresses; + const { optimisticMultisig, timelock } = contractAddresses; await hre.network.provider.request({ method: 'hardhat_impersonateAccount', - params: [tribalChiefOptimisticMultisig] + params: [optimisticMultisig] }); await hre.network.provider.request({ @@ -142,7 +142,7 @@ describe('e2e-dao', function () { await ( await ethers.getSigner(timelock) - ).sendTransaction({ to: tribalChiefOptimisticMultisig, value: toBN('40000000000000000') }); + ).sendTransaction({ to: optimisticMultisig, value: toBN('40000000000000000') }); }); it('governor can assume timelock admin', async () => { @@ -158,12 +158,12 @@ describe('e2e-dao', function () { }); it('proposal can execute on tribalChief', async () => { - const { tribalChiefOptimisticMultisig } = contractAddresses; + const { optimisticMultisig } = contractAddresses; const { optimisticTimelock, tribalChief } = contracts; const oldBlockReward = await tribalChief.tribePerBlock(); await optimisticTimelock - .connect(await ethers.getSigner(tribalChiefOptimisticMultisig)) + .connect(await ethers.getSigner(optimisticMultisig)) .schedule( tribalChief.address, 0, @@ -184,7 +184,7 @@ describe('e2e-dao', function () { await increaseTime(500000); await optimisticTimelock - .connect(await ethers.getSigner(tribalChiefOptimisticMultisig)) + .connect(await ethers.getSigner(optimisticMultisig)) .execute( tribalChief.address, 0, @@ -218,7 +218,10 @@ describe('e2e-dao', function () { const id = ethers.utils.id(element); const numRoles = await core.getRoleMemberCount(id); doLogging && console.log(`Role count for ${element}: ${numRoles}`); - expect(numRoles.toNumber()).to.be.equal(accessRights[element].length, 'role ' + element); + expect(numRoles.toNumber()).to.be.equal( + accessRights[element as keyof ContractAccessRights].length, + 'role ' + element + ); } }); @@ -230,13 +233,16 @@ describe('e2e-dao', function () { for (let i = 0; i < roles.length; i++) { const element = roles[i]; const id = ethers.utils.id(element); - for (let i = 0; i < accessControl[element].length; i++) { - const contractAddress = accessControl[element][i]; + for (let i = 0; i < accessControl[element as keyof ContractAccessRights].length; i++) { + const contractAddress = accessControl[element as keyof ContractAccessRights][i]; doLogging && console.log(`${element} contract address: ${contractAddress}`); const hasRole = await core.hasRole(id, contractAddress); expect(hasRole).to.be.equal( true, - 'expect contract ' + accessControl[element][i] + ' expected to have role ' + element + 'expect contract ' + + accessControl[element as keyof ContractAccessRights][i] + + ' expected to have role ' + + element ); } } diff --git a/test/integration/tests/dependencies.ts b/test/integration/tests/dependencies.ts deleted file mode 100644 index bfced5e5a..000000000 --- a/test/integration/tests/dependencies.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { expect } from 'chai'; -import { ProposalCategory, ProposalDescription } from '@custom-types/types'; -import proposals from '@test/integration/proposals_config'; -import dependencies from '@protocol/dependencies'; -import addresses from '@protocol/mainnetAddresses'; -import collateralizationAddresses from '@protocol/collateralizationOracle'; -import { AddressCategory } from '@custom-types/types'; // imported without custom path to allow docs to autogen without ts errors - -describe('e2e-dependencies', function () { - const doLogging = Boolean(process.env.LOGGING); - let proposalNames: string[]; - - before(function () { - proposalNames = Object.keys(proposals); - }); - - describe('Check Dependencies', function () { - it('are all signed off', async function () { - for (let i = 0; i < proposalNames.length; i++) { - const proposalName = proposalNames[i]; - if (proposals[proposalName].category === ProposalCategory.None || proposals[proposalName].deploy) { - // Skip if not a DAO/OA proposal or not yet deployed - doLogging && console.log(`Skipping: ${proposalName}`); - continue; - } - - const contracts = getProposalContracts(proposals[proposalName].proposal); - doLogging && console.log(`Checking proposal: ${proposalName}`); - doLogging && console.log(`Proposal affects contracts: ${contracts}`); - - for (let j = 0; j < contracts.length; j++) { - const contract = contracts[j]; - doLogging && console.log(`Contract: ${contract}`); - const category = addresses[contract].category; - if (category === AddressCategory.External) { - continue; - } - - if (category === AddressCategory.Deprecated) { - doLogging && console.log(`Checking deprecated contract: ${contract}`); - - expect(dependencies).to.not.haveOwnProperty(contract); - - // Make sure proposal config has this deprecated contract signed off - expect(proposals[proposalName].deprecatedContractSignoff).to.contain(contract); - continue; - } - - doLogging && console.log(`Checking contract: ${contract}`); - - expect(dependencies).to.haveOwnProperty(contract); - - // Make sure proposal config has this fip signed off - expect(proposals[proposalName].affectedContractSignoff).to.contain(contract); - } - } - }); - - it('all have contract category correct', async function () { - for (let i = 0; i < proposalNames.length; i++) { - const proposalName = proposalNames[i]; - const contracts = proposals[proposalName].affectedContractSignoff; - const deprecated = proposals[proposalName].deprecatedContractSignoff; - - if (proposals[proposalName].deploy) { - // Skip these checks if not mainnet deployed - doLogging && console.log(`Skipping: ${proposalName}`); - continue; - } - doLogging && console.log(`Checking proposal: ${proposalName}`); - doLogging && console.log(`Proposal affects contracts: ${contracts}`); - - for (let j = 0; j < contracts.length; j++) { - const contract = contracts[j]; - const category = addresses[contract].category; - expect(category).to.not.be.equal( - AddressCategory.External, - 'contract ' + contract + ' expected not to be External' - ); - expect(category).to.not.be.equal( - AddressCategory.Deprecated, - 'contract ' + contract + ' expected not to be Deprecated' - ); - - expect(deprecated).to.not.contain(contract); - } - - for (let j = 0; j < deprecated.length; j++) { - const contract = deprecated[j]; - const category = addresses[contract].category; - expect(category).to.be.equal(AddressCategory.Deprecated); - - expect(contracts).to.not.contain(contract); - } - } - }); - - it('collateralization oracle deposits category correct', async function () { - const tokenAddresses = Object.keys(collateralizationAddresses); - const crDeposits = []; - for (let i = 0; i < tokenAddresses.length; i++) { - const element = tokenAddresses[i]; - - const deposits = collateralizationAddresses[element]; - - for (let i = 0; i < deposits.length; i++) { - const deposit = deposits[i]; - crDeposits.push(deposit); - - doLogging && console.log(`${element} contract address: ${deposit}`); - if (addresses[deposit]) { - // addresses[deposit] may be undefined if a deposit is added to the - // dependencies and permissions/collateralizationOracle files, but - // is not yet deployed on the mainnet (i.e. in mainnetAddresses.ts). - expect(addresses[deposit].category).to.not.be.equal('Deprecated'); - } - } - } - - const mainnetAddresses = Object.keys(addresses); - - for (let i = 0; i < mainnetAddresses.length; i++) { - const element = mainnetAddresses[i]; - - const category = addresses[element].category; - - if (category === 'PCV') { - expect(crDeposits).to.contain(element, 'expected in crDeposits'); - } - } - }); - - it('are listed bidirectionally', async function () { - const contractNames = Object.keys(dependencies); - for (let i = 0; i < contractNames.length; i++) { - const contract = contractNames[i]; - doLogging && console.log(`Checking contract: ${contract}`); - const contractDependencies = dependencies[contract].contractDependencies; - for (let j = 0; j < contractDependencies.length; j++) { - const dependency = contractDependencies[j]; - doLogging && console.log(`Checking contract dependency: ${dependency}`); - expect(dependencies).to.haveOwnProperty(dependency); - expect(dependencies[dependency].contractDependencies).to.contain(contract, 'dependencies of ' + dependency); - } - } - }); - }); -}); - -function getProposalContracts(proposal: ProposalDescription): string[] { - let contracts = []; - - for (let i = 0; i < proposal.commands.length; i++) { - const command = proposal.commands[i]; - contracts.push(command.target); - contracts = contracts.concat(getContractsFromArgs(command.arguments)); - } - - // dedup - return [...new Set(contracts)]; -} - -function getContractsFromArgs(args: any[]): string[] { - let result: string[] = []; - for (let i = 0; i < args.length; i++) { - const element = args[i]; - if (typeof element === typeof '') { - // find all contracts - let formatted: string[] = element.match(/\{\w+\}/g); - formatted = formatted || []; - - // Remove braces - formatted = formatted.map((item) => item.replace('{', '').replace('}', '')); - - result = result.concat(formatted); - } else if (typeof element === typeof []) { - // recurse through levels of array - const moreContracts: string[] = getContractsFromArgs(element); - result = result.concat(moreContracts); - } - } - return result; -} diff --git a/test/integration/tests/ethPSM.ts b/test/integration/tests/ethPSM.ts index a2713519f..e898096e9 100644 --- a/test/integration/tests/ethPSM.ts +++ b/test/integration/tests/ethPSM.ts @@ -1,24 +1,23 @@ import { AavePCVDeposit, - PegStabilityModule, Fei, IERC20, PCVDripController, + PegStabilityModule, PSMRouter, WETH9 } from '@custom-types/contracts'; +import { NamedAddresses, NamedContracts } from '@custom-types/types'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import proposals from '@protocol/proposalsConfig'; +import { expectApprox, expectRevert, getImpersonatedSigner, increaseTime, time } from '@test/helpers'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { BigNumber } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { expectApprox, expectRevert, getImpersonatedSigner, increaseTime, resetFork } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; import { TestEndtoEndCoordinator } from '../setup'; import { forceEth } from '../setup/utils'; -import { time } from '@test/helpers'; const oneEth = ethers.constants.WeiPerEther; @@ -70,7 +69,7 @@ describe('eth PSM', function () { fei = await ethers.getContractAt('Fei', contractAddresses.fei); dripper = contracts.aaveEthPCVDripController as PCVDripController; await hre.network.provider.send('hardhat_setBalance', [deployAddress.address, '0x21E19E0C9BAB2400000']); - guardian = await getImpersonatedSigner(contractAddresses.guardian); + guardian = await getImpersonatedSigner(contractAddresses.guardianMultisig); await forceEth(guardian.address); }); @@ -194,9 +193,9 @@ describe('eth PSM', function () { // empty drip target to make sure it is empty await forceEth(ethPSM.address); const signer = await getImpersonatedSigner(ethPSM.address); - await contracts.wethERC20 + await contracts.weth .connect(signer) - .transfer(await dripper.source(), await contracts.wethERC20.balanceOf(ethPSM.address)); + .transfer(await dripper.source(), await contracts.weth.balanceOf(ethPSM.address)); }); it('sets ethpsm reserve threshold to 5250 eth', async () => { diff --git a/test/integration/tests/fei.ts b/test/integration/tests/fei.ts index 5a8687511..69dcac5b5 100644 --- a/test/integration/tests/fei.ts +++ b/test/integration/tests/fei.ts @@ -1,13 +1,13 @@ +import { Fei } from '@custom-types/contracts'; +import { NamedContracts } from '@custom-types/types'; +import { Signer } from '@ethersproject/abstract-signer'; +import proposals from '@protocol/proposalsConfig'; +import { ZERO_ADDRESS } from '@test/helpers'; +import { TestEndtoEndCoordinator } from '@test/integration/setup'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { getAddresses, getImpersonatedSigner, resetFork, ZERO_ADDRESS } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import { Fei } from '@custom-types/contracts'; -import { Signer } from '@ethersproject/abstract-signer'; const toBN = ethers.BigNumber.from; describe('e2e-fei', function () { diff --git a/test/integration/tests/fip-38-tokemak.ts b/test/integration/tests/fip-38-tokemak.ts deleted file mode 100644 index 1f24bd066..000000000 --- a/test/integration/tests/fip-38-tokemak.ts +++ /dev/null @@ -1,87 +0,0 @@ -import chai, { expect } from 'chai'; -import CBN from 'chai-bn'; -import { solidity } from 'ethereum-waffle'; -import { ethers } from 'hardhat'; -import { NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, time, resetFork } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import { forceEth } from '@test/integration/setup/utils'; -const toBN = ethers.BigNumber.from; -const tenPow18 = toBN('1000000000000000000'); - -const TOKEMAK_MANAGER_ROLLOVER_ADDRESS = '0x90b6C61B102eA260131aB48377E143D6EB3A9d4B'; // has the rollover role -const TOKEMAK_MANAGER_ADDRESS = '0xa86e412109f77c45a3bc1c5870b880492fb86a14'; // tokemak manager -const IPFS_JSON_FILE_HASH = 'QmP4Vzg45jExr3mcNsx9xxV1fNft95uVzgZGeLtkBXgpkx'; - -describe('e2e-fip-38-tokemak', function () { - let contracts: NamedContracts; - let deployAddress: string; - let e2eCoord: TestEndtoEndCoordinator; - let doLogging: boolean; - - before(async () => { - chai.use(CBN(ethers.BigNumber)); - chai.use(solidity); - }); - - before(async function () { - // Setup test environment and get contracts - const version = 1; - deployAddress = (await ethers.getSigners())[0].address; - if (!deployAddress) throw new Error(`No deploy address!`); - - doLogging = Boolean(process.env.LOGGING); - - const config = { - logging: doLogging, - deployAddress: deployAddress, - version: version - }; - - e2eCoord = new TestEndtoEndCoordinator(config, proposals); - - doLogging && console.log(`Loading environment...`); - ({ contracts } = await e2eCoord.loadEnvironment()); - doLogging && console.log(`Environment loaded.`); - }); - - it('should have deposited ETH, and be able to withdraw', async function () { - const { - ethTokemakPCVDeposit, - tWETH // Tokemak ETH reactor - } = contracts; - - // we should start with 10k tWETH, 0 ETH - expect((await tWETH.balanceOf(ethTokemakPCVDeposit.address)).toString()).to.be.equal( - ethers.utils.parseEther('10000') - ); - expect((await ethers.provider.getBalance(ethTokemakPCVDeposit.address)).toString()).to.be.equal( - ethers.utils.parseEther('0') - ); - - // request to withdraw 10k ETH - await ethTokemakPCVDeposit.requestWithdrawal(tenPow18.mul(toBN(10_000))); - - // impersonate the rollover signer, and make the Tokemak pool go to next cycle - await forceEth(TOKEMAK_MANAGER_ROLLOVER_ADDRESS); - const tokemakRolloverSigner = await getImpersonatedSigner(TOKEMAK_MANAGER_ROLLOVER_ADDRESS); - const tokemakManagerAbi = [ - 'function nextCycleStartTime() view returns (uint256)', - 'function completeRollover(string calldata rewardsIpfsHash)' - ]; - const tokemakManager = new ethers.Contract(TOKEMAK_MANAGER_ADDRESS, tokemakManagerAbi, tokemakRolloverSigner); - const cycleEnd = await tokemakManager.nextCycleStartTime(); - await time.increaseTo(cycleEnd + 1); - await tokemakManager.completeRollover(IPFS_JSON_FILE_HASH); - - // Perform withdraw - await ethTokemakPCVDeposit.withdraw(ethTokemakPCVDeposit.address, tenPow18.mul(toBN(10_000))); - - // Should end with 0 tWETH, 10k ETH - expect((await tWETH.balanceOf(ethTokemakPCVDeposit.address)).toString()).to.be.equal(ethers.utils.parseEther('0')); - expect((await ethers.provider.getBalance(ethTokemakPCVDeposit.address)).toString()).to.be.equal( - ethers.utils.parseEther('10000') - ); - }); -}); diff --git a/test/integration/tests/fuse.ts b/test/integration/tests/fuse.ts index 99a298480..8183df452 100644 --- a/test/integration/tests/fuse.ts +++ b/test/integration/tests/fuse.ts @@ -1,10 +1,10 @@ +import { NamedAddresses, NamedContracts } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; +import { getImpersonatedSigner, time } from '@test/helpers'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, resetFork, time } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; import { TestEndtoEndCoordinator } from '../setup'; import { forceEth } from '../setup/utils'; diff --git a/test/integration/tests/lusdPSM.ts b/test/integration/tests/lusdPSM.ts index bf7ed53ba..f91f68e8e 100644 --- a/test/integration/tests/lusdPSM.ts +++ b/test/integration/tests/lusdPSM.ts @@ -1,19 +1,13 @@ -import { PegStabilityModule, Fei, IERC20, PCVDripController, BAMMDeposit, FeiSkimmer } from '@custom-types/contracts'; +import { BAMMDeposit, Fei, FeiSkimmer, IERC20, PCVDripController, PegStabilityModule } from '@custom-types/contracts'; +import { NamedAddresses, NamedContracts } from '@custom-types/types'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import proposals from '@protocol/proposalsConfig'; +import { expectRevert, getImpersonatedSigner, increaseTime, overwriteChainlinkAggregator } from '@test/helpers'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { BigNumber } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { - expectRevert, - getImpersonatedSigner, - increaseTime, - overwriteChainlinkAggregator, - resetFork -} from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; import { TestEndtoEndCoordinator } from '../setup'; import { forceEth } from '../setup/utils'; @@ -68,7 +62,7 @@ describe('lusd PSM', function () { dripper = contracts.lusdPCVDripController as PCVDripController; await hre.network.provider.send('hardhat_setBalance', [deployAddress.address, '0x21E19E0C9BAB2400000']); await fei.mint(deployAddress.address, amount); - guardian = await getImpersonatedSigner(contractAddresses.guardian); + guardian = await getImpersonatedSigner(contractAddresses.guardianMultisig); await hre.network.provider.send('hardhat_setBalance', [guardian.address, '0x21E19E0C9BAB2400000']); await overwriteChainlinkAggregator(contractAddresses.chainlinkEthUsdOracle, '400000000000', '8'); }); diff --git a/test/integration/tests/metagov/BalancerGaugeStaker.ts b/test/integration/tests/metagov/BalancerGaugeStaker.ts new file mode 100644 index 000000000..db60f65fd --- /dev/null +++ b/test/integration/tests/metagov/BalancerGaugeStaker.ts @@ -0,0 +1,168 @@ +import chai, { expect } from 'chai'; +import CBN from 'chai-bn'; +import { solidity } from 'ethereum-waffle'; +import { ethers } from 'hardhat'; +import { NamedContracts } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; +import { TestEndtoEndCoordinator } from '@test/integration/setup'; +import { getImpersonatedSigner, expectRevert, expectEvent } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; +import { BalancerGaugeStaker } from '@custom-types/contracts'; + +const e18 = '000000000000000000'; + +describe('e2e-metagov', function () { + let deployAddress: string; + let contracts: NamedContracts; + let e2eCoord: TestEndtoEndCoordinator; + const logging = Boolean(process.env.LOGGING); + + before(async () => { + chai.use(CBN(ethers.BigNumber)); + chai.use(solidity); + }); + + before(async function () { + deployAddress = (await ethers.getSigners())[0].address; + const config = { + logging, + deployAddress, + version: 1 + }; + e2eCoord = new TestEndtoEndCoordinator(config, proposals); + ({ contracts } = await e2eCoord.loadEnvironment()); + }); + + describe('BalancerGaugeStaker.sol', function () { + let staker: BalancerGaugeStaker; + let daoSigner: any; + let randomSigner: any; + + before(async function () { + // Create the contract + const factory = await ethers.getContractFactory('BalancerGaugeStaker'); + staker = await factory.deploy( + contracts.core.address, + contracts.balancerGaugeController.address, + contracts.balancerMinter.address + ); + await staker.deployTransaction.wait(); + + // get signer for a random address + randomSigner = await getImpersonatedSigner('0x6ef71cA9cD708883E129559F5edBFb9d9D5C6148'); + await forceEth(randomSigner.address); + + // seed the staker with some LP tokens + const lpTokenHolder = '0x4f9463405f5bc7b4c1304222c1df76efbd81a407'; + const lpTokenSigner = await getImpersonatedSigner(lpTokenHolder); + await forceEth(lpTokenHolder); + await contracts.bpt30Fei70Weth.connect(lpTokenSigner).transfer(staker.address, `1000${e18}`); + + // also airdrop some BAL so that balance is not zero + const balTokenHolder = '0xBA12222222228d8Ba445958a75a0704d566BF2C8'; + const balTokenSigner = await getImpersonatedSigner(balTokenHolder); + await forceEth(balTokenHolder); + await contracts.bal.connect(balTokenSigner).transfer(staker.address, '10000'); + + // grant role to dao and initialize dao signer + await forceEth(contracts.feiDAOTimelock.address); + daoSigner = await getImpersonatedSigner(contracts.feiDAOTimelock.address); + await contracts.core + .connect(daoSigner) + .grantRole(ethers.utils.id('METAGOVERNANCE_GAUGE_ADMIN'), daoSigner.address); + }); + + it('init', async function () { + expect(await staker.balanceReportedIn()).to.be.equal(contracts.bal.address); + expect(await staker.balance()).to.be.equal('10000'); + expect((await staker.resistantBalanceAndFei())[0]).to.be.equal('10000'); + expect((await staker.resistantBalanceAndFei())[1]).to.be.equal('0'); + }); + + describe('setBalancerMinter()', function () { + it('should revert if user has no role', async function () { + await expectRevert(staker.setBalancerMinter(contracts.balancerMinter.address), 'UNAUTHORIZED'); + }); + + it('should work if user has METAGOVERNANCE_GAUGE_ADMIN role', async function () { + expect(await staker.balancerMinter()).to.be.equal(contracts.balancerMinter.address); + await staker.connect(daoSigner).setBalancerMinter(deployAddress); + expect(await staker.balancerMinter()).to.be.equal(deployAddress); + await staker.connect(daoSigner).setBalancerMinter(contracts.balancerMinter.address); + expect(await staker.balancerMinter()).to.be.equal(contracts.balancerMinter.address); + }); + }); + + describe('withdraw()', function () { + it('should revert if user has no role', async function () { + await expectRevert( + staker.connect(randomSigner).withdraw(daoSigner.address, '10'), + 'CoreRef: Caller is not a PCV controller' + ); + }); + + it('should revert if contract is paused', async function () { + await staker.connect(daoSigner).pause(); + await expectRevert(staker.withdraw(daoSigner.address, '10'), 'Pausable: paused'); + await staker.connect(daoSigner).unpause(); + }); + + it('should work if user has PCV_CONTROLLER_ROLE role', async function () { + const balanceBefore = await contracts.bal.balanceOf(daoSigner.address); + await staker.connect(daoSigner).withdraw(daoSigner.address, '10'); + const balanceAfter = await contracts.bal.balanceOf(daoSigner.address); + expect(balanceAfter.sub(balanceBefore)).to.be.equal('10'); + expect(await staker.balance()).to.be.equal('9990'); + }); + }); + + describe('mintGaugeRewards()', function () { + it('should revert for gauges that are not configured', async function () { + await expectRevert( + staker.mintGaugeRewards(contracts.bal.address), + 'BalancerGaugeStaker: token has no gauge configured' + ); + }); + + it('should be able to mint BAL', async function () { + // set gauge and stake a bunch of tokens + await staker + .connect(daoSigner) + .setTokenToGauge(contracts.bpt30Fei70Weth.address, contracts.balancerGaugeBpt30Fei70Weth.address); + await staker.connect(daoSigner).stakeAllInGauge(contracts.bpt30Fei70Weth.address); + + staker.mintGaugeRewards(contracts.bpt30Fei70Weth.address); + expect(await staker.balance()).to.be.at.least('9991'); + expect((await staker.resistantBalanceAndFei())[0]).to.be.at.least('9991'); + expect((await staker.resistantBalanceAndFei())[1]).to.be.equal('0'); + }); + }); + + describe('withdrawERC20()', function () { + it('should revert if user has no role', async function () { + await expectRevert( + staker.connect(randomSigner).withdraw(daoSigner.address, '10'), + 'CoreRef: Caller is not a PCV controller' + ); + }); + + it('should revert if contract is paused', async function () { + await staker.connect(daoSigner).pause(); + await expectRevert(staker.withdraw(daoSigner.address, '10'), 'Pausable: paused'); + await staker.connect(daoSigner).unpause(); + }); + + it('should work if user has PCV_CONTROLLER_ROLE role', async function () { + const balanceBefore = await contracts.bal.balanceOf(daoSigner.address); + await expectEvent( + staker.connect(daoSigner).withdrawERC20(contracts.bal.address, daoSigner.address, '10'), + staker, + 'WithdrawERC20', + [daoSigner.address, contracts.bal.address, daoSigner.address, '10'] + ); + const balanceAfter = await contracts.bal.balanceOf(daoSigner.address); + expect(balanceAfter.sub(balanceBefore)).to.be.equal('10'); + }); + }); + }); +}); diff --git a/test/integration/tests/metagov/GovernorVoter.ts b/test/integration/tests/metagov/GovernorVoter.ts index 7d7d3a313..a00555833 100644 --- a/test/integration/tests/metagov/GovernorVoter.ts +++ b/test/integration/tests/metagov/GovernorVoter.ts @@ -3,13 +3,13 @@ import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; import { NamedContracts } from '@custom-types/types'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; import { getImpersonatedSigner, expectRevert, time } from '@test/helpers'; import { forceEth } from '@test/integration/setup/utils'; import { MockGovernorVoter } from '@custom-types/contracts'; -const e18 = (x) => ethers.constants.WeiPerEther.mul(x); +const e18 = (x: any) => ethers.constants.WeiPerEther.mul(x); describe('e2e-metagov', function () { let deployAddress: string; diff --git a/test/integration/tests/metagov/LiquidityGaugeManager.ts b/test/integration/tests/metagov/LiquidityGaugeManager.ts index 199fc873a..cfeacc556 100644 --- a/test/integration/tests/metagov/LiquidityGaugeManager.ts +++ b/test/integration/tests/metagov/LiquidityGaugeManager.ts @@ -3,13 +3,13 @@ import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; import { NamedContracts } from '@custom-types/types'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; import { getImpersonatedSigner, expectRevert } from '@test/helpers'; import { forceEth } from '@test/integration/setup/utils'; import { AngleDelegatorPCVDeposit } from '@custom-types/contracts'; -const e18 = (x) => ethers.constants.WeiPerEther.mul(x); +const e18 = (x: any) => ethers.constants.WeiPerEther.mul(x); describe('e2e-metagov', function () { let deployAddress: string; diff --git a/test/integration/tests/metagov/VoteEscrowTokenManager.ts b/test/integration/tests/metagov/VoteEscrowTokenManager.ts index 0b891614b..c22533f28 100644 --- a/test/integration/tests/metagov/VoteEscrowTokenManager.ts +++ b/test/integration/tests/metagov/VoteEscrowTokenManager.ts @@ -3,13 +3,13 @@ import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; import { NamedContracts } from '@custom-types/types'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; import { getImpersonatedSigner, expectRevert, time } from '@test/helpers'; import { forceEth } from '@test/integration/setup/utils'; import { MockVoteEscrowTokenManager } from '@custom-types/contracts'; -const e18 = (x) => ethers.constants.WeiPerEther.mul(x); +const e18 = (x: any) => ethers.constants.WeiPerEther.mul(x); describe('e2e-metagov', function () { let deployAddress: string; diff --git a/test/integration/tests/merger.ts.disabled b/test/integration/tests/old/merger.ts.disabled similarity index 98% rename from test/integration/tests/merger.ts.disabled rename to test/integration/tests/old/merger.ts.disabled index 561000e02..a4fca4255 100644 --- a/test/integration/tests/merger.ts.disabled +++ b/test/integration/tests/old/merger.ts.disabled @@ -5,7 +5,7 @@ import { ethers } from 'hardhat'; import { NamedAddresses, NamedContracts } from '@custom-types/types'; import { getImpersonatedSigner, resetFork, time } from '@test/helpers'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import { PegExchanger, PegExchangerDripper } from '@custom-types/contracts'; import { expectApprox, expectRevert } from '@test/helpers'; import { forceEth } from '../setup/utils'; diff --git a/test/integration/tests/old/migrateProxies/index.ts b/test/integration/tests/old/migrateProxies/index.ts index 70d6cf2d3..ed505e65e 100644 --- a/test/integration/tests/old/migrateProxies/index.ts +++ b/test/integration/tests/old/migrateProxies/index.ts @@ -58,7 +58,7 @@ describe.skip('e2e-migrate-proxies', function () { feiDAO = contracts.feiDAO; await forceEth(feiDAO.address); - await reduceDAOVotingPeriod(feiDAO, contractAddresses.multisig); + await reduceDAOVotingPeriod(feiDAO, contractAddresses.guardianMultisig); }); it('should give Rari timelock governor and point FEI DAO timelock to oldTimelock (fip_84a)', async () => { @@ -78,7 +78,7 @@ describe.skip('e2e-migrate-proxies', function () { // Multisig address has sufficient TRIBE to pass quorum const targets = [contractAddresses.core, contractAddresses.core, feiDAO.address]; const values = [0, 0, 0]; - await performDAOAction(feiDAO, contractAddresses.multisig, fip_84aCalldata, targets, values); + await performDAOAction(feiDAO, contractAddresses.guardianMultisig, fip_84aCalldata, targets, values); // 1. Rari timelock granted GOVERN_ROLE role const rariTimelockHasRole = await contracts.core.hasRole(GOVERN_ROLE, contractAddresses.rariTimelock); @@ -108,7 +108,7 @@ describe.skip('e2e-migrate-proxies', function () { contractAddresses.timelock, contractAddresses.feiDAO ]; - await performDAOAction(feiDAO, contractAddresses.multisig, fip_84bCalldata, targets, values); + await performDAOAction(feiDAO, contractAddresses.guardianMultisig, fip_84bCalldata, targets, values); // 1. Check ProxyAdmin owner changed to newTimelock const newTimelockAddress = contractAddresses.feiDAOTimelock; @@ -136,7 +136,7 @@ describe.skip('e2e-migrate-proxies', function () { const values = [0]; const targets = [contractAddresses.timelock]; - await performDAOAction(feiDAO, contractAddresses.multisig, fip_84cCalldata, targets, values); + await performDAOAction(feiDAO, contractAddresses.guardianMultisig, fip_84cCalldata, targets, values); const oldTimelockAdmin = await oldTimelock.admin(); expect(oldTimelockAdmin).to.equal(contractAddresses.feiDAOTimelock); @@ -149,7 +149,7 @@ describe.skip('e2e-migrate-proxies', function () { const oldIncentivesBehaviour = await proxyAdmin .connect(newTimelockSigner) - .getProxyImplementation(contractAddresses.aaveTribeIncentivesControllerProxy); + .getProxyImplementation(contractAddresses.aaveTribeIncentivesController); expect(oldIncentivesBehaviour).to.equal(contractAddresses.aaveTribeIncentivesControllerImpl); console.log({ oldIncentivesBehaviour }); @@ -160,11 +160,11 @@ describe.skip('e2e-migrate-proxies', function () { const upgradeIncentivesCalldata = [ '0x99a88ec4000000000000000000000000dee5c1662bbff8f80f7c572d8091bf251b3b0dab000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' ]; - await performDAOAction(feiDAO, contractAddresses.multisig, upgradeIncentivesCalldata, targets, values); + await performDAOAction(feiDAO, contractAddresses.guardianMultisig, upgradeIncentivesCalldata, targets, values); const newIncentivesBehaviour = await proxyAdmin .connect(newTimelockSigner) - .getProxyImplementation(contractAddresses.aaveTribeIncentivesControllerProxy); + .getProxyImplementation(contractAddresses.aaveTribeIncentivesController); expect(newIncentivesBehaviour).to.equal(dummyUpgradeAddress); }); diff --git a/test/integration/tests/pcv.ts b/test/integration/tests/pcv.ts index 0e0ff263a..802d8462f 100644 --- a/test/integration/tests/pcv.ts +++ b/test/integration/tests/pcv.ts @@ -1,13 +1,13 @@ +import { NamedAddresses, NamedContracts } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; +import { expectApprox, getImpersonatedSigner, overwriteChainlinkAggregator, resetFork, time } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { Contract } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { expectApprox, getImpersonatedSigner, overwriteChainlinkAggregator, resetFork, time } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; import { TestEndtoEndCoordinator } from '../setup'; -import { forceEth } from '@test/integration/setup/utils'; const toBN = ethers.BigNumber.from; diff --git a/test/integration/tests/podOperation.ts b/test/integration/tests/podOperation.ts index 2343038c5..b359d2bd5 100644 --- a/test/integration/tests/podOperation.ts +++ b/test/integration/tests/podOperation.ts @@ -1,17 +1,18 @@ import { PodAdminGateway, PodFactory } from '@custom-types/contracts'; +import { NamedAddresses, NamedContracts } from '@custom-types/types'; +import Safe from '@gnosis.pm/safe-core-sdk'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { MIN_TIMELOCK_DELAY, TRIBAL_COUNCIL_POD_ID, tribeCouncilPodConfig } from '@protocol/optimisticGovernance'; +import proposals from '@protocol/proposalsConfig'; +import { getImpersonatedSigner, initialiseGnosisSDK, time } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; -import { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, resetFork, time, initialiseGnosisSDK } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import { forceEth } from '@test/integration/setup/utils'; -import { TestEndtoEndCoordinator } from '../setup'; import { BigNumberish, Contract } from 'ethers'; +import { ethers } from 'hardhat'; import { abi as timelockABI } from '../../../artifacts/@openzeppelin/contracts/governance/TimelockController.sol/TimelockController.json'; -import { MIN_TIMELOCK_DELAY } from '@protocol/optimisticGovernance'; +import { TestEndtoEndCoordinator } from '../setup'; function createSafeTxArgs(timelock: Contract, functionSig: string, args: any[]) { return { @@ -33,8 +34,7 @@ describe('Pod operation and veto', function () { let timelockAddress: string; let podTimelock: Contract; let registryTxData: string; - let registryTxData2: string; - let safeSDK: any; + let safeSDK: Safe; const proposalId = '1234'; const proposalMetadata = 'FIP_XX: This tests that the governance upgrade flow works'; @@ -68,6 +68,8 @@ describe('Pod operation and veto', function () { const podAdminGateway = contracts.podAdminGateway as PodAdminGateway; tribalCouncilTimelockSigner = await getImpersonatedSigner(contractAddresses.tribalCouncilTimelock); + await forceEth(contractAddresses.tribalCouncilTimelock); + await forceEth(contractAddresses.feiDAOTimelock); await forceEth(contractAddresses.tribalCouncilTimelock); await forceEth(contractAddresses.feiDAOTimelock); @@ -101,8 +103,8 @@ describe('Pod operation and veto', function () { // 1. Deploy a pod through which a proposal will be executed const deployTx = await podFactory.connect(tribalCouncilTimelockSigner).createOptimisticPod(podConfig); - const { args } = (await deployTx.wait()).events.find((elem) => elem.event === 'CreatePod'); - + const result = (await deployTx.wait()).events!.find((elem) => elem.event === 'CreatePod'); + const args = result!.args!; podId = args.podId; const safeAddress = await podFactory.getPodSafe(podId); timelockAddress = await podFactory.getPodTimelock(podId); @@ -194,7 +196,7 @@ describe('Pod operation and veto', function () { // call the podAdminGateway.veto() method with the proposalId that is in the timelock // 2. Have a member with >quorum TRIBE vote for proposal // 3. Validate that proposal is executed - const userWithTribe = await getImpersonatedSigner(contractAddresses.multisig); + const userWithTribe = await getImpersonatedSigner(contractAddresses.guardianMultisig); const timelockProposalId = await podTimelock.hashOperation( contractAddresses.governanceMetadataRegistry, 0, @@ -211,7 +213,8 @@ describe('Pod operation and veto', function () { const values = [0]; const proposeTx = await nopeDAO.propose(targets, values, calldatas, description); - const { args } = (await proposeTx.wait()).events.find((elem) => elem.event === 'ProposalCreated'); + const result = (await proposeTx.wait()).events!.find((elem: any) => elem.event === 'ProposalCreated'); + const args = result!.args!; const nopeDAOProposalId = args.proposalId; // Use the proposalID to vote for this proposal on the nopeDAO @@ -224,4 +227,136 @@ describe('Pod operation and veto', function () { const readyTimestamp = await podTimelock.getTimestamp(timelockProposalId); expect(readyTimestamp).to.equal(0); }); + + it('should allow TribalCouncil to operate on the protocol', async () => { + // 1. Get Gnosis SDK connections for each TC member + const tribalCouncilTimelock = contracts.tribalCouncilTimelock; + const tribalCouncilSafeSigner = await getImpersonatedSigner(contractAddresses.tribalCouncilSafe); + await forceEth(tribalCouncilTimelock.address); + await forceEth(contractAddresses.tribalCouncilSafe); + + const tribalCouncilMinDelay = await tribalCouncilTimelock.getMinDelay(); + expect(tribalCouncilMinDelay).to.be.equal(tribeCouncilPodConfig.minDelay); + + // 2. Prepare a proposal which requires a TribeRole. TribalCouncil timelock should have been granted + // ROLE_ADMIN and be able to call into RoleBastion to create a role + const dummyRole = ethers.utils.id('DUMMY_2_ROLE'); + const registryTCData = contracts.roleBastion.interface.encodeFunctionData('createRole', [dummyRole]); + await tribalCouncilTimelock + .connect(tribalCouncilSafeSigner) + .schedule( + contractAddresses.roleBastion, + 0, + registryTCData, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001', + tribeCouncilPodConfig.minDelay + ); + + // 5. Execute timelocked transaction - need to call via the podExecutor + // Fast forward time on timelock + await time.increase(tribeCouncilPodConfig.minDelay); + + const podExecutor = contracts.podExecutor; + const executeTx = await podExecutor.execute( + tribalCouncilTimelock.address, + contractAddresses.roleBastion, + 0, + registryTCData, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001' + ); + await executeTx.wait(); + + // 6.0 Validate that the expected role was created in core, should have a ROLE_ADMIN admin + const dummyRoleAdmin = await contracts.core.getRoleAdmin(dummyRole); + expect(dummyRoleAdmin).to.be.equal(ethers.utils.id('ROLE_ADMIN')); + }); + + it('should allow deployed NopeDAO to veto a TribalCouncil proposal', async () => { + // 1. Get Gnosis SDK connections for each TC member + const tribalCouncilTimelock = contracts.tribalCouncilTimelock; + const tribalCouncilSafeSigner = await getImpersonatedSigner(contractAddresses.tribalCouncilSafe); + await forceEth(tribalCouncilTimelock.address); + await forceEth(contractAddresses.tribalCouncilSafe); + + const tribalCouncilMinDelay = await tribalCouncilTimelock.getMinDelay(); + expect(tribalCouncilMinDelay).to.be.equal(tribeCouncilPodConfig.minDelay); + + // 2. Prepare a proposal which requires a TribeRole. TribalCouncil timelock should have been granted + // ROLE_ADMIN and be able to call into RoleBastion to create a role + const dummyRole = ethers.utils.id('DUMMY_ROLE'); + const roleCreationData = contracts.roleBastion.interface.encodeFunctionData('createRole', [dummyRole]); + await tribalCouncilTimelock + .connect(tribalCouncilSafeSigner) + .schedule( + contractAddresses.roleBastion, + 0, + roleCreationData, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001', + tribeCouncilPodConfig.minDelay + ); + + // 3. Create NopeDAO proposal to veto the timelocked transaction + const userWithTribe = await getImpersonatedSigner(contractAddresses.guardianMultisig); + const timelockProposalId = await tribalCouncilTimelock.hashOperation( + contractAddresses.roleBastion, + 0, + roleCreationData, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001' + ); + + // User proposes on NopeDAO + const nopeDAO = contracts.nopeDAO; + const description = 'Veto proposal'; + const calldatas = [ + contracts.podAdminGateway.interface.encodeFunctionData('veto', [TRIBAL_COUNCIL_POD_ID, timelockProposalId]) + ]; + const targets = [contractAddresses.podAdminGateway]; + const values = [0]; + + const proposeTx = await nopeDAO.propose(targets, values, calldatas, description); + const { args } = (await proposeTx.wait()).events.find((elem: any) => elem.event === 'ProposalCreated'); + const nopeDAOProposalId = args.proposalId; + + // Use the proposalID to vote for this proposal on the nopeDAO + await nopeDAO.connect(userWithTribe).castVote(nopeDAOProposalId, 1); + + const descriptionHash = ethers.utils.id(description); + await nopeDAO.execute(targets, values, calldatas, descriptionHash); + + // Validate proposal was nope'd + const readyTimestamp = await tribalCouncilTimelock.getTimestamp(timelockProposalId); + expect(readyTimestamp).to.equal(0); + }); + + it('should not allow non-Safe to queue on TribalCouncil timelock', async () => { + const attackerAddress = '0xFBbbedc28217550fa63ACA29e85b87c2646e11d4'; + const attackerSigner = await getImpersonatedSigner(attackerAddress); + + const tribalCouncilTimelock = contracts.tribalCouncilTimelock; + await forceEth(tribalCouncilTimelock.address); + await forceEth(attackerAddress); + + // 2. Prepare a proposal which requires a TribeRole. TribalCouncil timelock should have been granted + // ROLE_ADMIN and be able to call into RoleBastion to create a role + const dummyRole = ethers.utils.id('DUMMY_3_ROLE'); + const roleCreationData = contracts.roleBastion.interface.encodeFunctionData('createRole', [dummyRole]); + await expect( + tribalCouncilTimelock + .connect(attackerSigner) + .schedule( + contractAddresses.roleBastion, + 0, + roleCreationData, + '0x0000000000000000000000000000000000000000000000000000000000000000', + '0x0000000000000000000000000000000000000000000000000000000000000001', + tribeCouncilPodConfig.minDelay + ) + ).to.be.revertedWith( + 'AccessControl: account 0xfbbbedc28217550fa63aca29e85b87c2646e11d4 is missing role 0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1' + ); + }); }); diff --git a/test/integration/tests/psm.ts b/test/integration/tests/psm.ts index 944202fc2..431e31020 100644 --- a/test/integration/tests/psm.ts +++ b/test/integration/tests/psm.ts @@ -5,7 +5,7 @@ import { ethers } from 'hardhat'; import { NamedContracts } from '@custom-types/types'; import { expectRevert, getAddresses, getImpersonatedSigner, resetFork, time } from '@test/helpers'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import proposals from '@test/integration/proposals_config'; +import proposals from '@protocol/proposalsConfig'; import { forceEth } from '@test/integration/setup/utils'; import { Contract, Signer } from 'ethers'; import { expectApprox } from '@test/helpers'; @@ -21,8 +21,9 @@ describe('e2e-peg-stability-module', function () { let daiPCVDripController: Contract; let doLogging: boolean; let ethPSMRouter: Contract; - let userAddress; - let minterAddress; + let userAddress: string; + let minterAddress: string; + let governorAddress; let weth: Contract; let dai: Contract; let raiPriceBoundPSM: Contract; @@ -30,9 +31,9 @@ describe('e2e-peg-stability-module', function () { let fei: Contract; let rai: Contract; let core: Contract; - let feiDAOTimelock; - let beneficiaryAddress1; - let guardianAddress; + let feiDAOTimelock: Contract; + let beneficiaryAddress1: string; + let guardianAddress: string; let daiFixedPricePSM: Contract; before(async () => { @@ -88,7 +89,7 @@ describe('e2e-peg-stability-module', function () { contracts.feiDAOTimelock.address ]; - ({ userAddress, minterAddress, beneficiaryAddress1, guardianAddress } = addresses); + ({ userAddress, minterAddress, beneficiaryAddress1, guardianAddress, governorAddress } = addresses); await core.grantMinter(minterAddress); @@ -406,6 +407,15 @@ describe('e2e-peg-stability-module', function () { await forceEth(raiWhale); const raiWhaleSigner = await getImpersonatedSigner(raiWhale); await rai.connect(raiWhaleSigner).transfer(raiPriceBoundPSM.address, redeemAmount); + + // Set floor to something sufficiently low for tests to pass - RAI price on-chain fluctuates + await raiPriceBoundPSM.connect(impersonatedSigners[userAddress]).setOracleFloorBasisPoints(25000); + + // Ensure RAI PSM is not paused + const isPaused = await raiPriceBoundPSM.paused(); + if (isPaused) { + await raiPriceBoundPSM.connect(impersonatedSigners[userAddress]).unpause(); + } }); it('exchanges 1000 FEI for rai', async () => { @@ -457,6 +467,9 @@ describe('e2e-peg-stability-module', function () { await forceEth(raiAccount); await rai.connect(raiSigner).transfer(userAddress, mintAmount); await rai.connect(impersonatedSigners[userAddress]).approve(raiPriceBoundPSM.address, mintAmount * 2); + + // Set floor to something sufficiently low for tests to pass - RAI price on-chain fluctuates + await raiPriceBoundPSM.connect(impersonatedSigners[userAddress]).setOracleFloorBasisPoints(2500); }); it('cannot mint because the rai psm is paused', async () => { diff --git a/test/integration/tests/staking.ts b/test/integration/tests/staking.ts index 72d9caa4f..64d19725c 100644 --- a/test/integration/tests/staking.ts +++ b/test/integration/tests/staking.ts @@ -1,24 +1,64 @@ import { AutoRewardsDistributor, + Core, + FeiDAOTimelock, + RewardsDistributorAdmin, + StakingTokenWrapper, TribalChief, TribalChiefSyncExtension, - TribalChiefSyncV2 + TribalChiefSyncV2, + Tribe } from '@custom-types/contracts'; +import { NamedAddresses, NamedContracts } from '@custom-types/types'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import proposals from '@protocol/proposalsConfig'; +import { expectApprox, getImpersonatedSigner, time } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { BigNumber, Contract } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { expectApprox, getImpersonatedSigner, resetFork, time } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; import { TestEndtoEndCoordinator } from '../setup'; -import { forceEth } from '@test/integration/setup/utils'; -import { BN } from 'ethereumjs-util'; const toBN = ethers.BigNumber.from; +const setupIncentivesFixtures = async ( + core: Core, + tribalChief: TribalChief, + feiDAOTimelock: FeiDAOTimelock, + rewardsDistributorAdmin: RewardsDistributorAdmin, + autoRewardsDistributors: AutoRewardsDistributor[], + pid: number, + poolAllocPoints: number, + addresses: NamedAddresses +) => { + // TribalChief fixture: setup with non-zero block reward and various pools with allocation points + const daoSigner = await getImpersonatedSigner(feiDAOTimelock.address); + await forceEth(feiDAOTimelock.address); + await tribalChief.connect(daoSigner).updateBlockReward('26150000000000000000'); + + // Initialise various pools with rewards + await tribalChief.connect(daoSigner).set(pid, poolAllocPoints, ethers.constants.AddressZero, false); + await tribalChief.connect(daoSigner).set(12, 250, ethers.constants.AddressZero, false); + await tribalChief.connect(daoSigner).set(13, 250, ethers.constants.AddressZero, false); + await tribalChief.connect(daoSigner).set(14, 1000, ethers.constants.AddressZero, false); + await tribalChief.connect(daoSigner).set(15, 100, ethers.constants.AddressZero, false); + await tribalChief.connect(daoSigner).set(16, 500, ethers.constants.AddressZero, false); + await tribalChief.connect(daoSigner).set(17, 250, ethers.constants.AddressZero, false); + + // Grant out roles + await core.connect(daoSigner).grantRole(ethers.utils.id('TRIBAL_CHIEF_ADMIN_ROLE'), addresses.tribalChiefSyncV2); + await rewardsDistributorAdmin.connect(daoSigner).becomeAdmin(); + + for (const rewardDistributor of autoRewardsDistributors) { + console.log('granting role: ', rewardDistributor.address); + await rewardsDistributorAdmin + .connect(daoSigner) + .grantRole(ethers.utils.id('AUTO_REWARDS_DISTRIBUTOR_ROLE'), rewardDistributor.address); + } +}; + describe('e2e-staking', function () { let contracts: NamedContracts; let contractAddresses: NamedAddresses; @@ -173,25 +213,40 @@ describe('e2e-staking', function () { }); describe('FeiRari Tribe Staking Rewards', async () => { - let tribe: Contract; + let tribe: Tribe; let tribalChief: TribalChief; let tribePerBlock: BigNumber; let autoRewardsDistributor: AutoRewardsDistributor; - let rewardsDistributorAdmin: Contract; - let stakingTokenWrapper: Contract; + let rewardsDistributorAdmin: RewardsDistributorAdmin; + let stakingTokenWrapper: StakingTokenWrapper; const poolAllocPoints = 1000; const pid = 3; let optimisticTimelock: SignerWithAddress; let totalAllocPoint: BigNumber; before(async () => { - stakingTokenWrapper = contracts.stakingTokenWrapperRari; + stakingTokenWrapper = contracts.stakingTokenWrapperRari as StakingTokenWrapper; tribalChief = contracts.tribalChief as TribalChief; - tribePerBlock = await tribalChief.tribePerBlock(); - - rewardsDistributorAdmin = contracts.rewardsDistributorAdmin; + rewardsDistributorAdmin = contracts.rewardsDistributorAdmin as RewardsDistributorAdmin; autoRewardsDistributor = contracts.autoRewardsDistributor as AutoRewardsDistributor; - tribe = contracts.tribe; + tribe = contracts.tribe as Tribe; + + const feiDAOTimelock = contracts.feiDAOTimelock as FeiDAOTimelock; + const d3AutoRewardsDistributor = contracts.d3AutoRewardsDistributor as AutoRewardsDistributor; + const fei3CrvAutoRewardsDistributor = contracts.fei3CrvAutoRewardsDistributor as AutoRewardsDistributor; + + await setupIncentivesFixtures( + contracts.core as Core, + tribalChief, + feiDAOTimelock, + rewardsDistributorAdmin, + [autoRewardsDistributor, d3AutoRewardsDistributor, fei3CrvAutoRewardsDistributor], + pid, + poolAllocPoints, + contractAddresses + ); + + tribePerBlock = await tribalChief.tribePerBlock(); optimisticTimelock = await ethers.getSigner(contracts.optimisticTimelock.address); await hre.network.provider.request({ @@ -199,6 +254,8 @@ describe('e2e-staking', function () { params: [optimisticTimelock.address] }); await forceEth(optimisticTimelock.address); + + totalAllocPoint = await tribalChief.totalAllocPoint(); }); describe('Staking Token Wrapper', async () => { @@ -307,8 +364,8 @@ describe('e2e-staking', function () { describe('Guardian Disables Supply Rewards', async () => { it('does not receive reward when supply incentives are moved to zero', async () => { - const { erc20Dripper, multisig, rariRewardsDistributorDelegator } = contractAddresses; - const signer = await getImpersonatedSigner(multisig); + const { erc20Dripper, guardianMultisig, rariRewardsDistributorDelegator } = contractAddresses; + const signer = await getImpersonatedSigner(guardianMultisig); const { rariPool8Tribe } = contracts; const rewardsDistributorDelegator = await ethers.getContractAt( 'IRewardsAdmin', @@ -333,6 +390,31 @@ describe('e2e-staking', function () { }); describe('TribalChiefSyncV2', async () => { + before(async () => { + const tribalChief = contracts.tribalChief as TribalChief; + const rewardsDistributorAdmin = contracts.rewardsDistributorAdmin as RewardsDistributorAdmin; + const autoRewardsDistributor = contracts.autoRewardsDistributor as AutoRewardsDistributor; + const feiDAOTimelock = contracts.feiDAOTimelock as FeiDAOTimelock; + + const d3AutoRewardsDistributor = contracts.d3AutoRewardsDistributor as AutoRewardsDistributor; + const fei3CrvAutoRewardsDistributor = contracts.fei3CrvAutoRewardsDistributor as AutoRewardsDistributor; + + const pid = 3; + const poolAllocPoints = 1000; + + // Fixture: Set Tribe block reward to be greater than 0 + await setupIncentivesFixtures( + contracts.core as Core, + tribalChief, + feiDAOTimelock, + rewardsDistributorAdmin, + [autoRewardsDistributor, d3AutoRewardsDistributor, fei3CrvAutoRewardsDistributor], + pid, + poolAllocPoints, + contractAddresses + ); + }); + it('auto-sync works correctly', async () => { const tribalChiefSync: TribalChiefSyncV2 = contracts.tribalChiefSyncV2 as TribalChiefSyncV2; const tribalChiefSyncExtension: TribalChiefSyncExtension = diff --git a/test/integration/tests/tribalCouncil.ts b/test/integration/tests/tribalCouncil.ts index f21126f64..52b72f172 100644 --- a/test/integration/tests/tribalCouncil.ts +++ b/test/integration/tests/tribalCouncil.ts @@ -1,16 +1,16 @@ -import { PodFactory, PodAdminGateway, RoleBastion, Core } from '@custom-types/contracts'; +import { Core, PodAdminGateway, PodFactory, RoleBastion } from '@custom-types/contracts'; +import { NamedAddresses, NamedContracts } from '@custom-types/types'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { MIN_TIMELOCK_DELAY, tribalCouncilMembers } from '@protocol/optimisticGovernance'; +import proposals from '@protocol/proposalsConfig'; +import { getImpersonatedSigner } from '@test/helpers'; +import { forceEth } from '@test/integration/setup/utils'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; +import { BigNumber } from 'ethers'; import { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, resetFork } from '@test/helpers'; -import proposals from '@test/integration/proposals_config'; -import { forceEth } from '@test/integration/setup/utils'; import { TestEndtoEndCoordinator } from '../setup'; -import { BigNumber } from 'ethers'; -import { tribalCouncilMembers, MIN_TIMELOCK_DELAY } from '@protocol/optimisticGovernance'; const toBN = ethers.BigNumber.from; @@ -121,7 +121,8 @@ describe('Tribal Council', function () { /////////// TribalCouncil management of other pods ///////////// it('can create a child pod', async () => { const deployTx = await podFactory.connect(tribalCouncilTimelockSigner).createOptimisticPod(podConfig); - const { args } = (await deployTx.wait()).events.find((elem) => elem.event === 'CreatePod'); + const result = (await deployTx.wait()).events!.find((elem) => elem.event === 'CreatePod'); + const args = result!.args!; const podId = args.podId; const numPodMembers = await podFactory.getNumMembers(podId); expect(numPodMembers).to.equal(4); diff --git a/test/integration/tests/tribalchief.ts b/test/integration/tests/tribalchief.ts index 664938e2f..fa2e99232 100644 --- a/test/integration/tests/tribalchief.ts +++ b/test/integration/tests/tribalchief.ts @@ -1,12 +1,12 @@ +import { NamedContracts } from '@custom-types/types'; +import mainnetAddresses from '@protocol/mainnetAddresses'; +import proposals from '@protocol/proposalsConfig'; +import tribalchief from '@protocol/tribalchief'; +import { TestEndtoEndCoordinator } from '@test/integration/setup'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; -import { NamedContracts } from '@custom-types/types'; -import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import proposals from '@test/integration/proposals_config'; -import mainnetAddresses from '@protocol/mainnetAddresses'; -import tribalchief from '@protocol/tribalchief'; describe('e2e-tribalchief', function () { let contracts: NamedContracts; diff --git a/test/integration/tests/turboPCVDeposit.ts b/test/integration/tests/turboPCVDeposit.ts index b2b8b429e..cb24359df 100644 --- a/test/integration/tests/turboPCVDeposit.ts +++ b/test/integration/tests/turboPCVDeposit.ts @@ -1,12 +1,12 @@ +import { NamedAddresses, NamedContracts } from '@custom-types/types'; +import proposals from '@protocol/proposalsConfig'; +import { expectApprox, getImpersonatedSigner } from '@test/helpers'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; import { solidity } from 'ethereum-waffle'; import { ethers } from 'hardhat'; -import { NamedAddresses, NamedContracts } from '@custom-types/types'; -import proposals from '@test/integration/proposals_config'; -import { TestEndtoEndCoordinator } from '../setup'; -import { expectApprox, getImpersonatedSigner, resetFork } from '@test/helpers'; import { abi as PCVDepositAbi } from '../../../artifacts/contracts/pcv/compound/ERC20CompoundPCVDeposit.sol/ERC20CompoundPCVDeposit.json'; +import { TestEndtoEndCoordinator } from '../setup'; import { forceEth } from '../setup/utils'; describe('Turbo PCV deposit', function () { diff --git a/test/integration/tests/votium-bribe.ts b/test/integration/tests/votium-bribe.ts index 1f3b60e39..c95ab1f34 100644 --- a/test/integration/tests/votium-bribe.ts +++ b/test/integration/tests/votium-bribe.ts @@ -1,10 +1,9 @@ -import { expect } from 'chai'; -import { ethers } from 'hardhat'; import { NamedContracts } from '@custom-types/types'; -import { getImpersonatedSigner, time } from '@test/helpers'; +import proposals from '@protocol/proposalsConfig'; +import { expectRevert, getImpersonatedSigner, time } from '@test/helpers'; import { TestEndtoEndCoordinator } from '@test/integration/setup'; -import proposals from '@test/integration/proposals_config'; -import { expectRevert } from '@test/helpers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; import { forceEth } from '../setup/utils'; const VOTIUM_ADMIN = '0xdC7C7F0bEA8444c12ec98Ec626ff071c6fA27a19'; // tommyg.eth @@ -43,6 +42,15 @@ describe('votium-bribe', function () { await forceEth(contracts.opsOptimisticTimelock.address); daoSigner = await getImpersonatedSigner(contracts.feiDAOTimelock.address); await forceEth(contracts.feiDAOTimelock.address); + + // Setup TribalChief so that rewards are active + await contracts.tribalChief.connect(daoSigner).updateBlockReward('26150000000000000000'); + await contracts.tribalChief.connect(daoSigner).set(12, 250, ethers.constants.AddressZero, false); + + // Grant bribeSigner role to interact with VotiumBribers + await contracts.core + .connect(daoSigner) + .grantRole(ethers.utils.id('VOTIUM_ADMIN_ROLE'), contracts.opsOptimisticTimelock.address); }); describe('When no voting round is active', async function () { diff --git a/test/unit/dao/governor/FeiDao.test.ts b/test/unit/dao/governor/FeiDao.test.ts index 6c383bfef..96b72bb13 100644 --- a/test/unit/dao/governor/FeiDao.test.ts +++ b/test/unit/dao/governor/FeiDao.test.ts @@ -1,9 +1,9 @@ -import { expectRevert, time, getCore, getAddresses } from '@test/helpers'; +import { Core, FeiDAO, Timelock } from '@custom-types/contracts'; +import { TransactionResponse } from '@ethersproject/providers'; +import { expectRevert, getAddresses, getCore, time } from '@test/helpers'; import { expect } from 'chai'; -import hre, { artifacts, ethers, network } from 'hardhat'; import { Signer } from 'ethers'; -import { TransactionResponse } from '@ethersproject/providers'; -import { Core, FeiDAO, Timelock } from '@custom-types/contracts'; +import hre, { artifacts, ethers, network } from 'hardhat'; const Tribe = artifacts.readArtifactSync('Tribe'); diff --git a/test/unit/dao/timelocks/FeiDAOTimelock.test.ts b/test/unit/dao/timelocks/FeiDAOTimelock.test.ts index 6d37497b9..2c3b9c5c1 100644 --- a/test/unit/dao/timelocks/FeiDAOTimelock.test.ts +++ b/test/unit/dao/timelocks/FeiDAOTimelock.test.ts @@ -1,8 +1,8 @@ +import { Core, FeiDAOTimelock } from '@custom-types/contracts'; +import { Signer } from '@ethersproject/abstract-signer'; import { expectRevert, getAddresses, getCore, getImpersonatedSigner, latestTime } from '@test/helpers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; -import { Core, FeiDAOTimelock } from '@custom-types/contracts'; -import { Signer } from '@ethersproject/abstract-signer'; describe('FeiDAOTimelock', function () { let userAddress: string; diff --git a/test/unit/dao/timelocks/OptimisticTimelock.test.ts b/test/unit/dao/timelocks/OptimisticTimelock.test.ts index 294a93844..a23654ac2 100644 --- a/test/unit/dao/timelocks/OptimisticTimelock.test.ts +++ b/test/unit/dao/timelocks/OptimisticTimelock.test.ts @@ -1,15 +1,15 @@ import { expectRevert, getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; const impersonatedSigners: { [key: string]: Signer } = {}; describe('TimelockedDelegator', function () { - let userAddress; - let governorAddress; + let userAddress: string; + let governorAddress: string; before(async () => { const addresses = await getAddresses(); diff --git a/test/unit/fei/Fei.test.ts b/test/unit/fei/Fei.test.ts index 9f0c308b1..374d25510 100644 --- a/test/unit/fei/Fei.test.ts +++ b/test/unit/fei/Fei.test.ts @@ -1,15 +1,15 @@ -import { ZERO_ADDRESS, expectRevert, getAddresses, getCore } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore, ZERO_ADDRESS } from '../../helpers'; const toBN = ethers.BigNumber.from; describe('Fei', function () { - let userAddress; - let governorAddress; - let minterAddress; - let burnerAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let burnerAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/fei/minter/FeiTimedMinter.test.ts b/test/unit/fei/minter/FeiTimedMinter.test.ts index dab7b43cc..a94ed351f 100644 --- a/test/unit/fei/minter/FeiTimedMinter.test.ts +++ b/test/unit/fei/minter/FeiTimedMinter.test.ts @@ -1,18 +1,17 @@ -import { ZERO_ADDRESS, expectRevert, time, getAddresses, getCore, expectApprox } from '@test/helpers'; +import { expectApprox, expectRevert, getAddresses, getCore, time, ZERO_ADDRESS } from '@test/helpers'; import chai, { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; -import { Signer } from 'ethers'; - import CBN from 'chai-bn'; +import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; before(() => { chai.use(CBN(ethers.BigNumber)); }); describe('FeiTimedMinter', function () { - let userAddress; - let secondUserAddress; - let governorAddress; + let userAddress: string; + let secondUserAddress: string; + let governorAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/fei/minter/GlobalRateLimitedMinter.test.ts b/test/unit/fei/minter/GlobalRateLimitedMinter.test.ts index d5cee4e6a..402f2c2e0 100644 --- a/test/unit/fei/minter/GlobalRateLimitedMinter.test.ts +++ b/test/unit/fei/minter/GlobalRateLimitedMinter.test.ts @@ -1,16 +1,15 @@ +import { Core, Fei, GlobalRateLimitedMinter, MockMinter } from '@custom-types/contracts'; import { expectRevert, getAddresses, getCore, ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; -import { Signer, utils } from 'ethers'; -import { Core, Fei, GlobalRateLimitedMinter, MockMinter } from '@custom-types/contracts'; +import { BigNumber, Signer, utils } from 'ethers'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; -const toBN = ethers.BigNumber.from; const scale = ethers.constants.WeiPerEther; describe('GlobalRateLimitedMinterGovernor', function () { - let userAddress; - let governorAddress; + let userAddress: string; + let governorAddress: string; let globalRateLimitedMinter: GlobalRateLimitedMinter; let authorizedMinter: MockMinter; let core: Core; @@ -148,8 +147,8 @@ describe('GlobalRateLimitedMinterGovernor', function () { }); describe('Add Minter Under Caps', function () { - let rateLimitPerSecond; - let bufferCap; + let rateLimitPerSecond: BigNumber; + let bufferCap: BigNumber; beforeEach(async function () { rateLimitPerSecond = await globalRateLimitedMinter.individualMaxRateLimitPerSecond(); diff --git a/test/unit/fei/minter/GlobalRateLimitedMinterGovernor.test.ts b/test/unit/fei/minter/GlobalRateLimitedMinterGovernor.test.ts index 4ce98fa05..5a95fa1cd 100644 --- a/test/unit/fei/minter/GlobalRateLimitedMinterGovernor.test.ts +++ b/test/unit/fei/minter/GlobalRateLimitedMinterGovernor.test.ts @@ -1,14 +1,14 @@ -import { time, expectRevert, expectApprox, getAddresses, getCore } from '@test/helpers'; +import { Core, Fei, GlobalRateLimitedMinter } from '@custom-types/contracts'; +import { expectApprox, expectRevert, getAddresses, getCore, time } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Contract, Signer } from 'ethers'; -import { Core, Fei, GlobalRateLimitedMinter } from '@custom-types/contracts'; +import hre, { ethers } from 'hardhat'; const scale = ethers.constants.WeiPerEther; describe('GlobalRateLimitedMinterBuffer', function () { - let userAddress; - let governorAddress; + let userAddress: string; + let governorAddress: string; let globalRateLimitedMinter: GlobalRateLimitedMinter; let authorizedMinter: Contract; let core: Core; diff --git a/test/unit/fei/minter/PCVEquityMinter.test.ts b/test/unit/fei/minter/PCVEquityMinter.test.ts index 72ba2dec1..717024006 100644 --- a/test/unit/fei/minter/PCVEquityMinter.test.ts +++ b/test/unit/fei/minter/PCVEquityMinter.test.ts @@ -1,7 +1,7 @@ -import { ZERO_ADDRESS, expectRevert, time, getAddresses, getCore, expectApprox } from '@test/helpers'; +import { expectApprox, expectRevert, getAddresses, getCore, time, ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; describe('PCVEquityMinter', function () { let userAddress: string; diff --git a/test/unit/fei/minter/RateLimitedMinter.test.ts b/test/unit/fei/minter/RateLimitedMinter.test.ts index 8b5888239..b17012060 100644 --- a/test/unit/fei/minter/RateLimitedMinter.test.ts +++ b/test/unit/fei/minter/RateLimitedMinter.test.ts @@ -1,13 +1,13 @@ -import { time, expectRevert, expectApprox, getAddresses, getCore } from '@test/helpers'; +import { expectApprox, expectRevert, getAddresses, getCore, time } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('RateLimitedMinter', function () { - let userAddress; - let governorAddress; + let userAddress: string; + let governorAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/fuse/AutoRewardsDistributor.test.ts b/test/unit/fuse/AutoRewardsDistributor.test.ts index cc5e3e0ec..e9fc35c68 100644 --- a/test/unit/fuse/AutoRewardsDistributor.test.ts +++ b/test/unit/fuse/AutoRewardsDistributor.test.ts @@ -1,12 +1,12 @@ -import { expectRevert, getAddresses, getCore } from '../../helpers'; import { expect } from 'chai'; +import { BigNumber, Signer } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { Signer, BigNumber } from 'ethers'; import { AutoRewardsDistributor } from '../../../types/contracts/AutoRewardsDistributor'; +import { Core } from '../../../types/contracts/Core'; import { MockRewardsDistributor } from '../../../types/contracts/MockRewardsDistributor'; import { MockTribalChief } from '../../../types/contracts/MockTribalChief'; -import { Core } from '../../../types/contracts/Core'; import { Tribe } from '../../../types/contracts/Tribe'; +import { expectRevert, getAddresses, getCore } from '../../helpers'; const toBN = ethers.BigNumber.from; diff --git a/test/unit/fuse/RewardsDistributorAdmin.test.ts b/test/unit/fuse/RewardsDistributorAdmin.test.ts index 3da5e4e95..004aba9e0 100644 --- a/test/unit/fuse/RewardsDistributorAdmin.test.ts +++ b/test/unit/fuse/RewardsDistributorAdmin.test.ts @@ -1,9 +1,9 @@ +import { Core, MockRewardsDistributor, RewardsDistributorAdmin } from '@custom-types/contracts'; import { expectRevert, getAddresses, getCore, ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer, utils } from 'ethers'; -import { Core, RewardsDistributorAdmin, MockRewardsDistributor } from '@custom-types/contracts'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; diff --git a/test/unit/oracle/ChainlinkOracleWrapper.test.ts b/test/unit/oracle/ChainlinkOracleWrapper.test.ts index 879b3c806..dc866cc2f 100644 --- a/test/unit/oracle/ChainlinkOracleWrapper.test.ts +++ b/test/unit/oracle/ChainlinkOracleWrapper.test.ts @@ -1,7 +1,7 @@ -import { getCore, getAddresses } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers, artifacts } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { artifacts, ethers } from 'hardhat'; +import { getAddresses, getCore } from '../../helpers'; const ChainlinkOracleWrapper = artifacts.readArtifactSync('ChainlinkOracleWrapper'); const MockChainlinkOracle = artifacts.readArtifactSync('MockChainlinkOracle'); diff --git a/test/unit/oracle/CompositeOracle.test.ts b/test/unit/oracle/CompositeOracle.test.ts index b06b46fb4..f530c0d82 100644 --- a/test/unit/oracle/CompositeOracle.test.ts +++ b/test/unit/oracle/CompositeOracle.test.ts @@ -1,7 +1,7 @@ -import { expectRevert, getAddresses, getCore } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore } from '../../helpers'; describe('CompositeOracle', function () { let governorAddress: string; diff --git a/test/unit/oracle/ConstantOracle.test.ts b/test/unit/oracle/ConstantOracle.test.ts index a974e808b..02361c8b2 100644 --- a/test/unit/oracle/ConstantOracle.test.ts +++ b/test/unit/oracle/ConstantOracle.test.ts @@ -1,7 +1,7 @@ -import { getCore, getAddresses } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers, artifacts } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { artifacts, ethers } from 'hardhat'; +import { getAddresses, getCore } from '../../helpers'; const ConstantOracle = artifacts.readArtifactSync('ConstantOracle'); diff --git a/test/unit/oracle/collateralization/CollateralizationOracle.test.ts b/test/unit/oracle/collateralization/CollateralizationOracle.test.ts index 4be2cd885..79162da6c 100644 --- a/test/unit/oracle/collateralization/CollateralizationOracle.test.ts +++ b/test/unit/oracle/collateralization/CollateralizationOracle.test.ts @@ -1,7 +1,7 @@ -import { ZERO_ADDRESS, getCore, getAddresses, expectRevert, expectUnspecifiedRevert } from '../../../helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; +import { expectRevert, expectUnspecifiedRevert, getAddresses, getCore, ZERO_ADDRESS } from '../../../helpers'; const e18 = '000000000000000000'; diff --git a/test/unit/oracle/collateralization/CollateralizationOracleGuardian.test.ts b/test/unit/oracle/collateralization/CollateralizationOracleGuardian.test.ts index ddc49e56e..4514a0560 100644 --- a/test/unit/oracle/collateralization/CollateralizationOracleGuardian.test.ts +++ b/test/unit/oracle/collateralization/CollateralizationOracleGuardian.test.ts @@ -1,9 +1,9 @@ -import { getCore, getAddresses, expectRevert, increaseTime, getImpersonatedSigner } from '../../../helpers'; -import { expect } from 'chai'; -import { ethers } from 'hardhat'; -import { Signer } from 'ethers'; import { CollateralizationOracleWrapper, Core, MockCollateralizationOracle } from '@custom-types/contracts'; import { CollateralizationOracleGuardian } from '@custom-types/contracts/CollateralizationOracleGuardian'; +import { expect } from 'chai'; +import { Signer } from 'ethers'; +import { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore, getImpersonatedSigner, increaseTime } from '../../../helpers'; describe('CollateralizationOracleGuardian', function () { let userAddress: string; diff --git a/test/unit/oracle/collateralization/CollateralizationOracleWrapper.test.ts b/test/unit/oracle/collateralization/CollateralizationOracleWrapper.test.ts index 33858f8ee..4e98ec61d 100644 --- a/test/unit/oracle/collateralization/CollateralizationOracleWrapper.test.ts +++ b/test/unit/oracle/collateralization/CollateralizationOracleWrapper.test.ts @@ -1,7 +1,7 @@ -import { ZERO_ADDRESS, time, getCore, getAddresses, expectRevert } from '../../../helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore, time, ZERO_ADDRESS } from '../../../helpers'; const e18 = '000000000000000000'; diff --git a/test/unit/pcv/PCVGuardian.test.ts b/test/unit/pcv/PCVGuardian.test.ts index 7dd10e845..e626ddf71 100644 --- a/test/unit/pcv/PCVGuardian.test.ts +++ b/test/unit/pcv/PCVGuardian.test.ts @@ -1,17 +1,16 @@ -import { expectRevert, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; -import { expect } from 'chai'; -import { Signer } from 'ethers'; -import { ethers } from 'hardhat'; import { Core, + MockERC20, MockERC20__factory, MockPCVDepositV2__factory, PCVDeposit, - PCVGuardian, - MockERC20 + PCVGuardian } from '@custom-types/contracts'; -import chai from 'chai'; +import { expectRevert, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; import { forceEth } from '@test/integration/setup/utils'; +import chai, { expect } from 'chai'; +import { Signer } from 'ethers'; +import { ethers } from 'hardhat'; // This will theoretically make the error stack actually print! chai.config.includeStack = true; diff --git a/test/unit/pcv/aave/AavePCVDeposit.test.ts b/test/unit/pcv/aave/AavePCVDeposit.test.ts index afdc9ff2b..10cc49a00 100644 --- a/test/unit/pcv/aave/AavePCVDeposit.test.ts +++ b/test/unit/pcv/aave/AavePCVDeposit.test.ts @@ -1,7 +1,7 @@ import { expectRevert, getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; diff --git a/test/unit/pcv/angle/AngleUniswapPCVDeposit.test.ts b/test/unit/pcv/angle/AngleUniswapPCVDeposit.test.ts index 8fa52c791..0321f7d0d 100644 --- a/test/unit/pcv/angle/AngleUniswapPCVDeposit.test.ts +++ b/test/unit/pcv/angle/AngleUniswapPCVDeposit.test.ts @@ -1,4 +1,4 @@ -import { expectRevert, expectApprox, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import { expectApprox, expectRevert, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; diff --git a/test/unit/pcv/balancer/BPTLens.test.ts b/test/unit/pcv/balancer/BPTLens.test.ts index c97e1e617..c5648bf44 100644 --- a/test/unit/pcv/balancer/BPTLens.test.ts +++ b/test/unit/pcv/balancer/BPTLens.test.ts @@ -1,9 +1,9 @@ +import { BPTLens, MockERC20, MockOracle, MockVault, MockWeightedPool } from '@custom-types/contracts'; import { getAddresses, getImpersonatedSigner } from '@test/helpers'; import chai, { expect } from 'chai'; import CBN from 'chai-bn'; -import { ethers } from 'hardhat'; import { Signer } from 'ethers'; -import { BPTLens, MockERC20, MockOracle, MockVault, MockWeightedPool } from '@custom-types/contracts'; +import { ethers } from 'hardhat'; before(async () => { chai.use(CBN(ethers.BigNumber)); diff --git a/test/unit/pcv/balancer/BalancerLBPSwapper.test.ts b/test/unit/pcv/balancer/BalancerLBPSwapper.test.ts index c7990e1a3..e46d28e6f 100644 --- a/test/unit/pcv/balancer/BalancerLBPSwapper.test.ts +++ b/test/unit/pcv/balancer/BalancerLBPSwapper.test.ts @@ -1,18 +1,18 @@ +import { BalancerLBPSwapper, Core, Fei, Tribe } from '@custom-types/contracts'; +import { MockVault } from '@custom-types/contracts/MockVault'; +import { MockWeightedPool } from '@custom-types/contracts/MockWeightedPool'; import { expectRevert, getAddresses, getCore, getImpersonatedSigner, increaseTime, - ZERO_ADDRESS, - latestTime + latestTime, + ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; -import { ethers } from 'hardhat'; import { Signer } from 'ethers'; -import { BalancerLBPSwapper, Core, Fei, Tribe } from '@custom-types/contracts'; -import { MockVault } from '@custom-types/contracts/MockVault'; -import { MockWeightedPool } from '@custom-types/contracts/MockWeightedPool'; +import { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; @@ -22,6 +22,7 @@ describe('BalancerLBPSwapper', function () { let pcvControllerAddress: string; let governorAddress: string; let minterAddress: string; + let guardianAddress: string; let core: Core; let fei: Fei; let tribe: Tribe; @@ -39,7 +40,8 @@ describe('BalancerLBPSwapper', function () { addresses.pcvControllerAddress, addresses.governorAddress, addresses.minterAddress, - addresses.burnerAddress + addresses.burnerAddress, + addresses.guardianAddress ]; for (const address of impersonatedAddresses) { @@ -48,7 +50,8 @@ describe('BalancerLBPSwapper', function () { }); beforeEach(async function () { - ({ userAddress, pcvControllerAddress, governorAddress, minterAddress, burnerAddress } = await getAddresses()); + ({ userAddress, pcvControllerAddress, governorAddress, minterAddress, burnerAddress, guardianAddress } = + await getAddresses()); core = await getCore(); @@ -385,6 +388,23 @@ describe('BalancerLBPSwapper', function () { await balancerLBPSwapper.connect(impersonatedSigners[governorAddress]).swap(); }); + describe('exitPoolToSelf', function () { + it('guardian succeeds', async function () { + expect(await pool.balanceOf(balancerLBPSwapper.address)).to.be.bignumber.equal(await vault.LIQUIDITY_AMOUNT()); + await balancerLBPSwapper.connect(impersonatedSigners[guardianAddress]).exitPoolToSelf(); + expect(await pool.balanceOf(balancerLBPSwapper.address)).to.be.bignumber.equal(toBN(0)); + expect(await fei.balanceOf(balancerLBPSwapper.address)).to.be.bignumber.equal( + ethers.constants.WeiPerEther.mul(toBN(2)) + ); + }); + + it('non-authorized reverts', async function () { + await expectRevert( + balancerLBPSwapper.connect(impersonatedSigners[userAddress]).exitPoolToSelf(), + 'UNAUTHORIZED' + ); + }); + }); it('succeeds', async function () { expect(await pool.balanceOf(balancerLBPSwapper.address)).to.be.bignumber.equal(await vault.LIQUIDITY_AMOUNT()); await balancerLBPSwapper.connect(impersonatedSigners[pcvControllerAddress]).exitPool(userAddress); diff --git a/test/unit/pcv/balancer/BalancerPCVDepositWeightedPool.test.ts b/test/unit/pcv/balancer/BalancerPCVDepositWeightedPool.test.ts index 608353182..b3fce0d2b 100644 --- a/test/unit/pcv/balancer/BalancerPCVDepositWeightedPool.test.ts +++ b/test/unit/pcv/balancer/BalancerPCVDepositWeightedPool.test.ts @@ -1,24 +1,23 @@ -import { getImpersonatedSigner, balance, getAddresses, getCore } from '@test/helpers'; -import chai, { expect } from 'chai'; -import CBN from 'chai-bn'; -import { ethers } from 'hardhat'; import { + BalancerPCVDepositWeightedPool, + BalancerPCVDepositWeightedPool__factory, + Core, Fei, MockERC20, MockERC20__factory, + MockMerkleOrchard, + MockMerkleOrchard__factory, MockOracle, MockOracle__factory, - MockWeth, - MockWeth__factory, MockVault, MockVault__factory, - MockMerkleOrchard, - MockMerkleOrchard__factory, - BalancerPCVDepositWeightedPool, - BalancerPCVDepositWeightedPool__factory, - Core + MockWeth, + MockWeth__factory } from '@custom-types/contracts'; -import { expectApproxAbs } from '@test/helpers'; +import { expectApproxAbs, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import chai, { expect } from 'chai'; +import CBN from 'chai-bn'; +import { ethers } from 'hardhat'; chai.config.includeStack = true; const toBN = ethers.BigNumber.from; diff --git a/test/unit/pcv/balancer/BalancerPool2Lens.test.ts b/test/unit/pcv/balancer/BalancerPool2Lens.test.ts new file mode 100644 index 000000000..065963ccc --- /dev/null +++ b/test/unit/pcv/balancer/BalancerPool2Lens.test.ts @@ -0,0 +1,115 @@ +import { + BalancerPool2Lens, + MockERC20, + MockOracle, + MockPCVDepositV2, + MockVault, + MockWeightedPool +} from '@custom-types/contracts'; +import { expectApproxAbs, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import chai, { expect } from 'chai'; +import CBN from 'chai-bn'; +import { Signer } from 'ethers'; +import { ethers } from 'hardhat'; + +before(async () => { + chai.use(CBN(ethers.BigNumber)); +}); + +const toBN = ethers.BigNumber.from; + +describe('BalancerPool2Lens', function () { + let userAddress: string; + let pool: MockWeightedPool; + let vault: MockVault; + let token: MockERC20; + let oracle1: MockOracle; + let oracle2: MockOracle; + let deposit: MockPCVDepositV2; + let lens: BalancerPool2Lens; + + const impersonatedSigners: { [key: string]: Signer } = {}; + + before(async () => { + const addresses = await getAddresses(); + + // add any addresses you want to impersonate here + const impersonatedAddresses = [addresses.userAddress]; + + for (const address of impersonatedAddresses) { + impersonatedSigners[address] = await getImpersonatedSigner(address); + } + }); + + beforeEach(async function () { + ({ userAddress } = await getAddresses()); + + token = await (await ethers.getContractFactory('MockERC20')).deploy(); + const tokenB = await (await ethers.getContractFactory('MockERC20')).deploy(); + + vault = await (await ethers.getContractFactory('MockVault')).deploy([token.address, tokenB.address], userAddress); + + await vault.setBalances([ethers.constants.WeiPerEther.mul(20), ethers.constants.WeiPerEther.mul(30000)]); + + pool = await ethers.getContractAt('MockWeightedPool', await vault._pool()); + + const core = await getCore(); + deposit = await ( + await ethers.getContractFactory('MockPCVDepositV2') + ).deploy( + core.address, + pool.address, + 10000, // deposit reports 10000 LP tokens + 0 + ); + + await pool.mint(pool.address, 89999); + await pool.mint(deposit.address, 10000); + + // set weights to 70%, 30% + await pool.updateWeightsGradually(0, 0, [ + ethers.constants.WeiPerEther.div(100).mul(70), + ethers.constants.WeiPerEther.div(100).mul(30) + ]); + await pool.mockSetNormalizedWeights([ + ethers.constants.WeiPerEther.div(100).mul(70), + ethers.constants.WeiPerEther.div(100).mul(30) + ]); + + oracle1 = await (await ethers.getContractFactory('MockOracle')).deploy('3500'); + oracle2 = await (await ethers.getContractFactory('MockOracle')).deploy('1'); + + lens = await ( + await ethers.getContractFactory('BalancerPool2Lens') + ).deploy(deposit.address, token.address, pool.address, oracle1.address, oracle2.address, false, true); + }); + + // pool contains 20 tokenA, 30,000 tokenB + // tokenA price 3,500 $, tokenB price 1 $ + // -> pool contains 70,000$, 30,000$ + // pool weight 70% tokenA, 30% tokenB (currently balanced) + // userAddress owns 10% of the pool (10,000 / 100,000) + + it('initial state', async function () { + expect(await lens.balanceReportedIn()).to.be.equal(token.address); + expect(await lens.pool()).to.be.equal(pool.address); + expect(await lens.balancerVault()).to.be.equal(vault.address); + expect(await lens.feiInPair()).to.be.true; + expect(await lens.feiIsReportedIn()).to.be.false; + expect(await lens.reportedOracle()).to.be.equal(oracle1.address); + expect(await lens.otherOracle()).to.be.equal(oracle2.address); + + expect(await pool.balanceOf(pool.address)).to.be.equal('90000'); + expect(await pool.balanceOf(deposit.address)).to.be.equal('10000'); + }); + + it('balance', async function () { + expectApproxAbs(await lens.balance(), ethers.constants.WeiPerEther.mul('2'), '1'); + }); + + it('resistantBalanceAndFei', async function () { + const balances = await lens.resistantBalanceAndFei(); + expectApproxAbs(balances[0], ethers.constants.WeiPerEther.mul('2'), '1'); + expectApproxAbs(balances[1], ethers.constants.WeiPerEther.mul('3000'), '1'); + }); +}); diff --git a/test/unit/pcv/compound/ERC20CompoundPCVDeposit.test.ts b/test/unit/pcv/compound/ERC20CompoundPCVDeposit.test.ts index 9bf297275..269c51742 100644 --- a/test/unit/pcv/compound/ERC20CompoundPCVDeposit.test.ts +++ b/test/unit/pcv/compound/ERC20CompoundPCVDeposit.test.ts @@ -1,7 +1,7 @@ import { expectRevert, getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; diff --git a/test/unit/pcv/compound/EthCompoundPCVDeposit.test.ts b/test/unit/pcv/compound/EthCompoundPCVDeposit.test.ts index 827565d35..d2546ba89 100644 --- a/test/unit/pcv/compound/EthCompoundPCVDeposit.test.ts +++ b/test/unit/pcv/compound/EthCompoundPCVDeposit.test.ts @@ -1,7 +1,7 @@ -import { expectRevert, balance, getAddresses, getCore } from '@test/helpers'; +import { balance, expectRevert, getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; diff --git a/test/unit/pcv/convex/ConvexPCVDeposit.test.ts b/test/unit/pcv/convex/ConvexPCVDeposit.test.ts index ea35a0f61..4ec0efd4d 100644 --- a/test/unit/pcv/convex/ConvexPCVDeposit.test.ts +++ b/test/unit/pcv/convex/ConvexPCVDeposit.test.ts @@ -1,20 +1,20 @@ -import { getImpersonatedSigner, getAddresses, getCore } from '@test/helpers'; -import chai, { expect } from 'chai'; -import { ethers } from 'hardhat'; import { + ConvexPCVDeposit, + ConvexPCVDeposit__factory, Core, Fei, - MockERC20, - MockERC20__factory, - MockCurve3pool, - MockCurve3pool__factory, - MockConvexBooster, - MockConvexBooster__factory, MockConvexBaseRewardPool, MockConvexBaseRewardPool__factory, - ConvexPCVDeposit, - ConvexPCVDeposit__factory + MockConvexBooster, + MockConvexBooster__factory, + MockCurve3pool, + MockCurve3pool__factory, + MockERC20, + MockERC20__factory } from '@custom-types/contracts'; +import { getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import chai, { expect } from 'chai'; +import { ethers } from 'hardhat'; chai.config.includeStack = true; diff --git a/test/unit/pcv/curve/CurvePCVDepositPlainPool.test.ts b/test/unit/pcv/curve/CurvePCVDepositPlainPool.test.ts index da4e04c9f..aac2174c6 100644 --- a/test/unit/pcv/curve/CurvePCVDepositPlainPool.test.ts +++ b/test/unit/pcv/curve/CurvePCVDepositPlainPool.test.ts @@ -1,16 +1,16 @@ -import { getImpersonatedSigner, getAddresses, getCore } from '@test/helpers'; -import chai, { expect } from 'chai'; -import { ethers } from 'hardhat'; import { Core, + CurvePCVDepositPlainPool, + CurvePCVDepositPlainPool__factory, Fei, - MockERC20, - MockERC20__factory, MockCurve3pool, MockCurve3pool__factory, - CurvePCVDepositPlainPool, - CurvePCVDepositPlainPool__factory + MockERC20, + MockERC20__factory } from '@custom-types/contracts'; +import { getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import chai, { expect } from 'chai'; +import { ethers } from 'hardhat'; chai.config.includeStack = true; @@ -78,7 +78,7 @@ describe('CurvePCVDepositPlainPool', function () { await curvePool.transfer(deposit.address, '5000'); expect(await deposit.balance()).to.be.equal('6666'); // reduce if FEI share of the pool increases - fei.connect(await getImpersonatedSigner(minterAddress)).mint(curvePool.address, '10000'); + await fei.connect(await getImpersonatedSigner(minterAddress)).mint(curvePool.address, '10000'); expect(await deposit.balance()).to.be.equal('3333'); }); }); diff --git a/test/unit/pcv/lido/EthLidoPCVDeposit.test.ts b/test/unit/pcv/lido/EthLidoPCVDeposit.test.ts index d203353ed..adc6a2a6f 100644 --- a/test/unit/pcv/lido/EthLidoPCVDeposit.test.ts +++ b/test/unit/pcv/lido/EthLidoPCVDeposit.test.ts @@ -1,18 +1,18 @@ import { expectRevert, getAddresses, getCore } from '@test/helpers'; +import { forceSpecificEth } from '@test/integration/setup/utils'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; -import { forceSpecificEth } from '@test/integration/setup/utils'; +import hre, { ethers } from 'hardhat'; const e18 = '000000000000000000'; const toBN = ethers.BigNumber.from; describe('EthLidoPCVDeposit', function () { - let userAddress; - let secondUserAddress; - let governorAddress; - let pcvControllerAddress; + let userAddress: string; + let secondUserAddress: string; + let governorAddress: string; + let pcvControllerAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/pcv/tokemak/ERC20TokemakPCVDeposit.test.ts b/test/unit/pcv/tokemak/ERC20TokemakPCVDeposit.test.ts index e2f68d0ec..e5a09dd7e 100644 --- a/test/unit/pcv/tokemak/ERC20TokemakPCVDeposit.test.ts +++ b/test/unit/pcv/tokemak/ERC20TokemakPCVDeposit.test.ts @@ -1,20 +1,18 @@ -import { getImpersonatedSigner, balance, getAddresses, getCore } from '@test/helpers'; -import chai, { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; -import { Signer } from 'ethers'; import { + Core, + ERC20TokemakPCVDeposit, + ERC20TokemakPCVDeposit__factory, MockERC20, MockERC20__factory, - MockWeth, - MockWeth__factory, MockTokemakERC20Pool, MockTokemakERC20Pool__factory, MockTokemakRewards, - MockTokemakRewards__factory, - ERC20TokemakPCVDeposit, - ERC20TokemakPCVDeposit__factory, - Core + MockTokemakRewards__factory } from '@custom-types/contracts'; +import { balance, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import chai, { expect } from 'chai'; +import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; chai.config.includeStack = true; const toBN = ethers.BigNumber.from; @@ -31,7 +29,7 @@ describe('ERC20TokemakPCVDeposit', function () { let pcvControllerAddress: string; let governorAddress: string; - let depositAmount; + let depositAmount: BigNumber; before(async () => { const addresses = await getAddresses(); diff --git a/test/unit/pcv/tokemak/EthTokemakPCVDeposit.test.ts b/test/unit/pcv/tokemak/EthTokemakPCVDeposit.test.ts index 4c859a1df..e595ce22e 100644 --- a/test/unit/pcv/tokemak/EthTokemakPCVDeposit.test.ts +++ b/test/unit/pcv/tokemak/EthTokemakPCVDeposit.test.ts @@ -1,20 +1,20 @@ -import { getImpersonatedSigner, balance, getAddresses, getCore } from '@test/helpers'; -import chai, { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; -import { Signer } from 'ethers'; import { + Core, + EthTokemakPCVDeposit, + EthTokemakPCVDeposit__factory, MockERC20, MockERC20__factory, - MockWeth, - MockWeth__factory, MockTokemakEthPool, MockTokemakEthPool__factory, MockTokemakRewards, MockTokemakRewards__factory, - EthTokemakPCVDeposit, - EthTokemakPCVDeposit__factory, - Core + MockWeth, + MockWeth__factory } from '@custom-types/contracts'; +import { balance, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import chai, { expect } from 'chai'; +import { BigNumber } from 'ethers'; +import { ethers } from 'hardhat'; chai.config.includeStack = true; const toBN = ethers.BigNumber.from; @@ -31,7 +31,7 @@ describe('EthTokemakPCVDeposit', function () { let pcvControllerAddress: string; let governorAddress: string; - let depositAmount; + let depositAmount: BigNumber; before(async () => { const addresses = await getAddresses(); diff --git a/test/unit/pcv/uniswap/UniswapPCVDeposit.test.ts b/test/unit/pcv/uniswap/UniswapPCVDeposit.test.ts index e74486578..3dfabc3c5 100644 --- a/test/unit/pcv/uniswap/UniswapPCVDeposit.test.ts +++ b/test/unit/pcv/uniswap/UniswapPCVDeposit.test.ts @@ -1,17 +1,17 @@ -import { expectRevert, expectApprox, getAddresses, getCore } from '@test/helpers'; +import { expectApprox, expectRevert, getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('EthUniswapPCVDeposit', function () { const LIQUIDITY_INCREMENT = 10000; // amount of liquidity created by mock for each deposit - let userAddress; - let governorAddress; - let minterAddress; - let beneficiaryAddress1; - let pcvControllerAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let beneficiaryAddress1: string; + let pcvControllerAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/pcv/utils/DelayedPCVMover.test.ts b/test/unit/pcv/utils/DelayedPCVMover.test.ts index 10e8ebc26..056481faf 100644 --- a/test/unit/pcv/utils/DelayedPCVMover.test.ts +++ b/test/unit/pcv/utils/DelayedPCVMover.test.ts @@ -1,6 +1,6 @@ -import { Core, DelayedPCVMover, RatioPCVControllerV2, MockERC20, MockPCVDepositV2 } from '@custom-types/contracts'; +import { Core, DelayedPCVMover, MockERC20, MockPCVDepositV2, RatioPCVControllerV2 } from '@custom-types/contracts'; import { NamedAddresses } from '@custom-types/types'; -import { getCore, getAddresses, expectRevert, time, getImpersonatedSigner } from '@test/helpers'; +import { expectRevert, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; diff --git a/test/unit/pcv/utils/ERC20Dripper.test.ts b/test/unit/pcv/utils/ERC20Dripper.test.ts index aff7560e0..a9ad68fc3 100644 --- a/test/unit/pcv/utils/ERC20Dripper.test.ts +++ b/test/unit/pcv/utils/ERC20Dripper.test.ts @@ -1,4 +1,4 @@ -import { time, getCore, expectRevert, getAddresses, getImpersonatedSigner } from '@test/helpers'; +import { expectRevert, getAddresses, getCore, getImpersonatedSigner, time } from '@test/helpers'; import { expect } from 'chai'; import hre, { artifacts, ethers } from 'hardhat'; diff --git a/test/unit/pcv/utils/ERC20PCVDepositWrapper.test.ts b/test/unit/pcv/utils/ERC20PCVDepositWrapper.test.ts index cc83eb310..e01f522f5 100644 --- a/test/unit/pcv/utils/ERC20PCVDepositWrapper.test.ts +++ b/test/unit/pcv/utils/ERC20PCVDepositWrapper.test.ts @@ -1,13 +1,13 @@ import { getAddresses } from '@test/helpers'; import { expect } from 'chai'; +import { Contract, Signer } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { Signer } from 'ethers'; describe('ERC20PCVDepositWrapper', function () { const impersonatedSigners: { [key: string]: Signer } = {}; - let userAddress; - let token; + let userAddress: string; + let token: Contract; const balance = '2000'; diff --git a/test/unit/pcv/utils/ERC20Splitter.test.ts b/test/unit/pcv/utils/ERC20Splitter.test.ts index 3948339cb..36791d9eb 100644 --- a/test/unit/pcv/utils/ERC20Splitter.test.ts +++ b/test/unit/pcv/utils/ERC20Splitter.test.ts @@ -1,7 +1,7 @@ import { expectRevert, getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; describe('ERC20Splitter', function () { let userAddress: string; diff --git a/test/unit/pcv/utils/FeiSkimmer.test.ts b/test/unit/pcv/utils/FeiSkimmer.test.ts index f3a1890fd..a94ff9985 100644 --- a/test/unit/pcv/utils/FeiSkimmer.test.ts +++ b/test/unit/pcv/utils/FeiSkimmer.test.ts @@ -74,11 +74,28 @@ describe('FeiSkimmer', function () { expect(await skimmer.threshold()).to.be.equal(0); }); - it('not from governor succeeds', async function () { + it('not from governor fails', async function () { await expectRevert( skimmer.connect(impersonatedSigners[userAddress]).setThreshold(0), 'CoreRef: Caller is not a governor or contract admin' ); }); }); + + describe('Set Source', function () { + it('from governor succeeds', async function () { + expect(await skimmer.source()).to.be.equal(source.address); + + await skimmer.connect(impersonatedSigners[governorAddress]).setSource(userAddress); + + expect(await skimmer.source()).to.be.equal(userAddress); + }); + + it('not from governor fails', async function () { + await expectRevert( + skimmer.connect(impersonatedSigners[userAddress]).setSource(userAddress), + 'CoreRef: Caller is not a governor' + ); + }); + }); }); diff --git a/test/unit/pcv/utils/NamedStaticPCVDepositWrapper.test.ts b/test/unit/pcv/utils/NamedStaticPCVDepositWrapper.test.ts index a6e10a05c..e86397901 100644 --- a/test/unit/pcv/utils/NamedStaticPCVDepositWrapper.test.ts +++ b/test/unit/pcv/utils/NamedStaticPCVDepositWrapper.test.ts @@ -1,8 +1,8 @@ -import { getCore, getAddresses, expectRevert, expectEvent, getImpersonatedSigner } from '@test/helpers'; +import { Core, NamedStaticPCVDepositWrapper } from '@custom-types/contracts'; +import { expectEvent, expectRevert, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; -import { Core, Fei, NamedStaticPCVDepositWrapper } from '@custom-types/contracts'; +import { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('NamedStaticPCVDepositWrapper', function () { diff --git a/test/unit/pcv/utils/PCVDepositWrapper.test.ts b/test/unit/pcv/utils/PCVDepositWrapper.test.ts index 52919b4ac..905633132 100644 --- a/test/unit/pcv/utils/PCVDepositWrapper.test.ts +++ b/test/unit/pcv/utils/PCVDepositWrapper.test.ts @@ -1,8 +1,8 @@ -import { getCore, getAddresses } from '@test/helpers'; +import { Core, MockERC20, MockPCVDepositV2 } from '@custom-types/contracts'; +import { getAddresses, getCore } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; -import { Core, MockERC20, MockPCVDepositV2 } from '@custom-types/contracts'; +import hre, { ethers } from 'hardhat'; describe('PCVDepositWrapper', function () { const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/pcv/utils/PCVDripController.test.ts b/test/unit/pcv/utils/PCVDripController.test.ts index 16354cf2f..cfcb28cca 100644 --- a/test/unit/pcv/utils/PCVDripController.test.ts +++ b/test/unit/pcv/utils/PCVDripController.test.ts @@ -1,13 +1,13 @@ -import { expectRevert, time, balance, getAddresses, getCore } from '@test/helpers'; +import { balance, expectRevert, getAddresses, getCore, time } from '@test/helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('PCVDripController', function () { - let userAddress; - let governorAddress; + let userAddress: string; + let governorAddress: string; let beneficiaryAddress1; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/pcv/utils/RatioPCVControllerV2.test.ts b/test/unit/pcv/utils/RatioPCVControllerV2.test.ts index 532eaa78f..b6ca8ca52 100644 --- a/test/unit/pcv/utils/RatioPCVControllerV2.test.ts +++ b/test/unit/pcv/utils/RatioPCVControllerV2.test.ts @@ -1,23 +1,23 @@ import { - expectRevert, + Core, + MockERC20, + MockEthUniswapPCVDeposit, + MockPCVDepositV2, + RatioPCVControllerV2, + WETH9 +} from '@custom-types/contracts'; +import { balance, + deployDevelopmentWeth, + expectRevert, getAddresses, getCore, - getImpersonatedSigner, - deployDevelopmentWeth + getImpersonatedSigner } from '@test/helpers'; import { forceEth } from '@test/integration/setup/utils'; import { expect } from 'chai'; -import { ethers } from 'hardhat'; import { BigNumber, Signer } from 'ethers'; -import { - MockEthUniswapPCVDeposit, - MockPCVDepositV2, - WETH9, - Core, - RatioPCVControllerV2, - MockERC20 -} from '@custom-types/contracts'; +import { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; diff --git a/test/unit/peg/FixedPricePSM.test.ts b/test/unit/peg/FixedPricePSM.test.ts index 0a8ecdfc6..78632b8de 100644 --- a/test/unit/peg/FixedPricePSM.test.ts +++ b/test/unit/peg/FixedPricePSM.test.ts @@ -1,25 +1,25 @@ -import hre, { ethers } from 'hardhat'; +import { Core, Fei, FixedPricePSM, MockERC20, MockOracle, MockPCVDepositV2 } from '@custom-types/contracts'; import { + deployDevelopmentWeth, expectRevert, getAddresses, getCore, - deployDevelopmentWeth, - ZERO_ADDRESS, - getImpersonatedSigner + getImpersonatedSigner, + ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; import { Signer, utils } from 'ethers'; -import { Core, MockERC20, Fei, MockOracle, MockPCVDepositV2, FixedPricePSM } from '@custom-types/contracts'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('FixedPricePSM', function () { - let userAddress; - let governorAddress; - let minterAddress; - let pcvControllerAddress; - let psmAdminAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let pcvControllerAddress: string; + let psmAdminAddress: string; const mintFeeBasisPoints = 0; const redeemFeeBasisPoints = 30; diff --git a/test/unit/peg/MintRedeemPausePSM.test.ts b/test/unit/peg/MintRedeemPausePSM.test.ts index 63626edf6..132aaa2cc 100644 --- a/test/unit/peg/MintRedeemPausePSM.test.ts +++ b/test/unit/peg/MintRedeemPausePSM.test.ts @@ -1,26 +1,26 @@ -import hre, { ethers } from 'hardhat'; +import { Core, Fei, MockOracle, MockPCVDepositV2, PegStabilityModule, WETH9 } from '@custom-types/contracts'; import { + deployDevelopmentWeth, expectRevert, getAddresses, getCore, - deployDevelopmentWeth, - ZERO_ADDRESS, - getImpersonatedSigner + getImpersonatedSigner, + ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; import { Signer, utils } from 'ethers'; -import { Core, Fei, MockOracle, MockPCVDepositV2, WETH9, PegStabilityModule } from '@custom-types/contracts'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('PegStabilityModule', function () { - let userAddress; - let governorAddress; - let minterAddress; - let pcvControllerAddress; - let psmAdminAddress; - let guardianAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let pcvControllerAddress: string; + let psmAdminAddress: string; + let guardianAddress: string; const mintFeeBasisPoints = 30; const redeemFeeBasisPoints = 30; diff --git a/test/unit/peg/PSMRouter.test.ts b/test/unit/peg/PSMRouter.test.ts index 07ba8b938..7636b8982 100644 --- a/test/unit/peg/PSMRouter.test.ts +++ b/test/unit/peg/PSMRouter.test.ts @@ -1,24 +1,24 @@ -import hre, { ethers } from 'hardhat'; +import { Core, Fei, MockOracle, MockPCVDepositV2, PegStabilityModule, PSMRouter, WETH9 } from '@custom-types/contracts'; import { + deployDevelopmentWeth, + expectRevert, getAddresses, getCore, - deployDevelopmentWeth, getImpersonatedSigner, - MAX_UINT256, - expectRevert + MAX_UINT256 } from '@test/helpers'; import { expect } from 'chai'; import { Signer, utils } from 'ethers'; -import { Core, Fei, MockOracle, MockPCVDepositV2, PegStabilityModule, PSMRouter, WETH9 } from '@custom-types/contracts'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('PSM Router', function () { - let userAddress; - let minterAddress; + let userAddress: string; + let minterAddress: string; let psmAdminAddress; - let receiver; + let receiver: string; const mintFeeBasisPoints = 30; const redeemFeeBasisPoints = 30; diff --git a/test/unit/peg/PegStabilityModule.test.ts b/test/unit/peg/PegStabilityModule.test.ts index d905fa1d9..fc353e1bc 100644 --- a/test/unit/peg/PegStabilityModule.test.ts +++ b/test/unit/peg/PegStabilityModule.test.ts @@ -1,25 +1,25 @@ -import hre, { ethers } from 'hardhat'; +import { Core, Fei, MockOracle, MockPCVDepositV2, PegStabilityModule, WETH9 } from '@custom-types/contracts'; import { + deployDevelopmentWeth, expectRevert, getAddresses, getCore, - deployDevelopmentWeth, - ZERO_ADDRESS, - getImpersonatedSigner + getImpersonatedSigner, + ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; import { Signer, utils } from 'ethers'; -import { Core, Fei, MockOracle, PegStabilityModule, MockPCVDepositV2, WETH9 } from '@custom-types/contracts'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('PegStabilityModule', function () { - let userAddress; - let governorAddress; - let minterAddress; - let pcvControllerAddress; - let psmAdminAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let pcvControllerAddress: string; + let psmAdminAddress: string; const mintFeeBasisPoints = 30; const redeemFeeBasisPoints = 30; diff --git a/test/unit/peg/PriceBoundPegStabilityModule.test.ts b/test/unit/peg/PriceBoundPegStabilityModule.test.ts index 0271e97d9..9ded3f794 100644 --- a/test/unit/peg/PriceBoundPegStabilityModule.test.ts +++ b/test/unit/peg/PriceBoundPegStabilityModule.test.ts @@ -1,25 +1,25 @@ -import hre, { ethers } from 'hardhat'; +import { Core, Fei, MockERC20, MockOracle, MockPCVDepositV2, PriceBoundPSM } from '@custom-types/contracts'; import { + deployDevelopmentWeth, expectRevert, getAddresses, getCore, - deployDevelopmentWeth, - ZERO_ADDRESS, - getImpersonatedSigner + getImpersonatedSigner, + ZERO_ADDRESS } from '@test/helpers'; import { expect } from 'chai'; import { Signer, utils } from 'ethers'; -import { Core, MockERC20, Fei, MockOracle, PriceBoundPSM, MockPCVDepositV2 } from '@custom-types/contracts'; import { keccak256 } from 'ethers/lib/utils'; +import hre, { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('PriceBoundPegStabilityModule', function () { - let userAddress; - let governorAddress; - let minterAddress; - let pcvControllerAddress; - let psmAdminAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let pcvControllerAddress: string; + let psmAdminAddress: string; const mintFeeBasisPoints = 30; const redeemFeeBasisPoints = 30; diff --git a/test/unit/peg/ReserveStabilizer.test.ts b/test/unit/peg/ReserveStabilizer.test.ts index be4792d5f..c059f9038 100644 --- a/test/unit/peg/ReserveStabilizer.test.ts +++ b/test/unit/peg/ReserveStabilizer.test.ts @@ -1,15 +1,15 @@ -import { expectRevert, getAddresses, getCore } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore } from '../../helpers'; const toBN = ethers.BigNumber.from; describe('ReserveStabilizer', function () { - let userAddress; - let governorAddress; - let minterAddress; - let pcvControllerAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let pcvControllerAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/test/unit/refs/OracleRef.test.ts b/test/unit/refs/OracleRef.test.ts index 6377fa0d1..246b06a16 100644 --- a/test/unit/refs/OracleRef.test.ts +++ b/test/unit/refs/OracleRef.test.ts @@ -1,13 +1,13 @@ -import { expectRevert, getAddresses, getCore } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore } from '../../helpers'; const toBN = ethers.BigNumber.from; describe('OracleRef', () => { - let userAddress; - let governorAddress; + let userAddress: string; + let governorAddress: string; const impersonatedSigners: { [key: string]: Signer } = {}; @@ -167,17 +167,28 @@ describe('OracleRef', () => { ); }); - it('positive decimal normalizer scales down', async function () { - await this.oracleRef.connect(impersonatedSigners[governorAddress]).setDecimalsNormalizer(4), - expect((await this.oracleRef.connect(impersonatedSigners[userAddress]).readOracle())[0]).to.be.equal( - '200000000000' - ); + it('positive decimal normalizer scales up', async function () { + // Raw peg price: 500000000000000000000, 500e18 + // Inversion is set to True by default in ReserveStabilizer + // Price after inversion = (1e18 * 1e18) / 500e18 = 0.2e16 = 2e15 + // Scaling factor is set to 1e4. After applying scaling factor + // 2e15 * 1e4 = 2e19 = 20000000000000000000 + await this.oracleRef.connect(impersonatedSigners[governorAddress]).setDecimalsNormalizer(4); + + expect((await this.oracleRef.connect(impersonatedSigners[userAddress]).readOracle())[0]).to.be.equal( + '20000000000000000000' + ); }); - it('negative decimal normalizer scales up', async function () { + it('negative decimal normalizer scales down', async function () { + // Raw peg price: 500000000000000000000, 500e18 + // Inversion is set to True by default in ReserveStabilizer + // Price after inversion = (1e18 * 1e18) / 500e18 = 0.2e16 = 2e15 + // Scaling factor is set to -1e4. After applying scaling factor + // 2e15 / 1e4 = 2e11 = 200000000000 await this.oracleRef.connect(impersonatedSigners[governorAddress]).setDecimalsNormalizer(-4), expect((await this.oracleRef.connect(impersonatedSigners[userAddress]).readOracle())[0]).to.be.equal( - '20000000000000000000' + '200000000000' ); }); }); diff --git a/test/unit/sentinel/PCVSentinel.test.ts b/test/unit/sentinel/PCVSentinel.test.ts index d063684e3..b98b647fe 100644 --- a/test/unit/sentinel/PCVSentinel.test.ts +++ b/test/unit/sentinel/PCVSentinel.test.ts @@ -1,22 +1,17 @@ -import { balance, expectRevert, getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; -import { expect } from 'chai'; -import { Signer } from 'ethers'; -import { ethers } from 'hardhat'; import { - Core, - MockERC20__factory, - MockPCVDepositV2__factory, - PCVDeposit, - PCVSentinel, - MockERC20, - NoOpGuard, BalanceGuard, + Core, MultiActionGuard, - ReEntrancyGuard, - RecoverEthGuard + NoOpGuard, + PCVSentinel, + RecoverEthGuard, + ReEntrancyGuard } from '@custom-types/contracts'; -import chai from 'chai'; -import { forceEth, forceSpecificEth } from '@test/integration/setup/utils'; +import { getAddresses, getCore, getImpersonatedSigner } from '@test/helpers'; +import { forceSpecificEth } from '@test/integration/setup/utils'; +import chai, { expect } from 'chai'; +import { Signer } from 'ethers'; +import { ethers } from 'hardhat'; // This will theoretically make the error stack actually print! chai.config.includeStack = true; diff --git a/test/unit/staking/TribalChiefPart1.test.ts b/test/unit/staking/TribalChiefPart1.test.ts index c49be5ecf..fb3977a5c 100644 --- a/test/unit/staking/TribalChiefPart1.test.ts +++ b/test/unit/staking/TribalChiefPart1.test.ts @@ -5,13 +5,11 @@ /* eslint-disable no-unused-expressions */ /* eslint-disable no-plusplus */ /* eslint-disable no-await-in-loop */ -import { time } from '../../helpers'; -import { expectRevert, expectUnspecifiedRevert, getCore, getAddresses, expectApprox } from '../../helpers'; +import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider'; import { expect } from 'chai'; +import { BigNumber, Contract, Signer } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { BigNumber, Signer } from 'ethers'; -import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider'; -import { BN } from 'ethereumjs-util'; +import { expectApprox, expectRevert, getAddresses, getCore, time } from '../../helpers'; const toBN = ethers.BigNumber.from; @@ -23,14 +21,14 @@ const blockReward = '100000000000000000000'; const impersonatedSigners: { [key: string]: Signer } = {}; async function testMultipleUsersPooling( - tribalChief, - lpToken, - userAddresses, - incrementAmount, - blocksToAdvance, - lockLength, - totalStaked, - pid + tribalChief: Contract, + lpToken: Contract, + userAddresses: string[], + incrementAmount: BigNumber | BigNumber[], + blocksToAdvance: number, + lockLength: number | number[], + totalStaked: string, + pid: number ) { // if lock length isn't defined, it defaults to 0 lockLength = lockLength === undefined ? 0 : lockLength; @@ -85,34 +83,34 @@ async function testMultipleUsersPooling( await expectApprox( toBN(await tribalChief.pendingRewards(pid, userAddresses[j])), - pendingBalances[j].add(userIncrementAmount) + pendingBalances[j].add(userIncrementAmount as any) ); } } } -const emergencyWithdrawReport = []; -const withdrawAllAndHarvestReport = []; -const withdrawFromDepositReport = []; -const harvestReport = []; -const depositReport = []; +const emergencyWithdrawReport: any[] = []; +const withdrawAllAndHarvestReport: any[] = []; +const withdrawFromDepositReport: any[] = []; +const harvestReport: any[] = []; +const depositReport: any[] = []; describe('TribalChief', () => { // this is the process ID of the staking rewards that we will use - let pid; - let minterAddress; - let governorAddress; - let userAddress; - let secondUserAddress; - let thirdUserAddress; - let fourthUserAddress; - let fifthUserAddress; - let sixthUserAddress; - let seventhUserAddress; - let eigthUserAddress; - let ninthUserAddress; - let tenthUserAddress; - let perBlockReward; + let pid: number; + let minterAddress: string; + let governorAddress: string; + let userAddress: string; + let secondUserAddress: string; + let thirdUserAddress: string; + let fourthUserAddress: string; + let fifthUserAddress: string; + let sixthUserAddress: string; + let seventhUserAddress: string; + let eigthUserAddress: string; + let ninthUserAddress: string; + let tenthUserAddress: string; + let perBlockReward: number; const multiplier10x = '100000'; const multiplier5x = '50000'; @@ -1102,7 +1100,7 @@ describe('TribalChief', () => { thirdPid ); - async function testFailureWithdraw(poolPid, users, tribalChief) { + async function testFailureWithdraw(poolPid: number, users: string[], tribalChief: Contract) { for (const user of users) { await expectRevert( tribalChief.connect(impersonatedSigners[user]).withdrawFromDeposit(poolPid, totalStaked, user, 0), @@ -1969,9 +1967,9 @@ describe('TribalChief', () => { }); it('', async () => { - function printData(data, message) { + function printData(data: any, message: any) { console.log(message); - data.forEach((e) => { + data.forEach((e: any) => { console.log(`${e.msg} ${e.gas}`); }); } diff --git a/test/unit/staking/TribalChiefPart2.test.ts b/test/unit/staking/TribalChiefPart2.test.ts index 79f9f4aaf..998abc362 100644 --- a/test/unit/staking/TribalChiefPart2.test.ts +++ b/test/unit/staking/TribalChiefPart2.test.ts @@ -5,13 +5,11 @@ /* eslint-disable no-unused-expressions */ /* eslint-disable no-plusplus */ /* eslint-disable no-await-in-loop */ -import { time } from '../../helpers'; -import { expectRevert, expectUnspecifiedRevert, getCore, getAddresses, expectApprox } from '../../helpers'; +import { TransactionResponse } from '@ethersproject/abstract-provider'; import { expect } from 'chai'; +import { BigNumber, Contract, Signer } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { BigNumber, Signer } from 'ethers'; -import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider'; -import { BN } from 'ethereumjs-util'; +import { expectApprox, expectRevert, expectUnspecifiedRevert, getAddresses, getCore, time } from '../../helpers'; const toBN = ethers.BigNumber.from; @@ -23,14 +21,14 @@ const blockReward = '100000000000000000000'; const impersonatedSigners: { [key: string]: Signer } = {}; async function testMultipleUsersPooling( - tribalChief, - lpToken, - userAddresses, - incrementAmount, - blocksToAdvance, - lockLength, - totalStaked, - pid + tribalChief: Contract, + lpToken: Contract, + userAddresses: string[], + incrementAmount: BigNumber | BigNumber[], + blocksToAdvance: number, + lockLength: number | number[], + totalStaked: string, + pid: number ) { // if lock length isn't defined, it defaults to 0 lockLength = lockLength === undefined ? 0 : lockLength; @@ -85,7 +83,7 @@ async function testMultipleUsersPooling( await expectApprox( toBN(await tribalChief.pendingRewards(pid, userAddresses[j])), - pendingBalances[j].add(userIncrementAmount) + pendingBalances[j].add(userIncrementAmount as any) ); } } @@ -99,20 +97,20 @@ const depositReport = []; describe('TribalChief', () => { // this is the process ID of the staking rewards that we will use - let pid; - let minterAddress; - let governorAddress; - let userAddress; - let secondUserAddress; - let thirdUserAddress; - let fourthUserAddress; - let fifthUserAddress; - let sixthUserAddress; - let seventhUserAddress; - let eigthUserAddress; - let ninthUserAddress; - let tenthUserAddress; - let perBlockReward; + let pid: number; + let minterAddress: string; + let governorAddress: string; + let userAddress: string; + let secondUserAddress: string; + let thirdUserAddress: string; + let fourthUserAddress: string; + let fifthUserAddress: string; + let sixthUserAddress: string; + let seventhUserAddress: string; + let eigthUserAddress: string; + let ninthUserAddress: string; + let tenthUserAddress: string; + let perBlockReward: number; const multiplier10x = '100000'; const multiplier5x = '50000'; diff --git a/test/unit/staking/TribalChiefPart3.test.ts b/test/unit/staking/TribalChiefPart3.test.ts index e127d9259..b8d832933 100644 --- a/test/unit/staking/TribalChiefPart3.test.ts +++ b/test/unit/staking/TribalChiefPart3.test.ts @@ -5,12 +5,11 @@ /* eslint-disable no-unused-expressions */ /* eslint-disable no-plusplus */ /* eslint-disable no-await-in-loop */ -import { time } from '../../helpers'; -import { expectRevert, expectUnspecifiedRevert, getCore, getAddresses, expectApprox } from '../../helpers'; +import { TransactionResponse } from '@ethersproject/abstract-provider'; import { expect } from 'chai'; +import { BigNumber, Contract, Signer } from 'ethers'; import hre, { ethers } from 'hardhat'; -import { Signer } from 'ethers'; -import { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider'; +import { expectApprox, expectRevert, getAddresses, getCore, time } from '../../helpers'; const toBN = ethers.BigNumber.from; @@ -22,14 +21,14 @@ const blockReward = '100000000000000000000'; const impersonatedSigners: { [key: string]: Signer } = {}; async function testMultipleUsersPooling( - tribalChief, - lpToken, - userAddresses, - incrementAmount, - blocksToAdvance, - lockLength, - totalStaked, - pid + tribalChief: Contract, + lpToken: Contract, + userAddresses: string[], + incrementAmount: BigNumber | BigNumber[], + blocksToAdvance: number, + lockLength: number | number[], + totalStaked: string, + pid: number ) { // if lock length isn't defined, it defaults to 0 lockLength = lockLength === undefined ? 0 : lockLength; @@ -84,7 +83,7 @@ async function testMultipleUsersPooling( await expectApprox( toBN(await tribalChief.pendingRewards(pid, userAddresses[j])), - pendingBalances[j].add(userIncrementAmount) + pendingBalances[j].add(userIncrementAmount as any) ); } } @@ -98,20 +97,20 @@ const depositReport = []; describe('TribalChief', () => { // this is the process ID of the staking rewards that we will use - let pid; - let minterAddress; - let governorAddress; - let userAddress; - let secondUserAddress; - let thirdUserAddress; - let fourthUserAddress; - let fifthUserAddress; - let sixthUserAddress; - let seventhUserAddress; - let eigthUserAddress; - let ninthUserAddress; - let tenthUserAddress; - let perBlockReward; + let pid: number; + let minterAddress: string; + let governorAddress: string; + let userAddress: string; + let secondUserAddress: string; + let thirdUserAddress: string; + let fourthUserAddress: string; + let fifthUserAddress: string; + let sixthUserAddress: string; + let seventhUserAddress: string; + let eigthUserAddress: string; + let ninthUserAddress: string; + let tenthUserAddress: string; + let perBlockReward: number; const multiplier10x = '100000'; const multiplier5x = '50000'; diff --git a/test/unit/timelocks/QuadraticTimelock.test.ts b/test/unit/timelocks/QuadraticTimelock.test.ts index 8095c00fd..012879c90 100644 --- a/test/unit/timelocks/QuadraticTimelock.test.ts +++ b/test/unit/timelocks/QuadraticTimelock.test.ts @@ -1,19 +1,20 @@ +import { MockTribe, QuadraticTimelockedDelegator } from '@custom-types/contracts'; import { expectEvent, expectRevert, getAddresses, getImpersonatedSigner, time } from '@test/helpers'; import { expect } from 'chai'; +import { BigNumber, Signer } from 'ethers'; import { ethers } from 'hardhat'; -import { Signer } from 'ethers'; import { forceEth } from '../../integration/setup/utils'; const toBN = ethers.BigNumber.from; describe('QuadraticTimelockedDelegator', function () { - let userAddress; - let secondUserAddress; - let beneficiaryAddress1; - let delegator; - let tribe; - let window; - let totalTribe; + let userAddress: string; + let secondUserAddress: string; + let beneficiaryAddress1: string; + let delegator: QuadraticTimelockedDelegator; + let tribe: MockTribe; + let window: BigNumber; + let totalTribe: BigNumber; const impersonatedSigners: { [key: string]: Signer } = {}; @@ -80,10 +81,10 @@ describe('QuadraticTimelockedDelegator', function () { }); describe('One Quarter (1/4)', function () { - let quarter; - let alreadyClaimed; - let available; - let remainingBalance; + let quarter: BigNumber; + let alreadyClaimed: BigNumber; + let available: BigNumber; + let remainingBalance: BigNumber; beforeEach(async function () { quarter = window.div(toBN(4)); @@ -91,7 +92,7 @@ describe('QuadraticTimelockedDelegator', function () { alreadyClaimed = toBN(0); // 0 available = totalTribe.div(toBN(16)); // (1*1)/(4*4) remainingBalance = totalTribe.sub(available); - expectEvent(await delegator.release(userAddress, available), delegator, 'Release', [ + expectEvent(delegator.release(userAddress, available), delegator, 'Release', [ userAddress, userAddress, available @@ -160,7 +161,7 @@ describe('QuadraticTimelockedDelegator', function () { describe('Total Release', function () { beforeEach(async function () { - expectEvent(await delegator.release(userAddress, totalTribe), delegator, 'Release', [ + expectEvent(delegator.release(userAddress, totalTribe), delegator, 'Release', [ userAddress, userAddress, totalTribe @@ -180,7 +181,7 @@ describe('QuadraticTimelockedDelegator', function () { describe('Release To', function () { beforeEach(async function () { - expectEvent(await delegator.release(userAddress, totalTribe), delegator, 'Release', [ + expectEvent(delegator.release(userAddress, totalTribe), delegator, 'Release', [ userAddress, userAddress, totalTribe @@ -199,11 +200,11 @@ describe('QuadraticTimelockedDelegator', function () { }); describe('Partial Release', function () { - let halfAmount; + let halfAmount: BigNumber; beforeEach(async function () { halfAmount = totalTribe.div(toBN(2)); - expectEvent(await delegator.release(userAddress, halfAmount), delegator, 'Release', [ + expectEvent(delegator.release(userAddress, halfAmount), delegator, 'Release', [ userAddress, userAddress, halfAmount @@ -236,9 +237,7 @@ describe('QuadraticTimelockedDelegator', function () { describe('Access', function () { describe('Set Pending Beneficiary', function () { it('Beneficiary set succeeds', async function () { - expectEvent(await delegator.setPendingBeneficiary(userAddress), delegator, 'PendingBeneficiaryUpdate', [ - userAddress - ]); + expectEvent(delegator.setPendingBeneficiary(userAddress), delegator, 'PendingBeneficiaryUpdate', [userAddress]); expect(await delegator.pendingBeneficiary()).to.be.equal(userAddress); }); @@ -253,7 +252,7 @@ describe('QuadraticTimelockedDelegator', function () { it('Pending Beneficiary succeeds', async function () { await delegator.setPendingBeneficiary(userAddress); expectEvent( - await delegator.connect(impersonatedSigners[userAddress]).acceptBeneficiary(), + delegator.connect(impersonatedSigners[userAddress]).acceptBeneficiary(), delegator, 'BeneficiaryUpdate', [userAddress] @@ -290,7 +289,7 @@ describe('QuadraticTimelockedDelegator', function () { }); describe('Clawback', function () { - let clawbackAdmin; + let clawbackAdmin: string; beforeEach(async function () { clawbackAdmin = await delegator.clawbackAdmin(); diff --git a/test/unit/timelocks/TimelockedDelegator.test.ts b/test/unit/timelocks/TimelockedDelegator.test.ts index 895d5443c..6ec5c03f8 100644 --- a/test/unit/timelocks/TimelockedDelegator.test.ts +++ b/test/unit/timelocks/TimelockedDelegator.test.ts @@ -1,7 +1,7 @@ -import { getAddresses, time } from '../../helpers'; import { expect } from 'chai'; -import hre, { ethers, artifacts } from 'hardhat'; import { Signer } from 'ethers'; +import hre, { artifacts, ethers } from 'hardhat'; +import { getAddresses, time } from '../../helpers'; const TimelockedDelegator = artifacts.readArtifactSync('TimelockedDelegator'); const MockTribe = artifacts.readArtifactSync('MockTribe'); diff --git a/test/unit/tribe/TribeMinter.test.ts b/test/unit/tribe/TribeMinter.test.ts index 759f34fa2..8e00d05ef 100644 --- a/test/unit/tribe/TribeMinter.test.ts +++ b/test/unit/tribe/TribeMinter.test.ts @@ -1,10 +1,9 @@ -import { expectRevert, getAddresses, getCore, getImpersonatedSigner, increaseTime, ZERO_ADDRESS } from '../../helpers'; -import { ethers } from 'hardhat'; -import { expect } from 'chai'; -import { Signer } from 'ethers'; import { Core, Tribe, TribeMinter } from '@custom-types/contracts'; -import chai from 'chai'; +import chai, { expect } from 'chai'; import CBN from 'chai-bn'; +import { BigNumber, Signer } from 'ethers'; +import { ethers } from 'hardhat'; +import { expectRevert, getAddresses, getCore, getImpersonatedSigner, increaseTime, ZERO_ADDRESS } from '../../helpers'; const toBN = ethers.BigNumber.from; before(() => { @@ -83,8 +82,8 @@ describe('TribeMinter', function () { }); describe('Poke', function () { - let mintAmount; - let inflationIncrement; + let mintAmount: BigNumber; + let inflationIncrement: BigNumber; beforeEach(async function () { mintAmount = ethers.constants.WeiPerEther.mul(10_000); @@ -154,7 +153,7 @@ describe('TribeMinter', function () { }); describe('Mint', function () { - let mintAmount; + let mintAmount: BigNumber; beforeEach(async function () { mintAmount = ethers.constants.WeiPerEther.mul(10_000); }); diff --git a/test/unit/tribe/TribeReserveStabilizer.test.ts b/test/unit/tribe/TribeReserveStabilizer.test.ts index d21c6cf42..c118219fa 100644 --- a/test/unit/tribe/TribeReserveStabilizer.test.ts +++ b/test/unit/tribe/TribeReserveStabilizer.test.ts @@ -1,23 +1,23 @@ -import { expectRevert, getAddresses, getCore, increaseTime, getImpersonatedSigner } from '@test/helpers'; -import { ethers } from 'hardhat'; +import { Core, Fei, Tribe, TribeReserveStabilizer } from '@custom-types/contracts'; +import { expectRevert, getAddresses, getCore, getImpersonatedSigner, increaseTime } from '@test/helpers'; import { expect } from 'chai'; -import { Signer } from 'ethers'; -import { Core, Tribe, Fei, TribeReserveStabilizer } from '@custom-types/contracts'; +import { Contract, Signer } from 'ethers'; +import { ethers } from 'hardhat'; const toBN = ethers.BigNumber.from; describe('TribeReserveStabilizer', function () { - let userAddress; - let governorAddress; - let minterAddress; - let pcvControllerAddress; + let userAddress: string; + let governorAddress: string; + let minterAddress: string; + let pcvControllerAddress: string; let reserveStabilizer: TribeReserveStabilizer; let core: Core; let fei: Fei; let tribe: Tribe; - let tribeMinter; - let oracle; - let collateralizationOracle; + let tribeMinter: Contract; + let oracle: Contract; + let collateralizationOracle: Contract; const impersonatedSigners: { [key: string]: Signer } = {}; diff --git a/tsconfig.json b/tsconfig.json index e00fa2541..25ef1d3bd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,8 +3,9 @@ "moduleResolution": "node", "allowJs": true, "checkJs": true, - "noImplicitAny": false, - "noImplicitThis": false, + "strict": true, + "noImplicitAny": true, + "noImplicitThis": true, "target": "es2018", "module": "commonjs", "esModuleInterop": true, @@ -24,11 +25,12 @@ "test/*", "test/**/*", "scripts/*", "scripts/**/*", "proposals/*", "proposals/**/*", - "./types/contracts/*", "./types/contracts/**/*", + "protocol-configuration/*", "protocol-configuration/**/*", + "types/*", "types/**/*", ], "exclude": [ "scripts/deploy/old/*", "proposals/dao/old/*" ], "files": ["./hardhat.config.ts"], -} +} \ No newline at end of file diff --git a/types/types.ts b/types/types.ts index f0021d668..84334c5c5 100644 --- a/types/types.ts +++ b/types/types.ts @@ -1,4 +1,4 @@ -import { Contract, ethers } from 'ethers'; +import { ethers } from 'ethers'; import { AavePCVDeposit, AutoRewardsDistributor, @@ -29,6 +29,7 @@ import { RewardsDistributorAdmin, StakingTokenWrapper, Timelock, + TimelockController, TribalChief, Tribe, TribeReserveStabilizer, @@ -36,13 +37,13 @@ import { } from './contracts'; import { RestrictedPermissions } from './contracts/RestrictedPermissions'; -export type Env = { +export type ContractsAndAddresses = { contracts: NamedContracts; contractAddresses: NamedAddresses; }; export interface TestCoordinator { - loadEnvironment(): Promise; + loadEnvironment(): Promise; } export function namedContractsToNamedAddresses(contracts: NamedContracts): NamedAddresses { @@ -64,10 +65,12 @@ export enum ProposalCategory { DAO, DEBUG, OA, + TC, // Tribal Council + DEBUG_TC, None } -export type ProposalConfig = { +export interface ProposalConfig { deploy: boolean; category: ProposalCategory; totalValue: number; @@ -75,28 +78,56 @@ export type ProposalConfig = { affectedContractSignoff: string[]; deprecatedContractSignoff: string[]; proposalId: string; -}; +} + +export interface TemplatedProposalConfig { + deploy: boolean; + category: ProposalCategory; + totalValue: number; + proposal: TemplatedProposalDescription; + affectedContractSignoff: string[]; + deprecatedContractSignoff: string[]; + proposalId: string; +} -export type ProposalsConfigMap = { +export interface ProposalsConfigMap { [key: string]: ProposalConfig; -}; +} + +export interface TemplatedProposalsConfigMap { + [key: string]: TemplatedProposalConfig; +} -export type ProposalDescription = { +export interface ProposalDescription { title: string; commands: ProposalCommand[]; description: string; -}; +} -export type ProposalCommand = { +export interface TemplatedProposalDescription { + title: string; + commands: TemplatedProposalCommand[]; + description: string; +} + +export interface ProposalCommand { target: string; values: string; method: string; arguments: any[]; description: string; -}; +} + +export interface TemplatedProposalCommand { + target: string; + values: string; + method: string; + arguments: (namedAddresses: NamedAddresses) => any[]; + description: string; +} -export interface MainnetAddresses { - [key: string]: AddressConfig; +export interface MainnetContractsConfig { + [key: string]: ContractConfig; } export type TribalChiefPoolConfig = { @@ -108,7 +139,7 @@ export interface TribalChiefConfig { [key: string]: TribalChiefPoolConfig; } -export interface AddressConfig { +export interface ContractConfig { artifactName: string; address: string; category: AddressCategory; @@ -196,7 +227,6 @@ export interface MainnetContracts { compoundEthPCVDeposit: EthCompoundPCVDeposit; compoundDaiPCVDeposit: ERC20CompoundPCVDeposit; curveMetapoolDeposit: ethers.Contract; - curveMetapool: ethers.Contract; curve3pool: ethers.Contract; curve3crv: ethers.Contract; aaveEthPCVDeposit: AavePCVDeposit; @@ -206,11 +236,11 @@ export interface MainnetContracts { dai: IERC20; chainlinkDpiUsdOracleWrapper: ChainlinkOracleWrapper; dpiUniswapPCVDeposit: UniswapPCVDeposit; - indexCoopFusePoolDpiPCVDeposit: ERC20CompoundPCVDeposit; + rariPool19DpiPCVDeposit: ERC20CompoundPCVDeposit; rai: IERC20; chainlinkRaiEthOracleWrapper: ChainlinkOracleWrapper; chainlinkRaiUsdCompositeOracle: CompositeOracle; - reflexerStableAssetFusePoolRaiPCVDeposit: ERC20CompoundPCVDeposit; + rariPool9RaiPCVDeposit: ERC20CompoundPCVDeposit; kashiFeiTribe: IKashiPair; bentoBox: IMasterContractManager; aaveEthPCVDripController: PCVDripController; @@ -219,7 +249,7 @@ export interface MainnetContracts { stakingTokenWrapper: StakingTokenWrapper; feiTribePair: IUniswapV2Pair; rariPool8Tribe: CErc20Delegator; - curve3Metapool: IERC20; + curveFei3crvMetapool: IERC20; erc20Dripper: ERC20Dripper; tribalChiefOptimisticTimelock: OptimisticTimelock; collateralizationOracle: CollateralizationOracle; @@ -236,6 +266,7 @@ export interface MainnetContracts { autoRewardsDistributor: AutoRewardsDistributor; rewardsDistributorAdmin: RewardsDistributorAdmin; restrictedPermissions: RestrictedPermissions; + tribalCouncilTimelock: TimelockController; } export interface MainnetContractAddresses { @@ -257,19 +288,20 @@ export interface MainnetContractAddresses { feiRewardsDistributor: string; tribeReserveStabilizer: string; timelock: string; - multisig: string; + guardianMultisig: string; governorAlpha: string; - indexCoopFusePoolDpi: string; - reflexerStableAssetFusePoolRai: string; + rariPool19Dpi: string; + rariPool9Rai: string; bentoBox: string; masterKashi: string; feiTribePair: string; rariPool8Tribe: string; - curve3Metapool: string; - tribalChiefOptimisticMultisig: string; + curveFei3crvMetapool: string; + optimisticMultisig: string; stakingTokenWrapperRari: string; rariRewardsDistributorDelegator: string; restrictedPermissions: string; + tribalCouncilTimelock: string; } export type ContractAccessRights = {