From 3dbeded0783a3664169a21ad9e4b3148d3bbe0de Mon Sep 17 00:00:00 2001 From: GuillaumeNervoXS <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Fri, 27 May 2022 09:14:43 +0200 Subject: [PATCH] saving Aave USDC and DAI genericAave (#38) --- .../GenericCompoundUpgradeable.sol | 4 +- deploy/GenericCompoundV3.ts | 78 ------ deploy/StrategyAaveFlashLoanImplementation.ts | 27 +-- deploy/lenders/GenericAave.ts | 88 +++++++ deploy/lenders/GenericAaveImplementation.ts | 19 ++ deploy/lenders/GenericCompoundV3.ts | 118 +++++++++ .../GenericCompoundV3Implementation.ts | 19 ++ deploy/lenders/saveFunds.ts | 146 +++++++++++ deploy/networks/mainnet.json | 10 +- package.json | 4 +- .../genericLender/fraxConvexStaker.ts | 9 +- .../genericLender/removeGenericCompound.ts | 12 - test/optimizerApr/fraxConvexStaking.test.ts | 13 +- test/optimizerApr/lenderCompound.test.ts | 36 +-- .../aaveFlashloanStrategyCoverage.test.ts | 226 +++++++++--------- 15 files changed, 544 insertions(+), 265 deletions(-) delete mode 100644 deploy/GenericCompoundV3.ts create mode 100644 deploy/lenders/GenericAave.ts create mode 100644 deploy/lenders/GenericAaveImplementation.ts create mode 100644 deploy/lenders/GenericCompoundV3.ts create mode 100644 deploy/lenders/GenericCompoundV3Implementation.ts create mode 100644 deploy/lenders/saveFunds.ts diff --git a/contracts/strategies/OptimizerAPR/genericLender/GenericCompoundUpgradeable.sol b/contracts/strategies/OptimizerAPR/genericLender/GenericCompoundUpgradeable.sol index 448b7d2..7f716c2 100644 --- a/contracts/strategies/OptimizerAPR/genericLender/GenericCompoundUpgradeable.sol +++ b/contracts/strategies/OptimizerAPR/genericLender/GenericCompoundUpgradeable.sol @@ -48,8 +48,8 @@ contract GenericCompoundUpgradeable is GenericLenderBaseUpgradeable { string memory _name, address _cToken, address[] memory governorList, - address[] memory keeperList, - address guardian + address guardian, + address[] memory keeperList ) external { _initialize(_strategy, _name, governorList, guardian, keeperList); diff --git a/deploy/GenericCompoundV3.ts b/deploy/GenericCompoundV3.ts deleted file mode 100644 index 1a8b25e..0000000 --- a/deploy/GenericCompoundV3.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { network } from 'hardhat'; -import { DeployFunction } from 'hardhat-deploy/types'; -import { CONTRACTS_ADDRESSES, ChainId } from '@angleprotocol/sdk'; -import { BigNumber } from 'ethers'; -import { GenericCompoundUpgradeable, GenericCompoundUpgradeable__factory } from '../typechain'; -import { parseUnits } from 'ethers/lib/utils'; -import { ProxyAdmin, ProxyAdmin__factory } from '@angleprotocol/sdk/dist/constants/types'; - -const func: DeployFunction = async ({ deployments, ethers }) => { - const { deploy } = deployments; - const { deployer, keeper: fakeKeeper } = await ethers.getNamedSigners(); - const collateralName = 'DAI'; - - let guardian: string; - let governor: string; - let strategyAddress, lenderAddress, proxyAdminAddress: string; - let keeper: string; - - // if fork we suppose that we are in mainnet - // eslint-disable-next-line - let json = (await import('./networks/mainnet.json')) as any; - if (!network.live) { - guardian = CONTRACTS_ADDRESSES[ChainId.MAINNET].Guardian as string; - governor = CONTRACTS_ADDRESSES[ChainId.MAINNET].GovernanceMultiSig as string; - strategyAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName]?.Strategies - ?.GenericOptimisedLender as string; - lenderAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName] - ?.GenericCompound as string; - proxyAdminAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].ProxyAdmin as string; - keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E'; - } else { - guardian = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].Guardian!; - governor = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].GovernanceMultiSig as string; - strategyAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] - ?.Strategies?.GenericOptimisedLender as string; - lenderAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] - ?.GenericCompound as string; - proxyAdminAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].ProxyAdmin as string; - keeper = fakeKeeper.address; - } - - const lenderImplementation = await deploy(`GenericCompoundV3_Implementation`, { - contract: 'GenericCompoundUpgradeable', - from: deployer.address, - args: [], - }); - const lenderImplementationAddress = (await ethers.getContract(`GenericCompoundV3_Implementation`)).address; - console.log('success: deployed lender implementation', lenderImplementationAddress); - console.log(`Deploy cost: ${(lenderImplementation?.receipt?.gasUsed as BigNumber)?.toString()} (implem)`); - - if (!network.live) { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [governor], - }); - const governorSigner = await ethers.getSigner(governor); - await network.provider.send('hardhat_setBalance', [governor, '0x10000000000000000000000000000']); - - const proxyAdmin = new ethers.Contract( - proxyAdminAddress, - ProxyAdmin__factory.createInterface(), - governorSigner, - ) as ProxyAdmin; - await (await proxyAdmin.connect(governorSigner).upgrade(lenderAddress, lenderImplementation?.address)).wait(); - console.log('Upgrade lender: success'); - - const lenderCompound = new ethers.Contract( - lenderAddress, - GenericCompoundUpgradeable__factory.createInterface(), - deployer, - ) as GenericCompoundUpgradeable; - await await lenderCompound.connect(governorSigner).setDust(parseUnits('1', 8)); - console.log('Set dust: success'); - } -}; - -func.tags = ['genericCompoundV3']; -export default func; diff --git a/deploy/StrategyAaveFlashLoanImplementation.ts b/deploy/StrategyAaveFlashLoanImplementation.ts index 89c3b10..518f615 100644 --- a/deploy/StrategyAaveFlashLoanImplementation.ts +++ b/deploy/StrategyAaveFlashLoanImplementation.ts @@ -1,27 +1,24 @@ import { DeployFunction } from 'hardhat-deploy/types'; -import { CONTRACTS_ADDRESSES, Interfaces } from '@angleprotocol/sdk'; -import { BigNumber, Contract } from 'ethers'; -import { AaveFlashloanStrategy__factory, PoolManager } from '../typechain'; const func: DeployFunction = async ({ deployments, ethers }) => { const { deploy } = deployments; const [deployer] = await ethers.getSigners(); - const governor = CONTRACTS_ADDRESSES[1].GovernanceMultiSig as string; - const guardian = CONTRACTS_ADDRESSES[1].Guardian as string; - const proxyAdmin = '0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b'; + // const governor = CONTRACTS_ADDRESSES[1].GovernanceMultiSig as string; + // const guardian = CONTRACTS_ADDRESSES[1].Guardian as string; + // const proxyAdmin = '0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b'; const flashMintLib = '0x169487a55dE79476125A56B07C36cA8dbF37a373'; // (await deployments.getOrNull('FlashMintLib')).address - const collats: { [key: string]: { interestRateStrategyAddress: string } } = { - DAI: { - interestRateStrategyAddress: '0xfffE32106A68aA3eD39CcCE673B646423EEaB62a', - }, - // USDC: { - // interestRateStrategyAddress: '0x8Cae0596bC1eD42dc3F04c4506cfe442b3E74e27', - // }, - }; + // const collats: { [key: string]: { interestRateStrategyAddress: string } } = { + // DAI: { + // interestRateStrategyAddress: '0xfffE32106A68aA3eD39CcCE673B646423EEaB62a', + // }, + // // USDC: { + // // interestRateStrategyAddress: '0x8Cae0596bC1eD42dc3F04c4506cfe442b3E74e27', + // // }, + // }; - const keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E'; + // const keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E'; let strategyImplementation = await deployments.getOrNull('AaveFlashloanStrategy_NewImplementation'); diff --git a/deploy/lenders/GenericAave.ts b/deploy/lenders/GenericAave.ts new file mode 100644 index 0000000..8bf83da --- /dev/null +++ b/deploy/lenders/GenericAave.ts @@ -0,0 +1,88 @@ +import { network } from 'hardhat'; +import { DeployFunction } from 'hardhat-deploy/types'; +import { CONTRACTS_ADDRESSES, ChainId } from '@angleprotocol/sdk'; +import { BigNumber } from 'ethers'; +import { GenericAaveNoStaker__factory, OptimizerAPRStrategy, OptimizerAPRStrategy__factory } from '../../typechain'; +import { impersonate } from '../../test/test-utils'; + +const func: DeployFunction = async ({ deployments, ethers }) => { + const { deploy } = deployments; + const { deployer, keeper: fakeKeeper } = await ethers.getNamedSigners(); + const collats = ['USDC', 'DAI']; + + let guardian: string; + let governor: string; + let strategyAddress, proxyAdminAddress: string; + let keeper: string; + + // if fork we suppose that we are in mainnet + // eslint-disable-next-line + let json = (await import('../networks/mainnet.json')) as any; + if (!network.live) { + guardian = CONTRACTS_ADDRESSES[ChainId.MAINNET].Guardian as string; + governor = CONTRACTS_ADDRESSES[ChainId.MAINNET].GovernanceMultiSig as string; + proxyAdminAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].ProxyAdmin as string; + keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E'; + } else { + guardian = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].Guardian!; + governor = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].GovernanceMultiSig as string; + proxyAdminAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].ProxyAdmin as string; + keeper = fakeKeeper.address; + } + + const lenderImplementationAddress = (await ethers.getContract(`GenericAaveNoStaker_Implementation`)).address; + console.log('deployed lender Aave implementation', lenderImplementationAddress); + console.log(''); + + for (const collat in collats) { + const collateralName = collats[collat]; + console.log(''); + console.log('Handling collat: ', collateralName); + if (!network.live) { + strategyAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName]?.Strategies + ?.GenericOptimisedLender as string; + } else { + strategyAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] + ?.Strategies?.GenericOptimisedLender as string; + } + + const initializeData = GenericAaveNoStaker__factory.createInterface().encodeFunctionData('initialize', [ + strategyAddress, + `Aave Lender ${collateralName}`, + true, + [governor], + guardian, + [keeper], + ]); + + const proxyLender = await deploy(`GenericAaveNoStaker_${collateralName}`, { + contract: 'TransparentUpgradeableProxy', + from: deployer.address, + args: [lenderImplementationAddress, proxyAdminAddress, initializeData], + }); + + console.log( + `Lender GenericAaveNoStaker_${collateralName} (proxy) successfully deployed at address: `, + proxyLender.address, + ); + console.log(`Deploy cost: ${(proxyLender.receipt?.gasUsed as BigNumber)?.toString()} (proxy)`); + + if (!network.live) { + const strategy = new ethers.Contract( + strategyAddress, + OptimizerAPRStrategy__factory.createInterface(), + deployer, + ) as OptimizerAPRStrategy; + + await impersonate(guardian, async acc => { + await network.provider.send('hardhat_setBalance', [guardian, '0x10000000000000000000000000000']); + await await strategy.connect(acc).addLender(proxyLender.address); + console.log('Add lender: success'); + }); + } + } +}; + +func.tags = ['genericAave']; +func.dependencies = ['genericAaveImplementation']; +export default func; diff --git a/deploy/lenders/GenericAaveImplementation.ts b/deploy/lenders/GenericAaveImplementation.ts new file mode 100644 index 0000000..a3a7eb8 --- /dev/null +++ b/deploy/lenders/GenericAaveImplementation.ts @@ -0,0 +1,19 @@ +import { DeployFunction } from 'hardhat-deploy/types'; +import { BigNumber } from 'ethers'; + +const func: DeployFunction = async ({ deployments, ethers }) => { + const { deploy } = deployments; + const { deployer } = await ethers.getNamedSigners(); + + const lenderImplementation = await deploy(`GenericAaveNoStaker_Implementation`, { + contract: 'GenericAaveNoStaker', + from: deployer.address, + args: [], + }); + console.log('success: deployed lender implementation', lenderImplementation.address); + console.log(`Deploy cost: ${(lenderImplementation?.receipt?.gasUsed as BigNumber)?.toString()} (implem)`); + console.log(''); +}; + +func.tags = ['genericAaveImplementation']; +export default func; diff --git a/deploy/lenders/GenericCompoundV3.ts b/deploy/lenders/GenericCompoundV3.ts new file mode 100644 index 0000000..4c80685 --- /dev/null +++ b/deploy/lenders/GenericCompoundV3.ts @@ -0,0 +1,118 @@ +import { network } from 'hardhat'; +import { DeployFunction } from 'hardhat-deploy/types'; +import { CONTRACTS_ADDRESSES, ChainId } from '@angleprotocol/sdk'; +import { BigNumber } from 'ethers'; +import { + ERC20, + ERC20__factory, + GenericCompoundUpgradeable, + GenericCompoundUpgradeable__factory, + OptimizerAPRStrategy, + OptimizerAPRStrategy__factory, +} from '../../typechain'; +import { parseUnits } from 'ethers/lib/utils'; +import { impersonate } from '../../test/test-utils'; + +const func: DeployFunction = async ({ deployments, ethers }) => { + const { deploy } = deployments; + const { deployer, keeper: fakeKeeper } = await ethers.getNamedSigners(); + const collats = ['USDC', 'DAI']; + + let guardian: string; + let governor: string; + let strategyAddress, proxyAdminAddress: string; + let keeper: string; + + // if fork we suppose that we are in mainnet + // eslint-disable-next-line + let json = (await import('../networks/mainnet.json')) as any; + if (!network.live) { + guardian = CONTRACTS_ADDRESSES[ChainId.MAINNET].Guardian as string; + governor = CONTRACTS_ADDRESSES[ChainId.MAINNET].GovernanceMultiSig as string; + proxyAdminAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].ProxyAdmin as string; + keeper = '0xcC617C6f9725eACC993ac626C7efC6B96476916E'; + } else { + guardian = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].Guardian!; + governor = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].GovernanceMultiSig as string; + proxyAdminAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].ProxyAdmin as string; + keeper = fakeKeeper.address; + } + + const lenderImplementationAddress = (await ethers.getContract(`GenericCompoundV3_Implementation`)).address; + console.log('deployed lender Compound implementation', lenderImplementationAddress); + console.log(''); + + for (const collat in collats) { + const collateralName = collats[collat]; + console.log(''); + console.log('Handling collat: ', collateralName); + if (!network.live) { + strategyAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName]?.Strategies + ?.GenericOptimisedLender as string; + } else { + strategyAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] + ?.Strategies?.GenericOptimisedLender as string; + } + + const token = (await ethers.getContractAt(ERC20__factory.abi, json[collateralName])) as ERC20; + const tokenDecimal = await token.decimals(); + const cToken = json.Compound[collateralName]; + + console.log('token ', token.address); + console.log('cToken ', cToken); + + const initializeData = GenericCompoundUpgradeable__factory.createInterface().encodeFunctionData('initialize', [ + strategyAddress, + `Compound Lender ${collateralName}`, + cToken, + [governor], + guardian, + [keeper], + ]); + + const proxyLender = await deploy(`GenericCompoundV3_${collateralName}`, { + contract: 'TransparentUpgradeableProxy', + from: deployer.address, + args: [lenderImplementationAddress, proxyAdminAddress, initializeData], + }); + + console.log( + `Lender GenericCompoundV3_${collateralName} (proxy) successfully deployed at address: `, + proxyLender.address, + ); + console.log(`Deploy cost: ${(proxyLender.receipt?.gasUsed as BigNumber)?.toString()} (proxy)`); + + if (!network.live) { + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [governor], + }); + const governorSigner = await ethers.getSigner(governor); + await network.provider.send('hardhat_setBalance', [governor, '0x10000000000000000000000000000']); + + const lenderCompound = new ethers.Contract( + proxyLender.address, + GenericCompoundUpgradeable__factory.createInterface(), + deployer, + ) as GenericCompoundUpgradeable; + + const strategy = new ethers.Contract( + strategyAddress, + OptimizerAPRStrategy__factory.createInterface(), + deployer, + ) as OptimizerAPRStrategy; + + await impersonate(guardian, async acc => { + await network.provider.send('hardhat_setBalance', [guardian, '0x10000000000000000000000000000']); + await await lenderCompound.connect(acc).setDust(parseUnits('1', tokenDecimal + 2)); + console.log('Set dust: success'); + await await strategy.connect(acc).addLender(proxyLender.address); + console.log('Add lender: success'); + }); + } + } +}; + +func.tags = ['genericCompoundV3']; +func.dependencies = ['genericCompoundV3Implementation']; +export default func; diff --git a/deploy/lenders/GenericCompoundV3Implementation.ts b/deploy/lenders/GenericCompoundV3Implementation.ts new file mode 100644 index 0000000..9e5c476 --- /dev/null +++ b/deploy/lenders/GenericCompoundV3Implementation.ts @@ -0,0 +1,19 @@ +import { DeployFunction } from 'hardhat-deploy/types'; +import { BigNumber } from 'ethers'; + +const func: DeployFunction = async ({ deployments, ethers }) => { + const { deploy } = deployments; + const { deployer } = await ethers.getNamedSigners(); + + const lenderImplementation = await deploy(`GenericCompoundV3_Implementation`, { + contract: 'GenericCompoundUpgradeable', + from: deployer.address, + args: [], + }); + console.log('success: deployed lender implementation', lenderImplementation.address); + console.log(`Deploy cost: ${(lenderImplementation?.receipt?.gasUsed as BigNumber)?.toString()} (implem)`); + console.log(''); +}; + +func.tags = ['genericCompoundV3Implementation']; +export default func; diff --git a/deploy/lenders/saveFunds.ts b/deploy/lenders/saveFunds.ts new file mode 100644 index 0000000..d793c3a --- /dev/null +++ b/deploy/lenders/saveFunds.ts @@ -0,0 +1,146 @@ +import { network } from 'hardhat'; +import { DeployFunction } from 'hardhat-deploy/types'; +import { CONTRACTS_ADDRESSES, ChainId } from '@angleprotocol/sdk'; +import { + ERC20, + ERC20__factory, + GenericAaveNoStaker, + GenericAaveNoStaker__factory, + IAaveIncentivesController, + IStakedAave, + IStakedAave__factory, + OptimizerAPRStrategy, + OptimizerAPRStrategy__factory, +} from '../../typechain'; +import { impersonate } from '../../test/test-utils'; +import { + GenericAave, + GenericAave__factory, + GenericCompound, + GenericCompound__factory, +} from '@angleprotocol/sdk/dist/constants/types'; +import { expect } from '../../test/test-utils/chai-setup'; +import { parseUnits } from 'ethers/lib/utils'; + +const func: DeployFunction = async ({ deployments, ethers }) => { + const { deployer } = await ethers.getNamedSigners(); + const collats = ['USDC', 'DAI']; + + let guardian: string; + let governor: string; + let strategyAddress, oldLenderAaveAddress, oldLenderCompoundAddress: string; + + for (const collat in collats) { + const collateralName = collats[collat]; + console.log(''); + console.log('Saving for collat: ', collateralName); + + let json = (await import('../networks/mainnet.json')) as any; + // operation only doable in fork + if (!network.live) { + guardian = CONTRACTS_ADDRESSES[ChainId.MAINNET].Guardian as string; + governor = CONTRACTS_ADDRESSES[ChainId.MAINNET].GovernanceMultiSig as string; + strategyAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName]?.Strategies + ?.GenericOptimisedLender as string; + oldLenderAaveAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName] + ?.GenericAave as string; + oldLenderCompoundAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName] + ?.GenericCompound as string; + const stkAaveAddress = json.Aave.stkAave; + const aaveAddress = json.Aave.aave; + const compAddress = json.Compound.COMP; + const incentiveControllerAddress = '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5'; + const aTokenAddress = json.Aave.aDAI; + + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [governor], + }); + const governorSigner = await ethers.getSigner(governor); + await network.provider.send('hardhat_setBalance', [governor, '0x10000000000000000000000000000']); + + const aToken = (await ethers.getContractAt(ERC20__factory.abi, aTokenAddress)) as ERC20; + const oldLenderAave = new ethers.Contract( + oldLenderAaveAddress, + GenericAave__factory.createInterface(), + deployer, + ) as GenericAave; + const oldLenderCompound = new ethers.Contract( + oldLenderCompoundAddress, + GenericCompound__factory.createInterface(), + deployer, + ) as GenericCompound; + + const newLenderCompAddress = (await ethers.getContract(`GenericCompoundV3_${collateralName}`)).address; + const newLenderAaveAddress = (await ethers.getContract(`GenericAaveNoStaker_${collateralName}`)).address; + const newLenderAave = new ethers.Contract( + newLenderAaveAddress, + GenericAaveNoStaker__factory.createInterface(), + deployer, + ) as GenericAaveNoStaker; + + const strategy = new ethers.Contract( + strategyAddress, + OptimizerAPRStrategy__factory.createInterface(), + deployer, + ) as OptimizerAPRStrategy; + + const stkAave = (await ethers.getContractAt(IStakedAave__factory.abi, stkAaveAddress)) as IStakedAave; + const aave = (await ethers.getContractAt(ERC20__factory.abi, aaveAddress)) as ERC20; + + const incentiveController = new ethers.Contract( + incentiveControllerAddress, + [ + 'function claimRewardsOnBehalf(address[] calldata assets,uint256 amount,address user,address to) external returns (uint256)', + 'function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256)', + ], + deployer, + ) as IAaveIncentivesController; + + const aTokenBalanceOld = await aToken.balanceOf(oldLenderAaveAddress); + console.log('old balnce fetched for lender '); + await strategy.connect(governorSigner).forceRemoveLender(oldLenderAaveAddress); + console.log('Remove old lender: success'); + + // Transfer, harvest and transfer the rewards to the new lender + // This is done in this order to set the cooldown to 0 on the oldLender such that no Aave will be sold + // while still being able to claim the new stkAave + const claimableRewards = await incentiveController.getRewardsBalance([aToken.address], oldLenderAaveAddress); + const oldLenderStkAaveBalance = await stkAave.balanceOf(oldLenderAaveAddress); + const oldLenderAaveBalance = await aave.balanceOf(oldLenderAaveAddress); + expect(oldLenderAaveBalance).to.be.equal(parseUnits('0', 18)); + await impersonate(guardian, async acc => { + await network.provider.send('hardhat_setBalance', [guardian, '0x10000000000000000000000000000']); + // USDC don't have this problem because there hasn't been any harvest yet + if (collateralName == 'DAI') { + await (await oldLenderAave.connect(acc).sweep(stkAave.address, newLenderAaveAddress)).wait(); + console.log('first sweep: success'); + } else if (collateralName == 'USDC') { + await (await oldLenderCompound.connect(acc).sweep(compAddress, newLenderCompAddress)).wait(); + console.log('Comp transfer: success'); + } + await (await oldLenderAave.connect(acc).harvest()).wait(); + console.log('lender harvest: success'); + await (await oldLenderAave.connect(acc).sweep(stkAave.address, newLenderAaveAddress)).wait(); + console.log('second sweep: success'); + }); + const newLenderStkAaveBalance = await stkAave.balanceOf(newLenderAaveAddress); + expect(newLenderStkAaveBalance).to.be.closeTo( + oldLenderStkAaveBalance.add(claimableRewards), + parseUnits('0.01', 18), + ); + + // Harvest and verify that all funds have been transferred to the new lender + await strategy.connect(deployer)['harvest()']; + console.log('strategy harvest: success'); + const aTokenBalanceNew = await aToken.balanceOf(newLenderAaveAddress); + expect(aTokenBalanceNew).to.be.closeTo(aTokenBalanceOld, parseUnits('0.1', 18)); + } + + // also sweep the old genericFrax aave + // await(await oldLenderAave.connect(acc).sweep(stkAave.address, newLenderAaveAddress)).wait(); + } +}; + +func.tags = ['saveFundsAave']; +export default func; diff --git a/deploy/networks/mainnet.json b/deploy/networks/mainnet.json index 9565aba..c0ac677 100644 --- a/deploy/networks/mainnet.json +++ b/deploy/networks/mainnet.json @@ -25,11 +25,11 @@ }, "Aave": { - "AgToken_DAI": "0x028171bCA77440897B824Ca71D1c56caC55b68A3", - "AgToken_BTC": "0x9ff58f4fFB29fA2266Ab25e75e2A8b3503311656", - "AgToken_USDC": "0xBcca60bB61934080951369a648Fb03DF4F96263C", - "AgToken_FEI": "0x683923dB55Fead99A79Fa01A27EeC3cB19679cC3", - "AgToken_FRAX": "0xd4937682df3C8aEF4FE912A96A74121C0829E664", + "aDAI": "0x028171bCA77440897B824Ca71D1c56caC55b68A3", + "aBTC": "0x9ff58f4fFB29fA2266Ab25e75e2A8b3503311656", + "aUSDC": "0xBcca60bB61934080951369a648Fb03DF4F96263C", + "aFEI": "0x683923dB55Fead99A79Fa01A27EeC3cB19679cC3", + "aFRAX": "0xd4937682df3C8aEF4FE912A96A74121C0829E664", "Pool": "0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9", "protocolDataProvider": "0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d", "stkAave": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", diff --git a/package.json b/package.json index f99a359..cefc833 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "lint": "yarn lint:js:fix && yarn lint:sol", "lint:js:fix": "eslint --ignore-path .gitignore --fix --max-warnings 30 'scripts/**/*.ts' 'test/**/*.{js,ts}' 'deploy/*.{js,ts}' '*.{js,ts}'", "lint:sol": "solhint --fix --max-warnings 20 \"contracts/**/*.sol\"", - "node:fork:upgrade:genericCompound": "hardhat deploy --network localhost --tags genericCompoundV3", + "node:fork:deploy:genericAave": "hardhat deploy --network localhost --tags genericAave", + "node:fork:saveAave": "hardhat deploy --network localhost --tags saveFundsAave", + "node:fork:deploy:genericCompound": "hardhat deploy --network localhost --tags genericCompoundV3", "node:fork:strategy:eth": "hardhat deploy --network localhost --tags collat_strategyStETH", "node:fork:strategy:fraxStaking": "hardhat deploy --network localhost --tags lenderConvexAFraxStaking", "node:fork:strategy:aaveUpgrade": "FORK=true hardhat node --tags aave_flashloan_strategy_upgrade", diff --git a/scripts/mainnet-fork/genericLender/fraxConvexStaker.ts b/scripts/mainnet-fork/genericLender/fraxConvexStaker.ts index c68aa1d..8db865d 100644 --- a/scripts/mainnet-fork/genericLender/fraxConvexStaker.ts +++ b/scripts/mainnet-fork/genericLender/fraxConvexStaker.ts @@ -8,11 +8,8 @@ import { import { CONTRACTS_ADDRESSES, ChainId } from '@angleprotocol/sdk'; import { network, ethers } from 'hardhat'; import { parseUnits } from 'ethers/lib/utils'; -import { ERC20, ERC20__factory, OptimizerAPRStrategy, OptimizerAPRStrategy__factory } from '../../../typechain'; -import { logBN } from '../../../test/utils-interaction'; -import { time } from '../../../test/test-utils/helpers'; +import { OptimizerAPRStrategy, OptimizerAPRStrategy__factory } from '../../../typechain'; import { DAY } from '../../../test/contants'; -import { BigNumber, providers } from 'ethers'; async function main() { // =============== Simulation parameters ==================== @@ -38,8 +35,8 @@ async function main() { ?.Strategies?.GenericOptimisedLender as string; } - const FRAX = '0x853d955aCEf822Db058eb8505911ED77F175b99e'; - const wantToken = (await ethers.getContractAt(ERC20__factory.abi, FRAX)) as ERC20; + // const FRAX = '0x853d955aCEf822Db058eb8505911ED77F175b99e'; + // const wantToken = (await ethers.getContractAt(ERC20__factory.abi, FRAX)) as ERC20; const strategy = new ethers.Contract( strategyAddress, diff --git a/scripts/mainnet-fork/genericLender/removeGenericCompound.ts b/scripts/mainnet-fork/genericLender/removeGenericCompound.ts index bc5d44a..9fe7757 100644 --- a/scripts/mainnet-fork/genericLender/removeGenericCompound.ts +++ b/scripts/mainnet-fork/genericLender/removeGenericCompound.ts @@ -1,5 +1,3 @@ -import { ProxyAdmin, ProxyAdmin__factory } from '@angleprotocol/sdk/dist/constants/interfaces'; - import { CONTRACTS_ADDRESSES, ChainId } from '@angleprotocol/sdk'; import { network, ethers } from 'hardhat'; import { parseUnits } from 'ethers/lib/utils'; @@ -9,8 +7,6 @@ import { OptimizerAPRStrategy, OptimizerAPRStrategy__factory, } from '../../../typechain'; -import yargs from 'yargs'; -const argv = yargs.env('').boolean('ci').parseSync(); async function main() { // =============== Simulation parameters ==================== @@ -19,32 +15,24 @@ async function main() { const collateralName = 'DAI'; let strategyAddress: string; - let poolManagerAddress: string; let guardian: string; let governor: string; let lenderAddress: string; - let proxyAdminAddress: string; if (!network.live) { guardian = CONTRACTS_ADDRESSES[ChainId.MAINNET].Guardian as string; governor = CONTRACTS_ADDRESSES[ChainId.MAINNET].GovernanceMultiSig as string; - poolManagerAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName] - ?.PoolManager as string; strategyAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName]?.Strategies ?.GenericOptimisedLender as string; lenderAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].agEUR?.collaterals?.[collateralName] ?.GenericCompound as string; - proxyAdminAddress = CONTRACTS_ADDRESSES[ChainId.MAINNET].ProxyAdmin as string; } else { guardian = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].Guardian!; governor = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].GovernanceMultiSig as string; - poolManagerAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] - ?.PoolManager as string; strategyAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] ?.Strategies?.GenericOptimisedLender as string; lenderAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].agEUR?.collaterals?.[collateralName] ?.GenericCompound as string; - proxyAdminAddress = CONTRACTS_ADDRESSES[network.config.chainId as ChainId].ProxyAdmin as string; } const strategy = new ethers.Contract( diff --git a/test/optimizerApr/fraxConvexStaking.test.ts b/test/optimizerApr/fraxConvexStaking.test.ts index 57d8e4b..5d51be4 100644 --- a/test/optimizerApr/fraxConvexStaking.test.ts +++ b/test/optimizerApr/fraxConvexStaking.test.ts @@ -10,7 +10,6 @@ import { IMockFraxUnifiedFarm, IMockFraxUnifiedFarm__factory, IPoolRegistryFrax, - IPoolRegistryFrax__factory, IStakedAave, IStakedAave__factory, MockToken, @@ -73,14 +72,12 @@ let governor: SignerWithAddress, guardian: SignerWithAddress, user: SignerWithAd let strategy: OptimizerAPRStrategy; let token: ERC20; let aToken: ERC20; -let frax: ERC20; let nativeRewardToken: MockToken; let tokenDecimal: number; let manager: PoolManager; let lenderAave: GenericAaveFraxConvexStaker; let stkAave: IStakedAave; let aFraxStakingContract: IMockFraxUnifiedFarm; -let poolRegistry: IPoolRegistryFrax; let oracleNativeReward: AggregatorV3Interface; let oracleStkAave: AggregatorV3Interface; let oneInch: string; @@ -112,7 +109,7 @@ describe('OptimizerAPR - lenderAaveFraxConvexStaker', () => { token = (await ethers.getContractAt(ERC20__factory.abi, '0x853d955aCEf822Db058eb8505911ED77F175b99e')) as ERC20; aToken = (await ethers.getContractAt(ERC20__factory.abi, '0xd4937682df3C8aEF4FE912A96A74121C0829E664')) as ERC20; - frax = (await ethers.getContractAt(ERC20__factory.abi, '0x853d955aCEf822Db058eb8505911ED77F175b99e')) as ERC20; + // frax = (await ethers.getContractAt(ERC20__factory.abi, '0x853d955aCEf822Db058eb8505911ED77F175b99e')) as ERC20; nativeRewardToken = (await ethers.getContractAt( MockToken__factory.abi, '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', @@ -140,10 +137,10 @@ describe('OptimizerAPR - lenderAaveFraxConvexStaker', () => { '0x547a514d5e3769680Ce22B2361c10Ea13619e8a9', )) as AggregatorV3Interface; - poolRegistry = (await ethers.getContractAt( - IPoolRegistryFrax__factory.abi, - '0x41a5881c17185383e19Df6FA4EC158a6F4851A69', - )) as IPoolRegistryFrax; + // poolRegistry = (await ethers.getContractAt( + // IPoolRegistryFrax__factory.abi, + // '0x41a5881c17185383e19Df6FA4EC158a6F4851A69', + // )) as IPoolRegistryFrax; guardianError = `AccessControl: account ${user.address.toLowerCase()} is missing role ${guardianRole}`; keeperError = `AccessControl: account ${user.address.toLowerCase()} is missing role ${keeperRole}`; diff --git a/test/optimizerApr/lenderCompound.test.ts b/test/optimizerApr/lenderCompound.test.ts index c97e60b..af6ad67 100644 --- a/test/optimizerApr/lenderCompound.test.ts +++ b/test/optimizerApr/lenderCompound.test.ts @@ -1,8 +1,6 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; -import { Contract, utils } from 'ethers'; +import { utils } from 'ethers'; import { - AggregatorV3Interface, - AggregatorV3Interface__factory, CErc20I, CErc20I__factory, ERC20, @@ -11,7 +9,6 @@ import { GenericCompoundUpgradeable__factory, IComptroller, IComptroller__factory, - MockToken, OptimizerAPRStrategy, OptimizerAPRStrategy__factory, PoolManager, @@ -22,9 +19,8 @@ import { ethers, network } from 'hardhat'; import { expect } from '../test-utils/chai-setup'; import { BASE_TOKENS } from '../utils'; import { parseUnits } from 'ethers/lib/utils'; -import { findBalancesSlot, logBN, setTokenBalanceFor } from '../utils-interaction'; +import { findBalancesSlot, setTokenBalanceFor } from '../utils-interaction'; import { time, ZERO_ADDRESS } from '../test-utils/helpers'; -import { DAY } from '../contants'; async function initStrategy( governor: SignerWithAddress, @@ -53,7 +49,7 @@ async function initLenderCompound( const lender = (await deployUpgradeable( new GenericCompoundUpgradeable__factory(guardian), )) as GenericCompoundUpgradeable; - await lender.initialize(strategy.address, name, cToken, [governor.address], [keeper.address], guardian.address); + await lender.initialize(strategy.address, name, cToken, [governor.address], guardian.address, [keeper.address]); await strategy.connect(governor).addLender(lender.address); return { lender }; } @@ -68,8 +64,6 @@ let manager: PoolManager; let lenderCompound: GenericCompoundUpgradeable; let comptroller: IComptroller; let cToken: CErc20I; -let ANGLE: MockToken; -let oracleReward: AggregatorV3Interface; const guardianRole = ethers.utils.solidityKeccak256(['string'], ['GUARDIAN_ROLE']); const strategyRole = ethers.utils.solidityKeccak256(['string'], ['STRATEGY_ROLE']); @@ -77,7 +71,6 @@ const keeperRole = ethers.utils.solidityKeccak256(['string'], ['KEEPER_ROLE']); let guardianError: string; let strategyError: string; let keeperError: string; -let oneInch: string; // Start test block describe('OptimizerAPR - lenderCompound', () => { @@ -97,17 +90,17 @@ describe('OptimizerAPR - lenderCompound', () => { ], '0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B', )) as IComptroller; - ANGLE = (await deploy('MockToken', ['ANGLE', 'ANGLE', 18])) as MockToken; + // ANGLE = (await deploy('MockToken', ['ANGLE', 'ANGLE', 18])) as MockToken; - oracleReward = (await ethers.getContractAt( - AggregatorV3Interface__factory.abi, - '0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5', - )) as AggregatorV3Interface; + // oracleReward = (await ethers.getContractAt( + // AggregatorV3Interface__factory.abi, + // '0xdbd020CAeF83eFd542f4De03e3cF0C28A4428bd5', + // )) as AggregatorV3Interface; guardianError = `AccessControl: account ${user.address.toLowerCase()} is missing role ${guardianRole}`; strategyError = `AccessControl: account ${user.address.toLowerCase()} is missing role ${strategyRole}`; keeperError = `AccessControl: account ${user.address.toLowerCase()} is missing role ${keeperRole}`; - oneInch = '0x1111111254fb6c44bAC0beD2854e76F90643097d'; + // oneInch = '0x1111111254fb6c44bAC0beD2854e76F90643097d'; }); beforeEach(async () => { @@ -153,14 +146,9 @@ describe('OptimizerAPR - lenderCompound', () => { new GenericCompoundUpgradeable__factory(guardian), )) as GenericCompoundUpgradeable; await expect( - lender.initialize( - strategy.address, - 'wrong lender', - wrongCToken.address, - [governor.address], - [keeper.address], - guardian.address, - ), + lender.initialize(strategy.address, 'wrong lender', wrongCToken.address, [governor.address], guardian.address, [ + keeper.address, + ]), ).to.be.revertedWith('WrongCToken'); }); it('Parameters', async () => { diff --git a/test/strategyAaveFlashLoan/aaveFlashloanStrategyCoverage.test.ts b/test/strategyAaveFlashLoan/aaveFlashloanStrategyCoverage.test.ts index 3eb9767..1f22c37 100644 --- a/test/strategyAaveFlashLoan/aaveFlashloanStrategyCoverage.test.ts +++ b/test/strategyAaveFlashLoan/aaveFlashloanStrategyCoverage.test.ts @@ -9,26 +9,22 @@ import { ERC20, ERC20__factory, IAaveIncentivesController__factory, - IStakedAave, - IStakedAave__factory, AaveFlashloanStrategy__factory, PoolManager, IAaveIncentivesController, IProtocolDataProvider__factory, IProtocolDataProvider, } from '../../typechain'; -import { findBalancesSlot, logBN, setTokenBalanceFor } from '../utils-interaction'; +import { findBalancesSlot, setTokenBalanceFor } from '../utils-interaction'; import { parseUnits } from 'ethers/lib/utils'; import { BASE_PARAMS } from '../utils'; -import qs from 'qs'; -import axios from 'axios'; describe('AaveFlashloanStrategy - Coverage', () => { // ATokens let aToken: ERC20, debtToken: ERC20; // Tokens - let wantToken: ERC20, aave: ERC20, stkAave: IStakedAave; + let wantToken: ERC20, aave: ERC20; let decimalsToken: number; // Guardians @@ -69,10 +65,10 @@ describe('AaveFlashloanStrategy - Coverage', () => { wantToken = (await ethers.getContractAt(ERC20__factory.abi, tokenAddress)) as ERC20; decimalsToken = await wantToken.decimals(); aave = (await ethers.getContractAt(ERC20__factory.abi, '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9')) as ERC20; - stkAave = (await ethers.getContractAt( - IStakedAave__factory.abi, - '0x4da27a545c0c5B758a6BA100e3a049001de870f5', - )) as IStakedAave; + // stkAave = (await ethers.getContractAt( + // IStakedAave__factory.abi, + // '0x4da27a545c0c5B758a6BA100e3a049001de870f5', + // )) as IStakedAave; [deployer, proxyAdmin, governor, guardian, user, keeper] = await ethers.getSigners(); @@ -141,29 +137,31 @@ describe('AaveFlashloanStrategy - Coverage', () => { await strategy.connect(keeper)['harvest()']({ gasLimit: 3e6 }); }); - it('adjustPosition - currentCollatRatio > _targetCollatRatio', async () => { - await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { - await incentivesController - .connect(acc) - .configureAssets([aToken.address, debtToken.address], [ethers.constants.Zero, ethers.constants.Zero]); - }); - - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - const { borrows } = await strategy.getCurrentPosition(); - expect(borrows).to.be.equal(ethers.constants.Zero); - }); - - it('_liquidatePosition - withdrawCheck - success', async () => { - await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { - await incentivesController - .connect(acc) - .configureAssets([aToken.address, debtToken.address], [ethers.constants.Zero, ethers.constants.Zero]); + describe('adjustPosition', () => { + it('adjustPosition - currentCollatRatio > _targetCollatRatio', async () => { + await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { + await incentivesController + .connect(acc) + .configureAssets([aToken.address, debtToken.address], [ethers.constants.Zero, ethers.constants.Zero]); + }); await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); const { borrows } = await strategy.getCurrentPosition(); expect(borrows).to.be.equal(ethers.constants.Zero); }); + it('_liquidatePosition - withdrawCheck - success', async () => { + await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { + await incentivesController + .connect(acc) + .configureAssets([aToken.address, debtToken.address], [ethers.constants.Zero, ethers.constants.Zero]); + + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); + const { borrows } = await strategy.getCurrentPosition(); + expect(borrows).to.be.equal(ethers.constants.Zero); + }); + }); + it('onFlashLoan - revert', async () => { await expect( strategy @@ -191,109 +189,109 @@ describe('AaveFlashloanStrategy - Coverage', () => { }); it('estimatedAPR', async () => { const estimatedAPR = await strategy.estimatedAPR(); - expect(estimatedAPR).to.be.closeTo(parseUnits('0.026836', 18), parseUnits('0.005', 18)); + expect(estimatedAPR).to.be.closeTo(parseUnits('0.054', 18), parseUnits('0.005', 18)); }); + }); - describe('freeFunds', () => { - // We should in anycase be able to be at the target debt ratio - it('Large borrow', async () => { - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - - let { borrows } = await strategy.getCurrentPosition(); - expect(borrows).to.gt(ethers.constants.Zero); + describe('freeFunds', () => { + // We should in anycase be able to be at the target debt ratio + it('Large borrow', async () => { + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - await impersonate(poolManager.address, async acc => { - const balanceStorage = utils.parseEther('1').toHexString().replace('0x0', '0x'); - await network.provider.send('hardhat_setBalance', [acc.address, balanceStorage]); - const balanceManager = await wantToken.balanceOf(acc.address); - await wantToken.connect(acc).transfer(user.address, balanceManager); - expect(balanceManager).to.gt(ethers.constants.Zero); - }); + let { borrows } = await strategy.getCurrentPosition(); + expect(borrows).to.gt(ethers.constants.Zero); - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - ({ borrows } = await strategy.getCurrentPosition()); - expect(borrows).to.gt(ethers.constants.Zero); - const balanceManager = await wantToken.balanceOf(poolManager.address); - const totalAsset = await poolManager.getTotalAsset(); - const debtRatio = await poolManager.debtRatio(); - expect(balanceManager).to.closeTo( - totalAsset.mul(BASE_PARAMS.sub(debtRatio)).div(BASE_PARAMS), - parseUnits('100', decimalsToken), - ); + await impersonate(poolManager.address, async acc => { + const balanceStorage = utils.parseEther('1').toHexString().replace('0x0', '0x'); + await network.provider.send('hardhat_setBalance', [acc.address, balanceStorage]); + const balanceManager = await wantToken.balanceOf(acc.address); + await wantToken.connect(acc).transfer(user.address, balanceManager); + expect(balanceManager).to.gt(ethers.constants.Zero); }); - it('Small borrow', async () => { - const emissionAToken = (await incentivesController.assets(aToken.address)).emissionPerSecond; - const emissionDebtToken = (await incentivesController.assets(debtToken.address)).emissionPerSecond; - const multiplier = parseUnits('0.5985', 4); - const basePoint = parseUnits('1', 4); - - // reduce the emission to limit leverage - await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { - await incentivesController - .connect(acc) - .configureAssets( - [aToken.address, debtToken.address], - [emissionAToken.mul(multiplier).div(basePoint), emissionDebtToken.mul(multiplier).div(basePoint)], - ); - }); - - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); + ({ borrows } = await strategy.getCurrentPosition()); + expect(borrows).to.gt(ethers.constants.Zero); + const balanceManager = await wantToken.balanceOf(poolManager.address); + const totalAsset = await poolManager.getTotalAsset(); + const debtRatio = await poolManager.debtRatio(); + expect(balanceManager).to.closeTo( + totalAsset.mul(BASE_PARAMS.sub(debtRatio)).div(BASE_PARAMS), + parseUnits('100', decimalsToken), + ); + }); - let { borrows } = await strategy.getCurrentPosition(); - expect(borrows).to.gt(ethers.constants.Zero); + it('Small borrow', async () => { + const emissionAToken = (await incentivesController.assets(aToken.address)).emissionPerSecond; + const emissionDebtToken = (await incentivesController.assets(debtToken.address)).emissionPerSecond; + const multiplier = parseUnits('0.5985', 4); + const basePoint = parseUnits('1', 4); + + // reduce the emission to limit leverage + await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { + await incentivesController + .connect(acc) + .configureAssets( + [aToken.address, debtToken.address], + [emissionAToken.mul(multiplier).div(basePoint), emissionDebtToken.mul(multiplier).div(basePoint)], + ); + }); - await impersonate(poolManager.address, async acc => { - const balanceStorage = utils.parseEther('1').toHexString().replace('0x0', '0x'); - await network.provider.send('hardhat_setBalance', [acc.address, balanceStorage]); - const balanceManager = await wantToken.balanceOf(acc.address); - await wantToken.connect(acc).transfer(user.address, balanceManager); - expect(balanceManager).to.gt(ethers.constants.Zero); - }); + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - const { borrows: newBorrows } = await strategy.getCurrentPosition(); - expect(borrows).to.lt(newBorrows); - const balanceManager = await wantToken.balanceOf(poolManager.address); - const totalAsset = await poolManager.getTotalAsset(); - const debtRatio = await poolManager.debtRatio(); - expect(balanceManager).to.closeTo( - totalAsset.mul(BASE_PARAMS.sub(debtRatio)).div(BASE_PARAMS), - parseUnits('100', decimalsToken), - ); + const { borrows } = await strategy.getCurrentPosition(); + expect(borrows).to.gt(ethers.constants.Zero); + + await impersonate(poolManager.address, async acc => { + const balanceStorage = utils.parseEther('1').toHexString().replace('0x0', '0x'); + await network.provider.send('hardhat_setBalance', [acc.address, balanceStorage]); + const balanceManager = await wantToken.balanceOf(acc.address); + await wantToken.connect(acc).transfer(user.address, balanceManager); + expect(balanceManager).to.gt(ethers.constants.Zero); }); - it('No borrow', async () => { - await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { - await incentivesController - .connect(acc) - .configureAssets([aToken.address, debtToken.address], [ethers.constants.Zero, ethers.constants.Zero]); - }); - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); + const { borrows: newBorrows } = await strategy.getCurrentPosition(); + expect(borrows).to.lt(newBorrows); + const balanceManager = await wantToken.balanceOf(poolManager.address); + const totalAsset = await poolManager.getTotalAsset(); + const debtRatio = await poolManager.debtRatio(); + expect(balanceManager).to.closeTo( + totalAsset.mul(BASE_PARAMS.sub(debtRatio)).div(BASE_PARAMS), + parseUnits('100', decimalsToken), + ); + }); + it('No borrow', async () => { + await impersonate('0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', async acc => { + await incentivesController + .connect(acc) + .configureAssets([aToken.address, debtToken.address], [ethers.constants.Zero, ethers.constants.Zero]); + }); - let { borrows } = await strategy.getCurrentPosition(); - expect(borrows).to.equal(ethers.constants.Zero); + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - await impersonate(poolManager.address, async acc => { - const balanceStorage = utils.parseEther('1').toHexString().replace('0x0', '0x'); - await network.provider.send('hardhat_setBalance', [acc.address, balanceStorage]); + let { borrows } = await strategy.getCurrentPosition(); + expect(borrows).to.equal(ethers.constants.Zero); - const balanceManager = await wantToken.balanceOf(acc.address); - await wantToken.connect(acc).transfer(user.address, balanceManager); - expect(balanceManager).to.gt(ethers.constants.Zero); - }); + await impersonate(poolManager.address, async acc => { + const balanceStorage = utils.parseEther('1').toHexString().replace('0x0', '0x'); + await network.provider.send('hardhat_setBalance', [acc.address, balanceStorage]); - await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); - ({ borrows } = await strategy.getCurrentPosition()); - expect(borrows).to.equal(ethers.constants.Zero); - const balanceManager = await wantToken.balanceOf(poolManager.address); - const totalAsset = await poolManager.getTotalAsset(); - const debtRatio = await poolManager.debtRatio(); - expect(balanceManager).to.closeTo( - totalAsset.mul(BASE_PARAMS.sub(debtRatio)).div(BASE_PARAMS), - parseUnits('100', decimalsToken), - ); + const balanceManager = await wantToken.balanceOf(acc.address); + await wantToken.connect(acc).transfer(user.address, balanceManager); + expect(balanceManager).to.gt(ethers.constants.Zero); }); + + await strategy.connect(keeper)['harvest(uint256)'](ethers.constants.Zero, { gasLimit: 3e6 }); + ({ borrows } = await strategy.getCurrentPosition()); + expect(borrows).to.equal(ethers.constants.Zero); + const balanceManager = await wantToken.balanceOf(poolManager.address); + const totalAsset = await poolManager.getTotalAsset(); + const debtRatio = await poolManager.debtRatio(); + expect(balanceManager).to.closeTo( + totalAsset.mul(BASE_PARAMS.sub(debtRatio)).div(BASE_PARAMS), + parseUnits('100', decimalsToken), + ); }); }); });