mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
feat: initial cache layer implementation
This commit is contained in:
parent
729194d587
commit
6cdfd8e31b
|
@ -26,6 +26,7 @@ import {ReserveConfiguration} from '../libraries/configuration/ReserveConfigurat
|
|||
import {UserConfiguration} from '../libraries/configuration/UserConfiguration.sol';
|
||||
import {DataTypes} from '../libraries/types/DataTypes.sol';
|
||||
import {LendingPoolStorage} from './LendingPoolStorage.sol';
|
||||
import {CachingHelper} from '../libraries/helpers/CachingHelper.sol';
|
||||
|
||||
/**
|
||||
* @title LendingPool contract
|
||||
|
@ -270,6 +271,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
**/
|
||||
function swapBorrowRateMode(address asset, uint256 rateMode) external override whenNotPaused {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
|
||||
|
||||
|
@ -283,7 +285,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
interestRateMode
|
||||
);
|
||||
|
||||
reserve.updateState();
|
||||
reserve.updateState(cachedData);
|
||||
|
||||
if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
|
||||
IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt);
|
||||
|
@ -323,6 +325,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
**/
|
||||
function rebalanceStableBorrowRate(address asset, address user) external override whenNotPaused {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress);
|
||||
IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress);
|
||||
|
@ -338,7 +341,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
aTokenAddress
|
||||
);
|
||||
|
||||
reserve.updateState();
|
||||
reserve.updateState(cachedData);
|
||||
|
||||
IStableDebtToken(address(stableDebtToken)).burn(user, stableDebt);
|
||||
IStableDebtToken(address(stableDebtToken)).mint(
|
||||
|
@ -435,6 +438,8 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
uint256 currentPremium;
|
||||
uint256 currentAmountPlusPremium;
|
||||
address debtToken;
|
||||
address[] aTokenAddresses;
|
||||
uint256[] premiums;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -465,40 +470,44 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
) external override whenNotPaused {
|
||||
FlashLoanLocalVars memory vars;
|
||||
|
||||
vars.aTokenAddresses = new address[](assets.length);
|
||||
vars.premiums = new uint256[](assets.length);
|
||||
|
||||
ValidationLogic.validateFlashloan(assets, amounts, _reserves);
|
||||
|
||||
address[] memory aTokenAddresses = new address[](assets.length);
|
||||
uint256[] memory premiums = new uint256[](assets.length);
|
||||
|
||||
vars.receiver = IFlashLoanReceiver(receiverAddress);
|
||||
|
||||
for (vars.i = 0; vars.i < assets.length; vars.i++) {
|
||||
aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
|
||||
vars.aTokenAddresses[vars.i] = _reserves[assets[vars.i]].aTokenAddress;
|
||||
|
||||
premiums[vars.i] = amounts[vars.i].mul(_flashLoanPremiumTotal).div(10000);
|
||||
vars.premiums[vars.i] = amounts[vars.i].mul(_flashLoanPremiumTotal).div(10000);
|
||||
|
||||
IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]);
|
||||
IAToken(vars.aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]);
|
||||
}
|
||||
|
||||
require(
|
||||
vars.receiver.executeOperation(assets, amounts, premiums, msg.sender, params),
|
||||
vars.receiver.executeOperation(assets, amounts, vars.premiums, msg.sender, params),
|
||||
Errors.LP_INVALID_FLASH_LOAN_EXECUTOR_RETURN
|
||||
);
|
||||
|
||||
for (vars.i = 0; vars.i < assets.length; vars.i++) {
|
||||
vars.currentAsset = assets[vars.i];
|
||||
vars.currentAmount = amounts[vars.i];
|
||||
vars.currentPremium = premiums[vars.i];
|
||||
vars.currentATokenAddress = aTokenAddresses[vars.i];
|
||||
vars.currentPremium = vars.premiums[vars.i];
|
||||
vars.currentATokenAddress = vars.aTokenAddresses[vars.i];
|
||||
vars.currentAmountPlusPremium = vars.currentAmount.add(vars.currentPremium);
|
||||
|
||||
if (DataTypes.InterestRateMode(modes[vars.i]) == DataTypes.InterestRateMode.NONE) {
|
||||
_reserves[vars.currentAsset].updateState();
|
||||
_reserves[vars.currentAsset].cumulateToLiquidityIndex(
|
||||
DataTypes.ReserveData storage reserve = _reserves[vars.currentAsset];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
reserve.updateState(cachedData);
|
||||
reserve.cumulateToLiquidityIndex(
|
||||
IERC20(vars.currentATokenAddress).totalSupply(),
|
||||
vars.currentPremium
|
||||
);
|
||||
_reserves[vars.currentAsset].updateInterestRates(
|
||||
reserve.updateInterestRates(
|
||||
vars.currentAsset,
|
||||
vars.currentATokenAddress,
|
||||
vars.currentAmountPlusPremium,
|
||||
|
@ -863,6 +872,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
function _executeBorrow(ExecuteBorrowParams memory vars) internal {
|
||||
DataTypes.ReserveData storage reserve = _reserves[vars.asset];
|
||||
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[vars.onBehalfOf];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
address oracle = _addressesProvider.getPriceOracle();
|
||||
|
||||
|
@ -886,7 +896,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
oracle
|
||||
);
|
||||
|
||||
reserve.updateState();
|
||||
reserve.updateState(cachedData);
|
||||
|
||||
uint256 currentStableRate = 0;
|
||||
|
||||
|
@ -944,17 +954,16 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
uint16 referralCode
|
||||
) internal {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
ValidationLogic.validateDeposit(reserve, amount);
|
||||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
reserve.updateState(cachedData);
|
||||
reserve.updateInterestRates(asset, cachedData.aTokenAddress, amount, 0);
|
||||
|
||||
reserve.updateState();
|
||||
reserve.updateInterestRates(asset, aToken, amount, 0);
|
||||
IERC20(asset).safeTransferFrom(msg.sender, cachedData.aTokenAddress, amount);
|
||||
|
||||
IERC20(asset).safeTransferFrom(msg.sender, aToken, amount);
|
||||
|
||||
bool isFirstDeposit = IAToken(aToken).mint(onBehalfOf, amount, reserve.liquidityIndex);
|
||||
bool isFirstDeposit = IAToken(cachedData.aTokenAddress).mint(onBehalfOf, amount, cachedData.newLiquidityIndex);
|
||||
|
||||
if (isFirstDeposit) {
|
||||
_usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
|
||||
|
@ -971,14 +980,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
) internal returns (uint256) {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
DataTypes.UserConfigurationMap storage userConfig = _usersConfig[msg.sender];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
|
||||
reserve.updateState();
|
||||
reserve.updateState(cachedData);
|
||||
|
||||
uint256 liquidityIndex = reserve.liquidityIndex;
|
||||
|
||||
uint256 userBalance = IAToken(aToken).scaledBalanceOf(msg.sender).rayMul(liquidityIndex);
|
||||
uint256 userBalance = IAToken(aToken).scaledBalanceOf(msg.sender).rayMul(cachedData.newLiquidityIndex);
|
||||
|
||||
uint256 amountToWithdraw = amount;
|
||||
|
||||
|
@ -990,7 +998,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
|
||||
reserve.updateInterestRates(asset, aToken, 0, amountToWithdraw);
|
||||
|
||||
IAToken(aToken).burn(msg.sender, to, amountToWithdraw, liquidityIndex);
|
||||
IAToken(aToken).burn(msg.sender, to, amountToWithdraw, cachedData.newLiquidityIndex);
|
||||
|
||||
if (userConfig.isUsingAsCollateral(reserve.id)) {
|
||||
if (userConfig.isBorrowingAny()) {
|
||||
|
@ -1022,6 +1030,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
address onBehalfOf
|
||||
) internal returns (uint256) {
|
||||
DataTypes.ReserveData storage reserve = _reserves[asset];
|
||||
CachingHelper.CachedData memory cachedData = CachingHelper.fetchData(reserve);
|
||||
|
||||
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
|
||||
|
||||
|
@ -1043,7 +1052,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
|
|||
paybackAmount = amount;
|
||||
}
|
||||
|
||||
reserve.updateState();
|
||||
reserve.updateState(cachedData);
|
||||
|
||||
if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
|
||||
IStableDebtToken(reserve.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
|
||||
|
|
|
@ -18,6 +18,7 @@ import {Errors} from '../libraries/helpers/Errors.sol';
|
|||
import {ValidationLogic} from '../libraries/logic/ValidationLogic.sol';
|
||||
import {DataTypes} from '../libraries/types/DataTypes.sol';
|
||||
import {LendingPoolStorage} from './LendingPoolStorage.sol';
|
||||
import {CachingHelper} from '../libraries/helpers/CachingHelper.sol';
|
||||
|
||||
/**
|
||||
* @title LendingPoolCollateralManager contract
|
||||
|
@ -160,7 +161,9 @@ contract LendingPoolCollateralManager is
|
|||
}
|
||||
}
|
||||
|
||||
debtReserve.updateState();
|
||||
CachingHelper.CachedData memory debtReserveCachedData = CachingHelper.fetchData(debtReserve);
|
||||
|
||||
debtReserve.updateState(debtReserveCachedData);
|
||||
|
||||
if (vars.userVariableDebt >= vars.actualDebtToLiquidate) {
|
||||
IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(
|
||||
|
@ -200,7 +203,9 @@ contract LendingPoolCollateralManager is
|
|||
emit ReserveUsedAsCollateralEnabled(collateralAsset, msg.sender);
|
||||
}
|
||||
} else {
|
||||
collateralReserve.updateState();
|
||||
CachingHelper.CachedData memory collateralReserveCachedData = CachingHelper.fetchData(collateralReserve);
|
||||
|
||||
collateralReserve.updateState(collateralReserveCachedData);
|
||||
collateralReserve.updateInterestRates(
|
||||
collateralAsset,
|
||||
address(vars.collateralAtoken),
|
||||
|
|
59
contracts/protocol/libraries/helpers/CachingHelper.sol
Normal file
59
contracts/protocol/libraries/helpers/CachingHelper.sol
Normal file
|
@ -0,0 +1,59 @@
|
|||
pragma solidity 0.6.12;
|
||||
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {DataTypes} from '../types/DataTypes.sol';
|
||||
import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
|
||||
|
||||
library CachingHelper {
|
||||
struct CachedData {
|
||||
uint256 oldScaledVariableDebt;
|
||||
uint256 oldTotalVariableDebt;
|
||||
uint256 newSscaledVariableDebt;
|
||||
uint256 newTtotalVariableDebt;
|
||||
uint256 oldPrincipalStableDebt;
|
||||
uint256 oldAvgStableBorrowRate;
|
||||
uint256 oldTotalStableDebt;
|
||||
uint256 newPrincipalStableDebt;
|
||||
uint256 newAvgStableBorrowRate;
|
||||
uint256 newTotalStableDebt;
|
||||
uint256 oldLiquidityIndex;
|
||||
uint256 newLiquidityIndex;
|
||||
uint256 oldVariableBorrowIndex;
|
||||
uint256 newVariableBorrowIndex;
|
||||
uint256 oldLiquidityRate;
|
||||
uint256 oldVariableBorrowRate;
|
||||
DataTypes.ReserveConfigurationMap reserveConfiguration;
|
||||
address aTokenAddress;
|
||||
address stableDebtTokenAddress;
|
||||
address variableDebtTokenAddress;
|
||||
uint40 reserveLastUpdateTimestamp;
|
||||
}
|
||||
|
||||
function fetchData(DataTypes.ReserveData storage reserveData)
|
||||
internal
|
||||
view
|
||||
returns (CachingHelper.CachedData memory)
|
||||
{
|
||||
CachedData memory cachedData;
|
||||
|
||||
cachedData.oldLiquidityIndex = reserveData.liquidityIndex;
|
||||
cachedData.oldVariableBorrowIndex = reserveData.variableBorrowIndex;
|
||||
|
||||
cachedData.aTokenAddress = reserveData.aTokenAddress;
|
||||
cachedData.stableDebtTokenAddress = reserveData.stableDebtTokenAddress;
|
||||
cachedData.variableDebtTokenAddress = reserveData.variableDebtTokenAddress;
|
||||
|
||||
cachedData.reserveConfiguration = reserveData.configuration;
|
||||
|
||||
cachedData.oldLiquidityRate = reserveData.currentLiquidityRate;
|
||||
cachedData.oldVariableBorrowRate = reserveData.currentVariableBorrowRate;
|
||||
|
||||
cachedData.reserveLastUpdateTimestamp = reserveData.lastUpdateTimestamp;
|
||||
|
||||
cachedData.oldScaledVariableDebt = IVariableDebtToken(cachedData.variableDebtTokenAddress)
|
||||
.scaledTotalSupply();
|
||||
|
||||
return cachedData;
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import {WadRayMath} from '../math/WadRayMath.sol';
|
|||
import {PercentageMath} from '../math/PercentageMath.sol';
|
||||
import {Errors} from '../helpers/Errors.sol';
|
||||
import {DataTypes} from '../types/DataTypes.sol';
|
||||
import {CachingHelper} from '../helpers/CachingHelper.sol';
|
||||
|
||||
/**
|
||||
* @title ReserveLogic library
|
||||
|
@ -107,29 +108,22 @@ library ReserveLogic {
|
|||
* @dev Updates the liquidity cumulative index and the variable borrow index.
|
||||
* @param reserve the reserve object
|
||||
**/
|
||||
function updateState(DataTypes.ReserveData storage reserve) internal {
|
||||
uint256 scaledVariableDebt =
|
||||
IVariableDebtToken(reserve.variableDebtTokenAddress).scaledTotalSupply();
|
||||
uint256 previousVariableBorrowIndex = reserve.variableBorrowIndex;
|
||||
uint256 previousLiquidityIndex = reserve.liquidityIndex;
|
||||
uint40 lastUpdatedTimestamp = reserve.lastUpdateTimestamp;
|
||||
function updateState(DataTypes.ReserveData storage reserve, CachingHelper.CachedData memory cachedData) internal {
|
||||
|
||||
(uint256 newLiquidityIndex, uint256 newVariableBorrowIndex) =
|
||||
_updateIndexes(
|
||||
reserve,
|
||||
scaledVariableDebt,
|
||||
previousLiquidityIndex,
|
||||
previousVariableBorrowIndex,
|
||||
lastUpdatedTimestamp
|
||||
cachedData
|
||||
);
|
||||
|
||||
|
||||
|
||||
_accrueToTreasury(
|
||||
reserve,
|
||||
scaledVariableDebt,
|
||||
previousVariableBorrowIndex,
|
||||
newLiquidityIndex,
|
||||
newVariableBorrowIndex,
|
||||
lastUpdatedTimestamp
|
||||
cachedData.oldScaledVariableDebt,
|
||||
cachedData.oldVariableBorrowIndex,
|
||||
cachedData.newLiquidityIndex,
|
||||
cachedData.newVariableBorrowIndex,
|
||||
cachedData.reserveLastUpdateTimestamp
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -209,9 +203,7 @@ library ReserveLogic {
|
|||
(vars.totalStableDebt, vars.avgStableRate) = IStableDebtToken(vars.stableDebtTokenAddress)
|
||||
.getTotalSupplyAndAvgRate();
|
||||
|
||||
//calculates the total variable debt locally using the scaled total supply instead
|
||||
//of totalSupply(), as it's noticeably cheaper. Also, the index has been
|
||||
//updated by the previous updateState() call
|
||||
|
||||
vars.totalVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress)
|
||||
.scaledTotalSupply()
|
||||
.rayMul(reserve.variableBorrowIndex);
|
||||
|
@ -327,47 +319,40 @@ library ReserveLogic {
|
|||
/**
|
||||
* @dev Updates the reserve indexes and the timestamp of the update
|
||||
* @param reserve The reserve reserve to be updated
|
||||
* @param scaledVariableDebt The scaled variable debt
|
||||
* @param liquidityIndex The last stored liquidity index
|
||||
* @param variableBorrowIndex The last stored variable borrow index
|
||||
* @param cachedData The cache layer holding the cached protocol data
|
||||
**/
|
||||
function _updateIndexes(
|
||||
DataTypes.ReserveData storage reserve,
|
||||
uint256 scaledVariableDebt,
|
||||
uint256 liquidityIndex,
|
||||
uint256 variableBorrowIndex,
|
||||
uint40 timestamp
|
||||
) internal returns (uint256, uint256) {
|
||||
uint256 currentLiquidityRate = reserve.currentLiquidityRate;
|
||||
CachingHelper.CachedData memory cachedData
|
||||
) internal {
|
||||
|
||||
uint256 newLiquidityIndex = liquidityIndex;
|
||||
uint256 newVariableBorrowIndex = variableBorrowIndex;
|
||||
cachedData.newLiquidityIndex = cachedData.oldLiquidityIndex;
|
||||
cachedData.newVariableBorrowIndex = cachedData.oldVariableBorrowIndex;
|
||||
|
||||
//only cumulating if there is any income being produced
|
||||
if (currentLiquidityRate > 0) {
|
||||
if (cachedData.oldLiquidityRate > 0) {
|
||||
uint256 cumulatedLiquidityInterest =
|
||||
MathUtils.calculateLinearInterest(currentLiquidityRate, timestamp);
|
||||
newLiquidityIndex = cumulatedLiquidityInterest.rayMul(liquidityIndex);
|
||||
require(newLiquidityIndex <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW);
|
||||
MathUtils.calculateLinearInterest(cachedData.oldLiquidityRate, cachedData.reserveLastUpdateTimestamp);
|
||||
cachedData.newLiquidityIndex = cumulatedLiquidityInterest.rayMul(cachedData.oldLiquidityIndex);
|
||||
require( cachedData.newLiquidityIndex <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW);
|
||||
|
||||
reserve.liquidityIndex = uint128(newLiquidityIndex);
|
||||
reserve.liquidityIndex = uint128(cachedData.newLiquidityIndex);
|
||||
|
||||
//as the liquidity rate might come only from stable rate loans, we need to ensure
|
||||
//that there is actual variable debt before accumulating
|
||||
if (scaledVariableDebt != 0) {
|
||||
if (cachedData.oldScaledVariableDebt != 0) {
|
||||
uint256 cumulatedVariableBorrowInterest =
|
||||
MathUtils.calculateCompoundedInterest(reserve.currentVariableBorrowRate, timestamp);
|
||||
newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex);
|
||||
MathUtils.calculateCompoundedInterest(cachedData.oldVariableBorrowRate, cachedData.reserveLastUpdateTimestamp);
|
||||
cachedData.newVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(cachedData.oldVariableBorrowIndex);
|
||||
require(
|
||||
newVariableBorrowIndex <= type(uint128).max,
|
||||
cachedData.newVariableBorrowIndex <= type(uint128).max,
|
||||
Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW
|
||||
);
|
||||
reserve.variableBorrowIndex = uint128(newVariableBorrowIndex);
|
||||
reserve.variableBorrowIndex = uint128(cachedData.newVariableBorrowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//solium-disable-next-line
|
||||
reserve.lastUpdateTimestamp = uint40(block.timestamp);
|
||||
return (newLiquidityIndex, newVariableBorrowIndex);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user