From 9e0e70f26ae6a33a166517ccd6cbfa52011998ed Mon Sep 17 00:00:00 2001 From: iamsahu Date: Wed, 4 May 2022 17:20:35 +0530 Subject: [PATCH 1/4] feat: StrategyAm3Crv & StrategyBtcCurve migration --- .gitignore | 5 + polygon/contracts/StrategyAm3Crv.sol | 409 +++++++++--------- polygon/contracts/StrategyBtcCurve.sol | 2 +- polygon/hardhat.config.ts | 17 +- polygon/package.json | 1 + polygon/tasks/migrate-am-3crv.ts | 34 ++ polygon/tasks/migrate-btcCrv.ts | 48 ++ polygon/test/strategyAm3crv.gaugemigration.ts | 68 +++ polygon/test/strategySbtc.migration.ts | 85 ++++ 9 files changed, 459 insertions(+), 210 deletions(-) create mode 100644 .gitignore create mode 100644 polygon/tasks/migrate-am-3crv.ts create mode 100644 polygon/tasks/migrate-btcCrv.ts create mode 100644 polygon/test/strategyAm3crv.gaugemigration.ts create mode 100644 polygon/test/strategySbtc.migration.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0690ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.env +artifacts +node_modules +typechain +cache \ No newline at end of file diff --git a/polygon/contracts/StrategyAm3Crv.sol b/polygon/contracts/StrategyAm3Crv.sol index 39f1cc0..851af62 100644 --- a/polygon/contracts/StrategyAm3Crv.sol +++ b/polygon/contracts/StrategyAm3Crv.sol @@ -3,250 +3,257 @@ pragma solidity ^0.5.17; pragma experimental ABIEncoderV2; -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import '@openzeppelin/contracts/math/SafeMath.sol'; -import '@openzeppelin/contracts/utils/Address.sol'; -import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol'; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; interface IController { - function withdraw(address, uint256) external; + function withdraw(address, uint256) external; - function balanceOf(address) external view returns (uint256); + function balanceOf(address) external view returns (uint256); - function earn(address, uint256) external; + function earn(address, uint256) external; - function want(address) external view returns (address); + function want(address) external view returns (address); - function rewards() external view returns (address); + function rewards() external view returns (address); - function vaults(address) external view returns (address); + function vaults(address) external view returns (address); - function strategies(address) external view returns (address); + function strategies(address) external view returns (address); } interface ICurveFi { - function add_liquidity( - uint256[3] calldata amounts, - uint256 min_mint_amount, - bool use_underlying - ) external returns (uint256); + function add_liquidity( + uint256[3] calldata amounts, + uint256 min_mint_amount, + bool use_underlying + ) external returns (uint256); } interface Gauge { - function deposit(uint256) external; + function deposit(uint256) external; - function balanceOf(address) external view returns (uint256); + function balanceOf(address) external view returns (uint256); - function withdraw(uint256) external; + function withdraw(uint256) external; - function claim_rewards() external; + function claim_rewards() external; } contract StrategyAm3Crv { - using SafeERC20 for IERC20; - using Address for address; - using SafeMath for uint256; - - address public constant want = - address(0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171); + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; - address public constant paraswap = - address(0x90249ed4d69D70E709fFCd8beE2c5A566f65dADE); + address public constant want = + address(0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171); - address public constant wmatic = - address(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270); + address public constant paraswap = + address(0x90249ed4d69D70E709fFCd8beE2c5A566f65dADE); - address public constant crv = - address(0x172370d5Cd63279eFa6d502DAB29171933a610AF); + address public constant wmatic = + address(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270); - address public constant dai = - address(0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063); + address public constant crv = + address(0x172370d5Cd63279eFa6d502DAB29171933a610AF); - address public constant pool = - address(0x445FE580eF8d70FF569aB36e80c647af338db351); + address public constant dai = + address(0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063); - address public constant gauge = - address(0xe381C25de995d62b453aF8B931aAc84fcCaa7A62); + address public constant pool = + address(0x445FE580eF8d70FF569aB36e80c647af338db351); - address public paraswapProxy = - address(0xCD52384e2A96F6E91e4e420de2F9a8C0f1FFB449); + address public gauge = + address(0x19793B454D3AfC7b454F206Ffe95aDE26cA6912c); - uint256 public performanceFee = 1500; - uint256 public constant performanceMax = 10000; + address public paraswapProxy = + address(0xCD52384e2A96F6E91e4e420de2F9a8C0f1FFB449); - uint256 public withdrawalFee = 50; - uint256 public constant withdrawalMax = 10000; + uint256 public performanceFee = 1500; + uint256 public constant performanceMax = 10000; - address public governance; - address public controller; - address public strategist; + uint256 public withdrawalFee = 50; + uint256 public constant withdrawalMax = 10000; - uint256 public earned; // lifetime strategy earnings denominated in `want` token + address public governance; + address public controller; + address public strategist; - event Harvested(uint256 wantEarned, uint256 lifetimeEarned); + uint256 public earned; // lifetime strategy earnings denominated in `want` token - modifier onlyGovernance() { - require(msg.sender == governance, '!governance'); - _; - } + event Harvested(uint256 wantEarned, uint256 lifetimeEarned); - modifier onlyController() { - require(msg.sender == controller, '!controller'); - _; - } - - constructor(address _controller) public { - governance = msg.sender; - strategist = msg.sender; - controller = _controller; - } - - function getName() external pure returns (string memory) { - return 'StrategyAm3Crv'; - } - - function setStrategist(address _strategist) external onlyGovernance { - strategist = _strategist; - } - - function setWithdrawalFee(uint256 _withdrawalFee) external onlyGovernance { - withdrawalFee = _withdrawalFee; - } - - function setPerformanceFee(uint256 _performanceFee) external onlyGovernance { - performanceFee = _performanceFee; - } - - function setParaswapProxy(address _paraswapProxy) external onlyGovernance { - paraswapProxy = _paraswapProxy; - } - - function deposit() public { - uint256 _want = IERC20(want).balanceOf(address(this)); - if (_want > 0) { - IERC20(want).approve(gauge, _want); - Gauge(gauge).deposit(_want); - } - } - - // Controller only function for creating additional rewards from dust - function withdraw(IERC20 _asset) - external - onlyController - returns (uint256 balance) - { - require(want != address(_asset), 'want'); - require(dai != address(_asset), 'dai'); - require(wmatic != address(_asset), 'wmatic'); - balance = _asset.balanceOf(address(this)); - _asset.safeTransfer(controller, balance); - } - - // Withdraw partial funds, normally used with a vault withdrawal - function withdraw(uint256 _amount) external onlyController { - uint256 _balance = IERC20(want).balanceOf(address(this)); - if (_balance < _amount) { - _withdrawSome(_amount.sub(_balance)); - } - - uint256 _fee = _amount.mul(withdrawalFee).div(withdrawalMax); - - IERC20(want).safeTransfer(IController(controller).rewards(), _fee); - address _vault = IController(controller).vaults(address(want)); - require(_vault != address(0), '!vault'); // additional protection so we don't burn the funds - - IERC20(want).safeTransfer(_vault, _amount.sub(_fee)); - } - - function _withdrawSome(uint256 _amount) internal { - Gauge(gauge).withdraw(_amount); - } - - // Withdraw all funds, normally used when migrating strategies - function withdrawAll() external onlyController returns (uint256 balance) { - _withdrawAll(); - - balance = balanceOfWant(); - - address _vault = IController(controller).vaults(address(want)); - require(_vault != address(0), '!vault'); // additional protection so we don't burn the funds - IERC20(want).safeTransfer(_vault, balance); - } - - function _withdrawAll() internal { - uint256 _before = balanceOf(); - _withdrawSome(balanceOfPool()); - require(_before == balanceOf(), '!slippage'); - } - - function harvest(bytes memory swapDataWmatic, bytes memory swapDataCrv) - public - { - require( - msg.sender == strategist || msg.sender == governance, - '!authorized' - ); - - Gauge(gauge).claim_rewards(); - - uint256 _crv = IERC20(crv).balanceOf(address(this)); - if (_crv > 0) { - IERC20(crv).approve(paraswapProxy, _crv); - (bool success, ) = paraswap.call(swapDataCrv); - if (!success) { - // Copy revert reason from call - assembly { - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) + modifier onlyGovernance() { + require(msg.sender == governance, "!governance"); + _; + } + + modifier onlyController() { + require(msg.sender == controller, "!controller"); + _; + } + + constructor(address _controller) public { + governance = msg.sender; + strategist = msg.sender; + controller = _controller; + } + + function getName() external pure returns (string memory) { + return "StrategyAm3Crv"; + } + + function setStrategist(address _strategist) external onlyGovernance { + strategist = _strategist; + } + + function setWithdrawalFee(uint256 _withdrawalFee) external onlyGovernance { + withdrawalFee = _withdrawalFee; + } + + function setPerformanceFee(uint256 _performanceFee) + external + onlyGovernance + { + performanceFee = _performanceFee; + } + + function setGauge(address _gauge) external onlyGovernance { + gauge = _gauge; + } + + function setParaswapProxy(address _paraswapProxy) external onlyGovernance { + paraswapProxy = _paraswapProxy; + } + + function deposit() public { + uint256 _want = IERC20(want).balanceOf(address(this)); + if (_want > 0) { + IERC20(want).approve(gauge, _want); + Gauge(gauge).deposit(_want); } - } - } - - uint256 _wmatic = IERC20(wmatic).balanceOf(address(this)); - if (_wmatic > 0) { - IERC20(wmatic).approve(paraswapProxy, _wmatic); - (bool success, ) = paraswap.call(swapDataWmatic); - if (!success) { - // Copy revert reason from call - assembly { - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) + } + + // Controller only function for creating additional rewards from dust + function withdraw(IERC20 _asset) + external + onlyController + returns (uint256 balance) + { + require(want != address(_asset), "want"); + require(dai != address(_asset), "dai"); + require(wmatic != address(_asset), "wmatic"); + balance = _asset.balanceOf(address(this)); + _asset.safeTransfer(controller, balance); + } + + // Withdraw partial funds, normally used with a vault withdrawal + function withdraw(uint256 _amount) external onlyController { + uint256 _balance = IERC20(want).balanceOf(address(this)); + if (_balance < _amount) { + _withdrawSome(_amount.sub(_balance)); } - } + + uint256 _fee = _amount.mul(withdrawalFee).div(withdrawalMax); + + IERC20(want).safeTransfer(IController(controller).rewards(), _fee); + address _vault = IController(controller).vaults(address(want)); + require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds + + IERC20(want).safeTransfer(_vault, _amount.sub(_fee)); } - uint256 _dai = IERC20(dai).balanceOf(address(this)); - if (_dai > 0) { - IERC20(dai).approve(pool, _dai); - ICurveFi(pool).add_liquidity([_dai, 0, 0], 0, true); + + function _withdrawSome(uint256 _amount) internal { + Gauge(gauge).withdraw(_amount); } - uint256 _want = IERC20(want).balanceOf(address(this)); - if (_want > 0) { - uint256 _fee = _want.mul(performanceFee).div(performanceMax); - IERC20(want).safeTransfer(IController(controller).rewards(), _fee); - deposit(); + + // Withdraw all funds, normally used when migrating strategies + function withdrawAll() external onlyController returns (uint256 balance) { + _withdrawAll(); + + balance = balanceOfWant(); + + address _vault = IController(controller).vaults(address(want)); + require(_vault != address(0), "!vault"); // additional protection so we don't burn the funds + IERC20(want).safeTransfer(_vault, balance); } - earned = earned.add(_want); - emit Harvested(_want, earned); - } + function _withdrawAll() internal { + uint256 _before = balanceOf(); + _withdrawSome(balanceOfPool()); + require(_before == balanceOf(), "!slippage"); + } - function balanceOfWant() public view returns (uint256) { - return IERC20(want).balanceOf(address(this)); - } + function harvest(bytes memory swapDataWmatic, bytes memory swapDataCrv) + public + { + require( + msg.sender == strategist || msg.sender == governance, + "!authorized" + ); + + Gauge(gauge).claim_rewards(); + + uint256 _crv = IERC20(crv).balanceOf(address(this)); + if (_crv > 0) { + IERC20(crv).approve(paraswapProxy, _crv); + (bool success, ) = paraswap.call(swapDataCrv); + if (!success) { + // Copy revert reason from call + assembly { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + } + } - function balanceOfPool() public view returns (uint256) { - return Gauge(gauge).balanceOf(address(this)); - } + uint256 _wmatic = IERC20(wmatic).balanceOf(address(this)); + if (_wmatic > 0) { + IERC20(wmatic).approve(paraswapProxy, _wmatic); + (bool success, ) = paraswap.call(swapDataWmatic); + if (!success) { + // Copy revert reason from call + assembly { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + } + } + uint256 _dai = IERC20(dai).balanceOf(address(this)); + if (_dai > 0) { + IERC20(dai).approve(pool, _dai); + ICurveFi(pool).add_liquidity([_dai, 0, 0], 0, true); + } + uint256 _want = IERC20(want).balanceOf(address(this)); + if (_want > 0) { + uint256 _fee = _want.mul(performanceFee).div(performanceMax); + IERC20(want).safeTransfer(IController(controller).rewards(), _fee); + deposit(); + } + + earned = earned.add(_want); + emit Harvested(_want, earned); + } + + function balanceOfWant() public view returns (uint256) { + return IERC20(want).balanceOf(address(this)); + } - function balanceOf() public view returns (uint256) { - return balanceOfWant().add(balanceOfPool()); - } + function balanceOfPool() public view returns (uint256) { + return Gauge(gauge).balanceOf(address(this)); + } - function setGovernance(address _governance) external onlyGovernance { - governance = _governance; - } + function balanceOf() public view returns (uint256) { + return balanceOfWant().add(balanceOfPool()); + } - function setController(address _controller) external onlyGovernance { - controller = _controller; - } + function setGovernance(address _governance) external onlyGovernance { + governance = _governance; + } + + function setController(address _controller) external onlyGovernance { + controller = _controller; + } } diff --git a/polygon/contracts/StrategyBtcCurve.sol b/polygon/contracts/StrategyBtcCurve.sol index 6932ff8..665d262 100644 --- a/polygon/contracts/StrategyBtcCurve.sol +++ b/polygon/contracts/StrategyBtcCurve.sol @@ -66,7 +66,7 @@ contract StrategyBtcCurve { address(0xC2d95EEF97Ec6C17551d45e77B590dc1F9117C67); address public gauge = - address(0x19793B454D3AfC7b454F206Ffe95aDE26cA6912c); + address(0x8D9649e50A0d1da8E939f800fB926cdE8f18B47D); address public paraswapProxy = address(0xCD52384e2A96F6E91e4e420de2F9a8C0f1FFB449); diff --git a/polygon/hardhat.config.ts b/polygon/hardhat.config.ts index 40936ee..ebf3c10 100644 --- a/polygon/hardhat.config.ts +++ b/polygon/hardhat.config.ts @@ -3,11 +3,12 @@ import '@nomiclabs/hardhat-ethers'; import '@nomiclabs/hardhat-waffle'; import '@nomiclabs/hardhat-etherscan'; import 'hardhat-tracer'; +import "hardhat-typechain"; -import './tasks/deploy-usd'; -import './tasks/deploy-btc'; -import './tasks/deploy-eur'; -import './tasks/deploy-am-3crv'; +// import './tasks/deploy-usd'; +// import './tasks/deploy-btc'; +// import './tasks/deploy-eur'; +// import './tasks/deploy-am-3crv'; require('dotenv').config(); @@ -18,17 +19,17 @@ export default { networks: { hardhat: { forking: { - //url: process.env.ALCHEMY_MAINNET - url: '' + url: process.env.ALCHEMY_MAINNET + // url: '' } }, mainnet: { url: process.env.ALCHEMY_MAINNET, - accounts: [`0x${DEPLOYER}`] + // accounts: [`0x${DEPLOYER}`] }, matic: { url: ``, - accounts: [`0x${DEPLOYER}`], + // accounts: [`0x${DEPLOYER}`], gasPrice: 9000000000 } }, diff --git a/polygon/package.json b/polygon/package.json index dcc722a..b69715f 100644 --- a/polygon/package.json +++ b/polygon/package.json @@ -27,6 +27,7 @@ "@uniswap/v3-periphery": "^1.1.0", "dotenv": "^8.2.0", "hardhat-tracer": "1.0.0-alpha.6", + "hardhat-typechain": "^0.3.5", "prettier": "^2.3.0" }, "scripts": { diff --git a/polygon/tasks/migrate-am-3crv.ts b/polygon/tasks/migrate-am-3crv.ts new file mode 100644 index 0000000..3335931 --- /dev/null +++ b/polygon/tasks/migrate-am-3crv.ts @@ -0,0 +1,34 @@ +import { ethers, network, waffle } from "hardhat"; +import { Contract } from "@ethersproject/contracts"; +import Controller from "../abis/Controller.json"; +import YVault from "../abis/YVault.json"; + +(async () => { + let [ownerAcc] = await ethers.getSigners(); + let controller: Contract; + let vault: Contract; + let currentStrategy: Contract; + + const WANT = "0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171"; // am3CRV + const CONTROLLER = "0x91aE00aaC6eE0D7853C8F92710B641F68Cd945Df"; + const VAULT = "0x7d60F21072b585351dFd5E8b17109458D97ec120"; + const NEWGAUGE = "0x20759F567BB3EcDB55c817c9a1d13076aB215EdC"; + const CURRENT_STRATEGY = "0xe7E66372f19C3E5Fc4D6c3c88c54178Bcd525040"; + + controller = await ethers.getContractAt(Controller, CONTROLLER); + vault = await ethers.getContractAt(YVault, VAULT); + currentStrategy = await ethers.getContractAt( + "StrategyAm3Crv", + CURRENT_STRATEGY + ); + + // Withdraw + await controller.withdrawAll(WANT); + console.log("Withdrawn"); + // Set new gauge + await currentStrategy.setGauge(NEWGAUGE); + console.log("new gauge set"); + // Call Earn + await vault.earn(); + console.log("earned call"); +})(); diff --git a/polygon/tasks/migrate-btcCrv.ts b/polygon/tasks/migrate-btcCrv.ts new file mode 100644 index 0000000..deb911d --- /dev/null +++ b/polygon/tasks/migrate-btcCrv.ts @@ -0,0 +1,48 @@ +import { ethers, network, waffle } from "hardhat"; +import StrategyBtcCurveArtifact from "../artifacts/contracts/StrategyBtcCurve.sol/StrategyBtcCurve.json"; +import { StrategyBtcCurve } from "../typechain"; +const { deployContract } = waffle; +import { Contract } from "@ethersproject/contracts"; +import Controller from "../abis/Controller.json"; +import YVault from '../abis/YVault.json'; + +(async () => { + let [ownerAcc] = await ethers.getSigners(); + let controller: Contract; + let vault: Contract; + let StrategyBtcCurve: StrategyBtcCurve; + const WANT = "0xf8a57c1d3b9629b77b6726a042ca48990a84fb49"; // am3CRV + const CONTROLLER = "0x91aE00aaC6eE0D7853C8F92710B641F68Cd945Df"; + const VAULT = '0x953Cf8f1f097c222015FFa32C7B9e3E96993b8c1'; + let args = [CONTROLLER]; + + controller = await ethers.getContractAt(Controller, CONTROLLER); + vault = await ethers.getContractAt(YVault, VAULT); + + //Deploy strategy + StrategyBtcCurve = (await deployContract( + ownerAcc, + StrategyBtcCurveArtifact, + args + )) as StrategyBtcCurve; + console.log( + "Deployed StrategyBtcCurve contract deployed at " + StrategyBtcCurve.address + ); + console.log( + `npx hardhat verify --network ${network.name} ${ + StrategyBtcCurve.address + } ${args.join(" ")}` + ); + + // Approve & set strategy + await controller.approveStrategy(WANT, StrategyBtcCurve.address); + console.log('Approved strategy') + await controller.setStrategy(WANT, StrategyBtcCurve.address); + console.log('Set strategy') + + // Call Earn + await vault.earn() + await vault.earn() + await vault.earn() + console.log('Earn called') +})(); diff --git a/polygon/test/strategyAm3crv.gaugemigration.ts b/polygon/test/strategyAm3crv.gaugemigration.ts new file mode 100644 index 0000000..fed5643 --- /dev/null +++ b/polygon/test/strategyAm3crv.gaugemigration.ts @@ -0,0 +1,68 @@ +import { ethers, network } from "hardhat"; +import { expect } from "chai"; +import { BigNumber } from "@ethersproject/bignumber"; +import { Contract } from "@ethersproject/contracts"; +import { parseEther } from "@ethersproject/units"; +import { JsonRpcSigner } from "@ethersproject/providers"; + +import Controller from "../abis/Controller.json"; +import YVault from "../abis/YVault.json"; +import ERC20 from "../abis/ERC20.json"; + +const VAULT = "0x7d60F21072b585351dFd5E8b17109458D97ec120"; +const CONTROLLER = "0x91aE00aaC6eE0D7853C8F92710B641F68Cd945Df"; +const GOVERNANCE = "0xb36a0671B3D49587236d7833B01E79798175875f"; +const OLD_STRATEGY = "0xe7E66372f19C3E5Fc4D6c3c88c54178Bcd525040"; + +const CRV = "0x172370d5Cd63279eFa6d502DAB29171933a610AF"; +const WANT = "0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171"; // am3CRV +const NEWGAUGE = "0x20759F567BB3EcDB55c817c9a1d13076aB215EdC"; +describe("StrategyAm3Crv Gauge Migration", function () { + let vault: Contract; + let want: Contract; + let crv: Contract; + let controller: Contract; + let currentStrategy: Contract; + let governanceSigner: JsonRpcSigner; + + let initialBalance: BigNumber; + + before(async function () { + const [owner] = await ethers.getSigners(); + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [CONTROLLER], + }); + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [GOVERNANCE], + }); + + vault = await ethers.getContractAt(YVault, VAULT); + controller = await ethers.getContractAt(Controller, CONTROLLER); + want = await ethers.getContractAt(ERC20, WANT); + crv = await ethers.getContractAt(ERC20, CRV); + currentStrategy = await ethers.getContractAt( + "StrategyAm3Crv", + OLD_STRATEGY + ); + + governanceSigner = await ethers.provider.getSigner(GOVERNANCE); + + initialBalance = await vault.balance(); + }); + + it("Migrate Gauge", async function () { + await controller.connect(governanceSigner).withdrawAll(WANT); + let availableBalance = await vault.available(); + + await currentStrategy.connect(governanceSigner).setGauge(NEWGAUGE); + await vault.earn(); + + expect(availableBalance).to.be.eq( + await currentStrategy.callStatic.balanceOfPool() + ); + }); +}); diff --git a/polygon/test/strategySbtc.migration.ts b/polygon/test/strategySbtc.migration.ts new file mode 100644 index 0000000..19def8e --- /dev/null +++ b/polygon/test/strategySbtc.migration.ts @@ -0,0 +1,85 @@ +import {ethers, network} from 'hardhat'; +import {expect} from 'chai'; +import {BigNumber} from '@ethersproject/bignumber'; +import {Contract} from '@ethersproject/contracts'; +import {parseEther} from '@ethersproject/units'; +import {JsonRpcSigner} from '@ethersproject/providers'; + +import Controller from '../abis/Controller.json'; +import YVault from '../abis/YVault.json'; +import ERC20 from '../abis/ERC20.json'; + +const VAULT = '0x953Cf8f1f097c222015FFa32C7B9e3E96993b8c1'; +const CONTROLLER = '0x91aE00aaC6eE0D7853C8F92710B641F68Cd945Df'; +const GOVERNANCE = '0xb36a0671B3D49587236d7833B01E79798175875f'; +const OLD_STRATEGY = '0x2fc878ad596939c36dd9f445ae0fab45a78a9830'; + +const CRV = '0x172370d5Cd63279eFa6d502DAB29171933a610AF'; +const WANT = '0xf8a57c1d3b9629b77b6726a042ca48990a84fb49'; + +describe('StrategyBtcCurve', function () { + let vault: Contract; + let want: Contract; + let crv: Contract; + let controller: Contract; + let strategy: Contract; + let oldStrategy: Contract; + let governanceSigner: JsonRpcSigner; + + let initialBalance: BigNumber; + + before(async function () { + // this.enableTimeouts(false); + const [owner] = await ethers.getSigners(); + + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [CONTROLLER] + }); + + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [GOVERNANCE] + }); + + const Strategy = await ethers.getContractFactory('StrategyBtcCurve'); + + vault = await ethers.getContractAt(YVault, VAULT); + controller = await ethers.getContractAt(Controller, CONTROLLER); + want = await ethers.getContractAt(ERC20, WANT); + crv = await ethers.getContractAt(ERC20, CRV); + oldStrategy = await ethers.getContractAt('StrategyBtcCurve', OLD_STRATEGY); + + strategy = await Strategy.deploy(CONTROLLER); + + governanceSigner = await ethers.provider.getSigner(GOVERNANCE); + + initialBalance = await vault.balance(); + + await ( + await controller + .connect(governanceSigner) + .approveStrategy(WANT, strategy.address) + ).wait(); + + await ( + await controller + .connect(governanceSigner) + .setStrategy(WANT, strategy.address) + ).wait(); + }); + + it('All funds should be in vault', async function () { + const vaultBalance = await want.balanceOf(vault.address); + expect(vaultBalance.eq(initialBalance)).to.be.true; + }); + + it('Should send funds to strategy', async function () { + await (await vault.earn()).wait(); + await (await vault.earn()).wait(); + await (await vault.earn()).wait(); + + const strategyPoolBalance = await strategy.balanceOfPool(); + expect(strategyPoolBalance.gt(0)).to.be.true; + }); +}); From 94ad7ac8286099ba1cffc6918be2cd5a0af0653d Mon Sep 17 00:00:00 2001 From: iamsahu Date: Sat, 7 May 2022 16:55:57 +0530 Subject: [PATCH 2/4] fix: extra earn for am3crv & old strategy check for btc strat --- polygon/tasks/migrate-am-3crv.ts | 2 ++ polygon/test/strategySbtc.migration.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/polygon/tasks/migrate-am-3crv.ts b/polygon/tasks/migrate-am-3crv.ts index 3335931..096271b 100644 --- a/polygon/tasks/migrate-am-3crv.ts +++ b/polygon/tasks/migrate-am-3crv.ts @@ -30,5 +30,7 @@ import YVault from "../abis/YVault.json"; console.log("new gauge set"); // Call Earn await vault.earn(); + await vault.earn(); + await vault.earn(); console.log("earned call"); })(); diff --git a/polygon/test/strategySbtc.migration.ts b/polygon/test/strategySbtc.migration.ts index 19def8e..699d718 100644 --- a/polygon/test/strategySbtc.migration.ts +++ b/polygon/test/strategySbtc.migration.ts @@ -81,5 +81,8 @@ describe('StrategyBtcCurve', function () { const strategyPoolBalance = await strategy.balanceOfPool(); expect(strategyPoolBalance.gt(0)).to.be.true; + const oldStrategyPoolBalance = await oldStrategy.balanceOfPool(); + + expect(oldStrategyPoolBalance.eq(0)).to.be.true; }); }); From eb8950b38c8de64171dad146752f8ad6d916e49b Mon Sep 17 00:00:00 2001 From: iamsahu Date: Mon, 9 May 2022 15:54:13 +0530 Subject: [PATCH 3/4] fix: added test to check old gauge values --- polygon/abis/ICurveGauge.json | 78 +++++++++++++++++++ polygon/test/strategyAm3crv.gaugemigration.ts | 19 ++++- polygon/test/strategySbtc.migration.ts | 8 +- 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 polygon/abis/ICurveGauge.json diff --git a/polygon/abis/ICurveGauge.json b/polygon/abis/ICurveGauge.json new file mode 100644 index 0000000..0856af7 --- /dev/null +++ b/polygon/abis/ICurveGauge.json @@ -0,0 +1,78 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claim_rewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_addr", + "type": "address" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "claimable_reward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] \ No newline at end of file diff --git a/polygon/test/strategyAm3crv.gaugemigration.ts b/polygon/test/strategyAm3crv.gaugemigration.ts index fed5643..ab91b7f 100644 --- a/polygon/test/strategyAm3crv.gaugemigration.ts +++ b/polygon/test/strategyAm3crv.gaugemigration.ts @@ -8,12 +8,13 @@ import { JsonRpcSigner } from "@ethersproject/providers"; import Controller from "../abis/Controller.json"; import YVault from "../abis/YVault.json"; import ERC20 from "../abis/ERC20.json"; +import ICurveGauge from "../abis/ICurveGauge.json"; const VAULT = "0x7d60F21072b585351dFd5E8b17109458D97ec120"; const CONTROLLER = "0x91aE00aaC6eE0D7853C8F92710B641F68Cd945Df"; const GOVERNANCE = "0xb36a0671B3D49587236d7833B01E79798175875f"; const OLD_STRATEGY = "0xe7E66372f19C3E5Fc4D6c3c88c54178Bcd525040"; - +const OLD_GAUGE = "0x19793B454D3AfC7b454F206Ffe95aDE26cA6912c"; const CRV = "0x172370d5Cd63279eFa6d502DAB29171933a610AF"; const WANT = "0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171"; // am3CRV const NEWGAUGE = "0x20759F567BB3EcDB55c817c9a1d13076aB215EdC"; @@ -23,6 +24,7 @@ describe("StrategyAm3Crv Gauge Migration", function () { let crv: Contract; let controller: Contract; let currentStrategy: Contract; + let crvGauge: Contract; let governanceSigner: JsonRpcSigner; let initialBalance: BigNumber; @@ -44,6 +46,7 @@ describe("StrategyAm3Crv Gauge Migration", function () { controller = await ethers.getContractAt(Controller, CONTROLLER); want = await ethers.getContractAt(ERC20, WANT); crv = await ethers.getContractAt(ERC20, CRV); + crvGauge = await ethers.getContractAt(ICurveGauge, OLD_GAUGE); currentStrategy = await ethers.getContractAt( "StrategyAm3Crv", OLD_STRATEGY @@ -64,5 +67,19 @@ describe("StrategyAm3Crv Gauge Migration", function () { expect(availableBalance).to.be.eq( await currentStrategy.callStatic.balanceOfPool() ); + + // Testing old gauge award remains + expect( + await crvGauge.claimable_reward( + currentStrategy.address, + "0x172370d5Cd63279eFa6d502DAB29171933a610AF" + ) + ).to.eq(0); + expect( + await crvGauge.claimable_reward( + currentStrategy.address, + "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270" + ) + ).to.eq(0); }); }); diff --git a/polygon/test/strategySbtc.migration.ts b/polygon/test/strategySbtc.migration.ts index 699d718..4b26a61 100644 --- a/polygon/test/strategySbtc.migration.ts +++ b/polygon/test/strategySbtc.migration.ts @@ -8,6 +8,7 @@ import {JsonRpcSigner} from '@ethersproject/providers'; import Controller from '../abis/Controller.json'; import YVault from '../abis/YVault.json'; import ERC20 from '../abis/ERC20.json'; +import ICurveGauge from '../abis/ICurveGauge.json' const VAULT = '0x953Cf8f1f097c222015FFa32C7B9e3E96993b8c1'; const CONTROLLER = '0x91aE00aaC6eE0D7853C8F92710B641F68Cd945Df'; @@ -24,6 +25,7 @@ describe('StrategyBtcCurve', function () { let controller: Contract; let strategy: Contract; let oldStrategy: Contract; + let crvGauge: Contract; let governanceSigner: JsonRpcSigner; let initialBalance: BigNumber; @@ -49,7 +51,7 @@ describe('StrategyBtcCurve', function () { want = await ethers.getContractAt(ERC20, WANT); crv = await ethers.getContractAt(ERC20, CRV); oldStrategy = await ethers.getContractAt('StrategyBtcCurve', OLD_STRATEGY); - + crvGauge = await ethers.getContractAt(ICurveGauge,'0x8D9649e50A0d1da8E939f800fB926cdE8f18B47D'); strategy = await Strategy.deploy(CONTROLLER); governanceSigner = await ethers.provider.getSigner(GOVERNANCE); @@ -84,5 +86,9 @@ describe('StrategyBtcCurve', function () { const oldStrategyPoolBalance = await oldStrategy.balanceOfPool(); expect(oldStrategyPoolBalance.eq(0)).to.be.true; + + // Testing old gauge award remains + expect(await crvGauge.claimable_reward(oldStrategy.address,'0x47536F17F4fF30e64A96a7555826b8f9e66ec468')).to.eq(0) + expect(await crvGauge.claimable_reward(oldStrategy.address,'0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7')).to.eq(0) }); }); From 60a3fabfb75efa8c79e3d1e5f11d8a0ecef7e0b9 Mon Sep 17 00:00:00 2001 From: iamsahu Date: Tue, 10 May 2022 11:47:42 +0530 Subject: [PATCH 4/4] feat: harvest added to Am3Crv migration test --- polygon/test/strategyAm3crv.gaugemigration.ts | 7 +++++++ polygon/test/strategySbtc.migration.ts | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/polygon/test/strategyAm3crv.gaugemigration.ts b/polygon/test/strategyAm3crv.gaugemigration.ts index ab91b7f..efcc860 100644 --- a/polygon/test/strategyAm3crv.gaugemigration.ts +++ b/polygon/test/strategyAm3crv.gaugemigration.ts @@ -58,6 +58,13 @@ describe("StrategyAm3Crv Gauge Migration", function () { }); it("Migrate Gauge", async function () { + this.timeout(0) + await currentStrategy + .connect(governanceSigner) + .harvest( + "0x", + "0xec1d21dd0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000172370d5cd63279efa6d502dab29171933a610af00000000000000000000000000000000000000000000001f6cf635fae0b5b85700000000000000000000000000000000000000000000003d97f8b0e3862aa91600000000000000000000000000000000000000000000003e373e6f71756bbce6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000087374616b6564616f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002400000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000002235a16eecf679b51e6de3f847cec2312564ff070000000000000000000000001de7a822a3c3dc50ee63cc06babde277a876909e000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000172370d5cd63279efa6d502dab29171933a610af0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a063000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000007ac899160b8f8c378b1528ab822c0ef7dbf037e20000000000000000000000000823573779edcac7486af5ddbfb91358df47dc3200000000000000000000000000000000000000000000000000000000000022b900000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a063000000000000000000000000ce1529fe0058e6b6fd98d907025a49deb0e472bf0000000000000000000000003fcd5de6a9fc8a99995c406c77dda3ed7e406f81000000000000000000000000000000000000000000000000000000000000045700000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000004b00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a0630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cb42e90de1439cc81e52a8c5028bc4679242933b000000000000000000000000b612d8b6b64d94a21c39ffd90a14f92e555d9151000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000172370d5cd63279efa6d502dab29171933a610af0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a063" + ); await controller.connect(governanceSigner).withdrawAll(WANT); let availableBalance = await vault.available(); diff --git a/polygon/test/strategySbtc.migration.ts b/polygon/test/strategySbtc.migration.ts index 4b26a61..56b86f9 100644 --- a/polygon/test/strategySbtc.migration.ts +++ b/polygon/test/strategySbtc.migration.ts @@ -58,6 +58,14 @@ describe('StrategyBtcCurve', function () { initialBalance = await vault.balance(); + this.timeout(0) + // await oldStrategy + // .connect(governanceSigner) + // .harvest( + // "0x", + // "0xec1d21dd0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000172370d5cd63279efa6d502dab29171933a610af00000000000000000000000000000000000000000000001f6cf635fae0b5b85700000000000000000000000000000000000000000000003d97f8b0e3862aa91600000000000000000000000000000000000000000000003e373e6f71756bbce6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000087374616b6564616f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002400000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f61900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000002235a16eecf679b51e6de3f847cec2312564ff070000000000000000000000001de7a822a3c3dc50ee63cc06babde277a876909e000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000172370d5cd63279efa6d502dab29171933a610af0000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a063000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000007ac899160b8f8c378b1528ab822c0ef7dbf037e20000000000000000000000000823573779edcac7486af5ddbfb91358df47dc3200000000000000000000000000000000000000000000000000000000000022b900000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a063000000000000000000000000ce1529fe0058e6b6fd98d907025a49deb0e472bf0000000000000000000000003fcd5de6a9fc8a99995c406c77dda3ed7e406f81000000000000000000000000000000000000000000000000000000000000045700000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000004b00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a0630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000cb42e90de1439cc81e52a8c5028bc4679242933b000000000000000000000000b612d8b6b64d94a21c39ffd90a14f92e555d9151000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000172370d5cd63279efa6d502dab29171933a610af0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000008f3cf7ad23cd3cadbd9735aff958023239c6a063" + // ); + await ( await controller .connect(governanceSigner)