From b5ba303e8f886ef72c3d28ab2fa50b9310ca48a1 Mon Sep 17 00:00:00 2001 From: David Racero Date: Tue, 22 Jun 2021 13:54:30 +0200 Subject: [PATCH] wip: Fix Curve tests to use underlying pool tokens instead of gauges --- ...CurveGaugeReserveInterestRateStrategy.sol} | 0 helpers/contracts-deployments.ts | 12 ++ .../mainnet/atoken-curve-rewards.main.ts | 174 +++++++++++++----- 3 files changed, 143 insertions(+), 43 deletions(-) rename contracts/adapters/interests-strategies/{CurveLpReserveInterestRateStratregy.sol => CurveGaugeReserveInterestRateStrategy.sol} (100%) diff --git a/contracts/adapters/interests-strategies/CurveLpReserveInterestRateStratregy.sol b/contracts/adapters/interests-strategies/CurveGaugeReserveInterestRateStrategy.sol similarity index 100% rename from contracts/adapters/interests-strategies/CurveLpReserveInterestRateStratregy.sol rename to contracts/adapters/interests-strategies/CurveGaugeReserveInterestRateStrategy.sol diff --git a/helpers/contracts-deployments.ts b/helpers/contracts-deployments.ts index 8dac278f..bcbe0aaa 100644 --- a/helpers/contracts-deployments.ts +++ b/helpers/contracts-deployments.ts @@ -53,6 +53,7 @@ import { RewardsATokenMockFactory, CurveGaugeRewardsAwareATokenFactory, CurveTreasuryFactory, + CurveGaugeReserveInterestRateStrategyFactory, } from '../types'; import { withSaveAndVerify, @@ -322,6 +323,17 @@ export const deployDefaultReserveInterestRateStrategy = async ( verify ); +export const deployCurveGaugeReserveInterestRateStrategy = async ( + args: [tEthereumAddress, string, string, string, string, string, string], + verify: boolean +) => + withSaveAndVerify( + await new CurveGaugeReserveInterestRateStrategyFactory(await getFirstSigner()).deploy(...args), + eContractid.DefaultReserveInterestRateStrategy, + args, + verify + ); + export const deployStableDebtToken = async ( args: [tEthereumAddress, tEthereumAddress, tEthereumAddress, string, string], verify: boolean diff --git a/test-suites/test-aave/mainnet/atoken-curve-rewards.main.ts b/test-suites/test-aave/mainnet/atoken-curve-rewards.main.ts index 52508175..39416686 100644 --- a/test-suites/test-aave/mainnet/atoken-curve-rewards.main.ts +++ b/test-suites/test-aave/mainnet/atoken-curve-rewards.main.ts @@ -1,4 +1,4 @@ -import { ZERO_ADDRESS } from '../../../helpers/constants'; +import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../../../helpers/constants'; import { makeSuite, SignerWithAddress, TestEnv } from '../helpers/make-suite'; import { advanceTimeAndBlock, @@ -15,7 +15,10 @@ import { getLendingPoolAddressesProvider, getLendingPoolConfiguratorProxy, } from '../../../helpers/contracts-getters'; -import { deployDefaultReserveInterestRateStrategy } from '../../../helpers/contracts-deployments'; +import { + deployCurveGaugeReserveInterestRateStrategy, + deployDefaultReserveInterestRateStrategy, +} from '../../../helpers/contracts-deployments'; import { IERC20Factory } from '../../../types/IERC20Factory'; import BigNumberJs from 'bignumber.js'; import { CurveGaugeRewardsAwareATokenFactory } from '../../../types'; @@ -25,35 +28,40 @@ import { checkRewards } from '../helpers/rewards-distribution/verify'; import { IRewardsAwareAToken } from '../../../types/IRewardsAwareAToken'; import { IRewardsAwareATokenFactory } from '../../../types/IRewardsAwareATokenFactory'; import { BigNumber } from 'ethers'; -import { parseEther } from 'ethers/lib/utils'; +import { AbiCoder, defaultAbiCoder, parseEther } from 'ethers/lib/utils'; import { IERC20 } from '../../../types/IERC20'; import { getContractAddressWithJsonFallback, getParamPerNetwork, } from '../../../helpers/contracts-helpers'; import { ConfigNames, loadPoolConfig } from '../../../helpers/configuration'; - +import { ICurveGaugeFactory } from '../../../types/ICurveGaugeFactory'; const ONE_DAY = 86400; const { expect } = require('chai'); interface GaugeInfo { + underlying: tEthereumAddress; address: tEthereumAddress; name: string; symbol: string; rewardTokens: tEthereumAddress[]; } +const BLOCK_HEIGHT = ''; const USER_ADDRESS = '0x9c5083dd4838E120Dbeac44C052179692Aa5dAC5'; const CRV_TOKEN = '0xd533a949740bb3306d119cc777fa900ba034cd52'; const SNX_TOKEN = '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f'; const GAUGE_3POOL: GaugeInfo = { + underlying: '0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490', address: '0xbFcF63294aD7105dEa65aA58F8AE5BE2D9d0952A', name: 'aToken 3pool Gauge Deposit', + symbol: 'a-3poolCRV-gauge', rewardTokens: [], }; const GAUGE_AAVE3: GaugeInfo = { + underlying: '0xFd2a8fA60Abd58Efe3EeE34dd494cD491dC14900', address: '0xd662908ADA2Ea1916B3318327A97eB18aD588b5d', name: 'aToken a3CRV Gauge Deposit', symbol: 'a-a3CRV-gauge', @@ -61,6 +69,7 @@ const GAUGE_AAVE3: GaugeInfo = { }; const GAUGE_EURS: GaugeInfo = { + underlying: '0x194eBd173F6cDacE046C53eACcE9B953F28411d1', address: '0x90Bb609649E0451E5aD952683D64BD2d1f245840', name: 'aToken eursCRV Gauge Deposit', symbol: 'a-eursCRV-gauge', @@ -68,6 +77,7 @@ const GAUGE_EURS: GaugeInfo = { }; const GAUGE_ANKR: GaugeInfo = { + underlying: '0xaA17A236F2bAdc98DDc0Cf999AbB47D47Fc0A6Cf', address: '0x6d10ed2cf043e6fcf51a0e7b4c2af3fa06695707', name: 'aToken ankrCRV Gauge Deposit', symbol: 'a-ankrCRV-gauge', @@ -77,6 +87,14 @@ const GAUGE_ANKR: GaugeInfo = { ], }; +const unstakeAllGauges = async (key: SignerWithAddress, gauges: tEthereumAddress[]) => { + for (let x = 0; x < gauges.length; x++) { + await waitForTx( + await ICurveGaugeFactory.connect(gauges[x], key.signer).withdraw(MAX_UINT_AMOUNT) + ); + } +}; + const listCurveLPToken = async (gauge: GaugeInfo, curveTreasury: tEthereumAddress) => { const { symbol } = gauge; const poolConfig = loadPoolConfig(ConfigNames.Aave); @@ -109,7 +127,7 @@ const listCurveLPToken = async (gauge: GaugeInfo, curveTreasury: tEthereumAddres ConfigNames.Aave ); // WBTC Strategy used as a template for tests scenario - const interestStrategy = await deployDefaultReserveInterestRateStrategy( + const interestStrategy = await deployCurveGaugeReserveInterestRateStrategy( [ addressProvider.address, strategyWBTC.strategy.optimalUtilizationRate, @@ -122,7 +140,7 @@ const listCurveLPToken = async (gauge: GaugeInfo, curveTreasury: tEthereumAddres false ); const interestRateStrategyAddress = interestStrategy.address; - + const encodedParams = defaultAbiCoder.encode(['string'], [gauge.address]); const curveReserveInitParams = [ { aTokenImpl, @@ -130,7 +148,7 @@ const listCurveLPToken = async (gauge: GaugeInfo, curveTreasury: tEthereumAddres variableDebtTokenImpl, underlyingAssetDecimals: '18', interestRateStrategyAddress, - underlyingAsset: gauge.address, + underlyingAsset: gauge.underlying, treasury, incentivesController: ZERO_ADDRESS, underlyingAssetName: gauge.symbol, @@ -140,60 +158,60 @@ const listCurveLPToken = async (gauge: GaugeInfo, curveTreasury: tEthereumAddres variableDebtTokenSymbol: `variableDebt${symbolPrefix}${symbol}`, stableDebtTokenName: `${stableDebtTokenNamePrefix} ${symbol}`, stableDebtTokenSymbol: `stableDebt${symbolPrefix}${symbol}`, - params: '0x10', + params: encodedParams, }, ]; await waitForTx(await poolConfigurator.batchInitReserve(curveReserveInitParams)); }; -const depositGauge = async ( +const depositPoolToken = async ( key: SignerWithAddress, gauge: GaugeInfo, - aGaugeAddress: tEthereumAddress, + aTokenAddress: tEthereumAddress, amount: BigNumber, shouldReward?: boolean ) => { const pool = await getLendingPool(); - const gaugeErc20 = IERC20Factory.connect(gauge.address, key.signer); + const curveReserveToken = IERC20Factory.connect(gauge.underlying, key.signer); - await gaugeErc20.connect(key.signer).approve(pool.address, amount); + await curveReserveToken.connect(key.signer).approve(pool.address, amount); const txDeposit = await waitForTx( - await pool.connect(key.signer).deposit(gauge.address, amount, key.address, '0') + await pool.connect(key.signer).deposit(gauge.underlying, amount, key.address, '0') ); - await checkRewards(key, aGaugeAddress, txDeposit.blockNumber, shouldReward); + await checkRewards(key, aTokenAddress, txDeposit.blockNumber, shouldReward); }; -const withdrawGauge = async ( +const withdrawPoolToken = async ( key: SignerWithAddress, gauge: GaugeInfo, - aGaugeAddress: tEthereumAddress, + aTokenAddress: tEthereumAddress, shouldReward = true ) => { const pool = await getLendingPool(); - const aGauge = IRewardsAwareATokenFactory.connect(aGaugeAddress, key.signer); + const aGauge = IRewardsAwareATokenFactory.connect(aTokenAddress, key.signer); const entireBalance = await aGauge.balanceOf(key.address); await aGauge.connect(key.signer).approve(pool.address, entireBalance); const txWithdraw = await waitForTx( - await pool.connect(key.signer).withdraw(gauge.address, entireBalance, key.address) + await pool.connect(key.signer).withdraw(gauge.underlying, entireBalance, key.address) ); - await checkRewards(key, aGaugeAddress, txWithdraw.blockNumber, shouldReward); + await checkRewards(key, aTokenAddress, txWithdraw.blockNumber, shouldReward); }; const claimFromGauge = async ( key: SignerWithAddress, gauge: GaugeInfo, - aGaugeAddress: tEthereumAddress, + aTokenAddress: tEthereumAddress, shouldReward = true ) => { - const aGauge = IRewardsAwareATokenFactory.connect(aGaugeAddress, key.signer); - const rewardTokens = await aGauge.getRewardsTokenAddressList(); + const aToken = IRewardsAwareATokenFactory.connect(aTokenAddress, key.signer); + const rewardTokens = await aToken.getRewardsTokenAddressList(); for (let x = 0; x < rewardTokens.length; x++) { if (rewardTokens[x] == ZERO_ADDRESS) break; @@ -201,11 +219,11 @@ const claimFromGauge = async ( const balanceBefore = await IERC20Factory.connect(rewardTokens[x], key.signer).balanceOf( key.address ); - const txClaim = await waitForTx(await aGauge.claim(rewardTokens[x])); + const txClaim = await waitForTx(await aToken.claim(rewardTokens[x])); await checkRewards( key, - aGaugeAddress, + aTokenAddress, txClaim.blockNumber, shouldReward, rewardTokens[x], @@ -218,10 +236,12 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { let evmSnapshotId; let depositor: SignerWithAddress; - let gaugeEursErc20: IERC20; - let gaugeAave3Erc20: IERC20; - let gaugeAnkrErc20: IERC20; + let curve3poolErc20: IERC20; + let curveEursErc20: IERC20; + let curveAave3Erc20: IERC20; + let curveAnkrErc20: IERC20; + let a3POOL: IRewardsAwareAToken; let aEURS: IRewardsAwareAToken; let aAAVE3: IRewardsAwareAToken; let aANKR: IRewardsAwareAToken; @@ -236,20 +256,34 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { // Set local vars depositor = await impersonateAddress(USER_ADDRESS); - gaugeEursErc20 = IERC20Factory.connect(GAUGE_EURS.address, depositor.signer); - gaugeAave3Erc20 = IERC20Factory.connect(GAUGE_AAVE3.address, depositor.signer); - gaugeAnkrErc20 = IERC20Factory.connect(GAUGE_ANKR.address, depositor.signer); + curve3poolErc20 = IERC20Factory.connect(GAUGE_3POOL.underlying, depositor.signer); + curveEursErc20 = IERC20Factory.connect(GAUGE_EURS.underlying, depositor.signer); + curveAave3Erc20 = IERC20Factory.connect(GAUGE_AAVE3.underlying, depositor.signer); + curveAnkrErc20 = IERC20Factory.connect(GAUGE_ANKR.underlying, depositor.signer); crvToken = IERC20Factory.connect(CRV_TOKEN, depositor.signer); snxToken = IERC20Factory.connect(SNX_TOKEN, depositor.signer); + // Unstake gauges to deposit into Aave + await unstakeAllGauges(depositor, [ + GAUGE_3POOL.address, + GAUGE_AAVE3.address, + GAUGE_EURS.address, + GAUGE_ANKR.address, + ]); - // Depositor should have EURS, AAVE3, and ANKR gauges balance - const gaugeEursBalance = await gaugeEursErc20.balanceOf(USER_ADDRESS); - const gaugeAave3Balance = await gaugeAave3Erc20.balanceOf(USER_ADDRESS); - const gaugeAnkrBalance = await gaugeAnkrErc20.balanceOf(USER_ADDRESS); + // Depositor should have 3pool, EURS, AAVE3, and ANKR balance + const curve3poolBalance = await curve3poolErc20.balanceOf(USER_ADDRESS); + const gaugeCurve3poolBalance = await IERC20Factory.connect( + GAUGE_3POOL.address, + depositor.signer + ).balanceOf(USER_ADDRESS); + const curveEursBalance = await curveEursErc20.balanceOf(USER_ADDRESS); + const curveAave3Balance = await curveAave3Erc20.balanceOf(USER_ADDRESS); + const curveAnkrBalance = await curveAnkrErc20.balanceOf(USER_ADDRESS); - expect(gaugeEursBalance).to.be.gt('0'); - expect(gaugeAave3Balance).to.be.gt('0'); - expect(gaugeAnkrBalance).to.be.gt('0'); + expect(curve3poolBalance).to.be.gt('0', 'insufficient 3pool'); + expect(curveEursBalance).to.be.gt('0', 'insufficient eurs'); + expect(curveAave3Balance).to.be.gt('0', 'insufficient aave3'); + expect(curveAnkrBalance).to.be.gt('0', 'insufficient ankr'); // Deploy Curve Treasury const poolConfig = loadPoolConfig(ConfigNames.Aave); @@ -264,12 +298,17 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { collector, }); // Gauge tokens should be listed at Aave test deployment + await listCurveLPToken(GAUGE_3POOL, curveTreasury); await listCurveLPToken(GAUGE_EURS, curveTreasury); await listCurveLPToken(GAUGE_AAVE3, curveTreasury); await listCurveLPToken(GAUGE_ANKR, curveTreasury); const allTokens = await testEnv.helpersContract.getAllATokens(); + a3POOL = IRewardsAwareATokenFactory.connect( + allTokens.find((aToken) => aToken.symbol.includes('3pool'))?.tokenAddress || ZERO_ADDRESS, + await getFirstSigner() + ); aEURS = IRewardsAwareATokenFactory.connect( allTokens.find((aToken) => aToken.symbol.includes('eurs'))?.tokenAddress || ZERO_ADDRESS, await getFirstSigner() @@ -301,7 +340,7 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { it('Deposit and generate user reward checkpoints', async () => { // Deposits - await depositGauge(depositor, GAUGE_AAVE3, aAAVE3.address, parseEther('100000')); + await depositPoolToken(depositor, GAUGE_AAVE3, aAAVE3.address, parseEther('100000')); const curveATokenBalance = await crvToken.balanceOf(aAAVE3.address); expect(curveATokenBalance).to.be.eq('0', 'CRV rewards should be zero'); }); @@ -324,7 +363,7 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { await increaseTime(ONE_DAY); // Withdraw - await withdrawGauge(depositor, GAUGE_AAVE3, aAAVE3.address); + await withdrawPoolToken(depositor, GAUGE_AAVE3, aAAVE3.address); const curveATokenBalance = await crvToken.balanceOf(aAAVE3.address); expect(curveATokenBalance).to.be.eq('0', 'CRV rewards should be zero'); }); @@ -340,6 +379,55 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { }); }); + describe('AToken with only CRV rewards - 3pool Gauge', () => { + before(async () => { + evmSnapshotId = await evmSnapshot(); + }); + + after(async () => { + await evmRevert(evmSnapshotId); + }); + + it('Deposit and generate user reward checkpoints', async () => { + // Deposits + await depositPoolToken(depositor, GAUGE_3POOL, a3POOL.address, parseEther('100000')); + const curveATokenBalance = await crvToken.balanceOf(a3POOL.address); + expect(curveATokenBalance).to.be.eq('0', 'CRV rewards should be zero'); + }); + + it('Increase time and claim CRV', async () => { + // Pass time to generate rewards + await increaseTime(ONE_DAY); + + // Claim + await claimFromGauge(depositor, GAUGE_3POOL, a3POOL.address); + const curveATokenBalance = await crvToken.balanceOf(a3POOL.address); + expect(curveATokenBalance).to.be.eq( + '0', + 'CRV Balance should be zero as there is only one aToken holder' + ); + }); + + it('Pass time and withdraw Staked AAVE3', async () => { + // Pass time to generate rewards + await increaseTime(ONE_DAY); + + // Withdraw + await withdrawPoolToken(depositor, GAUGE_3POOL, a3POOL.address); + const curveATokenBalance = await crvToken.balanceOf(a3POOL.address); + expect(curveATokenBalance).to.be.eq('0', 'CRV rewards should be zero'); + }); + + it('Claim the remaining CRV', async () => { + // Claim + await claimFromGauge(depositor, GAUGE_AAVE3, aAAVE3.address); + const curveATokenBalance = await crvToken.balanceOf(a3POOL.address); + expect(curveATokenBalance).to.be.eq( + '0', + 'CRV Balance should be zero as there is only one aToken holder' + ); + }); + }); describe('AToken with CRV and 1 extra rewards - EURS Gauge', () => { before(async () => { evmSnapshotId = await evmSnapshot(); @@ -352,7 +440,7 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { it('Deposit and generate user reward checkpoints', async () => { // Deposits - await depositGauge(depositor, GAUGE_EURS, aEURS.address, parseEther('100000')); + await depositPoolToken(depositor, GAUGE_EURS, aEURS.address, parseEther('100000')); const curveATokenBalance = await crvToken.balanceOf(aEURS.address); expect(curveATokenBalance).to.be.eq('0', 'CRV should be zero'); }); @@ -370,7 +458,7 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { await increaseTime(ONE_DAY); // Withdraw - await withdrawGauge(depositor, GAUGE_EURS, aEURS.address); + await withdrawPoolToken(depositor, GAUGE_EURS, aEURS.address); }); it('Claim the remaining CRV and SNX', async () => { @@ -390,7 +478,7 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { it('Deposit and generate user reward checkpoints', async () => { // Deposits - await depositGauge( + await depositPoolToken( depositor, GAUGE_ANKR, aANKR.address, @@ -411,7 +499,7 @@ makeSuite('Curve Rewards Aware aToken', (testEnv: TestEnv) => { await increaseTime(ONE_DAY * 30); // Withdraw - await withdrawGauge(depositor, GAUGE_ANKR, aANKR.address); + await withdrawPoolToken(depositor, GAUGE_ANKR, aANKR.address); }); it('Claim the CRV with extra rewards', async () => {