Skip to content

Commit

Permalink
Merge pull request #94 from aave/feat/mint-event-account-for-interest
Browse files Browse the repository at this point in the history
feat/mint event account for interest
  • Loading branch information
The-3D authored Sep 20, 2021
2 parents c22fd30 + 51c8762 commit d8942c1
Show file tree
Hide file tree
Showing 24 changed files with 1,285 additions and 950 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@ coverage
.coverage_cache
.coverage_contracts
coverage.json

7 changes: 7 additions & 0 deletions contracts/interfaces/IScaledBalanceToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,11 @@ interface IScaledBalanceToken {
* @return The scaled total supply
**/
function scaledTotalSupply() external view returns (uint256);

/**
* @notice Returns last index interest was accrued to the user's balance
* @param user The address of the user
* @return The last index interest was accrued to the user's balance
**/
function getPreviousIndex(address user) external view returns (uint256);
}
11 changes: 2 additions & 9 deletions contracts/protocol/libraries/helpers/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,8 @@ library Errors {
string public constant MATH_MULTIPLICATION_OVERFLOW = '48';
string public constant MATH_ADDITION_OVERFLOW = '49';
string public constant MATH_DIVISION_BY_ZERO = '50';
string public constant RL_LIQUIDITY_INDEX_OVERFLOW = '51'; // Liquidity index overflows uint128
string public constant RL_VARIABLE_BORROW_INDEX_OVERFLOW = '52'; // Variable borrow index overflows uint128
string public constant RL_LIQUIDITY_RATE_OVERFLOW = '53'; // Liquidity rate overflows uint128
string public constant RL_VARIABLE_BORROW_RATE_OVERFLOW = '54'; // Variable borrow rate overflows uint128
string public constant RL_STABLE_BORROW_RATE_OVERFLOW = '55'; // Stable borrow rate overflows uint128
string public constant CT_INVALID_MINT_AMOUNT = '56'; //invalid amount to mint
string public constant P_FAILED_REPAY_WITH_COLLATERAL = '57';
string public constant CT_INVALID_BURN_AMOUNT = '58'; //invalid amount to burn
string public constant P_FAILED_COLLATERAL_SWAP = '60';
string public constant P_INVALID_EQUAL_ASSETS_TO_SWAP = '61';
string public constant P_REENTRANCY_NOT_ALLOWED = '62';
string public constant P_CALLER_MUST_BE_AN_ATOKEN = '63';
string public constant P_IS_PAUSED = '64'; // Deprecated 'Pool is paused'
Expand All @@ -97,7 +89,7 @@ library Errors {
string public constant P_INCONSISTENT_PARAMS_LENGTH = '74';
string public constant UL_INVALID_INDEX = '77';
string public constant P_NOT_CONTRACT = '78';
string public constant SDT_STABLE_DEBT_OVERFLOW = '79';
string public constant SDT_STABLE_DEBT_OVERFLOW = '79'; // Deprecated moved to general `HLP_UINT128_OVERFLOW`
string public constant SDT_BURN_EXCEEDS_BALANCE = '80';
string public constant VL_BORROW_CAP_EXCEEDED = '81';
string public constant RC_INVALID_BORROW_CAP = '82';
Expand All @@ -114,4 +106,5 @@ library Errors {
string public constant PC_FLASHLOAN_PREMIUMS_MISMATCH = '95';
string public constant PC_FLASHLOAN_PREMIUM_INVALID = '96';
string public constant RC_INVALID_LIQUIDATION_PROTOCOL_FEE = '97';
string public constant HLP_UINT128_OVERFLOW = '98';
}
6 changes: 6 additions & 0 deletions contracts/protocol/libraries/helpers/Helpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.7;

import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
import {Errors} from './Errors.sol';
import {DataTypes} from '../types/DataTypes.sol';

/**
Expand Down Expand Up @@ -44,4 +45,9 @@ library Helpers {
IERC20(reserve.variableDebtTokenAddress).balanceOf(user)
);
}

function castUint128(uint256 input) internal pure returns (uint128) {
require(input <= type(uint128).max, Errors.HLP_UINT128_OVERFLOW);
return uint128(input);
}
}
2 changes: 0 additions & 2 deletions contracts/protocol/libraries/logic/BorrowLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ library BorrowLogic {
reserve.updateState(reserveCache);

ValidationLogic.validateRepay(
params.lastBorrower,
params.lastBorrowTimestamp,
reserveCache,
params.amount,
interestRateMode,
Expand Down
26 changes: 7 additions & 19 deletions contracts/protocol/libraries/logic/ReserveLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {MathUtils} from '../math/MathUtils.sol';
import {WadRayMath} from '../math/WadRayMath.sol';
import {PercentageMath} from '../math/PercentageMath.sol';
import {Errors} from '../helpers/Errors.sol';
import {Helpers} from '../helpers/Helpers.sol';
import {DataTypes} from '../types/DataTypes.sol';

/**
Expand Down Expand Up @@ -120,9 +121,7 @@ library ReserveLogic {
uint256 result = amountToLiquidityRatio + WadRayMath.RAY;

result = result.rayMul(reserve.liquidityIndex);
require(result <= type(uint128).max, Errors.RL_LIQUIDITY_INDEX_OVERFLOW);

reserve.liquidityIndex = uint128(result);
reserve.liquidityIndex = Helpers.castUint128(result);
}

/**
Expand Down Expand Up @@ -190,13 +189,10 @@ library ReserveLogic {
reserveCache.nextAvgStableBorrowRate,
reserveCache.reserveConfiguration.getReserveFactorMemory()
);
require(vars.nextLiquidityRate <= type(uint128).max, Errors.RL_LIQUIDITY_RATE_OVERFLOW);
require(vars.nextStableRate <= type(uint128).max, Errors.RL_STABLE_BORROW_RATE_OVERFLOW);
require(vars.nextVariableRate <= type(uint128).max, Errors.RL_VARIABLE_BORROW_RATE_OVERFLOW);

reserve.currentLiquidityRate = uint128(vars.nextLiquidityRate);
reserve.currentStableBorrowRate = uint128(vars.nextStableRate);
reserve.currentVariableBorrowRate = uint128(vars.nextVariableRate);
reserve.currentLiquidityRate = Helpers.castUint128(vars.nextLiquidityRate);
reserve.currentStableBorrowRate = Helpers.castUint128(vars.nextStableRate);
reserve.currentVariableBorrowRate = Helpers.castUint128(vars.nextVariableRate);

emit ReserveDataUpdated(
reserveAddress,
Expand Down Expand Up @@ -296,11 +292,7 @@ library ReserveLogic {
reserveCache.nextLiquidityIndex = cumulatedLiquidityInterest.rayMul(
reserveCache.currLiquidityIndex
);
require(
reserveCache.nextLiquidityIndex <= type(uint128).max,
Errors.RL_LIQUIDITY_INDEX_OVERFLOW
);
reserve.liquidityIndex = uint128(reserveCache.nextLiquidityIndex);
reserve.liquidityIndex = Helpers.castUint128(reserveCache.nextLiquidityIndex);

//as the liquidity rate might come only from stable rate loans, we need to ensure
//that there is actual variable debt before accumulating
Expand All @@ -312,11 +304,7 @@ library ReserveLogic {
reserveCache.nextVariableBorrowIndex = cumulatedVariableBorrowInterest.rayMul(
reserveCache.currVariableBorrowIndex
);
require(
reserveCache.nextVariableBorrowIndex <= type(uint128).max,
Errors.RL_VARIABLE_BORROW_INDEX_OVERFLOW
);
reserve.variableBorrowIndex = uint128(reserveCache.nextVariableBorrowIndex);
reserve.variableBorrowIndex = Helpers.castUint128(reserveCache.nextVariableBorrowIndex);
}
}

Expand Down
15 changes: 10 additions & 5 deletions contracts/protocol/libraries/logic/ValidationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ library ValidationLogic {

/**
* @notice Validates a repay action
* @param lastBorrower The address of the last borrower
* @param lastBorrowTimestamp The timestamp for last borrow
* @param reserveCache The cached data of the reserve
* @param amountSent The amount sent for the repayment. Can be an actual value or uint(-1)
* @param rateMode The interest rate mode of the debt being repaid
Expand All @@ -257,8 +255,6 @@ library ValidationLogic {
* @param variableDebt The borrow balance of the user
*/
function validateRepay(
address lastBorrower,
uint40 lastBorrowTimestamp,
DataTypes.ReserveCache memory reserveCache,
uint256 amountSent,
DataTypes.InterestRateMode rateMode,
Expand All @@ -272,8 +268,17 @@ library ValidationLogic {

require(amountSent > 0, Errors.VL_INVALID_AMOUNT);

uint256 variableDebtPreviousIndex = IScaledBalanceToken(reserveCache.variableDebtTokenAddress)
.getPreviousIndex(onBehalfOf);

uint40 stableRatePreviousTimestamp = IStableDebtToken(reserveCache.stableDebtTokenAddress)
.getUserLastUpdated(onBehalfOf);

require(
lastBorrower != onBehalfOf || lastBorrowTimestamp != uint40(block.timestamp),
(stableRatePreviousTimestamp < uint40(block.timestamp) &&
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.STABLE) ||
(variableDebtPreviousIndex < reserveCache.nextVariableBorrowIndex &&
DataTypes.InterestRateMode(rateMode) == DataTypes.InterestRateMode.VARIABLE),
Errors.VL_SAME_BLOCK_BORROW_REPAY
);

Expand Down
2 changes: 0 additions & 2 deletions contracts/protocol/libraries/types/DataTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ library DataTypes {
uint256 amount;
uint256 rateMode;
address onBehalfOf;
address lastBorrower;
uint40 lastBorrowTimestamp;
bool useATokens;
}

Expand Down
32 changes: 3 additions & 29 deletions contracts/protocol/pool/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,6 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
_addressesProvider.getPriceOracle()
)
);
_lastBorrower = msg.sender;
_lastBorrowTimestamp = uint40(block.timestamp);
}

/// @inheritdoc IPool
Expand All @@ -187,15 +185,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
BorrowLogic.executeRepay(
_reserves[asset],
_usersConfig[onBehalfOf],
DataTypes.ExecuteRepayParams(
asset,
amount,
rateMode,
onBehalfOf,
_lastBorrower,
_lastBorrowTimestamp,
false
)
DataTypes.ExecuteRepayParams(asset, amount, rateMode, onBehalfOf, false)
);
}

Expand Down Expand Up @@ -223,15 +213,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
BorrowLogic.executeRepay(
_reserves[asset],
_usersConfig[onBehalfOf],
DataTypes.ExecuteRepayParams(
asset,
amount,
rateMode,
onBehalfOf,
_lastBorrower,
_lastBorrowTimestamp,
false
)
DataTypes.ExecuteRepayParams(asset, amount, rateMode, onBehalfOf, false)
);
}

Expand All @@ -246,15 +228,7 @@ contract Pool is VersionedInitializable, IPool, PoolStorage {
BorrowLogic.executeRepay(
_reserves[asset],
_usersConfig[onBehalfOf],
DataTypes.ExecuteRepayParams(
asset,
amount,
rateMode,
onBehalfOf,
_lastBorrower,
_lastBorrowTimestamp,
true
)
DataTypes.ExecuteRepayParams(asset, amount, rateMode, onBehalfOf, true)
);
}

Expand Down
4 changes: 0 additions & 4 deletions contracts/protocol/pool/PoolStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,4 @@ contract PoolStorage {
mapping(address => bool) _authorizedFlashBorrowers;

uint256 internal _flashLoanPremiumToProtocol;

address internal _lastBorrower;

uint40 internal _lastBorrowTimestamp;
}
42 changes: 32 additions & 10 deletions contracts/protocol/tokenization/AToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol';
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {Helpers} from '../libraries/helpers/Helpers.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {IPool} from '../../interfaces/IPool.sol';
import {IAToken} from '../../interfaces/IAToken.sol';
Expand Down Expand Up @@ -111,14 +112,25 @@ contract AToken is
) external override onlyPool {
uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
_burn(user, amountScaled);

uint256 scaledBalance = super.balanceOf(user);
uint256 accumulatedInterest = scaledBalance.rayMul(index) -
scaledBalance.rayMul(_userState[user].additionalData);

_burn(user, Helpers.castUint128(amountScaled));

if (receiverOfUnderlying != address(this)) {
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
}

_userState[user].additionalData = Helpers.castUint128(index);

emit Transfer(user, address(0), amount);
emit Burn(user, receiverOfUnderlying, amount, index);
if (accumulatedInterest > amount) {
emit Mint(user, accumulatedInterest - amount, index);
} else {
emit Burn(user, receiverOfUnderlying, amount - accumulatedInterest, index);
}
}

/// @inheritdoc IAToken
Expand All @@ -127,16 +139,21 @@ contract AToken is
uint256 amount,
uint256 index
) external override onlyPool returns (bool) {
uint256 previousBalance = super.balanceOf(user);

uint256 amountScaled = amount.rayDiv(index);
require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
_mint(user, amountScaled);

uint256 scaledBalance = super.balanceOf(user);
uint256 accumulatedInterest = scaledBalance.rayMul(index) -
scaledBalance.rayMul(_userState[user].additionalData);

_mint(user, Helpers.castUint128(amountScaled));

_userState[user].additionalData = Helpers.castUint128(index);

emit Transfer(address(0), user, amount);
emit Mint(user, amount, index);
emit Mint(user, amount + accumulatedInterest, index);

return previousBalance == 0;
return scaledBalance == 0;
}

/// @inheritdoc IAToken
Expand All @@ -151,7 +168,7 @@ contract AToken is
// The amount to mint can easily be very small since it is a fraction of the interest ccrued.
// In that case, the treasury will experience a (very small) loss, but it
// wont cause potentially valid transactions to fail.
_mint(treasury, amount.rayDiv(index));
_mint(treasury, Helpers.castUint128(amount.rayDiv(index)));

emit Transfer(address(0), treasury, amount);
emit Mint(treasury, amount, index);
Expand Down Expand Up @@ -211,6 +228,11 @@ contract AToken is
return super.totalSupply();
}

/// @inheritdoc IScaledBalanceToken
function getPreviousIndex(address user) public view virtual override returns (uint256) {
return _userState[user].additionalData;
}

/**
* @notice Returns the address of the Aave treasury, receiving the fees on this aToken
* @return Address of the Aave treasury
Expand Down Expand Up @@ -294,7 +316,7 @@ contract AToken is
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);

super._transfer(from, to, amount.rayDiv(index));
super._transfer(from, to, Helpers.castUint128(amount.rayDiv(index)));

if (validate) {
pool.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
Expand All @@ -312,7 +334,7 @@ contract AToken is
function _transfer(
address from,
address to,
uint256 amount
uint128 amount
) internal override {
_transfer(from, to, amount, true);
}
Expand Down
Loading

0 comments on commit d8942c1

Please sign in to comment.