From 9bc41999aeaf59f556ca8dc7174838ea6c37c269 Mon Sep 17 00:00:00 2001 From: Cipio Date: Sat, 23 Apr 2022 11:14:58 -0500 Subject: [PATCH 01/13] temple/frax wip --- src/interfaces/templeRouter.sol | 19 +++ .../strategy-frax-temple-univ2.sol | 135 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/interfaces/templeRouter.sol create mode 100644 src/strategies/backscratcher/strategy-frax-temple-univ2.sol diff --git a/src/interfaces/templeRouter.sol b/src/interfaces/templeRouter.sol new file mode 100644 index 000000000..3f3ef6891 --- /dev/null +++ b/src/interfaces/templeRouter.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.12; + +interface ITempleRouter { + function swapExactTempleForFrax( + uint256 amountIn, + uint256 amountOutMin, + address to, + uint256 deadline + ) external returns (uint256); + + function swapExactFraxForTemple( + uint256 amountIn, + uint256 amountOutMin, + address to, + uint256 deadline + ) external returns (uint256 amountOut); +} diff --git a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol new file mode 100644 index 000000000..b05e3eb33 --- /dev/null +++ b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.12; +pragma experimental ABIEncoderV2; + +import "../strategy-base.sol"; +import "../../interfaces/backscratcher/IStrategyProxy.sol"; +import "../../interfaces/backscratcher/FraxGauge.sol"; +import "../../interfaces/templeRouter.sol"; + +contract StrategyFraxTempleUniV2 is StrategyBase { + address public strategyProxy; + + IERC20 public frax_temple_pool = IERC20(0x6021444f1706f15465bEe85463BCc7d7cC17Fc03); + address public frax_temple_gauge = 0x10460d02226d6ef7B2419aE150E6377BdbB7Ef16; + + address templeRouter = 0x8A5058100E60e8F7C42305eb505B12785bbA3BcA; + + address public constant FXS = 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0; + address public constant TEMPLE = 0x470EBf5f030Ed85Fc1ed4C2d36B9DD02e77CF1b7; + address public constant FRAX = 0x853d955aCEf822Db058eb8505911ED77F175b99e; + + address[] public rewardTokens = [FXS, TEMPLE]; + + constructor( + address _governance, + address _strategist, + address _controller, + address _timelock + ) public StrategyBase(address(frax_temple_pool), _governance, _strategist, _controller, _timelock) {} + + // **** Views **** + function setStrategyProxy(address _proxy) external { + require(msg.sender == governance || msg.sender == strategist, "!governance"); + strategyProxy = _proxy; + } + + function getName() external pure override returns (string memory) { + return "StrategyFraxTempleUniV2"; + } + + // **** State Mutations **** + + function harvest() public override onlyBenevolent { + IStrategyProxy(strategyProxy).harvest(frax_temple_gauge, rewardTokens); + + uint256 _fxs = IERC20(FXS).balanceOf(address(this)); + + IERC20(FXS).safeApprove(univ2Router2, 0); + IERC20(FXS).safeApprove(univ2Router2, _fxs); + + address[] memory _path = new address[](2); + _path[0] = FXS; + _path[1] = FRAX; + _swapUniswapWithPath(_path, _fxs); + + uint256 _frax = IERC20(FRAX).balanceOf(address(this)); + IERC20(FRAX).safeApprove(templeRouter, 0); + IERC20(FRAX).safeApprove(templeRouter, _frax); + + ITempleRouter(templeRouter).swapExactFraxForTemple(_frax, 0, address(this), block.timestamp + 300); + + uint256 _temple = IERC20(TEMPLE).balanceOf(address(this)); + uint256 _amount = _temple.div(2); + + IERC20(TEMPLE).safeApprove(templeRouter, 0); + IERC20(TEMPLE).safeApprove(templeRouter, _amount); + + ITempleRouter(templeRouter).swapExactTempleForFrax(_amount, 0, address(this), block.timestamp + 300); + + _distributePerformanceFeesAndDeposit(); + } + + function balanceOfPool() public view override returns (uint256) { + return IStrategyProxy(strategyProxy).balanceOf(frax_temple_gauge); + } + + function getHarvestable() public view returns (uint256) { + return IFraxGaugeBase(frax_temple_gauge).earned(IStrategyProxy(strategyProxy).proxy()); + } + + // **** Setters **** + + function deposit() public override { + uint256 _amount = frax_temple_pool.balanceOf(address(this)); + frax_temple_pool.safeTransferFrom(address(this), strategyProxy, _amount); + IStrategyProxy(strategyProxy).depositV2( + frax_temple_gauge, + address(frax_temple_pool), + IFraxGaugeBase(frax_temple_gauge).lock_time_min() + ); + } + + function _withdrawSome(uint256 _liquidity) internal override returns (uint256) { + LockedStake[] memory lockedStakes = IStrategyProxy(strategyProxy).lockedStakesOf(frax_temple_gauge); + uint256[2] memory _amounts; + + uint256 _sum; + uint256 _count; + + for (uint256 i = 0; i < lockedStakes.length; i++) { + if (lockedStakes[i].kek_id == 0 || lockedStakes[i].liquidity == 0) { + _count++; + continue; + } + _sum = _sum.add( + IStrategyProxy(strategyProxy).withdrawV2( + frax_temple_gauge, + address(frax_temple_pool), + lockedStakes[i].kek_id, + rewardTokens + ) + ); + _count++; + if (_sum >= _liquidity) break; + } + + require(_sum >= _liquidity, "insufficient liquidity"); + + LockedStake memory lastStake = lockedStakes[_count - 1]; + + if (_sum > _liquidity) { + uint128 _withdraw = uint128(uint256(lastStake.liquidity).sub(_sum.sub(_liquidity))); + require(_withdraw <= lastStake.liquidity, "math error"); + + frax_temple_pool.safeTransferFrom(address(this), strategyProxy, _withdraw); + IStrategyProxy(strategyProxy).depositV2( + frax_temple_gauge, + address(frax_temple_pool), + IFraxGaugeBase(frax_temple_gauge).lock_time_min() + ); + } + + return (_liquidity); + } +} From 968c242157cf35fc9bb54de3a4c09aaf6a349ccf Mon Sep 17 00:00:00 2001 From: Cipio Date: Sat, 23 Apr 2022 15:40:43 -0500 Subject: [PATCH 02/13] Test WIP --- .../strategy-frax-temple.test.js | 338 ++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 src/tests/strategies/backscratcher/strategy-frax-temple.test.js diff --git a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js new file mode 100644 index 000000000..147e9634a --- /dev/null +++ b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js @@ -0,0 +1,338 @@ +const { + toWei, + deployContract, + getContractAt, + increaseTime, + increaseBlock, + unlockAccount, +} = require("../../utils/testHelper"); +const {getWantFromWhale} = require("../../utils/setupHelper"); +const {BigNumber: BN} = require("ethers"); + +describe("StrategyFraxTemple", () => { + const FRAX_TEMPLE_POOL = "0x6021444f1706f15465bEe85463BCc7d7cC17Fc03"; + const FRAX_TEMPLE_SWAP = "0x8A5058100E60e8F7C42305eb505B12785bbA3BcA"; + const FRAX_TEMPLE_GAUGE = "0x10460d02226d6ef7B2419aE150E6377BdbB7Ef16"; + const FraxToken = "0x853d955acef822db058eb8505911ed77f175b99e"; + const TEMPLEToken = "0x470EBf5f030Ed85Fc1ed4C2d36B9DD02e77CF1b7"; + const FXSToken = "0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0"; + const SMARTCHECKER = "0x53c13BA8834a1567474b19822aAD85c6F90D9f9F"; + + let alice; + let frax, temple, fxs, fraxDeployer, escrow; + let strategy, pickleJar, controller, proxyAdmin, strategyProxy, locker, veFxsVault; + let smartChecker; + let governance, strategist, devfund, treasury, timelock; + let preTestSnapshotID; + + before("Setup Contracts", async () => { + [alice, bob, charles, devfund, treasury] = await hre.ethers.getSigners(); + governance = alice; + strategist = alice; + timelock = alice; + + proxyAdmin = await deployContract("ProxyAdmin"); + console.log("✅ ProxyAdmin is deployed at ", proxyAdmin.address); + + const controllerImp = await deployContract("ControllerV5"); + + const controllerProxy = await deployContract( + "AdminUpgradeabilityProxy", + controllerImp.address, + proxyAdmin.address, + [] + ); + + controller = await getContractAt("ControllerV5", controllerProxy.address); + + await controller.initialize( + governance.address, + strategist.address, + timelock.address, + devfund.address, + treasury.address + ); + console.log("✅ Controller is deployed at ", controller.address); + + const upgradedController = await deployContract("ControllerV7"); + console.log("✅ Controller V7 is deployed at ", upgradedController.address); + + await proxyAdmin.upgrade(controllerProxy.address, upgradedController.address); + + let newController = await getContractAt("ControllerV7", controllerProxy.address); + + locker = await deployContract("FXSLocker"); + console.log("✅ Locker is deployed at ", locker.address); + + escrow = await getContractAt("VoteEscrow", "0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0"); + + strategyProxy = await deployContract("StrategyProxy"); + console.log("✅ StrategyProxy is deployed at ", strategyProxy.address); + + await locker.setStrategy(strategyProxy.address); + + await strategyProxy.setLocker(locker.address); + + strategy = await deployContract( + "StrategyFraxTempleUniV2", + governance.address, + strategist.address, + newController.address, + timelock.address + ); + await strategy.connect(governance).setStrategyProxy(strategyProxy.address); + await strategyProxy.approveStrategy(FRAX_TEMPLE_GAUGE, strategy.address); + + pickleJar = await deployContract( + "PickleJar", + FRAX_TEMPLE_POOL, + governance.address, + timelock.address, + newController.address + ); + console.log("✅ PickleJar is deployed at ", pickleJar.address); + + await newController.connect(governance).setJar(FRAX_TEMPLE_POOL, pickleJar.address); + await newController.connect(governance).approveStrategy(FRAX_TEMPLE_POOL, strategy.address); + await newController.connect(governance).setStrategy(FRAX_TEMPLE_POOL, strategy.address); + + veFxsVault = await deployContract("veFXSVault"); + console.log("✅ veFxsVault is deployed at ", veFxsVault.address); + + await veFxsVault.setProxy(strategyProxy.address); + await veFxsVault.setFeeDistribution(strategyProxy.address); + await veFxsVault.setLocker(locker.address); + + await strategyProxy.setFXSVault(veFxsVault.address); + + frax = await getContractAt("ERC20", FraxToken); + temple = await getContractAt("ERC20", TEMPLEToken); + fxs = await getContractAt("ERC20", FXSToken); + pool = await getContractAt("ERC20", FXSToken); + templeRouter = await getContractAt(poolABI, FRAX_TEMPLE_SWAP); + + await getWantFromWhale(FraxToken, toWei(10000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + + await getWantFromWhale(TEMPLEToken, toWei(10000), alice, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); + + await getWantFromWhale(FraxToken, toWei(10000), bob, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + + await getWantFromWhale(TEMPLEToken, toWei(10000), bob, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); + + await getWantFromWhale(FraxToken, toWei(10000), charles, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + + await getWantFromWhale(TEMPLEToken, toWei(10000), charles, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); + + await getWantFromWhale(FXSToken, toWei(10000), alice, "0xF977814e90dA44bFA03b6295A0616a897441aceC"); + + + // transfer FXS to distributor + await fxs.connect(alice).transfer("0x278dc748eda1d8efef1adfb518542612b49fcd34", toWei(5000)); + // transfer FXS to gauge + await fxs.connect(alice).transfer("0xF22471AC2156B489CC4a59092c56713F813ff53e", toWei(5000)); + + }); + + it("should harvest correctly", async () => { + let depositAmount = toWei(200); + + let aliceShare, bobShare, charlesShare; + + console.log("=============== Alice deposit =============="); + await deposit(alice, depositAmount); + await pickleJar.earn(); + await harvest(); + + console.log("=============== Bob deposit =============="); + depositAmount = toWei(400); + + await deposit(bob, depositAmount); + await pickleJar.earn(); + await harvest(); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + aliceShare = await pickleJar.balanceOf(alice.address); + console.log("Alice share amount => ", aliceShare.toString()); + + console.log("===============Alice partial withdraw=============="); + console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + await pickleJar.connect(alice).withdraw(aliceShare.div(BN.from(2))); + + console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + console.log("=============== Charles deposit =============="); + + depositAmount = toWei(700); + + await deposit(charles, depositAmount); + + console.log("===============Bob withdraw=============="); + console.log("Bob temple balance before withdrawal => ", (await temple.balanceOf(bob.address)).toString()); + console.log("Bob frax balance before withdrawal => ", (await frax.balanceOf(bob.address)).toString()); + await pickleJar.connect(bob).withdrawAll(); + + console.log("Bob temple balance after withdrawal => ", (await temple.balanceOf(bob.address)).toString()); + console.log("Bob frax balance after withdrawal => ", (await frax.balanceOf(bob.address)).toString()); + + await harvest(); + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + await pickleJar.earn(); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + console.log("=============== Controller withdraw ==============="); + console.log("PickleJar temple balance before withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + await controller.withdrawAll(FRAX_TEMPLE_POOL); + + console.log("PickleJar temple balance after withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + console.log("===============Alice Full withdraw=============="); + + console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + await pickleJar.connect(alice).withdrawAll(); + + console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + // await harvest(); + // await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + console.log("=============== charles withdraw =============="); + console.log("Charles temple balance before withdrawal => ", (await temple.balanceOf(charles.address)).toString()); + console.log("Charles frax balance before withdrawal => ", (await frax.balanceOf(charles.address)).toString()); + await pickleJar.connect(charles).withdrawAll(); + + console.log("Charles temple balance after withdrawal => ", (await temple.balanceOf(charles.address)).toString()); + console.log("Charles frax balance after withdrawal => ", (await frax.balanceOf(charles.address)).toString()); + + // console.log("=============== Alice redeposit =============="); + // depositA = toWei(50000); + // depositB = await getAmountB(depositA); + + // await deposit(alice, depositA, depositB); + // await pickleJar.earn(); + + // await harvest(); + // await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + // console.log("===============Alice final withdraw=============="); + + // console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + // console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + // await pickleJar.connect(alice).withdrawAll(); + + // console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + // console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + console.log("------------------ Finished -----------------------"); + + console.log("Treasury temple balance => ", (await temple.balanceOf(treasury.address)).toString()); + console.log("Treasury frax balance => ", (await frax.balanceOf(treasury.address)).toString()); + + console.log("Strategy temple balance => ", (await temple.balanceOf(strategy.address)).toString()); + console.log("Strategy frax balance => ", (await frax.balanceOf(strategy.address)).toString()); + console.log("Strategy fxs balance => ", (await fxs.balanceOf(strategy.address)).toString()); + + console.log("PickleJar temple balance => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance => ", (await frax.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar fxs balance => ", (await fxs.balanceOf(pickleJar.address)).toString()); + + console.log("Locker temple balance => ", (await temple.balanceOf(locker.address)).toString()); + console.log("Locker frax balance => ", (await frax.balanceOf(locker.address)).toString()); + console.log("Locker fxs balance => ", (await fxs.balanceOf(locker.address)).toString()); + + console.log("StrategyProxy temple balance => ", (await temple.balanceOf(strategyProxy.address)).toString()); + console.log("StrategyProxy frax balance => ", (await frax.balanceOf(strategyProxy.address)).toString()); + console.log("StrategyProxy fxs balance => ", (await fxs.balanceOf(strategyProxy.address)).toString()); + }); + /* + it("should withdraw correctly", async () => { + let depositA = toWei(50000); + let depositB = await getAmountB(depositA); + + console.log("=============== Alice deposit =============="); + await deposit(alice, depositA, depositB); + await pickleJar.earn(); + await harvest(); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + console.log("PickleJar temple balance before withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + await controller.withdrawAll(FRAX_TEMPLE_POOL); + + console.log("PickleJar temple balance after withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + await pickleJar.connect(alice).withdrawAll(); + + console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + }); +*/ + const deposit = async (user, depositAmount) => { + console.log("Starting Deposit"); + await depositing(user, depositAmount); + await pool.connect(user).approve(pickleJar.address, depositAmount); + console.log("depositAmount => ", depositAmount.toString()); + + await pickleJar.connect(user).deposit(depositAmount); + }; + + const harvest = async () => { + console.log("============ Harvest Started =============="); + + console.log("Ratio before harvest => ", (await pickleJar.getRatio()).toString()); + await increaseTime(60 * 60 * 24 * 14); //travel 30 days + await increaseBlock(1000); + console.log("Amount Harvestable => ", (await strategy.getHarvestable()).toString()); + await strategy.harvest(); + console.log("Amount Harvestable after => ", (await strategy.getHarvestable()).toString()); + console.log("Ratio after harvest => ", (await pickleJar.getRatio()).toString()); + console.log("============ Harvest Ended =============="); + }; + + const depositing = async (user, amount) => { + // getting timestamp + const blockNumBefore = await ethers.provider.getBlockNumber(); + const blockBefore = await ethers.provider.getBlock(blockNumBefore); + const timestampBefore = blockBefore.timestamp; + console.log("amount: ", amount.toString()); + console.log("Starting depositing"); + await temple.connect(user).approve(FRAX_TEMPLE_SWAP, amount); + console.log("Approved temple"); + await frax.connect(user).approve(FRAX_TEMPLE_SWAP, amount); + console.log("Approved Frax"); + await templeRouter.connect(user).addLiquidity( + amount, + amount, + 0, + 0, + user.address, + timestampBefore + 60 + ); + console.log("Finished Liquidity Add"); + }; + + // beforeEach(async () => { + // preTestSnapshotID = await hre.network.provider.send("evm_snapshot"); + // }); + + // afterEach(async () => { + // await hre.network.provider.send("evm_revert", [preTestSnapshotID]); + // }); + const poolABI = [{"inputs":[{"internalType":"contract IUniswapV2Pair","name":"_pair","type":"address"},{"internalType":"contract TempleERC20Token","name":"_templeToken","type":"address"},{"internalType":"contract IERC20","name":"_fraxToken","type":"address"},{"internalType":"contract ITempleTreasury","name":"_templeTreasury","type":"address"},{"internalType":"address","name":"_protocolMintEarningsAccount","type":"address"},{"components":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"internalType":"struct TempleFraxAMMRouter.Price","name":"_dynamicThresholdPrice","type":"tuple"},{"internalType":"uint256","name":"_dynamicThresholdDecayPerBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"internalType":"struct TempleFraxAMMRouter.Price","name":"_interpolateFromPrice","type":"tuple"},{"components":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"internalType":"struct TempleFraxAMMRouter.Price","name":"_interpolateToPrice","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currDynamicThresholdTemple","type":"uint256"}],"name":"DynamicThresholdChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"PriceCrossedBelowDynamicThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CAN_ADD_ALLOWED_USER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DYNAMIC_THRESHOLD_INCREASE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"addAllowedUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdDecayPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdIncreasePct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdPrice","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdPriceWithDecay","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interpolateFromPrice","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interpolateToPrice","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"temple","type":"uint256"},{"internalType":"uint256","name":"frax","type":"uint256"}],"name":"mintRatioAt","outputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openAccessEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceCrossedBelowDynamicThresholdBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"removeAllowedUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dynamicThresholdDecayPerBlock","type":"uint256"}],"name":"setDynamicThresholdDecayPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dynamicThresholdIncreasePct","type":"uint256"}],"name":"setDynamicThresholdIncreasePct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"name":"setInterpolateFromPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"name":"setInterpolateToPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolMintEarningsAccount","type":"address"}],"name":"setProtocolMintEarningsAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactFraxForTemple","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"swapExactFraxForTempleQuote","outputs":[{"internalType":"uint256","name":"amountInAMM","type":"uint256"},{"internalType":"uint256","name":"amountInProtocol","type":"uint256"},{"internalType":"uint256","name":"amountOutAMM","type":"uint256"},{"internalType":"uint256","name":"amountOutProtocol","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTempleForFrax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"swapExactTempleForFraxQuote","outputs":[{"internalType":"bool","name":"priceBelowIV","type":"bool"},{"internalType":"bool","name":"willCrossDynamicThreshold","type":"bool"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"templeToken","outputs":[{"internalType":"contract TempleERC20Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"templeTreasury","outputs":[{"internalType":"contract ITempleTreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleOpenAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]; +}); From 91596cdb610f0e2895af8a7d71c6896c1b2f15d0 Mon Sep 17 00:00:00 2001 From: Cipio Date: Mon, 25 Apr 2022 00:16:38 -0500 Subject: [PATCH 03/13] Fixes and tweaks --- src/backscratcher/StrategyProxy.sol | 15 +- src/interfaces/backscratcher/FraxGauge.sol | 6 +- src/interfaces/templeRouter.sol | 15 + .../backscratcher/strategy-frax-dai-univ3.sol | 2 +- .../strategy-frax-temple-univ2.sol | 21 +- .../strategy-frax-usdc-univ3.sol | 2 +- .../strategy-frax-temple.test.js | 527 +++++++++++++++++- 7 files changed, 546 insertions(+), 42 deletions(-) diff --git a/src/backscratcher/StrategyProxy.sol b/src/backscratcher/StrategyProxy.sol index 0e5eeb15b..bbb737736 100644 --- a/src/backscratcher/StrategyProxy.sol +++ b/src/backscratcher/StrategyProxy.sol @@ -53,6 +53,7 @@ contract StrategyProxy { // gauge => strategies mapping(address => address) public strategies; mapping(address => bool) public voters; + mapping(address => bytes) private claimRewardsString; address public governance; // TODO How much FXS tokens to give to backscratcher? @@ -93,14 +94,20 @@ contract StrategyProxy { feeDistribution = _feeDistribution; } - function approveStrategy(address _gauge, address _strategy) external { + function approveStrategy( + address _gauge, + address _strategy, + bytes calldata claimString + ) external { require(msg.sender == governance, "!governance"); strategies[_gauge] = _strategy; + claimRewardsString[_gauge] = claimString; } function revokeStrategy(address _gauge) external { require(msg.sender == governance, "!governance"); strategies[_gauge] = address(0); + claimRewardsString[_gauge] = ""; } function approveVoter(address _voter) external { @@ -283,13 +290,14 @@ contract StrategyProxy { function harvest(address _gauge, address[] calldata _tokens) external { require(strategies[_gauge] == msg.sender, "!strategy"); + uint256[] memory _balances = new uint256[](_tokens.length); for (uint256 i = 0; i < _tokens.length; i++) { _balances[i] = IERC20(_tokens[i]).balanceOf(address(proxy)); } - proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("getReward()")); + proxy.safeExecute(_gauge, 0, claimRewardsString[_gauge]); for (uint256 i = 0; i < _tokens.length; i++) { _balances[i] = (IERC20(_tokens[i]).balanceOf(address(proxy))).sub(_balances[i]); @@ -298,6 +306,7 @@ contract StrategyProxy { if (_tokens[i] == fxs) { uint256 _amountKeep = _balances[i].mul(keepFXS).div(keepFXSMax); _swapAmount = _balances[i].sub(_amountKeep); + proxy.safeExecute( _tokens[i], 0, @@ -328,7 +337,7 @@ contract StrategyProxy { function claimRewards(address _gauge, address _token) external { require(strategies[_gauge] == msg.sender, "!strategy"); - proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("getReward()")); + proxy.safeExecute(_gauge, 0, claimRewardsString[_gauge]); proxy.safeExecute( _token, diff --git a/src/interfaces/backscratcher/FraxGauge.sol b/src/interfaces/backscratcher/FraxGauge.sol index 071c38166..d8861c3f8 100644 --- a/src/interfaces/backscratcher/FraxGauge.sol +++ b/src/interfaces/backscratcher/FraxGauge.sol @@ -25,14 +25,14 @@ interface IFraxGaugeBase { function getReward() external returns (uint256); - function earned(address) external view returns (uint256); - function lock_time_min() external returns (uint256); function combinedWeightOf(address account) external view returns (uint256); } interface IFraxGaugeUniV3 is IFraxGaugeBase { + function earned(address) external view returns (uint256); + function stakeLocked(uint256 token_id, uint256 secs) external; function withdrawLocked(uint256 token_id) external; @@ -41,6 +41,8 @@ interface IFraxGaugeUniV3 is IFraxGaugeBase { } interface IFraxGaugeUniV2 { + function earned(address account) external view returns (uint256[] memory new_earned); + function stakeLocked(uint256 liquidity, uint256 secs) external; function lockedStakesOf(address) external view returns (LockedStake[] memory); diff --git a/src/interfaces/templeRouter.sol b/src/interfaces/templeRouter.sol index 3f3ef6891..4113ef56f 100644 --- a/src/interfaces/templeRouter.sol +++ b/src/interfaces/templeRouter.sol @@ -16,4 +16,19 @@ interface ITempleRouter { address to, uint256 deadline ) external returns (uint256 amountOut); + + function addLiquidity( + uint256 amountADesired, + uint256 amountBDesired, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) + external + returns ( + uint256 amountA, + uint256 amountB, + uint256 liquidity + ); } diff --git a/src/strategies/backscratcher/strategy-frax-dai-univ3.sol b/src/strategies/backscratcher/strategy-frax-dai-univ3.sol index ba664012d..5963561d1 100644 --- a/src/strategies/backscratcher/strategy-frax-dai-univ3.sol +++ b/src/strategies/backscratcher/strategy-frax-dai-univ3.sol @@ -101,7 +101,7 @@ contract StrategyFraxDaiUniV3 is StrategyFraxUniV3Base { } function getHarvestable() public view returns (uint256) { - return IFraxGaugeBase(frax_dai_gauge).earned(IStrategyProxy(strategyProxy).proxy()); + return IFraxGaugeUniV3(frax_dai_gauge).earned(IStrategyProxy(strategyProxy).proxy()); } // **** Setters **** diff --git a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol index b05e3eb33..4de4d66e8 100644 --- a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol +++ b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol @@ -44,7 +44,6 @@ contract StrategyFraxTempleUniV2 is StrategyBase { IStrategyProxy(strategyProxy).harvest(frax_temple_gauge, rewardTokens); uint256 _fxs = IERC20(FXS).balanceOf(address(this)); - IERC20(FXS).safeApprove(univ2Router2, 0); IERC20(FXS).safeApprove(univ2Router2, _fxs); @@ -54,6 +53,7 @@ contract StrategyFraxTempleUniV2 is StrategyBase { _swapUniswapWithPath(_path, _fxs); uint256 _frax = IERC20(FRAX).balanceOf(address(this)); + IERC20(FRAX).safeApprove(templeRouter, 0); IERC20(FRAX).safeApprove(templeRouter, _frax); @@ -67,6 +67,17 @@ contract StrategyFraxTempleUniV2 is StrategyBase { ITempleRouter(templeRouter).swapExactTempleForFrax(_amount, 0, address(this), block.timestamp + 300); + uint256 _templeAmt = IERC20(TEMPLE).balanceOf(address(this)); + uint256 _fraxAmt = IERC20(FRAX).balanceOf(address(this)); + + IERC20(TEMPLE).safeApprove(templeRouter, 0); + IERC20(TEMPLE).safeApprove(templeRouter, _templeAmt); + + IERC20(FRAX).safeApprove(templeRouter, 0); + IERC20(FRAX).safeApprove(templeRouter, _fraxAmt); + + ITempleRouter(templeRouter).addLiquidity(_templeAmt, _fraxAmt, 0, 0, address(this), now + 60); + _distributePerformanceFeesAndDeposit(); } @@ -74,15 +85,15 @@ contract StrategyFraxTempleUniV2 is StrategyBase { return IStrategyProxy(strategyProxy).balanceOf(frax_temple_gauge); } - function getHarvestable() public view returns (uint256) { - return IFraxGaugeBase(frax_temple_gauge).earned(IStrategyProxy(strategyProxy).proxy()); + function getHarvestable() public view returns (uint256[] memory) { + return IFraxGaugeUniV2(frax_temple_gauge).earned(IStrategyProxy(strategyProxy).proxy()); } // **** Setters **** function deposit() public override { uint256 _amount = frax_temple_pool.balanceOf(address(this)); - frax_temple_pool.safeTransferFrom(address(this), strategyProxy, _amount); + frax_temple_pool.safeTransfer(strategyProxy, _amount); IStrategyProxy(strategyProxy).depositV2( frax_temple_gauge, address(frax_temple_pool), @@ -122,7 +133,7 @@ contract StrategyFraxTempleUniV2 is StrategyBase { uint128 _withdraw = uint128(uint256(lastStake.liquidity).sub(_sum.sub(_liquidity))); require(_withdraw <= lastStake.liquidity, "math error"); - frax_temple_pool.safeTransferFrom(address(this), strategyProxy, _withdraw); + frax_temple_pool.safeTransfer(strategyProxy, _withdraw); IStrategyProxy(strategyProxy).depositV2( frax_temple_gauge, address(frax_temple_pool), diff --git a/src/strategies/backscratcher/strategy-frax-usdc-univ3.sol b/src/strategies/backscratcher/strategy-frax-usdc-univ3.sol index fe130d163..da83ca3ba 100644 --- a/src/strategies/backscratcher/strategy-frax-usdc-univ3.sol +++ b/src/strategies/backscratcher/strategy-frax-usdc-univ3.sol @@ -118,7 +118,7 @@ contract StrategyFraxUsdcUniV3 is StrategyFraxUniV3Base { function getHarvestable() public view returns (uint256) { return - IFraxGaugeBase(frax_usdc_gauge).earned( + IFraxGaugeUniV3(frax_usdc_gauge).earned( IStrategyProxy(strategyProxy).proxy() ); } diff --git a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js index 147e9634a..8c2d1bf72 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js @@ -31,6 +31,8 @@ describe("StrategyFraxTemple", () => { strategist = alice; timelock = alice; + let lockerGovernance = await unlockAccount("0xaCfE4511CE883C14c4eA40563F176C3C09b4c47C"); + proxyAdmin = await deployContract("ProxyAdmin"); console.log("✅ ProxyAdmin is deployed at ", proxyAdmin.address); @@ -61,7 +63,7 @@ describe("StrategyFraxTemple", () => { let newController = await getContractAt("ControllerV7", controllerProxy.address); - locker = await deployContract("FXSLocker"); + locker = await getContractAt("FXSLocker", "0xd639C2eA4eEFfAD39b599410d00252E6c80008DF"); console.log("✅ Locker is deployed at ", locker.address); escrow = await getContractAt("VoteEscrow", "0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0"); @@ -69,7 +71,7 @@ describe("StrategyFraxTemple", () => { strategyProxy = await deployContract("StrategyProxy"); console.log("✅ StrategyProxy is deployed at ", strategyProxy.address); - await locker.setStrategy(strategyProxy.address); + await locker.connect(lockerGovernance).setStrategy(strategyProxy.address); await strategyProxy.setLocker(locker.address); @@ -81,7 +83,11 @@ describe("StrategyFraxTemple", () => { timelock.address ); await strategy.connect(governance).setStrategyProxy(strategyProxy.address); - await strategyProxy.approveStrategy(FRAX_TEMPLE_GAUGE, strategy.address); + await strategyProxy.approveStrategy( + FRAX_TEMPLE_GAUGE, + strategy.address, + "0xc00007b0000000000000000000000000d639c2ea4eeffad39b599410d00252e6c80008df" + ); pickleJar = await deployContract( "PickleJar", @@ -108,7 +114,7 @@ describe("StrategyFraxTemple", () => { frax = await getContractAt("ERC20", FraxToken); temple = await getContractAt("ERC20", TEMPLEToken); fxs = await getContractAt("ERC20", FXSToken); - pool = await getContractAt("ERC20", FXSToken); + pool = await getContractAt("ERC20", FRAX_TEMPLE_POOL); templeRouter = await getContractAt(poolABI, FRAX_TEMPLE_SWAP); await getWantFromWhale(FraxToken, toWei(10000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); @@ -123,14 +129,12 @@ describe("StrategyFraxTemple", () => { await getWantFromWhale(TEMPLEToken, toWei(10000), charles, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); - await getWantFromWhale(FXSToken, toWei(10000), alice, "0xF977814e90dA44bFA03b6295A0616a897441aceC"); - + await getWantFromWhale(FXSToken, toWei(1000000), alice, "0xF977814e90dA44bFA03b6295A0616a897441aceC"); // transfer FXS to distributor await fxs.connect(alice).transfer("0x278dc748eda1d8efef1adfb518542612b49fcd34", toWei(5000)); // transfer FXS to gauge - await fxs.connect(alice).transfer("0xF22471AC2156B489CC4a59092c56713F813ff53e", toWei(5000)); - + await fxs.connect(alice).transfer(FRAX_TEMPLE_GAUGE, toWei(700000)); }); it("should harvest correctly", async () => { @@ -140,7 +144,10 @@ describe("StrategyFraxTemple", () => { console.log("=============== Alice deposit =============="); await deposit(alice, depositAmount); + const _amt = await pool.balanceOf(pickleJar.address); + console.log("Calling Earn:", _amt.toString()); await pickleJar.earn(); + console.log("Calling Harvest:"); await harvest(); console.log("=============== Bob deposit =============="); @@ -187,12 +194,18 @@ describe("StrategyFraxTemple", () => { await increaseTime(60 * 60 * 24 * 1); //travel 14 days console.log("=============== Controller withdraw ==============="); - console.log("PickleJar temple balance before withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log( + "PickleJar temple balance before withdrawal => ", + (await temple.balanceOf(pickleJar.address)).toString() + ); console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); await controller.withdrawAll(FRAX_TEMPLE_POOL); - console.log("PickleJar temple balance after withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log( + "PickleJar temple balance after withdrawal => ", + (await temple.balanceOf(pickleJar.address)).toString() + ); console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); console.log("===============Alice Full withdraw=============="); @@ -284,22 +297,21 @@ describe("StrategyFraxTemple", () => { }); */ const deposit = async (user, depositAmount) => { - console.log("Starting Deposit"); await depositing(user, depositAmount); - await pool.connect(user).approve(pickleJar.address, depositAmount); - console.log("depositAmount => ", depositAmount.toString()); + const _amt = await pool.balanceOf(user.address); + await pool.connect(user).approve(pickleJar.address, _amt); - await pickleJar.connect(user).deposit(depositAmount); + await pickleJar.connect(user).deposit(_amt); }; const harvest = async () => { console.log("============ Harvest Started =============="); - + console.log("Harvest"); console.log("Ratio before harvest => ", (await pickleJar.getRatio()).toString()); await increaseTime(60 * 60 * 24 * 14); //travel 30 days await increaseBlock(1000); console.log("Amount Harvestable => ", (await strategy.getHarvestable()).toString()); - await strategy.harvest(); + await strategy.harvest({gasLimit: 10000000}); console.log("Amount Harvestable after => ", (await strategy.getHarvestable()).toString()); console.log("Ratio after harvest => ", (await pickleJar.getRatio()).toString()); console.log("============ Harvest Ended =============="); @@ -310,21 +322,9 @@ describe("StrategyFraxTemple", () => { const blockNumBefore = await ethers.provider.getBlockNumber(); const blockBefore = await ethers.provider.getBlock(blockNumBefore); const timestampBefore = blockBefore.timestamp; - console.log("amount: ", amount.toString()); - console.log("Starting depositing"); await temple.connect(user).approve(FRAX_TEMPLE_SWAP, amount); - console.log("Approved temple"); await frax.connect(user).approve(FRAX_TEMPLE_SWAP, amount); - console.log("Approved Frax"); - await templeRouter.connect(user).addLiquidity( - amount, - amount, - 0, - 0, - user.address, - timestampBefore + 60 - ); - console.log("Finished Liquidity Add"); + await templeRouter.connect(user).addLiquidity(amount, amount, 0, 0, user.address, timestampBefore + 60); }; // beforeEach(async () => { @@ -334,5 +334,472 @@ describe("StrategyFraxTemple", () => { // afterEach(async () => { // await hre.network.provider.send("evm_revert", [preTestSnapshotID]); // }); - const poolABI = [{"inputs":[{"internalType":"contract IUniswapV2Pair","name":"_pair","type":"address"},{"internalType":"contract TempleERC20Token","name":"_templeToken","type":"address"},{"internalType":"contract IERC20","name":"_fraxToken","type":"address"},{"internalType":"contract ITempleTreasury","name":"_templeTreasury","type":"address"},{"internalType":"address","name":"_protocolMintEarningsAccount","type":"address"},{"components":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"internalType":"struct TempleFraxAMMRouter.Price","name":"_dynamicThresholdPrice","type":"tuple"},{"internalType":"uint256","name":"_dynamicThresholdDecayPerBlock","type":"uint256"},{"components":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"internalType":"struct TempleFraxAMMRouter.Price","name":"_interpolateFromPrice","type":"tuple"},{"components":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"internalType":"struct TempleFraxAMMRouter.Price","name":"_interpolateToPrice","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currDynamicThresholdTemple","type":"uint256"}],"name":"DynamicThresholdChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"PriceCrossedBelowDynamicThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CAN_ADD_ALLOWED_USER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DYNAMIC_THRESHOLD_INCREASE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"addAllowedUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdDecayPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdIncreasePct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdPrice","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dynamicThresholdPriceWithDecay","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interpolateFromPrice","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interpolateToPrice","outputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"temple","type":"uint256"},{"internalType":"uint256","name":"frax","type":"uint256"}],"name":"mintRatioAt","outputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openAccessEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceCrossedBelowDynamicThresholdBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"removeAllowedUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dynamicThresholdDecayPerBlock","type":"uint256"}],"name":"setDynamicThresholdDecayPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dynamicThresholdIncreasePct","type":"uint256"}],"name":"setDynamicThresholdIncreasePct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"name":"setInterpolateFromPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax","type":"uint256"},{"internalType":"uint256","name":"temple","type":"uint256"}],"name":"setInterpolateToPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolMintEarningsAccount","type":"address"}],"name":"setProtocolMintEarningsAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactFraxForTemple","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"swapExactFraxForTempleQuote","outputs":[{"internalType":"uint256","name":"amountInAMM","type":"uint256"},{"internalType":"uint256","name":"amountInProtocol","type":"uint256"},{"internalType":"uint256","name":"amountOutAMM","type":"uint256"},{"internalType":"uint256","name":"amountOutProtocol","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTempleForFrax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"swapExactTempleForFraxQuote","outputs":[{"internalType":"bool","name":"priceBelowIV","type":"bool"},{"internalType":"bool","name":"willCrossDynamicThreshold","type":"bool"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"templeToken","outputs":[{"internalType":"contract TempleERC20Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"templeTreasury","outputs":[{"internalType":"contract ITempleTreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleOpenAccess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]; + const poolABI = [ + { + inputs: [ + {internalType: "contract IUniswapV2Pair", name: "_pair", type: "address"}, + {internalType: "contract TempleERC20Token", name: "_templeToken", type: "address"}, + {internalType: "contract IERC20", name: "_fraxToken", type: "address"}, + {internalType: "contract ITempleTreasury", name: "_templeTreasury", type: "address"}, + {internalType: "address", name: "_protocolMintEarningsAccount", type: "address"}, + { + components: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + internalType: "struct TempleFraxAMMRouter.Price", + name: "_dynamicThresholdPrice", + type: "tuple", + }, + {internalType: "uint256", name: "_dynamicThresholdDecayPerBlock", type: "uint256"}, + { + components: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + internalType: "struct TempleFraxAMMRouter.Price", + name: "_interpolateFromPrice", + type: "tuple", + }, + { + components: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + internalType: "struct TempleFraxAMMRouter.Price", + name: "_interpolateToPrice", + type: "tuple", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [{indexed: false, internalType: "uint256", name: "currDynamicThresholdTemple", type: "uint256"}], + name: "DynamicThresholdChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "address", name: "previousOwner", type: "address"}, + {indexed: true, internalType: "address", name: "newOwner", type: "address"}, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [{indexed: false, internalType: "uint256", name: "blockNumber", type: "uint256"}], + name: "PriceCrossedBelowDynamicThreshold", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "bytes32", name: "role", type: "bytes32"}, + {indexed: true, internalType: "bytes32", name: "previousAdminRole", type: "bytes32"}, + {indexed: true, internalType: "bytes32", name: "newAdminRole", type: "bytes32"}, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "bytes32", name: "role", type: "bytes32"}, + {indexed: true, internalType: "address", name: "account", type: "address"}, + {indexed: true, internalType: "address", name: "sender", type: "address"}, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "bytes32", name: "role", type: "bytes32"}, + {indexed: true, internalType: "address", name: "account", type: "address"}, + {indexed: true, internalType: "address", name: "sender", type: "address"}, + ], + name: "RoleRevoked", + type: "event", + }, + { + inputs: [], + name: "CAN_ADD_ALLOWED_USER", + outputs: [{internalType: "bytes32", name: "", type: "bytes32"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [{internalType: "bytes32", name: "", type: "bytes32"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DYNAMIC_THRESHOLD_INCREASE_DENOMINATOR", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [{internalType: "address", name: "userAddress", type: "address"}], + name: "addAllowedUser", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountADesired", type: "uint256"}, + {internalType: "uint256", name: "amountBDesired", type: "uint256"}, + {internalType: "uint256", name: "amountAMin", type: "uint256"}, + {internalType: "uint256", name: "amountBMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "addLiquidity", + outputs: [ + {internalType: "uint256", name: "amountA", type: "uint256"}, + {internalType: "uint256", name: "amountB", type: "uint256"}, + {internalType: "uint256", name: "liquidity", type: "uint256"}, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "address", name: "", type: "address"}], + name: "allowed", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdDecayPerBlock", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdIncreasePct", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdPrice", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdPriceWithDecay", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "fraxToken", + outputs: [{internalType: "contract IERC20", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountIn", type: "uint256"}, + {internalType: "uint256", name: "reserveIn", type: "uint256"}, + {internalType: "uint256", name: "reserveOut", type: "uint256"}, + ], + name: "getAmountOut", + outputs: [{internalType: "uint256", name: "amountOut", type: "uint256"}], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{internalType: "bytes32", name: "role", type: "bytes32"}], + name: "getRoleAdmin", + outputs: [{internalType: "bytes32", name: "", type: "bytes32"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "hasRole", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "interpolateFromPrice", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "interpolateToPrice", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "temple", type: "uint256"}, + {internalType: "uint256", name: "frax", type: "uint256"}, + ], + name: "mintRatioAt", + outputs: [ + {internalType: "uint256", name: "numerator", type: "uint256"}, + {internalType: "uint256", name: "denominator", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "openAccessEnabled", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{internalType: "address", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pair", + outputs: [{internalType: "contract IUniswapV2Pair", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "priceCrossedBelowDynamicThresholdBlock", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountA", type: "uint256"}, + {internalType: "uint256", name: "reserveA", type: "uint256"}, + {internalType: "uint256", name: "reserveB", type: "uint256"}, + ], + name: "quote", + outputs: [{internalType: "uint256", name: "amountB", type: "uint256"}], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{internalType: "address", name: "userAddress", type: "address"}], + name: "removeAllowedUser", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "liquidity", type: "uint256"}, + {internalType: "uint256", name: "amountAMin", type: "uint256"}, + {internalType: "uint256", name: "amountBMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "removeLiquidity", + outputs: [ + {internalType: "uint256", name: "amountA", type: "uint256"}, + {internalType: "uint256", name: "amountB", type: "uint256"}, + ], + stateMutability: "nonpayable", + type: "function", + }, + {inputs: [], name: "renounceOwnership", outputs: [], stateMutability: "nonpayable", type: "function"}, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "_dynamicThresholdDecayPerBlock", type: "uint256"}], + name: "setDynamicThresholdDecayPerBlock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "_dynamicThresholdIncreasePct", type: "uint256"}], + name: "setDynamicThresholdIncreasePct", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + name: "setInterpolateFromPrice", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + name: "setInterpolateToPrice", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "address", name: "_protocolMintEarningsAccount", type: "address"}], + name: "setProtocolMintEarningsAccount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "bytes4", name: "interfaceId", type: "bytes4"}], + name: "supportsInterface", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountIn", type: "uint256"}, + {internalType: "uint256", name: "amountOutMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "swapExactFraxForTemple", + outputs: [{internalType: "uint256", name: "amountOut", type: "uint256"}], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "amountIn", type: "uint256"}], + name: "swapExactFraxForTempleQuote", + outputs: [ + {internalType: "uint256", name: "amountInAMM", type: "uint256"}, + {internalType: "uint256", name: "amountInProtocol", type: "uint256"}, + {internalType: "uint256", name: "amountOutAMM", type: "uint256"}, + {internalType: "uint256", name: "amountOutProtocol", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountIn", type: "uint256"}, + {internalType: "uint256", name: "amountOutMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "swapExactTempleForFrax", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "amountIn", type: "uint256"}], + name: "swapExactTempleForFraxQuote", + outputs: [ + {internalType: "bool", name: "priceBelowIV", type: "bool"}, + {internalType: "bool", name: "willCrossDynamicThreshold", type: "bool"}, + {internalType: "uint256", name: "amountOut", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "templeToken", + outputs: [{internalType: "contract TempleERC20Token", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "templeTreasury", + outputs: [{internalType: "contract ITempleTreasury", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + {inputs: [], name: "toggleOpenAccess", outputs: [], stateMutability: "nonpayable", type: "function"}, + { + inputs: [{internalType: "address", name: "newOwner", type: "address"}], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "address", name: "token", type: "address"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "amount", type: "uint256"}, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + ]; }); From f12ed0936bccdb1d9c1e4bc18b534e4c2a526546 Mon Sep 17 00:00:00 2001 From: Cipio Date: Mon, 25 Apr 2022 00:31:39 -0500 Subject: [PATCH 04/13] clean --- src/strategies/backscratcher/strategy-frax-temple-univ2.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol index 4de4d66e8..ed6442056 100644 --- a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol +++ b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol @@ -13,7 +13,7 @@ contract StrategyFraxTempleUniV2 is StrategyBase { IERC20 public frax_temple_pool = IERC20(0x6021444f1706f15465bEe85463BCc7d7cC17Fc03); address public frax_temple_gauge = 0x10460d02226d6ef7B2419aE150E6377BdbB7Ef16; - address templeRouter = 0x8A5058100E60e8F7C42305eb505B12785bbA3BcA; + address public constant templeRouter = 0x8A5058100E60e8F7C42305eb505B12785bbA3BcA; address public constant FXS = 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0; address public constant TEMPLE = 0x470EBf5f030Ed85Fc1ed4C2d36B9DD02e77CF1b7; From 6e6986020f1c230ba1910d47903c1f779f07e6e1 Mon Sep 17 00:00:00 2001 From: Cipio Date: Wed, 27 Apr 2022 21:00:47 -0500 Subject: [PATCH 05/13] Fix Withdrawals, set strategyBase to 20% default fee. --- src/backscratcher/StrategyProxy.sol | 2 +- .../strategy-frax-temple-univ2.sol | 21 +++++---- src/strategies/strategy-base.sol | 2 +- .../strategy-frax-temple.test.js | 44 +++++++------------ 4 files changed, 27 insertions(+), 42 deletions(-) diff --git a/src/backscratcher/StrategyProxy.sol b/src/backscratcher/StrategyProxy.sol index bbb737736..34e873d9f 100644 --- a/src/backscratcher/StrategyProxy.sol +++ b/src/backscratcher/StrategyProxy.sol @@ -188,7 +188,6 @@ contract StrategyProxy { _balances[i] = IERC20(_rewardTokens[i]).balanceOf(address(proxy)); } - proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("withdrawLocked(bytes32)", _kek_id)); LockedStake[] memory lockedStakes = IFraxGaugeUniV2(_gauge).lockedStakesOf(address(proxy)); LockedStake memory thisStake; @@ -201,6 +200,7 @@ contract StrategyProxy { require(thisStake.liquidity != 0, "kek_id not found"); if (thisStake.liquidity > 0) { + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("withdrawLocked(bytes32,address)", _kek_id, address(proxy))); proxy.safeExecute( _token, 0, diff --git a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol index ed6442056..bafb73d60 100644 --- a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol +++ b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol @@ -113,34 +113,33 @@ contract StrategyFraxTempleUniV2 is StrategyBase { _count++; continue; } - _sum = _sum.add( - IStrategyProxy(strategyProxy).withdrawV2( - frax_temple_gauge, - address(frax_temple_pool), - lockedStakes[i].kek_id, - rewardTokens - ) - ); + + _sum = _sum.add(IStrategyProxy(strategyProxy).withdrawV2( + frax_temple_gauge, + address(frax_temple_pool), + lockedStakes[i].kek_id, + rewardTokens + )); + _count++; if (_sum >= _liquidity) break; } - require(_sum >= _liquidity, "insufficient liquidity"); LockedStake memory lastStake = lockedStakes[_count - 1]; if (_sum > _liquidity) { - uint128 _withdraw = uint128(uint256(lastStake.liquidity).sub(_sum.sub(_liquidity))); + uint256 _withdraw = _sum.sub(_liquidity); require(_withdraw <= lastStake.liquidity, "math error"); frax_temple_pool.safeTransfer(strategyProxy, _withdraw); + IStrategyProxy(strategyProxy).depositV2( frax_temple_gauge, address(frax_temple_pool), IFraxGaugeBase(frax_temple_gauge).lock_time_min() ); } - return (_liquidity); } } diff --git a/src/strategies/strategy-base.sol b/src/strategies/strategy-base.sol index e609f17ef..baa93e80d 100644 --- a/src/strategies/strategy-base.sol +++ b/src/strategies/strategy-base.sol @@ -16,7 +16,7 @@ abstract contract StrategyBase { using SafeMath for uint256; // Perfomance fees - start with 20% - uint256 public performanceTreasuryFee = 0; + uint256 public performanceTreasuryFee = 2000; uint256 public constant performanceTreasuryMax = 10000; uint256 public performanceDevFee = 0; diff --git a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js index 8c2d1bf72..b98722d98 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js @@ -36,33 +36,16 @@ describe("StrategyFraxTemple", () => { proxyAdmin = await deployContract("ProxyAdmin"); console.log("✅ ProxyAdmin is deployed at ", proxyAdmin.address); - const controllerImp = await deployContract("ControllerV5"); - const controllerProxy = await deployContract( - "AdminUpgradeabilityProxy", - controllerImp.address, - proxyAdmin.address, - [] - ); - - controller = await getContractAt("ControllerV5", controllerProxy.address); + controller = await deployContract("src/controller-v4.sol:ControllerV4", + governance.address, + strategist.address, + timelock.address, + devfund.address, + treasury.address); - await controller.initialize( - governance.address, - strategist.address, - timelock.address, - devfund.address, - treasury.address - ); console.log("✅ Controller is deployed at ", controller.address); - const upgradedController = await deployContract("ControllerV7"); - console.log("✅ Controller V7 is deployed at ", upgradedController.address); - - await proxyAdmin.upgrade(controllerProxy.address, upgradedController.address); - - let newController = await getContractAt("ControllerV7", controllerProxy.address); - locker = await getContractAt("FXSLocker", "0xd639C2eA4eEFfAD39b599410d00252E6c80008DF"); console.log("✅ Locker is deployed at ", locker.address); @@ -79,7 +62,7 @@ describe("StrategyFraxTemple", () => { "StrategyFraxTempleUniV2", governance.address, strategist.address, - newController.address, + controller.address, timelock.address ); await strategy.connect(governance).setStrategyProxy(strategyProxy.address); @@ -94,13 +77,13 @@ describe("StrategyFraxTemple", () => { FRAX_TEMPLE_POOL, governance.address, timelock.address, - newController.address + controller.address ); console.log("✅ PickleJar is deployed at ", pickleJar.address); - await newController.connect(governance).setJar(FRAX_TEMPLE_POOL, pickleJar.address); - await newController.connect(governance).approveStrategy(FRAX_TEMPLE_POOL, strategy.address); - await newController.connect(governance).setStrategy(FRAX_TEMPLE_POOL, strategy.address); + await controller.connect(governance).setJar(FRAX_TEMPLE_POOL, pickleJar.address); + await controller.connect(governance).approveStrategy(FRAX_TEMPLE_POOL, strategy.address); + await controller.connect(governance).setStrategy(FRAX_TEMPLE_POOL, strategy.address); veFxsVault = await deployContract("veFXSVault"); console.log("✅ veFxsVault is deployed at ", veFxsVault.address); @@ -200,7 +183,7 @@ describe("StrategyFraxTemple", () => { ); console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); - await controller.withdrawAll(FRAX_TEMPLE_POOL); + await controller.withdrawAll(FRAX_TEMPLE_POOL,{gasLimit:2000000}); console.log( "PickleJar temple balance after withdrawal => ", @@ -251,6 +234,7 @@ describe("StrategyFraxTemple", () => { console.log("Treasury temple balance => ", (await temple.balanceOf(treasury.address)).toString()); console.log("Treasury frax balance => ", (await frax.balanceOf(treasury.address)).toString()); + console.log("Treasury Frax/Temple LP balance => ", (await pool.balanceOf(treasury.address)).toString()); console.log("Strategy temple balance => ", (await temple.balanceOf(strategy.address)).toString()); console.log("Strategy frax balance => ", (await frax.balanceOf(strategy.address)).toString()); @@ -308,12 +292,14 @@ describe("StrategyFraxTemple", () => { console.log("============ Harvest Started =============="); console.log("Harvest"); console.log("Ratio before harvest => ", (await pickleJar.getRatio()).toString()); + console.log("Amount in Treasury before: ", (await pool.balanceOf(treasury.address)).toString()); await increaseTime(60 * 60 * 24 * 14); //travel 30 days await increaseBlock(1000); console.log("Amount Harvestable => ", (await strategy.getHarvestable()).toString()); await strategy.harvest({gasLimit: 10000000}); console.log("Amount Harvestable after => ", (await strategy.getHarvestable()).toString()); console.log("Ratio after harvest => ", (await pickleJar.getRatio()).toString()); + console.log("Amount in Treasury after: ", (await pool.balanceOf(treasury.address)).toString()); console.log("============ Harvest Ended =============="); }; From fee0e595e8dedad436fb2762c398cbf291816570 Mon Sep 17 00:00:00 2001 From: Cipio Date: Thu, 28 Apr 2022 16:08:04 -0500 Subject: [PATCH 06/13] Fixes --- .../strategy-frax-temple-univ2.sol | 22 ++++++------------- .../backscratcher/strategy-frax-dai.test.js | 2 +- .../backscratcher/strategy-frax-usdc-test.js | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol index bafb73d60..009c88529 100644 --- a/src/strategies/backscratcher/strategy-frax-temple-univ2.sol +++ b/src/strategies/backscratcher/strategy-frax-temple-univ2.sol @@ -26,7 +26,11 @@ contract StrategyFraxTempleUniV2 is StrategyBase { address _strategist, address _controller, address _timelock - ) public StrategyBase(address(frax_temple_pool), _governance, _strategist, _controller, _timelock) {} + ) public StrategyBase(address(frax_temple_pool), _governance, _strategist, _controller, _timelock) { + IERC20(FXS).safeApprove(univ2Router2, uint(-1)); + IERC20(FRAX).safeApprove(templeRouter, uint(-1)); + IERC20(TEMPLE).safeApprove(templeRouter, uint(-1)); + } // **** Views **** function setStrategyProxy(address _proxy) external { @@ -44,8 +48,8 @@ contract StrategyFraxTempleUniV2 is StrategyBase { IStrategyProxy(strategyProxy).harvest(frax_temple_gauge, rewardTokens); uint256 _fxs = IERC20(FXS).balanceOf(address(this)); - IERC20(FXS).safeApprove(univ2Router2, 0); - IERC20(FXS).safeApprove(univ2Router2, _fxs); + + address[] memory _path = new address[](2); _path[0] = FXS; @@ -54,28 +58,16 @@ contract StrategyFraxTempleUniV2 is StrategyBase { uint256 _frax = IERC20(FRAX).balanceOf(address(this)); - IERC20(FRAX).safeApprove(templeRouter, 0); - IERC20(FRAX).safeApprove(templeRouter, _frax); - ITempleRouter(templeRouter).swapExactFraxForTemple(_frax, 0, address(this), block.timestamp + 300); uint256 _temple = IERC20(TEMPLE).balanceOf(address(this)); uint256 _amount = _temple.div(2); - IERC20(TEMPLE).safeApprove(templeRouter, 0); - IERC20(TEMPLE).safeApprove(templeRouter, _amount); - ITempleRouter(templeRouter).swapExactTempleForFrax(_amount, 0, address(this), block.timestamp + 300); uint256 _templeAmt = IERC20(TEMPLE).balanceOf(address(this)); uint256 _fraxAmt = IERC20(FRAX).balanceOf(address(this)); - IERC20(TEMPLE).safeApprove(templeRouter, 0); - IERC20(TEMPLE).safeApprove(templeRouter, _templeAmt); - - IERC20(FRAX).safeApprove(templeRouter, 0); - IERC20(FRAX).safeApprove(templeRouter, _fraxAmt); - ITempleRouter(templeRouter).addLiquidity(_templeAmt, _fraxAmt, 0, 0, address(this), now + 60); _distributePerformanceFeesAndDeposit(); diff --git a/src/tests/strategies/backscratcher/strategy-frax-dai.test.js b/src/tests/strategies/backscratcher/strategy-frax-dai.test.js index cd0e71185..334ffb1a4 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-dai.test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-dai.test.js @@ -80,7 +80,7 @@ describe("StrategyFraxDAI", () => { timelock.address ); await strategy.connect(governance).setStrategyProxy(strategyProxy.address); - await strategyProxy.approveStrategy(FRAX_DAI_GAUGE, strategy.address); + await strategyProxy.approveStrategy(FRAX_DAI_GAUGE, strategy.address, "0x3d18b912"); pickleJar = await deployContract( "PickleJarStablesUniV3", diff --git a/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js b/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js index a64e906a1..77d864818 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js @@ -80,7 +80,7 @@ describe("StrategyFraxUSDC", () => { timelock.address ); await strategy.connect(governance).setStrategyProxy(strategyProxy.address); - await strategyProxy.approveStrategy(FRAX_USDC_GAUGE, strategy.address); + await strategyProxy.approveStrategy(FRAX_USDC_GAUGE, strategy.address, "0x3d18b912"); pickleJar = await deployContract( "PickleJarStablesUniV3", From 992b4a71a8217adc61e6bc8481bea83302fcf8b3 Mon Sep 17 00:00:00 2001 From: Cipio Date: Thu, 28 Apr 2022 21:09:12 -0500 Subject: [PATCH 07/13] Cleanup, set correct default values --- src/backscratcher/StrategyProxy.sol | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/backscratcher/StrategyProxy.sol b/src/backscratcher/StrategyProxy.sol index 34e873d9f..6f4a14cac 100644 --- a/src/backscratcher/StrategyProxy.sol +++ b/src/backscratcher/StrategyProxy.sol @@ -35,28 +35,22 @@ contract StrategyProxy { using SafeMath for uint256; using SafeProxy for IProxy; - IProxy public proxy; - - address public veFxsVault; - - // address public constant gaugeFXSRewardsDistributor = - // 0x278dC748edA1d8eFEf1aDFB518542612b49Fcd34; - IUniswapV3PositionsNFT public constant nftManager = IUniswapV3PositionsNFT(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); + IProxy public proxy = IProxy(0xd639C2eA4eEFfAD39b599410d00252E6c80008DF); + + address public veFxsVault = 0x62826760CC53AE076a7523Fd9dCF4f8Dbb1dA140; address public constant fxs = address(0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0); address public constant rewards = address(0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0); address public gauge = address(0x3669C421b77340B2979d1A00a792CC2ee0FcE737); address public feeDistribution = 0xc6764e58b36e26b08Fd1d2AeD4538c02171fA872; - // gauge => strategies + address public governance; mapping(address => address) public strategies; mapping(address => bool) public voters; mapping(address => bytes) private claimRewardsString; - address public governance; - // TODO How much FXS tokens to give to backscratcher? uint256 public keepFXS = 1000; uint256 public constant keepFXSMax = 10000; From 9358be8e8b762639850729dbcf2cc6e1b67811da Mon Sep 17 00:00:00 2001 From: Cipio Date: Sun, 1 May 2022 00:13:50 -0500 Subject: [PATCH 08/13] Revert StrategyProxy to original deployment and split file for V2. --- src/backscratcher/StrategyProxy.sol | 31 +-- src/backscratcher/StrategyProxyV2.sol | 375 ++++++++++++++++++++++++++ 2 files changed, 389 insertions(+), 17 deletions(-) create mode 100644 src/backscratcher/StrategyProxyV2.sol diff --git a/src/backscratcher/StrategyProxy.sol b/src/backscratcher/StrategyProxy.sol index 6f4a14cac..0e5eeb15b 100644 --- a/src/backscratcher/StrategyProxy.sol +++ b/src/backscratcher/StrategyProxy.sol @@ -35,22 +35,27 @@ contract StrategyProxy { using SafeMath for uint256; using SafeProxy for IProxy; + IProxy public proxy; + + address public veFxsVault; + + // address public constant gaugeFXSRewardsDistributor = + // 0x278dC748edA1d8eFEf1aDFB518542612b49Fcd34; + IUniswapV3PositionsNFT public constant nftManager = IUniswapV3PositionsNFT(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); - IProxy public proxy = IProxy(0xd639C2eA4eEFfAD39b599410d00252E6c80008DF); - - address public veFxsVault = 0x62826760CC53AE076a7523Fd9dCF4f8Dbb1dA140; address public constant fxs = address(0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0); address public constant rewards = address(0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0); address public gauge = address(0x3669C421b77340B2979d1A00a792CC2ee0FcE737); address public feeDistribution = 0xc6764e58b36e26b08Fd1d2AeD4538c02171fA872; - address public governance; + // gauge => strategies mapping(address => address) public strategies; mapping(address => bool) public voters; - mapping(address => bytes) private claimRewardsString; + address public governance; + // TODO How much FXS tokens to give to backscratcher? uint256 public keepFXS = 1000; uint256 public constant keepFXSMax = 10000; @@ -88,20 +93,14 @@ contract StrategyProxy { feeDistribution = _feeDistribution; } - function approveStrategy( - address _gauge, - address _strategy, - bytes calldata claimString - ) external { + function approveStrategy(address _gauge, address _strategy) external { require(msg.sender == governance, "!governance"); strategies[_gauge] = _strategy; - claimRewardsString[_gauge] = claimString; } function revokeStrategy(address _gauge) external { require(msg.sender == governance, "!governance"); strategies[_gauge] = address(0); - claimRewardsString[_gauge] = ""; } function approveVoter(address _voter) external { @@ -182,6 +181,7 @@ contract StrategyProxy { _balances[i] = IERC20(_rewardTokens[i]).balanceOf(address(proxy)); } + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("withdrawLocked(bytes32)", _kek_id)); LockedStake[] memory lockedStakes = IFraxGaugeUniV2(_gauge).lockedStakesOf(address(proxy)); LockedStake memory thisStake; @@ -194,7 +194,6 @@ contract StrategyProxy { require(thisStake.liquidity != 0, "kek_id not found"); if (thisStake.liquidity > 0) { - proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("withdrawLocked(bytes32,address)", _kek_id, address(proxy))); proxy.safeExecute( _token, 0, @@ -284,14 +283,13 @@ contract StrategyProxy { function harvest(address _gauge, address[] calldata _tokens) external { require(strategies[_gauge] == msg.sender, "!strategy"); - uint256[] memory _balances = new uint256[](_tokens.length); for (uint256 i = 0; i < _tokens.length; i++) { _balances[i] = IERC20(_tokens[i]).balanceOf(address(proxy)); } - proxy.safeExecute(_gauge, 0, claimRewardsString[_gauge]); + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("getReward()")); for (uint256 i = 0; i < _tokens.length; i++) { _balances[i] = (IERC20(_tokens[i]).balanceOf(address(proxy))).sub(_balances[i]); @@ -300,7 +298,6 @@ contract StrategyProxy { if (_tokens[i] == fxs) { uint256 _amountKeep = _balances[i].mul(keepFXS).div(keepFXSMax); _swapAmount = _balances[i].sub(_amountKeep); - proxy.safeExecute( _tokens[i], 0, @@ -331,7 +328,7 @@ contract StrategyProxy { function claimRewards(address _gauge, address _token) external { require(strategies[_gauge] == msg.sender, "!strategy"); - proxy.safeExecute(_gauge, 0, claimRewardsString[_gauge]); + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("getReward()")); proxy.safeExecute( _token, diff --git a/src/backscratcher/StrategyProxyV2.sol b/src/backscratcher/StrategyProxyV2.sol new file mode 100644 index 000000000..81954ad64 --- /dev/null +++ b/src/backscratcher/StrategyProxyV2.sol @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; +pragma experimental ABIEncoderV2; + +import "../lib/safe-math.sol"; +import "../lib/erc20.sol"; +import "../interfaces/univ3/IUniswapV3PositionsNFT.sol"; +import "../interfaces/backscratcher/FraxGauge.sol"; + +interface IProxy { + function execute( + address to, + uint256 value, + bytes calldata data + ) external returns (bool, bytes memory); + + function increaseAmount(uint256) external; +} + +library SafeProxy { + function safeExecute( + IProxy proxy, + address to, + uint256 value, + bytes memory data + ) internal { + (bool success, ) = proxy.execute(to, value, data); + require(success == true, "execute failed"); + } +} + +contract StrategyProxyV2 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + using SafeProxy for IProxy; + + IUniswapV3PositionsNFT public constant nftManager = + IUniswapV3PositionsNFT(0xC36442b4a4522E871399CD717aBDD847Ab11FE88); + + IProxy public proxy = IProxy(0xd639C2eA4eEFfAD39b599410d00252E6c80008DF); + + address public veFxsVault = 0x62826760CC53AE076a7523Fd9dCF4f8Dbb1dA140; + address public constant fxs = address(0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0); + address public constant rewards = address(0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0); + address public gauge = address(0x3669C421b77340B2979d1A00a792CC2ee0FcE737); + address public feeDistribution = 0xc6764e58b36e26b08Fd1d2AeD4538c02171fA872; + + address public governance; + mapping(address => address) public strategies; + mapping(address => bool) public voters; + mapping(address => bytes) private claimRewardsString; + + uint256 public keepFXS = 1000; + uint256 public constant keepFXSMax = 10000; + + constructor() public { + governance = msg.sender; + } + + function setGovernance(address _governance) external { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setKeepFXS(uint256 _keepFXS) external { + require(msg.sender == governance, "!governance"); + keepFXS = _keepFXS; + } + + function setFXSVault(address _vault) external { + require(msg.sender == governance, "!governance"); + veFxsVault = _vault; + } + + function setLocker(address _proxy) external { + require(msg.sender == governance, "!governance"); + proxy = IProxy(_proxy); + } + + function setGauge(address _gauge) external { + require(msg.sender == governance, "!governance"); + gauge = _gauge; + } + + function setFeeDistribution(address _feeDistribution) external { + require(msg.sender == governance, "!governance"); + feeDistribution = _feeDistribution; + } + + function approveStrategy( + address _gauge, + address _strategy, + bytes calldata claimString + ) external { + require(msg.sender == governance, "!governance"); + strategies[_gauge] = _strategy; + claimRewardsString[_gauge] = claimString; + } + + function revokeStrategy(address _gauge) external { + require(msg.sender == governance, "!governance"); + strategies[_gauge] = address(0); + claimRewardsString[_gauge] = ""; + } + + function approveVoter(address _voter) external { + require(msg.sender == governance, "!governance"); + voters[_voter] = true; + } + + function revokeVoter(address _voter) external { + require(msg.sender == governance, "!governance"); + voters[_voter] = false; + } + + function lock() external { + uint256 amount = IERC20(fxs).balanceOf(address(proxy)); + if (amount > 0) proxy.increaseAmount(amount); + } + + function vote(address _gauge, uint256 _amount) public { + require(voters[msg.sender], "!voter"); + proxy.safeExecute( + gauge, + 0, + abi.encodeWithSignature("vote_for_gauge_weights(address,uint256)", _gauge, _amount) + ); + } + + function withdrawV3( + address _gauge, + uint256 _tokenId, + address[] memory _rewardTokens + ) public returns (uint256) { + require(strategies[_gauge] == msg.sender, "!strategy"); + + uint256[] memory _balances = new uint256[](_rewardTokens.length); + for (uint256 i = 0; i < _rewardTokens.length; i++) { + _balances[i] = IERC20(_rewardTokens[i]).balanceOf(address(proxy)); + } + + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("withdrawLocked(uint256)", _tokenId)); + + (, , , , , , , uint256 _liquidity, , , , ) = nftManager.positions(_tokenId); + + if (_liquidity > 0) { + proxy.safeExecute( + address(nftManager), + 0, + abi.encodeWithSignature( + "safeTransferFrom(address,address,uint256)", + address(proxy), + msg.sender, + _tokenId + ) + ); + } + + for (uint256 i = 0; i < _rewardTokens.length; i++) { + _balances[i] = (IERC20(_rewardTokens[i]).balanceOf(address(proxy))).sub(_balances[i]); + if (_balances[i] > 0) + proxy.safeExecute( + _rewardTokens[i], + 0, + abi.encodeWithSignature("transfer(address,uint256)", msg.sender, _balances[i]) + ); + } + return _liquidity; + } + + function withdrawV2( + address _gauge, + address _token, + bytes32 _kek_id, + address[] memory _rewardTokens + ) public returns (uint256) { + require(strategies[_gauge] == msg.sender, "!strategy"); + + uint256[] memory _balances = new uint256[](_rewardTokens.length); + for (uint256 i = 0; i < _rewardTokens.length; i++) { + _balances[i] = IERC20(_rewardTokens[i]).balanceOf(address(proxy)); + } + + LockedStake[] memory lockedStakes = IFraxGaugeUniV2(_gauge).lockedStakesOf(address(proxy)); + LockedStake memory thisStake; + + for (uint256 i = 0; i < lockedStakes.length; i++) { + if (_kek_id == lockedStakes[i].kek_id) { + thisStake = lockedStakes[i]; + break; + } + } + require(thisStake.liquidity != 0, "kek_id not found"); + + if (thisStake.liquidity > 0) { + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("withdrawLocked(bytes32,address)", _kek_id, address(proxy))); + proxy.safeExecute( + _token, + 0, + abi.encodeWithSignature("transfer(address,uint256)", msg.sender, thisStake.liquidity) + ); + } + + for (uint256 i = 0; i < _rewardTokens.length; i++) { + _balances[i] = (IERC20(_rewardTokens[i]).balanceOf(address(proxy))).sub(_balances[i]); + if (_balances[i] > 0) + proxy.safeExecute( + _rewardTokens[i], + 0, + abi.encodeWithSignature("transfer(address,uint256)", msg.sender, _balances[i]) + ); + } + return thisStake.liquidity; + } + + function balanceOf(address _gauge) public view returns (uint256) { + return IFraxGaugeBase(_gauge).lockedLiquidityOf(address(proxy)); + } + + function lockedNFTsOf(address _gauge) public view returns (LockedNFT[] memory) { + return IFraxGaugeUniV3(_gauge).lockedNFTsOf(address(proxy)); + } + + function lockedStakesOf(address _gauge) public view returns (LockedStake[] memory) { + return IFraxGaugeUniV2(_gauge).lockedStakesOf(address(proxy)); + } + + function withdrawAllV3(address _gauge, address[] calldata _rewardTokens) external returns (uint256 amount) { + require(strategies[_gauge] == msg.sender, "!strategy"); + LockedNFT[] memory lockedNfts = IFraxGaugeUniV3(_gauge).lockedNFTsOf(address(proxy)); + for (uint256 i = 0; i < lockedNfts.length; i++) { + uint256 _withdrawnLiquidity = withdrawV3(_gauge, lockedNfts[i].token_id, _rewardTokens); + amount = amount.add(_withdrawnLiquidity); + } + } + + function withdrawAllV2( + address _gauge, + address _token, + address[] calldata _rewardTokens + ) external returns (uint256 amount) { + require(strategies[_gauge] == msg.sender, "!strategy"); + LockedStake[] memory lockedStakes = IFraxGaugeUniV2(_gauge).lockedStakesOf(address(proxy)); + + for (uint256 i = 0; i < lockedStakes.length; i++) { + uint256 _withdrawnLiquidity = withdrawV2(_gauge, _token, lockedStakes[i].kek_id, _rewardTokens); + amount = amount.add(_withdrawnLiquidity); + } + } + + function depositV3( + address _gauge, + uint256 _tokenId, + uint256 _secs + ) external { + require(strategies[_gauge] == msg.sender, "!strategy"); + + nftManager.safeTransferFrom(address(this), address(proxy), _tokenId); + + proxy.safeExecute( + address(nftManager), + 0, + abi.encodeWithSignature("approve(address,uint256)", _gauge, _tokenId) + ); + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("stakeLocked(uint256,uint256)", _tokenId, _secs)); + } + + function depositV2( + address _gauge, + address _token, + uint256 _secs + ) external { + require(strategies[_gauge] == msg.sender, "!strategy"); + + uint256 _balance = IERC20(_token).balanceOf(address(this)); + IERC20(_token).safeTransfer(address(proxy), _balance); + _balance = IERC20(_token).balanceOf(address(proxy)); + + proxy.safeExecute(_token, 0, abi.encodeWithSignature("approve(address,uint256)", _gauge, 0)); + proxy.safeExecute(_token, 0, abi.encodeWithSignature("approve(address,uint256)", _gauge, _balance)); + proxy.safeExecute(_gauge, 0, abi.encodeWithSignature("stakeLocked(uint256,uint256)", _balance, _secs)); + } + + function harvest(address _gauge, address[] calldata _tokens) external { + require(strategies[_gauge] == msg.sender, "!strategy"); + + uint256[] memory _balances = new uint256[](_tokens.length); + + for (uint256 i = 0; i < _tokens.length; i++) { + _balances[i] = IERC20(_tokens[i]).balanceOf(address(proxy)); + } + + proxy.safeExecute(_gauge, 0, claimRewardsString[_gauge]); + + for (uint256 i = 0; i < _tokens.length; i++) { + _balances[i] = (IERC20(_tokens[i]).balanceOf(address(proxy))).sub(_balances[i]); + if (_balances[i] > 0) { + uint256 _swapAmount = _balances[i]; + if (_tokens[i] == fxs) { + uint256 _amountKeep = _balances[i].mul(keepFXS).div(keepFXSMax); + _swapAmount = _balances[i].sub(_amountKeep); + + proxy.safeExecute( + _tokens[i], + 0, + abi.encodeWithSignature("transfer(address,uint256)", veFxsVault, _amountKeep) + ); + } + + proxy.safeExecute( + _tokens[i], + 0, + abi.encodeWithSignature("transfer(address,uint256)", msg.sender, _swapAmount) + ); + } + } + } + + function claim(address recipient) external { + require(msg.sender == veFxsVault, "!vault"); + + proxy.safeExecute(feeDistribution, 0, abi.encodeWithSignature("getYield()")); + + uint256 amount = IERC20(rewards).balanceOf(address(proxy)); + if (amount > 0) { + proxy.safeExecute(rewards, 0, abi.encodeWithSignature("transfer(address,uint256)", recipient, amount)); + } + } + + function claimRewards(address _gauge, address _token) external { + require(strategies[_gauge] == msg.sender, "!strategy"); + + proxy.safeExecute(_gauge, 0, claimRewardsString[_gauge]); + + proxy.safeExecute( + _token, + 0, + abi.encodeWithSignature("transfer(address,uint256)", msg.sender, IERC20(_token).balanceOf(address(proxy))) + ); + } + + function onERC721Received( + address, + address, + uint256, + bytes memory + ) public pure returns (bytes4) { + return this.onERC721Received.selector; + } + + // **** Emergency functions **** + + function execute(address _target, bytes memory _data) public payable returns (bytes memory response) { + require(msg.sender == governance, "!governance"); + require(_target != address(0), "!target"); + + // call contract in current context + assembly { + let succeeded := delegatecall(sub(gas(), 5000), _target, add(_data, 0x20), mload(_data), 0, 0) + let size := returndatasize() + + response := mload(0x40) + mstore(0x40, add(response, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + mstore(response, size) + returndatacopy(add(response, 0x20), 0, size) + + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + revert(add(response, 0x20), size) + } + } + } +} From 2fd5243622bed90fdc2a5a42b24cf038580fe144 Mon Sep 17 00:00:00 2001 From: Cipio Date: Tue, 3 May 2022 20:38:48 -0500 Subject: [PATCH 09/13] WIP Migration Test --- .../migrationOfStrategyProxy.test.js | 874 ++++++++++++++++++ 1 file changed, 874 insertions(+) create mode 100644 src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js diff --git a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js new file mode 100644 index 000000000..67c0095b1 --- /dev/null +++ b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js @@ -0,0 +1,874 @@ +const { + toWei, + deployContract, + getContractAt, + increaseTime, + increaseBlock, + unlockAccount, +} = require("../../utils/testHelper"); +const {getWantFromWhale} = require("../../utils/setupHelper"); +const {BigNumber: BN} = require("ethers"); +/* +StrategyProxy: 0x552D92Ad2bb3Aba00872491ea2DC5d6EC3B8A31D +veFXSVault: 0x62826760CC53AE076a7523Fd9dCF4f8Dbb1dA140 +locker: 0xd639C2eA4eEFfAD39b599410d00252E6c80008DF + +Frax/Dai Strategy: 0x219747CA16907330FAe76673facB6e67860ED4C9 +Frax/Dai Jar: 0xe7b69a17B3531d01FCEAd66FaF7d9f7655469267 + +Frax/USDC Strategy: 0x68d467443529f4cC24055ff244826F624dbEff19 +Frax/USDC Jar: 0x7f3514CBC6825410Ca3fA4deA41d46964a953Afb + +ProxyAdmin: 0xEB6044CF48b07ba87D7922362f1aFf5C52FD7Ed3 +AdminUpgradableProxy: 0x7B5916C61bCEeaa2646cf49D9541ac6F5DCe3637 +implController: 0xfa601B32b0B731981845c86557B54e66D2eb23fA +*/ + +describe("StrategyFraxTemple", () => { + const FRAX_TEMPLE_POOL = "0x6021444f1706f15465bEe85463BCc7d7cC17Fc03"; + const FRAX_TEMPLE_SWAP = "0x8A5058100E60e8F7C42305eb505B12785bbA3BcA"; + const FRAX_TEMPLE_GAUGE = "0x10460d02226d6ef7B2419aE150E6377BdbB7Ef16"; + const FraxToken = "0x853d955acef822db058eb8505911ed77f175b99e"; + const TEMPLEToken = "0x470EBf5f030Ed85Fc1ed4C2d36B9DD02e77CF1b7"; + const FXSToken = "0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0"; + const SMARTCHECKER = "0x53c13BA8834a1567474b19822aAD85c6F90D9f9F"; + const GOVADDR = "0x000000000088E0120F9E6652CC058AeC07564F69"; + const TIMELOCK = "0xD92c7fAa0Ca0e6AE4918f3a83d9832d9CAEAA0d3"; + const DAIToken = "0x6b175474e89094c44da98b954eedeac495271d0f"; + const USDCToken = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; + + let alice; + let frax, temple, fxs, fraxDeployer, escrow; + let strategy, pickleJar, controller, proxyAdmin, multisig, strategyProxy, oldStrategyProxy, locker, veFxsVault; + let smartChecker; + let governance, strategist, devfund, treasury, timelock; + let preTestSnapshotID; + let usdcStrategy, daiStrategy, usdcJar, daiJar, dai, usdc; + let lockerGovernance; + + before("Setup Contracts", async () => { + [alice, bob, charles, devfund, treasury] = await hre.ethers.getSigners(); + + lockerGovernance = await unlockAccount("0xaCfE4511CE883C14c4eA40563F176C3C09b4c47C"); + governance = await unlockAccount(GOVADDR); + multisig = await unlockAccount("0x9d074E37d408542FD38be78848e8814AFB38db17"); + timelock = await unlockAccount(TIMELOCK); + strategist = governance; + proxyAdmin = await getContractAt("ProxyAdmin", "0x7B5916C61bCEeaa2646cf49D9541ac6F5DCe3637"); + console.log("✅ ProxyAdmin is deployed at ", proxyAdmin.address); + + + controllerv7 = await getContractAt("src/controller-v7.sol:ControllerV7", "0x7B5916C61bCEeaa2646cf49D9541ac6F5DCe3637"); + //TODO get controllerv4 + controller = await getContractAt("src/controller-v4.sol:ControllerV4", "0x6847259b2B3A4c17e7c43C54409810aF48bA5210"); + + console.log("✅ Controller is deployed at ", controller.address); + + locker = await getContractAt("FXSLocker", "0xd639C2eA4eEFfAD39b599410d00252E6c80008DF"); + console.log("✅ Locker is deployed at ", locker.address); + + escrow = await getContractAt("VoteEscrow", "0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0"); + + oldStrategyProxy = await getContractAt("StrategyProxy", "0x552D92Ad2bb3Aba00872491ea2DC5d6EC3B8A31D"); + + strategyProxy = await deployContract("StrategyProxyV2"); + await strategyProxy.setGovernance(GOVADDR); + console.log("✅ StrategyProxy is deployed at ", strategyProxy.address); + + await locker.connect(lockerGovernance).setStrategy(strategyProxy.address); + await strategyProxy.connect(governance).setLocker(locker.address); + + strategy = await deployContract( + "StrategyFraxTempleUniV2", + GOVADDR, + GOVADDR, + controller.address, + GOVADDR + ); + + await strategy.connect(governance).setStrategyProxy(strategyProxy.address); + + await strategyProxy.connect(governance).approveStrategy( + FRAX_TEMPLE_GAUGE, + strategy.address, + "0xc00007b0000000000000000000000000d639c2ea4eeffad39b599410d00252e6c80008df" + ); + + pickleJar = await deployContract( + "PickleJar", + FRAX_TEMPLE_POOL, + GOVADDR, + GOVADDR, + controller.address + ); + console.log("✅ PickleJar is deployed at ", pickleJar.address); + + usdcStrategy = await getContractAt("StrategyFraxUsdcUniV3", "0x68d467443529f4cC24055ff244826F624dbEff19"); + daiStrategy = await getContractAt("StrategyFraxDaiUniV3","0x219747CA16907330FAe76673facB6e67860ED4C9"); + usdcJar = await getContractAt("PickleJarStablesUniV3","0x7f3514CBC6825410Ca3fA4deA41d46964a953Afb"); + daiJar = await getContractAt("PickleJarStablesUniV3","0xe7b69a17B3531d01FCEAd66FaF7d9f7655469267"); + + await alice.sendTransaction({ + to: "0x9d074E37d408542FD38be78848e8814AFB38db17", + value: toWei(5), + }); + + await alice.sendTransaction({ + to: TIMELOCK, + value: toWei(5), + }); + + await controller.connect(multisig).setJar(FRAX_TEMPLE_POOL, pickleJar.address); + await controller.connect(timelock).approveStrategy(FRAX_TEMPLE_POOL, strategy.address); + await controller.connect(multisig).setStrategy(FRAX_TEMPLE_POOL, strategy.address); + + veFxsVault = await getContractAt("veFXSVault", "0x62826760CC53AE076a7523Fd9dCF4f8Dbb1dA140"); + console.log("✅ veFxsVault is deployed at ", veFxsVault.address); + + await veFxsVault.connect(governance).setProxy(strategyProxy.address); + await veFxsVault.connect(governance).setFeeDistribution(strategyProxy.address); + await veFxsVault.connect(governance).setLocker(locker.address); + + await strategyProxy.connect(governance).setFXSVault(veFxsVault.address); + + frax = await getContractAt("ERC20", FraxToken); + temple = await getContractAt("ERC20", TEMPLEToken); + fxs = await getContractAt("ERC20", FXSToken); + dai = await getContractAt("ERC20", DAIToken); + usdc = await getContractAt("ERC20", USDCToken); + pool = await getContractAt("ERC20", FRAX_TEMPLE_POOL); + templeRouter = await getContractAt(poolABI, FRAX_TEMPLE_SWAP); + + await getWantFromWhale(FraxToken, toWei(10000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + + await getWantFromWhale(TEMPLEToken, toWei(10000), alice, "0xbfc2790ca5f7f1649ffc98d0ffd2573b716cbd0d"); + + await getWantFromWhale(FraxToken, toWei(10000), bob, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + + await getWantFromWhale(TEMPLEToken, toWei(10000), bob, "0xbfc2790ca5f7f1649ffc98d0ffd2573b716cbd0d"); + + await getWantFromWhale(FraxToken, toWei(10000), charles, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + + await getWantFromWhale(TEMPLEToken, toWei(10000), charles, "0xbfc2790ca5f7f1649ffc98d0ffd2573b716cbd0d"); + + await getWantFromWhale(FXSToken, toWei(1000000), alice, "0xF977814e90dA44bFA03b6295A0616a897441aceC"); + + // transfer FXS to distributor + await fxs.connect(alice).transfer("0x278dc748eda1d8efef1adfb518542612b49fcd34", toWei(5000)); + // transfer FXS to gauge + await fxs.connect(alice).transfer(FRAX_TEMPLE_GAUGE, toWei(700000)); + }); + + it("should harvest correctly", async () => { + let depositAmount = toWei(200); + + let aliceShare, bobShare, charlesShare; + + console.log("=============== Alice deposit =============="); + await deposit(alice, depositAmount); + const _amt = await pool.balanceOf(pickleJar.address); + console.log("Calling Earn:", _amt.toString()); + await pickleJar.earn(); + console.log("Calling Harvest:"); + await harvest(); + + console.log("=============== Bob deposit =============="); + depositAmount = toWei(400); + + await deposit(bob, depositAmount); + await pickleJar.earn(); + await harvest(); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + aliceShare = await pickleJar.balanceOf(alice.address); + console.log("Alice share amount => ", aliceShare.toString()); + + console.log("===============Alice partial withdraw=============="); + console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + await pickleJar.connect(alice).withdraw(aliceShare.div(BN.from(2))); + + console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + console.log("=============== Charles deposit =============="); + + depositAmount = toWei(700); + + await deposit(charles, depositAmount); + + console.log("===============Bob withdraw=============="); + console.log("Bob temple balance before withdrawal => ", (await temple.balanceOf(bob.address)).toString()); + console.log("Bob frax balance before withdrawal => ", (await frax.balanceOf(bob.address)).toString()); + await pickleJar.connect(bob).withdrawAll(); + + console.log("Bob temple balance after withdrawal => ", (await temple.balanceOf(bob.address)).toString()); + console.log("Bob frax balance after withdrawal => ", (await frax.balanceOf(bob.address)).toString()); + + await harvest(); + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + await pickleJar.earn(); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + console.log("=============== Controller withdraw ==============="); + console.log( + "PickleJar temple balance before withdrawal => ", + (await temple.balanceOf(pickleJar.address)).toString() + ); + console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + await controller.connect(lockerGovernance).withdrawAll(FRAX_TEMPLE_POOL,{gasLimit:2000000}); + + console.log( + "PickleJar temple balance after withdrawal => ", + (await temple.balanceOf(pickleJar.address)).toString() + ); + console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + console.log("===============Alice Full withdraw=============="); + + console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + await pickleJar.connect(alice).withdrawAll(); + + console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + // await harvest(); + // await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + console.log("=============== charles withdraw =============="); + console.log("Charles temple balance before withdrawal => ", (await temple.balanceOf(charles.address)).toString()); + console.log("Charles frax balance before withdrawal => ", (await frax.balanceOf(charles.address)).toString()); + await pickleJar.connect(charles).withdrawAll(); + + console.log("Charles temple balance after withdrawal => ", (await temple.balanceOf(charles.address)).toString()); + console.log("Charles frax balance after withdrawal => ", (await frax.balanceOf(charles.address)).toString()); + + // console.log("=============== Alice redeposit =============="); + // depositA = toWei(50000); + // depositB = await getAmountB(depositA); + + // await deposit(alice, depositA, depositB); + // await pickleJar.earn(); + + // await harvest(); + // await increaseTime(60 * 60 * 24 * 1); //travel 14 days + + // console.log("===============Alice final withdraw=============="); + + // console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + // console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + // await pickleJar.connect(alice).withdrawAll(); + + // console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + // console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + console.log("------------------ Finished -----------------------"); + + console.log("Treasury temple balance => ", (await temple.balanceOf(treasury.address)).toString()); + console.log("Treasury frax balance => ", (await frax.balanceOf(treasury.address)).toString()); + console.log("Treasury Frax/Temple LP balance => ", (await pool.balanceOf(treasury.address)).toString()); + + console.log("Strategy temple balance => ", (await temple.balanceOf(strategy.address)).toString()); + console.log("Strategy frax balance => ", (await frax.balanceOf(strategy.address)).toString()); + console.log("Strategy fxs balance => ", (await fxs.balanceOf(strategy.address)).toString()); + + console.log("PickleJar temple balance => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance => ", (await frax.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar fxs balance => ", (await fxs.balanceOf(pickleJar.address)).toString()); + + console.log("Locker temple balance => ", (await temple.balanceOf(locker.address)).toString()); + console.log("Locker frax balance => ", (await frax.balanceOf(locker.address)).toString()); + console.log("Locker fxs balance => ", (await fxs.balanceOf(locker.address)).toString()); + + console.log("StrategyProxy temple balance => ", (await temple.balanceOf(strategyProxy.address)).toString()); + console.log("StrategyProxy frax balance => ", (await frax.balanceOf(strategyProxy.address)).toString()); + console.log("StrategyProxy fxs balance => ", (await fxs.balanceOf(strategyProxy.address)).toString()); + }); + it("Migrate UniV3 Strategies", async () => { + /* + usdcStrategy = await getContractAt("StrategyFraxUsdcUniV3", "0x68d467443529f4cC24055ff244826F624dbEff19"); + daiStrategy = await getContractAt("StrategyFraxDaiUniV3","0x219747CA16907330FAe76673facB6e67860ED4C9"); + usdcJar = await getContractAt("PickleJarStablesUniV3","0x7f3514CBC6825410Ca3fA4deA41d46964a953Afb"); + daiJar + */ + + await usdcStrategy.connect(governance).setStrategyProxy(strategyProxy.address); + await daiStrategy.connect(governance).setStrategyProxy(strategyProxy.address); + + await getWantFromWhale(FraxToken, toWei(100000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + await getWantFromWhale(DAIToken, toWei(100000), alice, "0x921760e71fb58dcc8de902ce81453e9e3d7fe253"); + + await getWantFromWhale(FraxToken, toWei(100000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); + await getWantFromWhale(USDCToken, "100000000000000", alice, "0xE78388b4CE79068e89Bf8aA7f218eF6b9AB0e9d0"); + + console.log("=============== Alice deposit Frax/USDC =============="); + + let depositA = toWei(20000); + let depositB = await getAmountB(depositA); + + await depositV3(alice, depositA, depositB); + console.log("Deposit V3 Done"); + await usdcJar.earn(); + console.log("Earn Complete"); + await harvest(); + console.log("Harvest complete"); + }); + /* + it("should withdraw correctly", async () => { + let depositA = toWei(50000); + let depositB = await getAmountB(depositA); + + console.log("=============== Alice deposit =============="); + await deposit(alice, depositA, depositB); + await pickleJar.earn(); + await harvest(); + + await increaseTime(60 * 60 * 24 * 1); //travel 14 days + console.log("PickleJar temple balance before withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + await controller.withdrawAll(FRAX_TEMPLE_POOL); + + console.log("PickleJar temple balance after withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); + console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); + + console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + + await pickleJar.connect(alice).withdrawAll(); + + console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); + console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); + }); +*/ + +const getAmountB = async (amountA) => { + const proportion = await usdcJar.getProportion(); + const amountB = amountA.mul(proportion).div(hre.ethers.BigNumber.from("1000000000000000000")); + return amountB; +}; + + const deposit = async (user, depositAmount) => { + await depositing(user, depositAmount); + const _amt = await pool.balanceOf(user.address); + await pool.connect(user).approve(pickleJar.address, _amt); + + await pickleJar.connect(user).deposit(_amt); + }; + const depositV3 = async (user, depositA, depositB) => { + await frax.connect(user).approve(usdcJar.address, depositA); + await usdc.connect(user).approve(usdcJar.address, depositB); + console.log("depositA => ", depositA.toString()); + console.log("depositB => ", depositB.toString()); + + await usdcJar.connect(user).deposit(depositA, depositB); + }; + + const harvest = async () => { + console.log("============ Harvest Started =============="); + console.log("Harvest"); + console.log("Ratio before harvest => ", (await pickleJar.getRatio()).toString()); + console.log("Amount in Treasury before: ", (await pool.balanceOf(treasury.address)).toString()); + await increaseTime(60 * 60 * 24 * 14); //travel 30 days + await increaseBlock(1000); + console.log("Amount Harvestable => ", (await strategy.getHarvestable()).toString()); + await strategy.connect(governance).harvest({gasLimit: 10000000}); + console.log("Amount Harvestable after => ", (await strategy.getHarvestable()).toString()); + console.log("Ratio after harvest => ", (await pickleJar.getRatio()).toString()); + console.log("Amount in Treasury after: ", (await pool.balanceOf(treasury.address)).toString()); + console.log("============ Harvest Ended =============="); + }; + + const depositing = async (user, amount) => { + // getting timestamp + const blockNumBefore = await ethers.provider.getBlockNumber(); + const blockBefore = await ethers.provider.getBlock(blockNumBefore); + const timestampBefore = blockBefore.timestamp; + await temple.connect(user).approve(FRAX_TEMPLE_SWAP, amount); + await frax.connect(user).approve(FRAX_TEMPLE_SWAP, amount); + await templeRouter.connect(user).addLiquidity(amount, amount, 0, 0, user.address, timestampBefore + 60); + }; + + // beforeEach(async () => { + // preTestSnapshotID = await hre.network.provider.send("evm_snapshot"); + // }); + + // afterEach(async () => { + // await hre.network.provider.send("evm_revert", [preTestSnapshotID]); + // }); + const poolABI = [ + { + inputs: [ + {internalType: "contract IUniswapV2Pair", name: "_pair", type: "address"}, + {internalType: "contract TempleERC20Token", name: "_templeToken", type: "address"}, + {internalType: "contract IERC20", name: "_fraxToken", type: "address"}, + {internalType: "contract ITempleTreasury", name: "_templeTreasury", type: "address"}, + {internalType: "address", name: "_protocolMintEarningsAccount", type: "address"}, + { + components: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + internalType: "struct TempleFraxAMMRouter.Price", + name: "_dynamicThresholdPrice", + type: "tuple", + }, + {internalType: "uint256", name: "_dynamicThresholdDecayPerBlock", type: "uint256"}, + { + components: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + internalType: "struct TempleFraxAMMRouter.Price", + name: "_interpolateFromPrice", + type: "tuple", + }, + { + components: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + internalType: "struct TempleFraxAMMRouter.Price", + name: "_interpolateToPrice", + type: "tuple", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [{indexed: false, internalType: "uint256", name: "currDynamicThresholdTemple", type: "uint256"}], + name: "DynamicThresholdChange", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "address", name: "previousOwner", type: "address"}, + {indexed: true, internalType: "address", name: "newOwner", type: "address"}, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [{indexed: false, internalType: "uint256", name: "blockNumber", type: "uint256"}], + name: "PriceCrossedBelowDynamicThreshold", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "bytes32", name: "role", type: "bytes32"}, + {indexed: true, internalType: "bytes32", name: "previousAdminRole", type: "bytes32"}, + {indexed: true, internalType: "bytes32", name: "newAdminRole", type: "bytes32"}, + ], + name: "RoleAdminChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "bytes32", name: "role", type: "bytes32"}, + {indexed: true, internalType: "address", name: "account", type: "address"}, + {indexed: true, internalType: "address", name: "sender", type: "address"}, + ], + name: "RoleGranted", + type: "event", + }, + { + anonymous: false, + inputs: [ + {indexed: true, internalType: "bytes32", name: "role", type: "bytes32"}, + {indexed: true, internalType: "address", name: "account", type: "address"}, + {indexed: true, internalType: "address", name: "sender", type: "address"}, + ], + name: "RoleRevoked", + type: "event", + }, + { + inputs: [], + name: "CAN_ADD_ALLOWED_USER", + outputs: [{internalType: "bytes32", name: "", type: "bytes32"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DEFAULT_ADMIN_ROLE", + outputs: [{internalType: "bytes32", name: "", type: "bytes32"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "DYNAMIC_THRESHOLD_INCREASE_DENOMINATOR", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [{internalType: "address", name: "userAddress", type: "address"}], + name: "addAllowedUser", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountADesired", type: "uint256"}, + {internalType: "uint256", name: "amountBDesired", type: "uint256"}, + {internalType: "uint256", name: "amountAMin", type: "uint256"}, + {internalType: "uint256", name: "amountBMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "addLiquidity", + outputs: [ + {internalType: "uint256", name: "amountA", type: "uint256"}, + {internalType: "uint256", name: "amountB", type: "uint256"}, + {internalType: "uint256", name: "liquidity", type: "uint256"}, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "address", name: "", type: "address"}], + name: "allowed", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdDecayPerBlock", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdIncreasePct", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdPrice", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "dynamicThresholdPriceWithDecay", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "fraxToken", + outputs: [{internalType: "contract IERC20", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountIn", type: "uint256"}, + {internalType: "uint256", name: "reserveIn", type: "uint256"}, + {internalType: "uint256", name: "reserveOut", type: "uint256"}, + ], + name: "getAmountOut", + outputs: [{internalType: "uint256", name: "amountOut", type: "uint256"}], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{internalType: "bytes32", name: "role", type: "bytes32"}], + name: "getRoleAdmin", + outputs: [{internalType: "bytes32", name: "", type: "bytes32"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "grantRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "hasRole", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "interpolateFromPrice", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "interpolateToPrice", + outputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "temple", type: "uint256"}, + {internalType: "uint256", name: "frax", type: "uint256"}, + ], + name: "mintRatioAt", + outputs: [ + {internalType: "uint256", name: "numerator", type: "uint256"}, + {internalType: "uint256", name: "denominator", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "openAccessEnabled", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{internalType: "address", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pair", + outputs: [{internalType: "contract IUniswapV2Pair", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "priceCrossedBelowDynamicThresholdBlock", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountA", type: "uint256"}, + {internalType: "uint256", name: "reserveA", type: "uint256"}, + {internalType: "uint256", name: "reserveB", type: "uint256"}, + ], + name: "quote", + outputs: [{internalType: "uint256", name: "amountB", type: "uint256"}], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{internalType: "address", name: "userAddress", type: "address"}], + name: "removeAllowedUser", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "liquidity", type: "uint256"}, + {internalType: "uint256", name: "amountAMin", type: "uint256"}, + {internalType: "uint256", name: "amountBMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "removeLiquidity", + outputs: [ + {internalType: "uint256", name: "amountA", type: "uint256"}, + {internalType: "uint256", name: "amountB", type: "uint256"}, + ], + stateMutability: "nonpayable", + type: "function", + }, + {inputs: [], name: "renounceOwnership", outputs: [], stateMutability: "nonpayable", type: "function"}, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "renounceRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "bytes32", name: "role", type: "bytes32"}, + {internalType: "address", name: "account", type: "address"}, + ], + name: "revokeRole", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "_dynamicThresholdDecayPerBlock", type: "uint256"}], + name: "setDynamicThresholdDecayPerBlock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "_dynamicThresholdIncreasePct", type: "uint256"}], + name: "setDynamicThresholdIncreasePct", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + name: "setInterpolateFromPrice", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "frax", type: "uint256"}, + {internalType: "uint256", name: "temple", type: "uint256"}, + ], + name: "setInterpolateToPrice", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "address", name: "_protocolMintEarningsAccount", type: "address"}], + name: "setProtocolMintEarningsAccount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "bytes4", name: "interfaceId", type: "bytes4"}], + name: "supportsInterface", + outputs: [{internalType: "bool", name: "", type: "bool"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountIn", type: "uint256"}, + {internalType: "uint256", name: "amountOutMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "swapExactFraxForTemple", + outputs: [{internalType: "uint256", name: "amountOut", type: "uint256"}], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "amountIn", type: "uint256"}], + name: "swapExactFraxForTempleQuote", + outputs: [ + {internalType: "uint256", name: "amountInAMM", type: "uint256"}, + {internalType: "uint256", name: "amountInProtocol", type: "uint256"}, + {internalType: "uint256", name: "amountOutAMM", type: "uint256"}, + {internalType: "uint256", name: "amountOutProtocol", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + {internalType: "uint256", name: "amountIn", type: "uint256"}, + {internalType: "uint256", name: "amountOutMin", type: "uint256"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "deadline", type: "uint256"}, + ], + name: "swapExactTempleForFrax", + outputs: [{internalType: "uint256", name: "", type: "uint256"}], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{internalType: "uint256", name: "amountIn", type: "uint256"}], + name: "swapExactTempleForFraxQuote", + outputs: [ + {internalType: "bool", name: "priceBelowIV", type: "bool"}, + {internalType: "bool", name: "willCrossDynamicThreshold", type: "bool"}, + {internalType: "uint256", name: "amountOut", type: "uint256"}, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "templeToken", + outputs: [{internalType: "contract TempleERC20Token", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "templeTreasury", + outputs: [{internalType: "contract ITempleTreasury", name: "", type: "address"}], + stateMutability: "view", + type: "function", + }, + {inputs: [], name: "toggleOpenAccess", outputs: [], stateMutability: "nonpayable", type: "function"}, + { + inputs: [{internalType: "address", name: "newOwner", type: "address"}], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + {internalType: "address", name: "token", type: "address"}, + {internalType: "address", name: "to", type: "address"}, + {internalType: "uint256", name: "amount", type: "uint256"}, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + ]; +}); From e6244727a63ab2d95c838c8e45cb9ee5b6cd06f9 Mon Sep 17 00:00:00 2001 From: Cipio Date: Wed, 4 May 2022 20:18:43 -0500 Subject: [PATCH 10/13] Update Test --- .../migrationOfStrategyProxy.test.js | 114 ++++++------------ .../backscratcher/strategy-frax-dai.test.js | 2 +- .../backscratcher/strategy-frax-usdc-test.js | 2 +- 3 files changed, 37 insertions(+), 81 deletions(-) diff --git a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js index 67c0095b1..2a418a631 100644 --- a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js +++ b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js @@ -28,6 +28,10 @@ describe("StrategyFraxTemple", () => { const FRAX_TEMPLE_POOL = "0x6021444f1706f15465bEe85463BCc7d7cC17Fc03"; const FRAX_TEMPLE_SWAP = "0x8A5058100E60e8F7C42305eb505B12785bbA3BcA"; const FRAX_TEMPLE_GAUGE = "0x10460d02226d6ef7B2419aE150E6377BdbB7Ef16"; + const FRAX_DAI_POOL = "0x97e7d56A0408570bA1a7852De36350f7713906ec"; + const FRAX_DAI_GAUGE = "0xF22471AC2156B489CC4a59092c56713F813ff53e"; + const FRAX_USDC_POOL = "0xc63B0708E2F7e69CB8A1df0e1389A98C35A76D52"; + const FRAX_USDC_GAUGE = "0x3EF26504dbc8Dd7B7aa3E97Bc9f3813a9FC0B4B0"; const FraxToken = "0x853d955acef822db058eb8505911ed77f175b99e"; const TEMPLEToken = "0x470EBf5f030Ed85Fc1ed4C2d36B9DD02e77CF1b7"; const FXSToken = "0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0"; @@ -94,6 +98,7 @@ describe("StrategyFraxTemple", () => { "0xc00007b0000000000000000000000000d639c2ea4eeffad39b599410d00252e6c80008df" ); + pickleJar = await deployContract( "PickleJar", FRAX_TEMPLE_POOL, @@ -108,6 +113,17 @@ describe("StrategyFraxTemple", () => { usdcJar = await getContractAt("PickleJarStablesUniV3","0x7f3514CBC6825410Ca3fA4deA41d46964a953Afb"); daiJar = await getContractAt("PickleJarStablesUniV3","0xe7b69a17B3531d01FCEAd66FaF7d9f7655469267"); + await strategyProxy.connect(governance).approveStrategy( + FRAX_USDC_GAUGE, + "0x68d467443529f4cC24055ff244826F624dbEff19", + "0x3d18b912" + ); + + await strategyProxy.connect(governance).approveStrategy( + FRAX_DAI_GAUGE, + "0x219747CA16907330FAe76673facB6e67860ED4C9", + "0x3d18b912" + ); await alice.sendTransaction({ to: "0x9d074E37d408542FD38be78848e8814AFB38db17", value: toWei(5), @@ -170,14 +186,14 @@ describe("StrategyFraxTemple", () => { console.log("Calling Earn:", _amt.toString()); await pickleJar.earn(); console.log("Calling Harvest:"); - await harvest(); + await harvest(pickleJar, strategy); console.log("=============== Bob deposit =============="); depositAmount = toWei(400); await deposit(bob, depositAmount); await pickleJar.earn(); - await harvest(); + await harvest(pickleJar, strategy); await increaseTime(60 * 60 * 24 * 1); //travel 14 days @@ -208,7 +224,7 @@ describe("StrategyFraxTemple", () => { console.log("Bob temple balance after withdrawal => ", (await temple.balanceOf(bob.address)).toString()); console.log("Bob frax balance after withdrawal => ", (await frax.balanceOf(bob.address)).toString()); - await harvest(); + await harvest(pickleJar, strategy); await increaseTime(60 * 60 * 24 * 1); //travel 14 days await pickleJar.earn(); @@ -239,9 +255,6 @@ describe("StrategyFraxTemple", () => { console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - // await harvest(); - // await increaseTime(60 * 60 * 24 * 1); //travel 14 days - console.log("=============== charles withdraw =============="); console.log("Charles temple balance before withdrawal => ", (await temple.balanceOf(charles.address)).toString()); console.log("Charles frax balance before withdrawal => ", (await frax.balanceOf(charles.address)).toString()); @@ -250,25 +263,6 @@ describe("StrategyFraxTemple", () => { console.log("Charles temple balance after withdrawal => ", (await temple.balanceOf(charles.address)).toString()); console.log("Charles frax balance after withdrawal => ", (await frax.balanceOf(charles.address)).toString()); - // console.log("=============== Alice redeposit =============="); - // depositA = toWei(50000); - // depositB = await getAmountB(depositA); - - // await deposit(alice, depositA, depositB); - // await pickleJar.earn(); - - // await harvest(); - // await increaseTime(60 * 60 * 24 * 1); //travel 14 days - - // console.log("===============Alice final withdraw=============="); - - // console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - // console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - // await pickleJar.connect(alice).withdrawAll(); - - // console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - // console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - console.log("------------------ Finished -----------------------"); console.log("Treasury temple balance => ", (await temple.balanceOf(treasury.address)).toString()); @@ -311,46 +305,18 @@ describe("StrategyFraxTemple", () => { console.log("=============== Alice deposit Frax/USDC =============="); let depositA = toWei(20000); - let depositB = await getAmountB(depositA); + let depositB = await getAmountB(daiJar, depositA); - await depositV3(alice, depositA, depositB); + await depositV3(daiJar, alice, depositA, depositB); console.log("Deposit V3 Done"); - await usdcJar.earn(); + await daiJar.earn(); console.log("Earn Complete"); - await harvest(); + await harvest(daiJar, daiStrategy); console.log("Harvest complete"); }); - /* - it("should withdraw correctly", async () => { - let depositA = toWei(50000); - let depositB = await getAmountB(depositA); - console.log("=============== Alice deposit =============="); - await deposit(alice, depositA, depositB); - await pickleJar.earn(); - await harvest(); - - await increaseTime(60 * 60 * 24 * 1); //travel 14 days - console.log("PickleJar temple balance before withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); - console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); - - await controller.withdrawAll(FRAX_TEMPLE_POOL); - - console.log("PickleJar temple balance after withdrawal => ", (await temple.balanceOf(pickleJar.address)).toString()); - console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); - - console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - - await pickleJar.connect(alice).withdrawAll(); - - console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - }); -*/ - -const getAmountB = async (amountA) => { - const proportion = await usdcJar.getProportion(); +const getAmountB = async (jar, amountA) => { + const proportion = await jar.getProportion(); const amountB = amountA.mul(proportion).div(hre.ethers.BigNumber.from("1000000000000000000")); return amountB; }; @@ -362,27 +328,24 @@ const getAmountB = async (amountA) => { await pickleJar.connect(user).deposit(_amt); }; - const depositV3 = async (user, depositA, depositB) => { - await frax.connect(user).approve(usdcJar.address, depositA); - await usdc.connect(user).approve(usdcJar.address, depositB); + const depositV3 = async (jar, user, depositA, depositB) => { + await frax.connect(user).approve(jar.address, depositA); + await usdc.connect(user).approve(jar.address, depositB); console.log("depositA => ", depositA.toString()); console.log("depositB => ", depositB.toString()); - await usdcJar.connect(user).deposit(depositA, depositB); + await jar.connect(user).deposit(depositA, depositB); }; - const harvest = async () => { + const harvest = async (jar, strat) => { console.log("============ Harvest Started =============="); - console.log("Harvest"); - console.log("Ratio before harvest => ", (await pickleJar.getRatio()).toString()); - console.log("Amount in Treasury before: ", (await pool.balanceOf(treasury.address)).toString()); + console.log("Ratio before harvest => ", (await jar.getRatio()).toString()); await increaseTime(60 * 60 * 24 * 14); //travel 30 days await increaseBlock(1000); - console.log("Amount Harvestable => ", (await strategy.getHarvestable()).toString()); - await strategy.connect(governance).harvest({gasLimit: 10000000}); - console.log("Amount Harvestable after => ", (await strategy.getHarvestable()).toString()); - console.log("Ratio after harvest => ", (await pickleJar.getRatio()).toString()); - console.log("Amount in Treasury after: ", (await pool.balanceOf(treasury.address)).toString()); + console.log("Amount Harvestable => ", (await strat.getHarvestable()).toString()); + await strat.connect(governance).harvest({gasLimit: 10000000}); + console.log("Amount Harvestable after => ", (await strat.getHarvestable()).toString()); + console.log("Ratio after harvest => ", (await jar.getRatio()).toString()); console.log("============ Harvest Ended =============="); }; @@ -396,13 +359,6 @@ const getAmountB = async (amountA) => { await templeRouter.connect(user).addLiquidity(amount, amount, 0, 0, user.address, timestampBefore + 60); }; - // beforeEach(async () => { - // preTestSnapshotID = await hre.network.provider.send("evm_snapshot"); - // }); - - // afterEach(async () => { - // await hre.network.provider.send("evm_revert", [preTestSnapshotID]); - // }); const poolABI = [ { inputs: [ diff --git a/src/tests/strategies/backscratcher/strategy-frax-dai.test.js b/src/tests/strategies/backscratcher/strategy-frax-dai.test.js index 334ffb1a4..cd0e71185 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-dai.test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-dai.test.js @@ -80,7 +80,7 @@ describe("StrategyFraxDAI", () => { timelock.address ); await strategy.connect(governance).setStrategyProxy(strategyProxy.address); - await strategyProxy.approveStrategy(FRAX_DAI_GAUGE, strategy.address, "0x3d18b912"); + await strategyProxy.approveStrategy(FRAX_DAI_GAUGE, strategy.address); pickleJar = await deployContract( "PickleJarStablesUniV3", diff --git a/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js b/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js index 77d864818..a64e906a1 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-usdc-test.js @@ -80,7 +80,7 @@ describe("StrategyFraxUSDC", () => { timelock.address ); await strategy.connect(governance).setStrategyProxy(strategyProxy.address); - await strategyProxy.approveStrategy(FRAX_USDC_GAUGE, strategy.address, "0x3d18b912"); + await strategyProxy.approveStrategy(FRAX_USDC_GAUGE, strategy.address); pickleJar = await deployContract( "PickleJarStablesUniV3", From e01bc75a0a24373c93f5f710f46090bed515ddfa Mon Sep 17 00:00:00 2001 From: Cipio Date: Wed, 4 May 2022 22:44:51 -0500 Subject: [PATCH 11/13] cleanup, shorten test --- .../migrationOfStrategyProxy.test.js | 132 +++--------------- 1 file changed, 17 insertions(+), 115 deletions(-) diff --git a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js index 2a418a631..4c491f007 100644 --- a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js +++ b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js @@ -175,116 +175,6 @@ describe("StrategyFraxTemple", () => { await fxs.connect(alice).transfer(FRAX_TEMPLE_GAUGE, toWei(700000)); }); - it("should harvest correctly", async () => { - let depositAmount = toWei(200); - - let aliceShare, bobShare, charlesShare; - - console.log("=============== Alice deposit =============="); - await deposit(alice, depositAmount); - const _amt = await pool.balanceOf(pickleJar.address); - console.log("Calling Earn:", _amt.toString()); - await pickleJar.earn(); - console.log("Calling Harvest:"); - await harvest(pickleJar, strategy); - - console.log("=============== Bob deposit =============="); - depositAmount = toWei(400); - - await deposit(bob, depositAmount); - await pickleJar.earn(); - await harvest(pickleJar, strategy); - - await increaseTime(60 * 60 * 24 * 1); //travel 14 days - - aliceShare = await pickleJar.balanceOf(alice.address); - console.log("Alice share amount => ", aliceShare.toString()); - - console.log("===============Alice partial withdraw=============="); - console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - await pickleJar.connect(alice).withdraw(aliceShare.div(BN.from(2))); - - console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - - await increaseTime(60 * 60 * 24 * 1); //travel 14 days - - console.log("=============== Charles deposit =============="); - - depositAmount = toWei(700); - - await deposit(charles, depositAmount); - - console.log("===============Bob withdraw=============="); - console.log("Bob temple balance before withdrawal => ", (await temple.balanceOf(bob.address)).toString()); - console.log("Bob frax balance before withdrawal => ", (await frax.balanceOf(bob.address)).toString()); - await pickleJar.connect(bob).withdrawAll(); - - console.log("Bob temple balance after withdrawal => ", (await temple.balanceOf(bob.address)).toString()); - console.log("Bob frax balance after withdrawal => ", (await frax.balanceOf(bob.address)).toString()); - - await harvest(pickleJar, strategy); - await increaseTime(60 * 60 * 24 * 1); //travel 14 days - - await pickleJar.earn(); - - await increaseTime(60 * 60 * 24 * 1); //travel 14 days - - console.log("=============== Controller withdraw ==============="); - console.log( - "PickleJar temple balance before withdrawal => ", - (await temple.balanceOf(pickleJar.address)).toString() - ); - console.log("PickleJar frax balance before withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); - - await controller.connect(lockerGovernance).withdrawAll(FRAX_TEMPLE_POOL,{gasLimit:2000000}); - - console.log( - "PickleJar temple balance after withdrawal => ", - (await temple.balanceOf(pickleJar.address)).toString() - ); - console.log("PickleJar frax balance after withdrawal => ", (await frax.balanceOf(pickleJar.address)).toString()); - - console.log("===============Alice Full withdraw=============="); - - console.log("Alice temple balance before withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - console.log("Alice frax balance before withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - await pickleJar.connect(alice).withdrawAll(); - - console.log("Alice temple balance after withdrawal => ", (await temple.balanceOf(alice.address)).toString()); - console.log("Alice frax balance after withdrawal => ", (await frax.balanceOf(alice.address)).toString()); - - console.log("=============== charles withdraw =============="); - console.log("Charles temple balance before withdrawal => ", (await temple.balanceOf(charles.address)).toString()); - console.log("Charles frax balance before withdrawal => ", (await frax.balanceOf(charles.address)).toString()); - await pickleJar.connect(charles).withdrawAll(); - - console.log("Charles temple balance after withdrawal => ", (await temple.balanceOf(charles.address)).toString()); - console.log("Charles frax balance after withdrawal => ", (await frax.balanceOf(charles.address)).toString()); - - console.log("------------------ Finished -----------------------"); - - console.log("Treasury temple balance => ", (await temple.balanceOf(treasury.address)).toString()); - console.log("Treasury frax balance => ", (await frax.balanceOf(treasury.address)).toString()); - console.log("Treasury Frax/Temple LP balance => ", (await pool.balanceOf(treasury.address)).toString()); - - console.log("Strategy temple balance => ", (await temple.balanceOf(strategy.address)).toString()); - console.log("Strategy frax balance => ", (await frax.balanceOf(strategy.address)).toString()); - console.log("Strategy fxs balance => ", (await fxs.balanceOf(strategy.address)).toString()); - - console.log("PickleJar temple balance => ", (await temple.balanceOf(pickleJar.address)).toString()); - console.log("PickleJar frax balance => ", (await frax.balanceOf(pickleJar.address)).toString()); - console.log("PickleJar fxs balance => ", (await fxs.balanceOf(pickleJar.address)).toString()); - - console.log("Locker temple balance => ", (await temple.balanceOf(locker.address)).toString()); - console.log("Locker frax balance => ", (await frax.balanceOf(locker.address)).toString()); - console.log("Locker fxs balance => ", (await fxs.balanceOf(locker.address)).toString()); - - console.log("StrategyProxy temple balance => ", (await temple.balanceOf(strategyProxy.address)).toString()); - console.log("StrategyProxy frax balance => ", (await frax.balanceOf(strategyProxy.address)).toString()); - console.log("StrategyProxy fxs balance => ", (await fxs.balanceOf(strategyProxy.address)).toString()); - }); it("Migrate UniV3 Strategies", async () => { /* usdcStrategy = await getContractAt("StrategyFraxUsdcUniV3", "0x68d467443529f4cC24055ff244826F624dbEff19"); @@ -302,17 +192,29 @@ describe("StrategyFraxTemple", () => { await getWantFromWhale(FraxToken, toWei(100000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); await getWantFromWhale(USDCToken, "100000000000000", alice, "0xE78388b4CE79068e89Bf8aA7f218eF6b9AB0e9d0"); - console.log("=============== Alice deposit Frax/USDC =============="); + console.log("=============== Alice Frax/Dai =============="); let depositA = toWei(20000); let depositB = await getAmountB(daiJar, depositA); - await depositV3(daiJar, alice, depositA, depositB); + await depositV3(daiJar, alice, dai, frax, depositA, depositB); console.log("Deposit V3 Done"); await daiJar.earn(); console.log("Earn Complete"); await harvest(daiJar, daiStrategy); console.log("Harvest complete"); + + console.log("=============== Alice Frax/USDC =============="); + + depositA = toWei(20000); + depositB = await getAmountB(usdcJar, depositA); + + await depositV3(usdcJar, alice, frax, usdc, depositA, depositB); + console.log("Deposit V3 Done"); + await usdcJar.earn(); + console.log("Earn Complete"); + await harvest(usdcJar, usdcStrategy); + console.log("Harvest complete"); }); const getAmountB = async (jar, amountA) => { @@ -328,9 +230,9 @@ const getAmountB = async (jar, amountA) => { await pickleJar.connect(user).deposit(_amt); }; - const depositV3 = async (jar, user, depositA, depositB) => { - await frax.connect(user).approve(jar.address, depositA); - await usdc.connect(user).approve(jar.address, depositB); + const depositV3 = async (jar, user, tokenA, tokenB, depositA, depositB) => { + await tokenA.connect(user).approve(jar.address, depositA); + await tokenB.connect(user).approve(jar.address, depositB); console.log("depositA => ", depositA.toString()); console.log("depositB => ", depositB.toString()); From 66a870f4398dac39a0df53d3561a185e8f3c52f4 Mon Sep 17 00:00:00 2001 From: Larry the Cucumber Date: Thu, 5 May 2022 00:19:10 -0700 Subject: [PATCH 12/13] fix temple-frax test --- .../strategies/backscratcher/strategy-frax-temple.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js index b98722d98..b17cd18e4 100644 --- a/src/tests/strategies/backscratcher/strategy-frax-temple.test.js +++ b/src/tests/strategies/backscratcher/strategy-frax-temple.test.js @@ -51,7 +51,7 @@ describe("StrategyFraxTemple", () => { escrow = await getContractAt("VoteEscrow", "0xc8418aF6358FFddA74e09Ca9CC3Fe03Ca6aDC5b0"); - strategyProxy = await deployContract("StrategyProxy"); + strategyProxy = await deployContract("StrategyProxyV2"); console.log("✅ StrategyProxy is deployed at ", strategyProxy.address); await locker.connect(lockerGovernance).setStrategy(strategyProxy.address); @@ -102,15 +102,15 @@ describe("StrategyFraxTemple", () => { await getWantFromWhale(FraxToken, toWei(10000), alice, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); - await getWantFromWhale(TEMPLEToken, toWei(10000), alice, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); + await getWantFromWhale(TEMPLEToken, toWei(10000), alice, "0xf6C75d85Ef66d57339f859247C38f8F47133BD39"); await getWantFromWhale(FraxToken, toWei(10000), bob, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); - await getWantFromWhale(TEMPLEToken, toWei(10000), bob, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); + await getWantFromWhale(TEMPLEToken, toWei(10000), bob, "0xf6C75d85Ef66d57339f859247C38f8F47133BD39"); await getWantFromWhale(FraxToken, toWei(10000), charles, "0x820A9eb227BF770A9dd28829380d53B76eAf1209"); - await getWantFromWhale(TEMPLEToken, toWei(10000), charles, "0x238eDaB57c91D1DB2f05FE85295B5F32d355567c"); + await getWantFromWhale(TEMPLEToken, toWei(10000), charles, "0xf6C75d85Ef66d57339f859247C38f8F47133BD39"); await getWantFromWhale(FXSToken, toWei(1000000), alice, "0xF977814e90dA44bFA03b6295A0616a897441aceC"); From b68b48b50732b906bb3ffbef4d8e8ac8d8c672d7 Mon Sep 17 00:00:00 2001 From: Cipio Date: Thu, 5 May 2022 20:38:33 -0500 Subject: [PATCH 13/13] Add Migration test for withdrawals --- .../backscratcher/migrationOfStrategyProxy.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js index 4c491f007..ecfa92129 100644 --- a/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js +++ b/src/tests/strategies/backscratcher/migrationOfStrategyProxy.test.js @@ -215,6 +215,12 @@ describe("StrategyFraxTemple", () => { console.log("Earn Complete"); await harvest(usdcJar, usdcStrategy); console.log("Harvest complete"); + + await daiJar.connect(alice).withdrawAll(); + console.log("Dai WithdrawAll complete"); + + await usdcJar.connect(alice).withdrawAll(); + console.log("USDC WithdrawAll complete"); }); const getAmountB = async (jar, amountA) => {