mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'fix/24' into 'master'
Resolve "Gas optimizations" Closes #24 See merge request aave-tech/protocol-v2!31
This commit is contained in:
commit
0085458da4
|
@ -301,8 +301,8 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
||||||
// user must be borrowing on asset at a stable rate
|
// user must be borrowing on asset at a stable rate
|
||||||
require(stableBorrowBalance > 0, Errors.NOT_ENOUGH_STABLE_BORROW_BALANCE);
|
require(stableBorrowBalance > 0, Errors.NOT_ENOUGH_STABLE_BORROW_BALANCE);
|
||||||
|
|
||||||
uint256 rebalanceDownRateThreshold = reserve.currentStableBorrowRate.rayMul(
|
uint256 rebalanceDownRateThreshold = WadRayMath.ray().add(REBALANCE_DOWN_RATE_DELTA).rayMul(
|
||||||
WadRayMath.ray().add(REBALANCE_DOWN_RATE_DELTA)
|
reserve.currentStableBorrowRate
|
||||||
);
|
);
|
||||||
|
|
||||||
//1. user stable borrow rate is below the current liquidity rate. The loan needs to be rebalanced,
|
//1. user stable borrow rate is below the current liquidity rate. The loan needs to be rebalanced,
|
||||||
|
|
|
@ -37,6 +37,7 @@ library Errors {
|
||||||
string public constant REQUESTED_AMOUNT_TOO_SMALL = '25'; // 'The requested amount is too small for a FlashLoan.'
|
string public constant REQUESTED_AMOUNT_TOO_SMALL = '25'; // 'The requested amount is too small for a FlashLoan.'
|
||||||
string public constant INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent'
|
string public constant INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent'
|
||||||
string public constant CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The actual balance of the protocol is inconsistent'
|
string public constant CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The actual balance of the protocol is inconsistent'
|
||||||
|
string public constant INVALID_FLASHLOAN_MODE = '43'; //Invalid flashloan mode selected
|
||||||
|
|
||||||
// require error messages - aToken
|
// require error messages - aToken
|
||||||
string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
|
string public constant CALLER_MUST_BE_LENDING_POOL = '28'; // 'The caller of this function must be a lending pool'
|
||||||
|
@ -48,6 +49,11 @@ library Errors {
|
||||||
|
|
||||||
// require error messages - ReserveLogic
|
// require error messages - ReserveLogic
|
||||||
string public constant RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized'
|
string public constant RESERVE_ALREADY_INITIALIZED = '34'; // 'Reserve has already been initialized'
|
||||||
|
string public constant LIQUIDITY_INDEX_OVERFLOW = '47'; // Liquidity index overflows uint128
|
||||||
|
string public constant VARIABLE_BORROW_INDEX_OVERFLOW = '48'; // Variable borrow index overflows uint128
|
||||||
|
string public constant LIQUIDITY_RATE_OVERFLOW = '49'; // Liquidity rate overflows uint128
|
||||||
|
string public constant VARIABLE_BORROW_RATE_OVERFLOW = '50'; // Variable borrow rate overflows uint128
|
||||||
|
string public constant STABLE_BORROW_RATE_OVERFLOW = '51'; // Stable borrow rate overflows uint128
|
||||||
|
|
||||||
//require error messages - LendingPoolConfiguration
|
//require error messages - LendingPoolConfiguration
|
||||||
string public constant CALLER_NOT_LENDING_POOL_MANAGER = '35'; // 'The caller must be a lending pool manager'
|
string public constant CALLER_NOT_LENDING_POOL_MANAGER = '35'; // 'The caller must be a lending pool manager'
|
||||||
|
@ -62,5 +68,9 @@ library Errors {
|
||||||
string public constant SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '40'; // 'User did not borrow the specified currency'
|
string public constant SPECIFIED_CURRENCY_NOT_BORROWED_BY_USER = '40'; // 'User did not borrow the specified currency'
|
||||||
string public constant NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = '41'; // "There isn't enough liquidity available to liquidate"
|
string public constant NOT_ENOUGH_LIQUIDITY_TO_LIQUIDATE = '41'; // "There isn't enough liquidity available to liquidate"
|
||||||
string public constant NO_ERRORS = '42'; // 'No errors'
|
string public constant NO_ERRORS = '42'; // 'No errors'
|
||||||
string public constant INVALID_FLASHLOAN_MODE = '43'; //Invalid flashloan mode selected
|
|
||||||
|
//require error messages - Math libraries
|
||||||
|
string public constant MULTIPLICATION_OVERFLOW = '44';
|
||||||
|
string public constant ADDITION_OVERFLOW = '45';
|
||||||
|
string public constant DIVISION_BY_ZERO = '46';
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,25 +49,26 @@ library ReserveLogic {
|
||||||
|
|
||||||
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
|
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
|
||||||
struct ReserveData {
|
struct ReserveData {
|
||||||
//the liquidity index. Expressed in ray
|
|
||||||
uint256 lastLiquidityIndex;
|
|
||||||
//the current supply rate. Expressed in ray
|
|
||||||
uint256 currentLiquidityRate;
|
|
||||||
//the current variable borrow rate. Expressed in ray
|
|
||||||
uint256 currentVariableBorrowRate;
|
|
||||||
//the current stable borrow rate. Expressed in ray
|
|
||||||
uint256 currentStableBorrowRate;
|
|
||||||
//variable borrow index. Expressed in ray
|
|
||||||
uint256 lastVariableBorrowIndex;
|
|
||||||
//stores the reserve configuration
|
//stores the reserve configuration
|
||||||
ReserveConfiguration.Map configuration;
|
ReserveConfiguration.Map configuration;
|
||||||
address aTokenAddress;
|
address aTokenAddress;
|
||||||
address stableDebtTokenAddress;
|
address stableDebtTokenAddress;
|
||||||
address variableDebtTokenAddress;
|
address variableDebtTokenAddress;
|
||||||
address interestRateStrategyAddress;
|
address interestRateStrategyAddress;
|
||||||
|
//the liquidity index. Expressed in ray
|
||||||
|
uint128 lastLiquidityIndex;
|
||||||
|
//the current supply rate. Expressed in ray
|
||||||
|
uint128 currentLiquidityRate;
|
||||||
|
//the current variable borrow rate. Expressed in ray
|
||||||
|
uint128 currentVariableBorrowRate;
|
||||||
|
//the current stable borrow rate. Expressed in ray
|
||||||
|
uint128 currentStableBorrowRate;
|
||||||
|
//variable borrow index. Expressed in ray
|
||||||
|
uint128 lastVariableBorrowIndex;
|
||||||
uint40 lastUpdateTimestamp;
|
uint40 lastUpdateTimestamp;
|
||||||
//the index of the reserve in the list of the active reserves
|
//the index of the reserve in the list of the active reserves
|
||||||
uint8 index;
|
uint8 index;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,27 +123,33 @@ library ReserveLogic {
|
||||||
* @param reserve the reserve object
|
* @param reserve the reserve object
|
||||||
**/
|
**/
|
||||||
function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
|
function updateCumulativeIndexesAndTimestamp(ReserveData storage reserve) internal {
|
||||||
//only cumulating if there is any income being produced
|
uint256 currentLiquidityRate = reserve.currentLiquidityRate;
|
||||||
if (
|
|
||||||
IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0 ||
|
|
||||||
IERC20(reserve.stableDebtTokenAddress).totalSupply() > 0
|
|
||||||
) {
|
|
||||||
uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp;
|
|
||||||
|
|
||||||
|
//only cumulating if there is any income being produced
|
||||||
|
if (currentLiquidityRate > 0) {
|
||||||
|
uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp;
|
||||||
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
|
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
|
||||||
reserve.currentLiquidityRate,
|
currentLiquidityRate,
|
||||||
lastUpdateTimestamp
|
lastUpdateTimestamp
|
||||||
);
|
);
|
||||||
|
uint256 index = cumulatedLiquidityInterest.rayMul(reserve.lastLiquidityIndex);
|
||||||
|
require(index < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
|
||||||
|
|
||||||
reserve.lastLiquidityIndex = cumulatedLiquidityInterest.rayMul(reserve.lastLiquidityIndex);
|
reserve.lastLiquidityIndex = uint128(index);
|
||||||
|
|
||||||
|
//as the liquidity rate might come only from stable rate loans, we need to ensure
|
||||||
|
//that there is actual variable debt before accumulating
|
||||||
|
if (IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0) {
|
||||||
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
|
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
|
||||||
reserve.currentVariableBorrowRate,
|
reserve.currentVariableBorrowRate,
|
||||||
lastUpdateTimestamp
|
lastUpdateTimestamp
|
||||||
);
|
);
|
||||||
reserve.lastVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(
|
index = cumulatedVariableBorrowInterest.rayMul(
|
||||||
reserve.lastVariableBorrowIndex
|
reserve.lastVariableBorrowIndex
|
||||||
);
|
);
|
||||||
|
require(index < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW);
|
||||||
|
reserve.lastVariableBorrowIndex = uint128(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
|
@ -163,9 +170,14 @@ library ReserveLogic {
|
||||||
) internal {
|
) internal {
|
||||||
uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay());
|
uint256 amountToLiquidityRatio = amount.wadToRay().rayDiv(totalLiquidity.wadToRay());
|
||||||
|
|
||||||
uint256 cumulatedLiquidity = amountToLiquidityRatio.add(WadRayMath.ray());
|
uint256 result = amountToLiquidityRatio.add(WadRayMath.ray());
|
||||||
|
|
||||||
reserve.lastLiquidityIndex = cumulatedLiquidity.rayMul(reserve.lastLiquidityIndex);
|
result = result.rayMul(
|
||||||
|
reserve.lastLiquidityIndex
|
||||||
|
);
|
||||||
|
require(result < (1 << 128), Errors.LIQUIDITY_INDEX_OVERFLOW);
|
||||||
|
|
||||||
|
reserve.lastLiquidityIndex = uint128(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -184,11 +196,11 @@ library ReserveLogic {
|
||||||
require(reserve.aTokenAddress == address(0), Errors.RESERVE_ALREADY_INITIALIZED);
|
require(reserve.aTokenAddress == address(0), Errors.RESERVE_ALREADY_INITIALIZED);
|
||||||
if (reserve.lastLiquidityIndex == 0) {
|
if (reserve.lastLiquidityIndex == 0) {
|
||||||
//if the reserve has not been initialized yet
|
//if the reserve has not been initialized yet
|
||||||
reserve.lastLiquidityIndex = WadRayMath.ray();
|
reserve.lastLiquidityIndex = uint128(WadRayMath.ray());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reserve.lastVariableBorrowIndex == 0) {
|
if (reserve.lastVariableBorrowIndex == 0) {
|
||||||
reserve.lastVariableBorrowIndex = WadRayMath.ray();
|
reserve.lastVariableBorrowIndex = uint128(WadRayMath.ray());
|
||||||
}
|
}
|
||||||
|
|
||||||
reserve.aTokenAddress = aTokenAddress;
|
reserve.aTokenAddress = aTokenAddress;
|
||||||
|
@ -197,6 +209,14 @@ library ReserveLogic {
|
||||||
reserve.interestRateStrategyAddress = interestRateStrategyAddress;
|
reserve.interestRateStrategyAddress = interestRateStrategyAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UpdateInterestRatesLocalVars {
|
||||||
|
uint256 currentAvgStableRate;
|
||||||
|
uint256 availableLiquidity;
|
||||||
|
address stableDebtTokenAddress;
|
||||||
|
uint256 newLiquidityRate;
|
||||||
|
uint256 newStableRate;
|
||||||
|
uint256 newVariableRate;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl.
|
* @dev Updates the reserve current stable borrow rate Rf, the current variable borrow rate Rv and the current liquidity rate Rl.
|
||||||
* Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
|
* Also updates the lastUpdateTimestamp value. Please refer to the whitepaper for further information.
|
||||||
|
@ -211,31 +231,37 @@ library ReserveLogic {
|
||||||
uint256 liquidityAdded,
|
uint256 liquidityAdded,
|
||||||
uint256 liquidityTaken
|
uint256 liquidityTaken
|
||||||
) internal {
|
) internal {
|
||||||
uint256 currentAvgStableRate = IStableDebtToken(reserve.stableDebtTokenAddress)
|
UpdateInterestRatesLocalVars memory vars;
|
||||||
.getAverageStableRate();
|
|
||||||
|
vars.stableDebtTokenAddress = reserve.stableDebtTokenAddress;
|
||||||
|
vars.currentAvgStableRate = IStableDebtToken(vars.stableDebtTokenAddress).getAverageStableRate();
|
||||||
|
vars.availableLiquidity = IERC20(reserveAddress).balanceOf(aTokenAddress);
|
||||||
|
|
||||||
(
|
(
|
||||||
uint256 newLiquidityRate,
|
vars.newLiquidityRate,
|
||||||
uint256 newStableRate,
|
vars.newStableRate,
|
||||||
uint256 newVariableRate
|
vars.newVariableRate
|
||||||
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
|
) = IReserveInterestRateStrategy(reserve.interestRateStrategyAddress).calculateInterestRates(
|
||||||
reserveAddress,
|
reserveAddress,
|
||||||
IERC20(reserveAddress).balanceOf(aTokenAddress).add(liquidityAdded).sub(liquidityTaken),
|
vars.availableLiquidity.add(liquidityAdded).sub(liquidityTaken),
|
||||||
IERC20(reserve.stableDebtTokenAddress).totalSupply(),
|
IERC20(vars.stableDebtTokenAddress).totalSupply(),
|
||||||
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
|
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
|
||||||
currentAvgStableRate
|
vars.currentAvgStableRate
|
||||||
);
|
);
|
||||||
|
require(vars.newLiquidityRate < (1 << 128), "ReserveLogic: Liquidity rate overflow");
|
||||||
|
require(vars.newStableRate < (1 << 128), "ReserveLogic: Stable borrow rate overflow");
|
||||||
|
require(vars.newVariableRate < (1 << 128), "ReserveLogic: Variable borrow rate overflow");
|
||||||
|
|
||||||
reserve.currentLiquidityRate = newLiquidityRate;
|
reserve.currentLiquidityRate = uint128(vars.newLiquidityRate);
|
||||||
reserve.currentStableBorrowRate = newStableRate;
|
reserve.currentStableBorrowRate = uint128(vars.newStableRate);
|
||||||
reserve.currentVariableBorrowRate = newVariableRate;
|
reserve.currentVariableBorrowRate = uint128(vars.newVariableRate);
|
||||||
|
|
||||||
emit ReserveDataUpdated(
|
emit ReserveDataUpdated(
|
||||||
reserveAddress,
|
reserveAddress,
|
||||||
newLiquidityRate,
|
vars.newLiquidityRate,
|
||||||
newStableRate,
|
vars.newStableRate,
|
||||||
currentAvgStableRate,
|
vars.currentAvgStableRate,
|
||||||
newVariableRate,
|
vars.newVariableRate,
|
||||||
reserve.lastLiquidityIndex,
|
reserve.lastLiquidityIndex,
|
||||||
reserve.lastVariableBorrowIndex
|
reserve.lastVariableBorrowIndex
|
||||||
);
|
);
|
||||||
|
|
|
@ -55,17 +55,17 @@ library MathUtils {
|
||||||
return WadRayMath.ray();
|
return WadRayMath.ray();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 expMinusOne = exp.sub(1);
|
uint256 expMinusOne = exp-1;
|
||||||
|
|
||||||
uint256 expMinusTwo = exp > 2 ? exp.sub(2) : 0;
|
uint256 expMinusTwo = exp > 2 ? exp-2 : 0;
|
||||||
|
|
||||||
uint256 ratePerSecond = rate.div(31536000);
|
uint256 ratePerSecond = rate/SECONDS_PER_YEAR;
|
||||||
|
|
||||||
uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond);
|
uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond);
|
||||||
uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond);
|
uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond);
|
||||||
|
|
||||||
uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo).div(2);
|
uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo)/2;
|
||||||
uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree).div(6);
|
uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree)/6;
|
||||||
|
|
||||||
return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm);
|
return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
// SPDX-License-Identifier: agpl-3.0
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
pragma solidity ^0.6.8;
|
pragma solidity ^0.6.8;
|
||||||
|
|
||||||
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
|
|
||||||
|
import {Errors} from '../helpers/Errors.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title PercentageMath library
|
* @title PercentageMath library
|
||||||
|
@ -12,7 +13,6 @@ import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
|
||||||
**/
|
**/
|
||||||
|
|
||||||
library PercentageMath {
|
library PercentageMath {
|
||||||
using SafeMath for uint256;
|
|
||||||
|
|
||||||
uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals
|
uint256 constant PERCENTAGE_FACTOR = 1e4; //percentage plus two decimals
|
||||||
uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2;
|
uint256 constant HALF_PERCENT = PERCENTAGE_FACTOR / 2;
|
||||||
|
@ -24,7 +24,19 @@ library PercentageMath {
|
||||||
* @return the percentage of value
|
* @return the percentage of value
|
||||||
**/
|
**/
|
||||||
function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) {
|
function percentMul(uint256 value, uint256 percentage) internal pure returns (uint256) {
|
||||||
return HALF_PERCENT.add(value.mul(percentage)).div(PERCENTAGE_FACTOR);
|
if(value == 0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 result = value*percentage;
|
||||||
|
|
||||||
|
require(result/value == percentage, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
|
||||||
|
result+=HALF_PERCENT;
|
||||||
|
|
||||||
|
require(result >= HALF_PERCENT, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
|
return result/PERCENTAGE_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,8 +46,17 @@ library PercentageMath {
|
||||||
* @return the value divided the percentage
|
* @return the value divided the percentage
|
||||||
**/
|
**/
|
||||||
function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) {
|
function percentDiv(uint256 value, uint256 percentage) internal pure returns (uint256) {
|
||||||
|
require(percentage != 0, Errors.DIVISION_BY_ZERO);
|
||||||
uint256 halfPercentage = percentage / 2;
|
uint256 halfPercentage = percentage / 2;
|
||||||
|
|
||||||
return halfPercentage.add(value.mul(PERCENTAGE_FACTOR)).div(percentage);
|
uint256 result = value*PERCENTAGE_FACTOR;
|
||||||
|
|
||||||
|
require(result/PERCENTAGE_FACTOR == value, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
|
||||||
|
result += halfPercentage;
|
||||||
|
|
||||||
|
require(result >= halfPercentage, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
|
return result/percentage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: agpl-3.0
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
pragma solidity ^0.6.8;
|
pragma solidity ^0.6.8;
|
||||||
|
|
||||||
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
|
import {Errors} from '../helpers/Errors.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title WadRayMath library
|
* @title WadRayMath library
|
||||||
|
@ -10,7 +10,6 @@ import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
|
||||||
**/
|
**/
|
||||||
|
|
||||||
library WadRayMath {
|
library WadRayMath {
|
||||||
using SafeMath for uint256;
|
|
||||||
|
|
||||||
uint256 internal constant WAD = 1e18;
|
uint256 internal constant WAD = 1e18;
|
||||||
uint256 internal constant halfWAD = WAD / 2;
|
uint256 internal constant halfWAD = WAD / 2;
|
||||||
|
@ -56,7 +55,20 @@ library WadRayMath {
|
||||||
* @return the result of a*b, in wad
|
* @return the result of a*b, in wad
|
||||||
**/
|
**/
|
||||||
function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
|
function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||||
return halfWAD.add(a.mul(b)).div(WAD);
|
|
||||||
|
if(a == 0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 result = a*b;
|
||||||
|
|
||||||
|
require(result/a == b, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
|
||||||
|
result+=halfWAD;
|
||||||
|
|
||||||
|
require(result >= halfWAD, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
|
return result/WAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,9 +78,19 @@ library WadRayMath {
|
||||||
* @return the result of a/b, in wad
|
* @return the result of a/b, in wad
|
||||||
**/
|
**/
|
||||||
function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
|
function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||||
|
require(b != 0, Errors.DIVISION_BY_ZERO);
|
||||||
|
|
||||||
uint256 halfB = b / 2;
|
uint256 halfB = b / 2;
|
||||||
|
|
||||||
return halfB.add(a.mul(WAD)).div(b);
|
uint256 result = a*WAD;
|
||||||
|
|
||||||
|
require(result/WAD == a, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
|
||||||
|
result += halfB;
|
||||||
|
|
||||||
|
require(result >= halfB, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
|
return result/b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +100,19 @@ library WadRayMath {
|
||||||
* @return the result of a*b, in ray
|
* @return the result of a*b, in ray
|
||||||
**/
|
**/
|
||||||
function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
|
function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||||
return halfRAY.add(a.mul(b)).div(RAY);
|
if(a == 0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 result = a*b;
|
||||||
|
|
||||||
|
require(result/a == b, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
|
||||||
|
result+=halfRAY;
|
||||||
|
|
||||||
|
require(result >= halfRAY, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
|
return result/RAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,9 +122,20 @@ library WadRayMath {
|
||||||
* @return the result of a/b, in ray
|
* @return the result of a/b, in ray
|
||||||
**/
|
**/
|
||||||
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
|
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||||
|
require(b != 0, Errors.DIVISION_BY_ZERO);
|
||||||
|
|
||||||
uint256 halfB = b / 2;
|
uint256 halfB = b / 2;
|
||||||
|
|
||||||
return halfB.add(a.mul(RAY)).div(b);
|
uint256 result = a*RAY;
|
||||||
|
|
||||||
|
require(result/RAY == a, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
|
||||||
|
result += halfB;
|
||||||
|
|
||||||
|
require(result >= halfB, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
|
return result/b;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,8 +145,10 @@ library WadRayMath {
|
||||||
**/
|
**/
|
||||||
function rayToWad(uint256 a) internal pure returns (uint256) {
|
function rayToWad(uint256 a) internal pure returns (uint256) {
|
||||||
uint256 halfRatio = WAD_RAY_RATIO / 2;
|
uint256 halfRatio = WAD_RAY_RATIO / 2;
|
||||||
|
uint256 result = halfRatio+a;
|
||||||
|
require(result >= halfRatio, Errors.ADDITION_OVERFLOW);
|
||||||
|
|
||||||
return halfRatio.add(a).div(WAD_RAY_RATIO);
|
return result/WAD_RAY_RATIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,6 +157,8 @@ library WadRayMath {
|
||||||
* @return a converted in ray
|
* @return a converted in ray
|
||||||
**/
|
**/
|
||||||
function wadToRay(uint256 a) internal pure returns (uint256) {
|
function wadToRay(uint256 a) internal pure returns (uint256) {
|
||||||
return a.mul(WAD_RAY_RATIO);
|
uint256 result = a*WAD_RAY_RATIO;
|
||||||
|
require(result/WAD_RAY_RATIO == a, Errors.MULTIPLICATION_OVERFLOW);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,27 +11,17 @@ import {IStableDebtToken} from './interfaces/IStableDebtToken.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title contract StableDebtToken
|
* @title contract StableDebtToken
|
||||||
*
|
* @notice Implements a stable debt token to track the user positions
|
||||||
* @notice defines the interface for the stable debt token
|
|
||||||
*
|
|
||||||
* @dev it does not inherit from IERC20 to save in code size
|
|
||||||
*
|
|
||||||
* @author Aave
|
* @author Aave
|
||||||
*
|
|
||||||
**/
|
**/
|
||||||
contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
using WadRayMath for uint256;
|
using WadRayMath for uint256;
|
||||||
|
|
||||||
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
|
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
|
||||||
struct UserData {
|
|
||||||
uint256 currentRate;
|
|
||||||
uint40 lastUpdateTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint256 private avgStableRate;
|
uint256 private _avgStableRate;
|
||||||
|
mapping(address => uint40) _timestamps;
|
||||||
mapping(address => UserData) private _usersData;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
address pool,
|
address pool,
|
||||||
|
@ -53,7 +43,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
* @return the average stable rate
|
* @return the average stable rate
|
||||||
**/
|
**/
|
||||||
function getAverageStableRate() external virtual override view returns (uint256) {
|
function getAverageStableRate() external virtual override view returns (uint256) {
|
||||||
return avgStableRate;
|
return _avgStableRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,7 +51,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
* @return the last update timestamp
|
* @return the last update timestamp
|
||||||
**/
|
**/
|
||||||
function getUserLastUpdated(address user) external virtual override view returns (uint40) {
|
function getUserLastUpdated(address user) external virtual override view returns (uint40) {
|
||||||
return _usersData[user].lastUpdateTimestamp;
|
return _timestamps[user];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,7 +60,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
* @return the stable rate of user
|
* @return the stable rate of user
|
||||||
**/
|
**/
|
||||||
function getUserStableRate(address user) external virtual override view returns (uint256) {
|
function getUserStableRate(address user) external virtual override view returns (uint256) {
|
||||||
return _usersData[user].currentRate;
|
return _usersData[user].dataField;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,16 +68,14 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
* @return the accumulated debt of the user
|
* @return the accumulated debt of the user
|
||||||
**/
|
**/
|
||||||
function balanceOf(address account) public virtual override view returns (uint256) {
|
function balanceOf(address account) public virtual override view returns (uint256) {
|
||||||
uint256 accountBalance = _balances[account];
|
uint256 accountBalance = _usersData[account].balance;
|
||||||
|
uint256 stableRate = _usersData[account].dataField;
|
||||||
if (accountBalance == 0) {
|
if (accountBalance == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserData storage userData = _usersData[account];
|
|
||||||
|
|
||||||
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
|
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
|
||||||
userData.currentRate,
|
stableRate,
|
||||||
userData.lastUpdateTimestamp
|
_timestamps[account]
|
||||||
);
|
);
|
||||||
return accountBalance.wadToRay().rayMul(cumulatedInterest).rayToWad();
|
return accountBalance.wadToRay().rayMul(cumulatedInterest).rayToWad();
|
||||||
}
|
}
|
||||||
|
@ -126,19 +114,20 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
vars.amountInRay = amount.wadToRay();
|
vars.amountInRay = amount.wadToRay();
|
||||||
|
|
||||||
//calculates the new stable rate for the user
|
//calculates the new stable rate for the user
|
||||||
vars.newStableRate = _usersData[user]
|
vars.newStableRate = uint256(_usersData[user]
|
||||||
.currentRate
|
.dataField)
|
||||||
.rayMul(currentBalance.wadToRay())
|
.rayMul(currentBalance.wadToRay())
|
||||||
.add(vars.amountInRay.rayMul(rate))
|
.add(vars.amountInRay.rayMul(rate))
|
||||||
.rayDiv(currentBalance.add(amount).wadToRay());
|
.rayDiv(currentBalance.add(amount).wadToRay());
|
||||||
|
|
||||||
_usersData[user].currentRate = vars.newStableRate;
|
require(vars.newStableRate < (1 << 128), "Debt token: stable rate overflow");
|
||||||
|
_usersData[user].dataField = uint128(vars.newStableRate);
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
_usersData[user].lastUpdateTimestamp = uint40(block.timestamp);
|
_timestamps[user] = uint40(block.timestamp);
|
||||||
|
|
||||||
//calculates the updated average stable rate
|
//calculates the updated average stable rate
|
||||||
avgStableRate = avgStableRate
|
_avgStableRate = _avgStableRate
|
||||||
.rayMul(vars.supplyBeforeMint.wadToRay())
|
.rayMul(vars.supplyBeforeMint.wadToRay())
|
||||||
.add(rate.rayMul(vars.amountInRay))
|
.add(rate.rayMul(vars.amountInRay))
|
||||||
.rayDiv(vars.supplyAfterMint.wadToRay());
|
.rayDiv(vars.supplyAfterMint.wadToRay());
|
||||||
|
@ -171,20 +160,20 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
|
||||||
uint256 supplyAfterBurn = supplyBeforeBurn.sub(amount);
|
uint256 supplyAfterBurn = supplyBeforeBurn.sub(amount);
|
||||||
|
|
||||||
if (supplyAfterBurn == 0) {
|
if (supplyAfterBurn == 0) {
|
||||||
avgStableRate = 0;
|
_avgStableRate = 0;
|
||||||
} else {
|
} else {
|
||||||
avgStableRate = avgStableRate
|
_avgStableRate = _avgStableRate
|
||||||
.rayMul(supplyBeforeBurn.wadToRay())
|
.rayMul(supplyBeforeBurn.wadToRay())
|
||||||
.sub(_usersData[user].currentRate.rayMul(amount.wadToRay()))
|
.sub(uint256(_usersData[user].dataField).rayMul(amount.wadToRay()))
|
||||||
.rayDiv(supplyAfterBurn.wadToRay());
|
.rayDiv(supplyAfterBurn.wadToRay());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount == currentBalance) {
|
if (amount == currentBalance) {
|
||||||
_usersData[user].currentRate = 0;
|
_usersData[user].dataField = 0;
|
||||||
_usersData[user].lastUpdateTimestamp = 0;
|
_timestamps[user] = 0;
|
||||||
} else {
|
} else {
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
_usersData[user].lastUpdateTimestamp = uint40(block.timestamp);
|
_timestamps[user] = uint40(block.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (balanceIncrease > amount) {
|
if (balanceIncrease > amount) {
|
||||||
|
|
|
@ -9,10 +9,9 @@ import {WadRayMath} from '../libraries/math/WadRayMath.sol';
|
||||||
import {IVariableDebtToken} from './interfaces/IVariableDebtToken.sol';
|
import {IVariableDebtToken} from './interfaces/IVariableDebtToken.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title interface IVariableDebtToken
|
* @title contract VariableDebtToken
|
||||||
|
* @notice Implements a variable debt token to track the user positions
|
||||||
* @author Aave
|
* @author Aave
|
||||||
* @notice defines the basic interface for a variable debt token.
|
|
||||||
* @dev does not inherit from IERC20 to save in contract size
|
|
||||||
**/
|
**/
|
||||||
contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
@ -20,8 +19,6 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
|
|
||||||
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
|
uint256 public constant DEBT_TOKEN_REVISION = 0x1;
|
||||||
|
|
||||||
mapping(address => uint256) private _userIndexes;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
address pool,
|
address pool,
|
||||||
address underlyingAsset,
|
address underlyingAsset,
|
||||||
|
@ -42,7 +39,8 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
* @return the debt balance of the user
|
* @return the debt balance of the user
|
||||||
**/
|
**/
|
||||||
function balanceOf(address user) public virtual override view returns (uint256) {
|
function balanceOf(address user) public virtual override view returns (uint256) {
|
||||||
uint256 userBalance = _balances[user];
|
uint256 userBalance = _usersData[user].balance;
|
||||||
|
uint256 index = _usersData[user].dataField;
|
||||||
if (userBalance == 0) {
|
if (userBalance == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +49,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
userBalance
|
userBalance
|
||||||
.wadToRay()
|
.wadToRay()
|
||||||
.rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress))
|
.rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress))
|
||||||
.rayDiv(_userIndexes[user])
|
.rayDiv(index)
|
||||||
.rayToWad();
|
.rayToWad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +59,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
**/
|
**/
|
||||||
|
|
||||||
function getUserIndex(address user) external virtual override view returns (uint256) {
|
function getUserIndex(address user) external virtual override view returns (uint256) {
|
||||||
return _userIndexes[user];
|
return _usersData[user].dataField;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +77,8 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
_mint(user, amount.add(balanceIncrease));
|
_mint(user, amount.add(balanceIncrease));
|
||||||
|
|
||||||
uint256 newUserIndex = _pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress);
|
uint256 newUserIndex = _pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress);
|
||||||
_userIndexes[user] = newUserIndex;
|
require(newUserIndex < (1 << 128), "Debt token: Index overflow");
|
||||||
|
_usersData[user].dataField = uint128(newUserIndex);
|
||||||
|
|
||||||
emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
|
emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
|
||||||
}
|
}
|
||||||
|
@ -106,8 +105,9 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
|
||||||
//if user not repaid everything
|
//if user not repaid everything
|
||||||
if (currentBalance != amount) {
|
if (currentBalance != amount) {
|
||||||
newUserIndex = _pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress);
|
newUserIndex = _pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress);
|
||||||
|
require(newUserIndex < (1 << 128), "Debt token: Index overflow");
|
||||||
}
|
}
|
||||||
_userIndexes[user] = newUserIndex;
|
_usersData[user].dataField = uint128(newUserIndex);
|
||||||
|
|
||||||
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
|
emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,14 @@ abstract contract DebtTokenBase is IERC20Detailed, VersionedInitializable {
|
||||||
address internal immutable _underlyingAssetAddress;
|
address internal immutable _underlyingAssetAddress;
|
||||||
|
|
||||||
ILendingPool internal immutable _pool;
|
ILendingPool internal immutable _pool;
|
||||||
mapping(address => uint256) internal _balances;
|
|
||||||
|
struct UserData{
|
||||||
|
uint128 balance;
|
||||||
|
//this field will store the user index for the variable debt token, and the user stable rate for the stable debt token
|
||||||
|
uint128 dataField;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping(address => UserData) internal _usersData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev only lending pool can call functions marked by this modifier
|
* @dev only lending pool can call functions marked by this modifier
|
||||||
|
@ -97,7 +104,7 @@ abstract contract DebtTokenBase is IERC20Detailed, VersionedInitializable {
|
||||||
* @return the debt balance of the user since the last burn/mint action
|
* @return the debt balance of the user since the last burn/mint action
|
||||||
**/
|
**/
|
||||||
function principalBalanceOf(address user) public view returns (uint256) {
|
function principalBalanceOf(address user) public view returns (uint256) {
|
||||||
return _balances[user];
|
return _usersData[user].balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +114,9 @@ abstract contract DebtTokenBase is IERC20Detailed, VersionedInitializable {
|
||||||
**/
|
**/
|
||||||
function _mint(address user, uint256 amount) internal {
|
function _mint(address user, uint256 amount) internal {
|
||||||
_totalSupply = _totalSupply.add(amount);
|
_totalSupply = _totalSupply.add(amount);
|
||||||
_balances[user] = _balances[user].add(amount);
|
uint256 result = amount.add(_usersData[user].balance);
|
||||||
|
require(result < (1 << 128), "Debt token: balance overflow");
|
||||||
|
_usersData[user].balance = uint128(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,7 +126,9 @@ abstract contract DebtTokenBase is IERC20Detailed, VersionedInitializable {
|
||||||
**/
|
**/
|
||||||
function _burn(address user, uint256 amount) internal {
|
function _burn(address user, uint256 amount) internal {
|
||||||
_totalSupply = _totalSupply.sub(amount);
|
_totalSupply = _totalSupply.sub(amount);
|
||||||
_balances[user] = _balances[user].sub(amount);
|
uint256 result = uint256(_usersData[user].balance).sub(amount);
|
||||||
|
require(result < (1 << 128), "Debt token: balance overflow");
|
||||||
|
_usersData[user].balance = uint128(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -177,7 +188,7 @@ abstract contract DebtTokenBase is IERC20Detailed, VersionedInitializable {
|
||||||
uint256
|
uint256
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
uint256 previousPrincipalBalance = _balances[user];
|
uint256 previousPrincipalBalance = _usersData[user].balance;
|
||||||
|
|
||||||
if (previousPrincipalBalance == 0) {
|
if (previousPrincipalBalance == 0) {
|
||||||
return (0, 0, 0);
|
return (0, 0, 0);
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
|
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x193101EA4C68eb894aeb922D4aC9C612a464c735"
|
"address": "0x6642B57e4265BAD868C17Fc1d1F4F88DBBA04Aa8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"LendingPoolDataProvider": {
|
"LendingPoolDataProvider": {
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
|
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0xf9cD0476CFC1E983e9feA9366A2C08e10eFc9e25"
|
"address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PriceOracle": {
|
"PriceOracle": {
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x18C3df59BEb7babb81BC20f61c5C175D0Cb7603d",
|
"address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x39ed2aE701B56AD229A19E628Bf5A515795F0AA3",
|
"address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x9434029990cF00118c28a06E014F0d7d879f28CE",
|
"address": "0x7B6C3e5486D9e6959441ab554A889099eed76290",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0xccd7A2534fd4FD5119De8E368615b226e23F8F37",
|
"address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x4c010BA8A40e5c13Acc1E32c025c2b2aea405Dbb",
|
"address": "0x626FdE749F9d499d3777320CAf29484B624ab84a",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
|
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x2aE520a05B31f170a18C425a1e8626aB7Ef71984"
|
"address": "0x2B681757d757fbB80cc51c6094cEF5eE75bF55aA"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"WalletBalanceProvider": {
|
"WalletBalanceProvider": {
|
||||||
|
@ -178,7 +178,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0xBD2244f43f7BA73eB35A64302A6D8DBf17BdF2F1",
|
"address": "0xBEF0d4b9c089a5883741fC14cbA352055f35DDA2",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -417,7 +417,7 @@
|
||||||
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10"
|
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x18c3e48a45839B3BbC998c70A2fD41fB8D93a35D"
|
"address": "0xDf73fC454FA018051D4a1509e63D11530A59DE10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"StableDebtToken": {
|
"StableDebtToken": {
|
||||||
|
@ -426,7 +426,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x2ca7Aa6CcCdb5D77F1c1d3E6a21fF0F7ac24C825",
|
"address": "0xB660Fdd109a95718cB9d20E3A89EE6cE342aDcB6",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -436,13 +436,13 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x527a346011Cd6c71973f653426Ce609fa53dd59E",
|
"address": "0x830bceA96E56DBC1F8578f75fBaC0AF16B32A07d",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AToken": {
|
"AToken": {
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0x3035D5D127487Ee5Df5FD951D9624a8b877A8497",
|
"address": "0xA0AB1cB92A4AF81f84dCd258155B5c25D247b54E",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"buidlerevm": {
|
"buidlerevm": {
|
||||||
|
@ -456,7 +456,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0xAA6DfC2A802857Fadb75726B6166484e2c011cf5",
|
"address": "0x1203D1b97BF6E546c00C45Cda035D3010ACe1180",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -476,7 +476,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0xFd23fD3d937ae73a7b545B8Bfeb218395bDe9b8f",
|
"address": "0x8733AfE8174BA7c04c6CD694bD673294079b7E10",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -486,7 +486,7 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
},
|
},
|
||||||
"localhost": {
|
"localhost": {
|
||||||
"address": "0xEe821582b591CE5e4a9B7fFc4E2DAD47D3759C08",
|
"address": "0xA8083d78B6ABC328b4d3B714F76F384eCC7147e1",
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1408,8 +1408,8 @@ const calcExpectedLiquidityIndex = (reserveData: ReserveData, timestamp: BigNumb
|
||||||
};
|
};
|
||||||
|
|
||||||
const calcExpectedVariableBorrowIndex = (reserveData: ReserveData, timestamp: BigNumber) => {
|
const calcExpectedVariableBorrowIndex = (reserveData: ReserveData, timestamp: BigNumber) => {
|
||||||
//if utilization rate is 0, nothing to compound
|
//if totalBorrowsVariable is 0, nothing to compound
|
||||||
if (reserveData.utilizationRate.eq('0')) {
|
if (reserveData.totalBorrowsVariable.eq('0')) {
|
||||||
return reserveData.variableBorrowIndex;
|
return reserveData.variableBorrowIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user