mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Optimized debt tokens
This commit is contained in:
parent
4d054dd56d
commit
5b7a2f2a55
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,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
|
||||||
|
@ -96,7 +103,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +113,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,7 +125,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -176,7 +187,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);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user