Skip to content

Commit

Permalink
Fixes aave#730. Not including yet all the required tests, only for th…
Browse files Browse the repository at this point in the history
…e flash loan fee (same as bridging) imprecision
  • Loading branch information
eboadom committed Nov 11, 2022
1 parent f3e037b commit bb00525
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 15 deletions.
5 changes: 3 additions & 2 deletions contracts/protocol/libraries/logic/BridgeLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ library BridgeLogic {

reserve.updateState(reserveCache);

ValidationLogic.validateSupply(reserveCache, amount);
ValidationLogic.validateSupply(reserveCache, reserve, amount);

uint256 unbackedMintCap = reserveCache.reserveConfiguration.getUnbackedMintCap();
uint256 reserveDecimals = reserveCache.reserveConfiguration.getDecimals();
Expand Down Expand Up @@ -125,7 +125,8 @@ library BridgeLogic {
uint256 added = backingAmount + fee;

reserveCache.nextLiquidityIndex = reserve.cumulateToLiquidityIndex(
IERC20(reserveCache.aTokenAddress).totalSupply(),
IERC20(reserveCache.aTokenAddress).totalSupply() +
uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex),
feeToLP
);

Expand Down
3 changes: 2 additions & 1 deletion contracts/protocol/libraries/logic/FlashLoanLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ library FlashLoanLogic {
DataTypes.ReserveCache memory reserveCache = reserve.cache();
reserve.updateState(reserveCache);
reserveCache.nextLiquidityIndex = reserve.cumulateToLiquidityIndex(
IERC20(reserveCache.aTokenAddress).totalSupply(),
IERC20(reserveCache.aTokenAddress).totalSupply() +
uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex),
premiumToLP
);

Expand Down
9 changes: 7 additions & 2 deletions contracts/protocol/libraries/logic/SupplyLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ library SupplyLogic {

reserve.updateState(reserveCache);

ValidationLogic.validateSupply(reserveCache, params.amount);
ValidationLogic.validateSupply(reserveCache, reserve, params.amount);

reserve.updateInterestRates(reserveCache, params.asset, params.amount, 0);

Expand Down Expand Up @@ -264,7 +264,12 @@ library SupplyLogic {

if (useAsCollateral) {
require(
ValidationLogic.validateUseAsCollateral(reservesData, reservesList, userConfig, reserveCache.reserveConfiguration),
ValidationLogic.validateUseAsCollateral(
reservesData,
reservesList,
userConfig,
reserveCache.reserveConfiguration
),
Errors.USER_IN_ISOLATION_MODE
);

Expand Down
18 changes: 12 additions & 6 deletions contracts/protocol/libraries/logic/ValidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ library ValidationLogic {
* @param reserveCache The cached data of the reserve
* @param amount The amount to be supplied
*/
function validateSupply(DataTypes.ReserveCache memory reserveCache, uint256 amount)
internal
view
{
function validateSupply(
DataTypes.ReserveCache memory reserveCache,
DataTypes.ReserveData storage reserve,
uint256 amount
) internal view {
require(amount != 0, Errors.INVALID_AMOUNT);

(bool isActive, bool isFrozen, , , bool isPaused) = reserveCache
Expand All @@ -72,7 +73,9 @@ library ValidationLogic {
supplyCap == 0 ||
(IAToken(reserveCache.aTokenAddress).scaledTotalSupply().rayMul(
reserveCache.nextLiquidityIndex
) + amount) <=
) +
uint256(reserve.accruedToTreasury).rayMul(reserveCache.nextLiquidityIndex) +
amount) <=
supplyCap * (10**reserveCache.reserveConfiguration.getDecimals()),
Errors.SUPPLY_CAP_EXCEEDED
);
Expand Down Expand Up @@ -650,7 +653,10 @@ library ValidationLogic {
IERC20(reserve.variableDebtTokenAddress).totalSupply() == 0,
Errors.VARIABLE_DEBT_SUPPLY_NOT_ZERO
);
require(IERC20(reserve.aTokenAddress).totalSupply() == 0, Errors.ATOKEN_SUPPLY_NOT_ZERO);
require(
IERC20(reserve.aTokenAddress).totalSupply() == 0 && reserve.accruedToTreasury == 0,
Errors.ATOKEN_SUPPLY_NOT_ZERO
);
}

/**
Expand Down
8 changes: 5 additions & 3 deletions contracts/protocol/pool/PoolConfigurator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,11 @@ contract PoolConfigurator is VersionedInitializable, IPoolConfigurator {
}

function _checkNoSuppliers(address asset) internal view {
uint256 totalATokens = IPoolDataProvider(_addressesProvider.getPoolDataProvider())
.getATokenTotalSupply(asset);
require(totalATokens == 0, Errors.RESERVE_LIQUIDITY_NOT_ZERO);
(, uint256 accruedToTreasury, uint256 totalATokens, , , , , , , , , ) = IPoolDataProvider(
_addressesProvider.getPoolDataProvider()
).getReserveData(asset);

require(totalATokens == 0 && accruedToTreasury == 0, Errors.RESERVE_LIQUIDITY_NOT_ZERO);
}

function _checkNoBorrowers(address asset) internal view {
Expand Down
4 changes: 3 additions & 1 deletion test-suites/helpers/utils/calculations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ export const calcExpectedReserveDataAfterBackUnbacked = (

expectedReserveData.liquidityIndex = cumulateToLiquidityIndex(
expectedReserveData.liquidityIndex,
totalSupply,
totalSupply.add(
expectedReserveData.accruedToTreasuryScaled.rayMul(expectedReserveData.liquidityIndex)
),
premiumToLP
);

Expand Down
123 changes: 123 additions & 0 deletions test-suites/liquidity-indexes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {expect} from 'chai';
import {BigNumber, ethers} from 'ethers';
import {MAX_UINT_AMOUNT} from '../helpers/constants';
import {makeSuite, TestEnv} from './helpers/make-suite';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {
evmSnapshot,
evmRevert,
MockFlashLoanReceiver,
getMockFlashLoanReceiver,
} from '@aave/deploy-v3';
import './helpers/utils/wadraymath';

declare var hre: HardhatRuntimeEnvironment;

makeSuite('Pool: liquidity indexes misc tests', (testEnv: TestEnv) => {
const TOTAL_PREMIUM = 9;
const PREMIUM_TO_PROTOCOL = 3000;

let _mockFlashLoanReceiver = {} as MockFlashLoanReceiver;

let snap: string;

const setupForFlashloan = async (testEnv: TestEnv) => {
const {
configurator,
pool,
weth,
aave,
dai,
users: [user0],
} = testEnv;

_mockFlashLoanReceiver = await getMockFlashLoanReceiver();

await configurator.updateFlashloanPremiumTotal(TOTAL_PREMIUM);
await configurator.updateFlashloanPremiumToProtocol(PREMIUM_TO_PROTOCOL);

const userAddress = user0.address;
const amountToDeposit = ethers.utils.parseEther('1');

await weth['mint(uint256)'](amountToDeposit);

await weth.approve(pool.address, MAX_UINT_AMOUNT);

await pool.deposit(weth.address, amountToDeposit, userAddress, '0');

await aave['mint(uint256)'](amountToDeposit);

await aave.approve(pool.address, MAX_UINT_AMOUNT);

await pool.deposit(aave.address, amountToDeposit, userAddress, '0');
await dai['mint(uint256)'](amountToDeposit);

await dai.approve(pool.address, MAX_UINT_AMOUNT);

await pool.deposit(dai.address, amountToDeposit, userAddress, '0');
};

before(async () => {
await setupForFlashloan(testEnv);
});

beforeEach(async () => {
snap = await evmSnapshot();
});

afterEach(async () => {
await evmRevert(snap);
});

it('Validates that the flash loan fee properly takes into account both aToken supply and accruedToTreasury', async () => {
const {
pool,
helpersContract,
weth,
aWETH,
users: [depositorWeth],
} = testEnv;

/**
* 1. Flashes 0.8 WETH
* 2. Flashes again 0.8 ETH (to have accruedToTreasury)
* 3. Validates that liquidity index took into account both aToken supply and accruedToTreasury
*/

const wethFlashBorrowedAmount = ethers.utils.parseEther('0.8');

await pool.flashLoan(
_mockFlashLoanReceiver.address,
[weth.address],
[wethFlashBorrowedAmount],
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
);

await pool.flashLoan(
_mockFlashLoanReceiver.address,
[weth.address],
[wethFlashBorrowedAmount],
[0],
_mockFlashLoanReceiver.address,
'0x10',
'0'
);

const wethReserveDataAfterSecondFlash = await helpersContract.getReserveData(weth.address);

const totalScaledWithTreasuryAfterSecondFlash = (
await aWETH.scaledBalanceOf(depositorWeth.address)
).add(wethReserveDataAfterSecondFlash.accruedToTreasuryScaled.toString());

expect(await weth.balanceOf(aWETH.address)).to.be.closeTo(
BigNumber.from(totalScaledWithTreasuryAfterSecondFlash.toString()).rayMul(
wethReserveDataAfterSecondFlash.liquidityIndex
),
1,
'Scaled total supply not (+/- 1) equal to WETH balance of aWETH'
);
});
});

0 comments on commit bb00525

Please sign in to comment.