Merge branch 'master' into fix/22

This commit is contained in:
The3D 2020-08-21 15:14:43 +02:00
commit b7fa1bcac8
16 changed files with 542 additions and 524 deletions

View File

@ -9,7 +9,7 @@ import {
VersionedInitializable VersionedInitializable
} from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol'; import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
import {IAToken} from '../interfaces/IAToken.sol'; import {IAToken} from '../tokenization/interfaces/IAToken.sol';
import {Helpers} from '../libraries/helpers/Helpers.sol'; import {Helpers} from '../libraries/helpers/Helpers.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol'; import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol'; import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';

View File

@ -9,7 +9,7 @@ import {
VersionedInitializable VersionedInitializable
} from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol'; import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
import {IAToken} from '../interfaces/IAToken.sol'; import {IAToken} from '../tokenization/interfaces/IAToken.sol';
import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol'; import {IStableDebtToken} from '../tokenization/interfaces/IStableDebtToken.sol';
import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol'; import {IVariableDebtToken} from '../tokenization/interfaces/IVariableDebtToken.sol';
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol'; import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';

View File

@ -22,94 +22,94 @@ contract ChainlinkProxyPriceProvider is IPriceOracleGetter, Ownable {
event FallbackOracleUpdated(address indexed fallbackOracle); event FallbackOracleUpdated(address indexed fallbackOracle);
mapping(address => IChainlinkAggregator) private assetsSources; mapping(address => IChainlinkAggregator) private assetsSources;
IPriceOracleGetter private fallbackOracle; IPriceOracleGetter private _fallbackOracle;
/// @notice Constructor /// @notice Constructor
/// @param _assets The addresses of the assets /// @param assets The addresses of the assets
/// @param _sources The address of the source of each asset /// @param sources The address of the source of each asset
/// @param _fallbackOracle The address of the fallback oracle to use if the data of an /// @param fallbackOracle The address of the fallback oracle to use if the data of an
/// aggregator is not consistent /// aggregator is not consistent
constructor( constructor(
address[] memory _assets, address[] memory assets,
address[] memory _sources, address[] memory sources,
address _fallbackOracle address fallbackOracle
) public { ) public {
internalSetFallbackOracle(_fallbackOracle); _setFallbackOracle(fallbackOracle);
internalSetAssetsSources(_assets, _sources); _setAssetsSources(assets, sources);
} }
/// @notice External function called by the Aave governance to set or replace sources of assets /// @notice External function called by the Aave governance to set or replace sources of assets
/// @param _assets The addresses of the assets /// @param assets The addresses of the assets
/// @param _sources The address of the source of each asset /// @param sources The address of the source of each asset
function setAssetSources(address[] calldata _assets, address[] calldata _sources) function setAssetSources(address[] calldata assets, address[] calldata sources)
external external
onlyOwner onlyOwner
{ {
internalSetAssetsSources(_assets, _sources); _setAssetsSources(assets, sources);
} }
/// @notice Sets the fallbackOracle /// @notice Sets the fallbackOracle
/// - Callable only by the Aave governance /// - Callable only by the Aave governance
/// @param _fallbackOracle The address of the fallbackOracle /// @param fallbackOracle The address of the fallbackOracle
function setFallbackOracle(address _fallbackOracle) external onlyOwner { function setFallbackOracle(address fallbackOracle) external onlyOwner {
internalSetFallbackOracle(_fallbackOracle); _setFallbackOracle(fallbackOracle);
} }
/// @notice Internal function to set the sources for each asset /// @notice Internal function to set the sources for each asset
/// @param _assets The addresses of the assets /// @param assets The addresses of the assets
/// @param _sources The address of the source of each asset /// @param sources The address of the source of each asset
function internalSetAssetsSources(address[] memory _assets, address[] memory _sources) internal { function _setAssetsSources(address[] memory assets, address[] memory sources) internal {
require(_assets.length == _sources.length, 'INCONSISTENT_PARAMS_LENGTH'); require(assets.length == sources.length, 'INCONSISTENT_PARAMS_LENGTH');
for (uint256 i = 0; i < _assets.length; i++) { for (uint256 i = 0; i < assets.length; i++) {
assetsSources[_assets[i]] = IChainlinkAggregator(_sources[i]); assetsSources[assets[i]] = IChainlinkAggregator(sources[i]);
emit AssetSourceUpdated(_assets[i], _sources[i]); emit AssetSourceUpdated(assets[i], sources[i]);
} }
} }
/// @notice Internal function to set the fallbackOracle /// @notice Internal function to set the fallbackOracle
/// @param _fallbackOracle The address of the fallbackOracle /// @param fallbackOracle The address of the fallbackOracle
function internalSetFallbackOracle(address _fallbackOracle) internal { function _setFallbackOracle(address fallbackOracle) internal {
fallbackOracle = IPriceOracleGetter(_fallbackOracle); _fallbackOracle = IPriceOracleGetter(fallbackOracle);
emit FallbackOracleUpdated(_fallbackOracle); emit FallbackOracleUpdated(fallbackOracle);
} }
/// @notice Gets an asset price by address /// @notice Gets an asset price by address
/// @param _asset The asset address /// @param asset The asset address
function getAssetPrice(address _asset) public override view returns (uint256) { function getAssetPrice(address asset) public override view returns (uint256) {
IChainlinkAggregator source = assetsSources[_asset]; IChainlinkAggregator source = assetsSources[asset];
// If there is no registered source for the asset, call the fallbackOracle // If there is no registered source for the asset, call the fallbackOracle
if (address(source) == address(0)) { if (address(source) == address(0)) {
return IPriceOracleGetter(fallbackOracle).getAssetPrice(_asset); return _fallbackOracle.getAssetPrice(asset);
} else { } else {
int256 _price = IChainlinkAggregator(source).latestAnswer(); int256 price = IChainlinkAggregator(source).latestAnswer();
if (_price > 0) { if (price > 0) {
return uint256(_price); return uint256(price);
} else { } else {
return IPriceOracleGetter(fallbackOracle).getAssetPrice(_asset); return _fallbackOracle.getAssetPrice(asset);
} }
} }
} }
/// @notice Gets a list of prices from a list of assets addresses /// @notice Gets a list of prices from a list of assets addresses
/// @param _assets The list of assets addresses /// @param assets The list of assets addresses
function getAssetsPrices(address[] calldata _assets) external view returns (uint256[] memory) { function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory) {
uint256[] memory prices = new uint256[](_assets.length); uint256[] memory prices = new uint256[](assets.length);
for (uint256 i = 0; i < _assets.length; i++) { for (uint256 i = 0; i < assets.length; i++) {
prices[i] = getAssetPrice(_assets[i]); prices[i] = getAssetPrice(assets[i]);
} }
return prices; return prices;
} }
/// @notice Gets the address of the source for an asset address /// @notice Gets the address of the source for an asset address
/// @param _asset The address of the asset /// @param asset The address of the asset
/// @return address The address of the source /// @return address The address of the source
function getSourceOfAsset(address _asset) external view returns (address) { function getSourceOfAsset(address asset) external view returns (address) {
return address(assetsSources[_asset]); return address(assetsSources[asset]);
} }
/// @notice Gets the address of the fallback oracle /// @notice Gets the address of the fallback oracle
/// @return address The addres of the fallback oracle /// @return address The addres of the fallback oracle
function getFallbackOracle() external view returns (address) { function getFallbackOracle() external view returns (address) {
return address(fallbackOracle); return address(_fallbackOracle);
} }
} }

View File

@ -20,10 +20,10 @@ contract WalletBalanceProvider {
using Address for address; using Address for address;
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
LendingPoolAddressesProvider provider; LendingPoolAddressesProvider internal immutable _provider;
constructor(LendingPoolAddressesProvider _provider) public { constructor(LendingPoolAddressesProvider provider) public {
provider = _provider; _provider = provider;
} }
/** /**
@ -40,10 +40,10 @@ contract WalletBalanceProvider {
Returns the balance of the token for user. Avoids possible errors: Returns the balance of the token for user. Avoids possible errors:
- return 0 on non-contract address - return 0 on non-contract address
**/ **/
function balanceOf(address _user, address _token) public view returns (uint256) { function balanceOf(address user, address token) public view returns (uint256) {
// check if token is actually a contract // check if token is actually a contract
if (_token.isContract()) { if (token.isContract()) {
return IERC20(_token).balanceOf(_user); return IERC20(token).balanceOf(user);
} else { } else {
return 0; return 0;
} }
@ -51,24 +51,24 @@ contract WalletBalanceProvider {
/** /**
* @notice Fetches, for a list of _users and _tokens (ETH included with mock address), the balances * @notice Fetches, for a list of _users and _tokens (ETH included with mock address), the balances
* @param _users The list of users * @param users The list of users
* @param _tokens The list of tokens * @param tokens The list of tokens
* @return And array with the concatenation of, for each user, his/her balances * @return And array with the concatenation of, for each user, his/her balances
**/ **/
function batchBalanceOf(address[] memory _users, address[] memory _tokens) function batchBalanceOf(address[] calldata users, address[] calldata tokens)
public external
view view
returns (uint256[] memory) returns (uint256[] memory)
{ {
uint256[] memory balances = new uint256[](_users.length * _tokens.length); uint256[] memory balances = new uint256[](users.length * tokens.length);
for (uint256 i = 0; i < _users.length; i++) { for (uint256 i = 0; i < users.length; i++) {
for (uint256 j = 0; j < _tokens.length; j++) { for (uint256 j = 0; j < tokens.length; j++) {
uint256 _offset = i * _tokens.length; uint256 _offset = i * tokens.length;
if (!_tokens[j].isContract()) { if (!tokens[j].isContract()) {
revert('INVALID_TOKEN'); revert('INVALID_TOKEN');
} else { } else {
balances[_offset + j] = balanceOf(_users[i], _tokens[j]); balances[_offset + j] = balanceOf(users[i], tokens[j]);
} }
} }
} }
@ -79,12 +79,12 @@ contract WalletBalanceProvider {
/** /**
@dev provides balances of user wallet for all reserves available on the pool @dev provides balances of user wallet for all reserves available on the pool
*/ */
function getUserWalletBalances(address _user) function getUserWalletBalances(address user)
public external
view view
returns (address[] memory, uint256[] memory) returns (address[] memory, uint256[] memory)
{ {
ILendingPool pool = ILendingPool(provider.getLendingPool()); ILendingPool pool = ILendingPool(_provider.getLendingPool());
address[] memory reserves = pool.getReserves(); address[] memory reserves = pool.getReserves();
@ -97,7 +97,7 @@ contract WalletBalanceProvider {
balances[j] = 0; balances[j] = 0;
continue; continue;
} }
balances[j] = balanceOf(_user, reserves[j]); balances[j] = balanceOf(user, reserves[j]);
} }
return (reserves, balances); return (reserves, balances);

View File

@ -8,7 +8,7 @@ import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
import { import {
VersionedInitializable VersionedInitializable
} from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; } from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
import {IAToken, IERC20} from '../interfaces/IAToken.sol'; import {IAToken, IERC20} from './interfaces/IAToken.sol';
/** /**
* @title Aave ERC20 AToken * @title Aave ERC20 AToken
@ -24,116 +24,111 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
/** /**
* @dev emitted after aTokens are burned * @dev emitted after aTokens are burned
* @param _from the address performing the redeem * @param from the address performing the redeem
* @param _value the amount to be redeemed * @param value the amount to be redeemed
* @param _fromBalanceIncrease the cumulated balance since the last update of the user * @param fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user * @param fromIndex the last index of the user
**/ **/
event Burn( event Burn(
address indexed _from, address indexed from,
address indexed _target, address indexed target,
uint256 _value, uint256 value,
uint256 _fromBalanceIncrease, uint256 fromBalanceIncrease,
uint256 _fromIndex uint256 fromIndex
); );
/** /**
* @dev emitted after the mint action * @dev emitted after the mint action
* @param _from the address performing the mint * @param from the address performing the mint
* @param _value the amount to be minted * @param value the amount to be minted
* @param _fromBalanceIncrease the cumulated balance since the last update of the user * @param fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user * @param fromIndex the last index of the user
**/ **/
event Mint( event Mint(address indexed from, uint256 value, uint256 fromBalanceIncrease, uint256 fromIndex);
address indexed _from,
uint256 _value,
uint256 _fromBalanceIncrease,
uint256 _fromIndex
);
/** /**
* @dev emitted during the transfer action * @dev emitted during the transfer action
* @param _from the address from which the tokens are being transferred * @param from the address from which the tokens are being transferred
* @param _to the adress of the destination * @param to the adress of the destination
* @param _value the amount to be minted * @param value the amount to be minted
* @param _fromBalanceIncrease the cumulated balance since the last update of the user * @param fromBalanceIncrease the cumulated balance since the last update of the user
* @param _toBalanceIncrease the cumulated balance since the last update of the destination * @param toBalanceIncrease the cumulated balance since the last update of the destination
* @param _fromIndex the last index of the user * @param fromIndex the last index of the user
* @param _toIndex the last index of the liquidator * @param toIndex the last index of the liquidator
**/ **/
event BalanceTransfer( event BalanceTransfer(
address indexed _from, address indexed from,
address indexed _to, address indexed to,
uint256 _value, uint256 value,
uint256 _fromBalanceIncrease, uint256 fromBalanceIncrease,
uint256 _toBalanceIncrease, uint256 toBalanceIncrease,
uint256 _fromIndex, uint256 fromIndex,
uint256 _toIndex uint256 toIndex
); );
/** /**
* @dev emitted when the accumulation of the interest * @dev emitted when the accumulation of the interest
* by an user is redirected to another user * by an user is redirected to another user
* @param _from the address from which the interest is being redirected * @param from the address from which the interest is being redirected
* @param _to the adress of the destination * @param to the adress of the destination
* @param _fromBalanceIncrease the cumulated balance since the last update of the user * @param fromBalanceIncrease the cumulated balance since the last update of the user
* @param _fromIndex the last index of the user * @param fromIndex the last index of the user
**/ **/
event InterestStreamRedirected( event InterestStreamRedirected(
address indexed _from, address indexed from,
address indexed _to, address indexed to,
uint256 _redirectedBalance, uint256 redirectedBalance,
uint256 _fromBalanceIncrease, uint256 fromBalanceIncrease,
uint256 _fromIndex uint256 fromIndex
); );
/** /**
* @dev emitted when the redirected balance of an user is being updated * @dev emitted when the redirected balance of an user is being updated
* @param _targetAddress the address of which the balance is being updated * @param targetAddress the address of which the balance is being updated
* @param _targetBalanceIncrease the cumulated balance since the last update of the target * @param targetBalanceIncrease the cumulated balance since the last update of the target
* @param _targetIndex the last index of the user * @param targetIndex the last index of the user
* @param _redirectedBalanceAdded the redirected balance being added * @param redirectedBalanceAdded the redirected balance being added
* @param _redirectedBalanceRemoved the redirected balance being removed * @param redirectedBalanceRemoved the redirected balance being removed
**/ **/
event RedirectedBalanceUpdated( event RedirectedBalanceUpdated(
address indexed _targetAddress, address indexed targetAddress,
uint256 _targetBalanceIncrease, uint256 targetBalanceIncrease,
uint256 _targetIndex, uint256 targetIndex,
uint256 _redirectedBalanceAdded, uint256 redirectedBalanceAdded,
uint256 _redirectedBalanceRemoved uint256 redirectedBalanceRemoved
); );
event InterestRedirectionAllowanceChanged(address indexed _from, address indexed _to); event InterestRedirectionAllowanceChanged(address indexed from, address indexed to);
address public immutable underlyingAssetAddress; address public immutable UNDERLYING_ASSET_ADDRESS;
mapping(address => uint256) private userIndexes; mapping(address => uint256) private _userIndexes;
mapping(address => address) private interestRedirectionAddresses; mapping(address => address) private _interestRedirectionAddresses;
mapping(address => uint256) private redirectedBalances; mapping(address => uint256) private _redirectedBalances;
mapping(address => address) private interestRedirectionAllowances; mapping(address => address) private _interestRedirectionAllowances;
LendingPool private immutable pool; LendingPool private immutable _pool;
uint256 public constant ATOKEN_REVISION = 0x1; uint256 public constant ATOKEN_REVISION = 0x1;
modifier onlyLendingPool { modifier onlyLendingPool {
require(msg.sender == address(pool), 'The caller of this function must be a lending pool'); require(msg.sender == address(_pool), 'The caller of this function must be a lending pool');
_; _;
} }
modifier whenTransferAllowed(address _from, uint256 _amount) { modifier whenTransferAllowed(address from, uint256 amount) {
require(isTransferAllowed(_from, _amount), 'Transfer cannot be allowed.'); require(isTransferAllowed(from, amount), 'Transfer cannot be allowed.');
_; _;
} }
constructor( constructor(
LendingPool _pool, LendingPool pool,
address _underlyingAssetAddress, address underlyingAssetAddress,
string memory _tokenName, string memory tokenName,
string memory _tokenSymbol string memory tokenSymbol
) public ERC20(_tokenName, _tokenSymbol) { ) public ERC20(tokenName, tokenSymbol) {
pool = _pool; _pool = pool;
underlyingAssetAddress = _underlyingAssetAddress; UNDERLYING_ASSET_ADDRESS = underlyingAssetAddress;
} }
function getRevision() internal virtual override pure returns (uint256) { function getRevision() internal virtual override pure returns (uint256) {
@ -141,13 +136,13 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
} }
function initialize( function initialize(
uint8 _underlyingAssetDecimals, uint8 underlyingAssetDecimals,
string calldata _tokenName, string calldata tokenName,
string calldata _tokenSymbol string calldata tokenSymbol
) external virtual initializer { ) external virtual initializer {
_name = _tokenName; _name = tokenName;
_symbol = _tokenSymbol; _symbol = tokenSymbol;
_setupDecimals(_underlyingAssetDecimals); _setupDecimals(underlyingAssetDecimals);
} }
/** /**
@ -155,163 +150,164 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
* @dev validates the transfer before allowing it. NOTE: This is not standard ERC20 behavior * @dev validates the transfer before allowing it. NOTE: This is not standard ERC20 behavior
**/ **/
function _transfer( function _transfer(
address _from, address from,
address _to, address to,
uint256 _amount uint256 amount
) internal override whenTransferAllowed(_from, _amount) { ) internal override whenTransferAllowed(from, amount) {
executeTransferInternal(_from, _to, _amount); executeTransferInternal(from, to, amount);
} }
/** /**
* @dev redirects the interest generated to a target address. * @dev redirects the interest generated to a target address.
* when the interest is redirected, the user balance is added to * when the interest is redirected, the user balance is added to
* the recepient redirected balance. * the recepient redirected balance.
* @param _to the address to which the interest will be redirected * @param to the address to which the interest will be redirected
**/ **/
function redirectInterestStream(address _to) external override { function redirectInterestStream(address to) external override {
redirectInterestStreamInternal(msg.sender, _to); redirectInterestStreamInternal(msg.sender, to);
} }
/** /**
* @dev redirects the interest generated by _from to a target address. * @dev redirects the interest generated by from to a target address.
* when the interest is redirected, the user balance is added to * when the interest is redirected, the user balance is added to
* the recepient redirected balance. The caller needs to have allowance on * the recepient redirected balance. The caller needs to have allowance on
* the interest redirection to be able to execute the function. * the interest redirection to be able to execute the function.
* @param _from the address of the user whom interest is being redirected * @param from the address of the user whom interest is being redirected
* @param _to the address to which the interest will be redirected * @param to the address to which the interest will be redirected
**/ **/
function redirectInterestStreamOf(address _from, address _to) external override { function redirectInterestStreamOf(address from, address to) external override {
require( require(
msg.sender == interestRedirectionAllowances[_from], msg.sender == _interestRedirectionAllowances[from],
'Caller is not allowed to redirect the interest of the user' 'Caller is not allowed to redirect the interest of the user'
); );
redirectInterestStreamInternal(_from, _to); redirectInterestStreamInternal(from, to);
} }
/** /**
* @dev gives allowance to an address to execute the interest redirection * @dev gives allowance to an address to execute the interest redirection
* on behalf of the caller. * on behalf of the caller.
* @param _to the address to which the interest will be redirected. Pass address(0) to reset * @param to the address to which the interest will be redirected. Pass address(0) to reset
* the allowance. * the allowance.
**/ **/
function allowInterestRedirectionTo(address _to) external override { function allowInterestRedirectionTo(address to) external override {
require(_to != msg.sender, 'User cannot give allowance to himself'); require(to != msg.sender, 'User cannot give allowance to himself');
interestRedirectionAllowances[msg.sender] = _to; _interestRedirectionAllowances[msg.sender] = to;
emit InterestRedirectionAllowanceChanged(msg.sender, _to); emit InterestRedirectionAllowanceChanged(msg.sender, to);
} }
/** /**
* @dev burns the aTokens and sends the equivalent amount of underlying to the target. * @dev burns the aTokens and sends the equivalent amount of underlying to the target.
* only lending pools can call this function * only lending pools can call this function
* @param _amount the amount being burned * @param amount the amount being burned
**/ **/
function burn( function burn(
address _user, address user,
address _underlyingTarget, address underlyingTarget,
uint256 _amount uint256 amount
) external override onlyLendingPool { ) external override onlyLendingPool {
//cumulates the balance of the user //cumulates the balance of the user
(, uint256 currentBalance, uint256 balanceIncrease) = calculateBalanceIncreaseInternal(_user); (, uint256 currentBalance, uint256 balanceIncrease) = calculateBalanceIncreaseInternal(user);
//if the user is redirecting his interest towards someone else, //if the user is redirecting his interest towards someone else,
//we update the redirected balance of the redirection address by adding the accrued interest, //we update the redirected balance of the redirection address by adding the accrued interest,
//and removing the amount to redeem //and removing the amount to redeem
updateRedirectedBalanceOfRedirectionAddressInternal(_user, balanceIncrease, _amount); updateRedirectedBalanceOfRedirectionAddressInternal(user, balanceIncrease, amount);
if (balanceIncrease > _amount) { if (balanceIncrease > amount) {
_mint(_user, balanceIncrease.sub(_amount)); _mint(user, balanceIncrease.sub(amount));
} else { } else {
_burn(_user, _amount.sub(balanceIncrease)); _burn(user, amount.sub(balanceIncrease));
} }
uint256 userIndex = 0; uint256 userIndex = 0;
//reset the user data if the remaining balance is 0 //reset the user data if the remaining balance is 0
if (currentBalance.sub(_amount) == 0) { if (currentBalance.sub(amount) == 0) {
resetDataOnZeroBalanceInternal(_user); resetDataOnZeroBalanceInternal(user);
} else { } else {
//updates the user index //updates the user index
userIndex = userIndexes[_user] = pool.getReserveNormalizedIncome(underlyingAssetAddress); userIndex = _userIndexes[user] = _pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
} }
//transfers the underlying to the target //transfers the underlying to the target
ERC20(underlyingAssetAddress).safeTransfer(_underlyingTarget, _amount); ERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(underlyingTarget, amount);
emit Burn(msg.sender, _underlyingTarget, _amount, balanceIncrease, userIndex); emit Burn(msg.sender, underlyingTarget, amount, balanceIncrease, userIndex);
} }
/** /**
* @dev mints aTokens to _user * @dev mints aTokens to user
* only lending pools can call this function * only lending pools can call this function
* @param _user the address receiving the minted tokens * @param user the address receiving the minted tokens
* @param _amount the amount of tokens to mint * @param amount the amount of tokens to mint
*/ */
function mint(address _user, uint256 _amount) external override onlyLendingPool { function mint(address user, uint256 amount) external override onlyLendingPool {
//cumulates the balance of the user //cumulates the balance of the user
(, , uint256 balanceIncrease) = calculateBalanceIncreaseInternal(_user); (, , uint256 balanceIncrease) = calculateBalanceIncreaseInternal(user);
//updates the user index //updates the user index
uint256 index = userIndexes[_user] = pool.getReserveNormalizedIncome(underlyingAssetAddress); uint256 index = _userIndexes[user] = _pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
//if the user is redirecting his interest towards someone else, //if the user is redirecting his interest towards someone else,
//we update the redirected balance of the redirection address by adding the accrued interest //we update the redirected balance of the redirection address by adding the accrued interest
//and the amount deposited //and the amount deposited
updateRedirectedBalanceOfRedirectionAddressInternal(_user, balanceIncrease.add(_amount), 0); updateRedirectedBalanceOfRedirectionAddressInternal(user, balanceIncrease.add(amount), 0);
//mint an equivalent amount of tokens to cover the new deposit //mint an equivalent amount of tokens to cover the new deposit
_mint(_user, _amount.add(balanceIncrease)); _mint(user, amount.add(balanceIncrease));
emit Mint(_user, _amount, balanceIncrease, index); emit Mint(user, amount, balanceIncrease, index);
} }
/** /**
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken * @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* only lending pools can call this function * only lending pools can call this function
* @param _from the address from which transfer the aTokens * @param from the address from which transfer the aTokens
* @param _to the destination address * @param to the destination address
* @param _value the amount to transfer * @param value the amount to transfer
**/ **/
function transferOnLiquidation( function transferOnLiquidation(
address _from, address from,
address _to, address to,
uint256 _value uint256 value
) external override onlyLendingPool { ) external override onlyLendingPool {
//being a normal transfer, the Transfer() and BalanceTransfer() are emitted //being a normal transfer, the Transfer() and BalanceTransfer() are emitted
//so no need to emit a specific event here //so no need to emit a specific event here
executeTransferInternal(_from, _to, _value); executeTransferInternal(from, to, value);
} }
/** /**
* @dev calculates the balance of the user, which is the * @dev calculates the balance of the user, which is the
* principal balance + interest generated by the principal balance + interest generated by the redirected balance * principal balance + interest generated by the principal balance + interest generated by the redirected balance
* @param _user the user for which the balance is being calculated * @param user the user for which the balance is being calculated
* @return the total balance of the user * @return the total balance of the user
**/ **/
function balanceOf(address _user) public override(ERC20, IERC20) view returns (uint256) { function balanceOf(address user) public override(ERC20, IERC20) view returns (uint256) {
//current principal balance of the user //current principal balance of the user
uint256 currentPrincipalBalance = super.balanceOf(_user); uint256 currentPrincipalBalance = super.balanceOf(user);
//balance redirected by other users to _user for interest rate accrual //balance redirected by other users to user for interest rate accrual
uint256 redirectedBalance = redirectedBalances[_user]; uint256 redirectedBalance = _redirectedBalances[user];
if (currentPrincipalBalance == 0 && redirectedBalance == 0) { if (currentPrincipalBalance == 0 && redirectedBalance == 0) {
return 0; return 0;
} }
//if the _user is not redirecting the interest to anybody, accrues //if the user is not redirecting the interest to anybody, accrues
//the interest for himself //the interest for himself
if (interestRedirectionAddresses[_user] == address(0)) { if (_interestRedirectionAddresses[user] == address(0)) {
//accruing for himself means that both the principal balance and //accruing for himself means that both the principal balance and
//the redirected balance partecipate in the interest //the redirected balance partecipate in the interest
return return
calculateCumulatedBalanceInternal(_user, currentPrincipalBalance.add(redirectedBalance)) calculateCumulatedBalanceInternal(user, currentPrincipalBalance.add(redirectedBalance)).sub(
.sub(redirectedBalance); redirectedBalance
);
} else { } else {
//if the user redirected the interest, then only the redirected //if the user redirected the interest, then only the redirected
//balance generates interest. In that case, the interest generated //balance generates interest. In that case, the interest generated
//by the redirected balance is added to the current principal balance. //by the redirected balance is added to the current principal balance.
return return
currentPrincipalBalance.add( currentPrincipalBalance.add(
calculateCumulatedBalanceInternal(_user, redirectedBalance).sub(redirectedBalance) calculateCumulatedBalanceInternal(user, redirectedBalance).sub(redirectedBalance)
); );
} }
} }
@ -319,11 +315,11 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
/** /**
* @dev returns the principal balance of the user. The principal balance is the last * @dev returns the principal balance of the user. The principal balance is the last
* updated stored balance, which does not consider the perpetually accruing interest. * updated stored balance, which does not consider the perpetually accruing interest.
* @param _user the address of the user * @param user the address of the user
* @return the principal balance of the user * @return the principal balance of the user
**/ **/
function principalBalanceOf(address _user) external override view returns (uint256) { function principalBalanceOf(address user) external override view returns (uint256) {
return super.balanceOf(_user); return super.balanceOf(user);
} }
/** /**
@ -342,54 +338,54 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
return return
currentSupplyPrincipal currentSupplyPrincipal
.wadToRay() .wadToRay()
.rayMul(pool.getReserveNormalizedIncome(underlyingAssetAddress)) .rayMul(_pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS))
.rayToWad(); .rayToWad();
} }
/** /**
* @dev Used to validate transfers before actually executing them. * @dev Used to validate transfers before actually executing them.
* @param _user address of the user to check * @param user address of the user to check
* @param _amount the amount to check * @param amount the amount to check
* @return true if the _user can transfer _amount, false otherwise * @return true if the user can transfer amount, false otherwise
**/ **/
function isTransferAllowed(address _user, uint256 _amount) public override view returns (bool) { function isTransferAllowed(address user, uint256 amount) public override view returns (bool) {
return pool.balanceDecreaseAllowed(underlyingAssetAddress, _user, _amount); return _pool.balanceDecreaseAllowed(UNDERLYING_ASSET_ADDRESS, user, amount);
} }
/** /**
* @dev returns the last index of the user, used to calculate the balance of the user * @dev returns the last index of the user, used to calculate the balance of the user
* @param _user address of the user * @param user address of the user
* @return the last user index * @return the last user index
**/ **/
function getUserIndex(address _user) external override view returns (uint256) { function getUserIndex(address user) external override view returns (uint256) {
return userIndexes[_user]; return _userIndexes[user];
} }
/** /**
* @dev returns the address to which the interest is redirected * @dev returns the address to which the interest is redirected
* @param _user address of the user * @param user address of the user
* @return 0 if there is no redirection, an address otherwise * @return 0 if there is no redirection, an address otherwise
**/ **/
function getInterestRedirectionAddress(address _user) external override view returns (address) { function getInterestRedirectionAddress(address user) external override view returns (address) {
return interestRedirectionAddresses[_user]; return _interestRedirectionAddresses[user];
} }
/** /**
* @dev returns the redirected balance of the user. The redirected balance is the balance * @dev returns the redirected balance of the user. The redirected balance is the balance
* redirected by other accounts to the user, that is accrueing interest for him. * redirected by other accounts to the user, that is accrueing interest for him.
* @param _user address of the user * @param user address of the user
* @return the total redirected balance * @return the total redirected balance
**/ **/
function getRedirectedBalance(address _user) external override view returns (uint256) { function getRedirectedBalance(address user) external override view returns (uint256) {
return redirectedBalances[_user]; return _redirectedBalances[user];
} }
/** /**
* @dev calculates the increase in balance since the last user action * @dev calculates the increase in balance since the last user action
* @param _user the address of the user * @param user the address of the user
* @return the last user principal balance, the current balance and the balance increase * @return the last user principal balance, the current balance and the balance increase
**/ **/
function calculateBalanceIncreaseInternal(address _user) function calculateBalanceIncreaseInternal(address user)
internal internal
view view
returns ( returns (
@ -398,12 +394,12 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
uint256 uint256
) )
{ {
uint256 currentBalance = balanceOf(_user); uint256 currentBalance = balanceOf(user);
uint256 balanceIncrease = 0; uint256 balanceIncrease = 0;
uint256 previousBalance = 0; uint256 previousBalance = 0;
if (currentBalance != 0) { if (currentBalance != 0) {
previousBalance = super.balanceOf(_user); previousBalance = super.balanceOf(user);
//calculate the accrued interest since the last accumulation //calculate the accrued interest since the last accumulation
balanceIncrease = currentBalance.sub(previousBalance); balanceIncrease = currentBalance.sub(previousBalance);
} }
@ -413,11 +409,11 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
/** /**
* @dev accumulates the accrued interest of the user to the principal balance * @dev accumulates the accrued interest of the user to the principal balance
* @param _user the address of the user for which the interest is being accumulated * @param user the address of the user for which the interest is being accumulated
* @return the previous principal balance, the new principal balance, the balance increase * @return the previous principal balance, the new principal balance, the balance increase
* and the new user index * and the new user index
**/ **/
function cumulateBalanceInternal(address _user) function cumulateBalanceInternal(address user)
internal internal
returns ( returns (
uint256, uint256,
@ -430,12 +426,12 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
uint256 previousBalance, uint256 previousBalance,
uint256 currentBalance, uint256 currentBalance,
uint256 balanceIncrease uint256 balanceIncrease
) = calculateBalanceIncreaseInternal(_user); ) = calculateBalanceIncreaseInternal(user);
_mint(_user, balanceIncrease); _mint(user, balanceIncrease);
//updates the user index //updates the user index
uint256 index = userIndexes[_user] = pool.getReserveNormalizedIncome(underlyingAssetAddress); uint256 index = _userIndexes[user] = _pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
return (previousBalance, currentBalance, balanceIncrease, index); return (previousBalance, currentBalance, balanceIncrease, index);
} }
@ -443,16 +439,16 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
/** /**
* @dev updates the redirected balance of the user. If the user is not redirecting his * @dev updates the redirected balance of the user. If the user is not redirecting his
* interest, nothing is executed. * interest, nothing is executed.
* @param _user the address of the user for which the interest is being accumulated * @param user the address of the user for which the interest is being accumulated
* @param _balanceToAdd the amount to add to the redirected balance * @param balanceToAdd the amount to add to the redirected balance
* @param _balanceToRemove the amount to remove from the redirected balance * @param balanceToRemove the amount to remove from the redirected balance
**/ **/
function updateRedirectedBalanceOfRedirectionAddressInternal( function updateRedirectedBalanceOfRedirectionAddressInternal(
address _user, address user,
uint256 _balanceToAdd, uint256 balanceToAdd,
uint256 _balanceToRemove uint256 balanceToRemove
) internal { ) internal {
address redirectionAddress = interestRedirectionAddresses[_user]; address redirectionAddress = _interestRedirectionAddresses[user];
//if there isn't any redirection, nothing to be done //if there isn't any redirection, nothing to be done
if (redirectionAddress == address(0)) { if (redirectionAddress == address(0)) {
return; return;
@ -462,13 +458,13 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
(, , uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(redirectionAddress); (, , uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(redirectionAddress);
//updating the redirected balance //updating the redirected balance
redirectedBalances[redirectionAddress] = redirectedBalances[redirectionAddress] _redirectedBalances[redirectionAddress] = _redirectedBalances[redirectionAddress]
.add(_balanceToAdd) .add(balanceToAdd)
.sub(_balanceToRemove); .sub(balanceToRemove);
//if the interest of redirectionAddress is also being redirected, we need to update //if the interest of redirectionAddress is also being redirected, we need to update
//the redirected balance of the redirection target by adding the balance increase //the redirected balance of the redirection target by adding the balance increase
address targetOfRedirectionAddress = interestRedirectionAddresses[redirectionAddress]; address targetOfRedirectionAddress = _interestRedirectionAddresses[redirectionAddress];
// if the redirection address is also redirecting the interest, we accumulate his balance // if the redirection address is also redirecting the interest, we accumulate his balance
// and update his chain of redirection // and update his chain of redirection
@ -480,43 +476,43 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
redirectionAddress, redirectionAddress,
balanceIncrease, balanceIncrease,
index, index,
_balanceToAdd, balanceToAdd,
_balanceToRemove balanceToRemove
); );
} }
/** /**
* @dev calculate the interest accrued by _user on a specific balance * @dev calculate the interest accrued by user on a specific balance
* @param _user the address of the user for which the interest is being accumulated * @param user the address of the user for which the interest is being accumulated
* @param _balance the balance on which the interest is calculated * @param balance the balance on which the interest is calculated
* @return the interest rate accrued * @return the interest rate accrued
**/ **/
function calculateCumulatedBalanceInternal(address _user, uint256 _balance) function calculateCumulatedBalanceInternal(address user, uint256 balance)
internal internal
view view
returns (uint256) returns (uint256)
{ {
return return
_balance balance
.wadToRay() .wadToRay()
.rayMul(pool.getReserveNormalizedIncome(underlyingAssetAddress)) .rayMul(_pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS))
.rayDiv(userIndexes[_user]) .rayDiv(_userIndexes[user])
.rayToWad(); .rayToWad();
} }
/** /**
* @dev executes the transfer of aTokens, invoked by both _transfer() and * @dev executes the transfer of aTokens, invoked by both _transfer() and
* transferOnLiquidation() * transferOnLiquidation()
* @param _from the address from which transfer the aTokens * @param from the address from which transfer the aTokens
* @param _to the destination address * @param to the destination address
* @param _value the amount to transfer * @param value the amount to transfer
**/ **/
function executeTransferInternal( function executeTransferInternal(
address _from, address from,
address _to, address to,
uint256 _value uint256 value
) internal { ) internal {
require(_value > 0, 'Transferred amount needs to be greater than zero'); require(value > 0, 'Transferred amount needs to be greater than zero');
//cumulate the balance of the sender //cumulate the balance of the sender
( (
@ -524,34 +520,34 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
uint256 fromBalance, uint256 fromBalance,
uint256 fromBalanceIncrease, uint256 fromBalanceIncrease,
uint256 fromIndex uint256 fromIndex
) = cumulateBalanceInternal(_from); ) = cumulateBalanceInternal(from);
//cumulate the balance of the receiver //cumulate the balance of the receiver
(, , uint256 toBalanceIncrease, uint256 toIndex) = cumulateBalanceInternal(_to); (, , uint256 toBalanceIncrease, uint256 toIndex) = cumulateBalanceInternal(to);
//if the sender is redirecting his interest towards someone else, //if the sender is redirecting his interest towards someone else,
//adds to the redirected balance the accrued interest and removes the amount //adds to the redirected balance the accrued interest and removes the amount
//being transferred //being transferred
updateRedirectedBalanceOfRedirectionAddressInternal(_from, fromBalanceIncrease, _value); updateRedirectedBalanceOfRedirectionAddressInternal(from, fromBalanceIncrease, value);
//if the receiver is redirecting his interest towards someone else, //if the receiver is redirecting his interest towards someone else,
//adds to the redirected balance the accrued interest and the amount //adds to the redirected balance the accrued interest and the amount
//being transferred //being transferred
updateRedirectedBalanceOfRedirectionAddressInternal(_to, toBalanceIncrease.add(_value), 0); updateRedirectedBalanceOfRedirectionAddressInternal(to, toBalanceIncrease.add(value), 0);
//performs the transfer //performs the transfer
super._transfer(_from, _to, _value); super._transfer(from, to, value);
bool fromIndexReset = false; bool fromIndexReset = false;
//reset the user data if the remaining balance is 0 //reset the user data if the remaining balance is 0
if (fromBalance.sub(_value) == 0 && _from != _to) { if (fromBalance.sub(value) == 0 && from != to) {
fromIndexReset = resetDataOnZeroBalanceInternal(_from); fromIndexReset = resetDataOnZeroBalanceInternal(from);
} }
emit BalanceTransfer( emit BalanceTransfer(
_from, from,
_to, to,
_value, value,
fromBalanceIncrease, fromBalanceIncrease,
toBalanceIncrease, toBalanceIncrease,
fromIndexReset ? 0 : fromIndex, fromIndexReset ? 0 : fromIndex,
@ -562,13 +558,13 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
/** /**
* @dev executes the redirection of the interest from one address to another. * @dev executes the redirection of the interest from one address to another.
* immediately after redirection, the destination address will start to accrue interest. * immediately after redirection, the destination address will start to accrue interest.
* @param _from the address from which transfer the aTokens * @param from the address from which transfer the aTokens
* @param _to the destination address * @param to the destination address
**/ **/
function redirectInterestStreamInternal(address _from, address _to) internal { function redirectInterestStreamInternal(address from, address to) internal {
address currentRedirectionAddress = interestRedirectionAddresses[_from]; address currentRedirectionAddress = _interestRedirectionAddresses[from];
require(_to != currentRedirectionAddress, 'Interest is already redirected to the user'); require(to != currentRedirectionAddress, 'Interest is already redirected to the user');
//accumulates the accrued interest to the principal //accumulates the accrued interest to the principal
( (
@ -576,7 +572,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
uint256 fromBalance, uint256 fromBalance,
uint256 balanceIncrease, uint256 balanceIncrease,
uint256 fromIndex uint256 fromIndex
) = cumulateBalanceInternal(_from); ) = cumulateBalanceInternal(from);
require(fromBalance > 0, 'Interest stream can only be redirected if there is a valid balance'); require(fromBalance > 0, 'Interest stream can only be redirected if there is a valid balance');
@ -584,42 +580,42 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
//the redirection address we substract the redirected balance of the previous //the redirection address we substract the redirected balance of the previous
//recipient //recipient
if (currentRedirectionAddress != address(0)) { if (currentRedirectionAddress != address(0)) {
updateRedirectedBalanceOfRedirectionAddressInternal(_from, 0, previousPrincipalBalance); updateRedirectedBalanceOfRedirectionAddressInternal(from, 0, previousPrincipalBalance);
} }
//if the user is redirecting the interest back to himself, //if the user is redirecting the interest back to himself,
//we simply set to 0 the interest redirection address //we simply set to 0 the interest redirection address
if (_to == _from) { if (to == from) {
interestRedirectionAddresses[_from] = address(0); _interestRedirectionAddresses[from] = address(0);
emit InterestStreamRedirected(_from, address(0), fromBalance, balanceIncrease, fromIndex); emit InterestStreamRedirected(from, address(0), fromBalance, balanceIncrease, fromIndex);
return; return;
} }
//first set the redirection address to the new recipient //first set the redirection address to the new recipient
interestRedirectionAddresses[_from] = _to; _interestRedirectionAddresses[from] = to;
//adds the user balance to the redirected balance of the destination //adds the user balance to the redirected balance of the destination
updateRedirectedBalanceOfRedirectionAddressInternal(_from, fromBalance, 0); updateRedirectedBalanceOfRedirectionAddressInternal(from, fromBalance, 0);
emit InterestStreamRedirected(_from, _to, fromBalance, balanceIncrease, fromIndex); emit InterestStreamRedirected(from, to, fromBalance, balanceIncrease, fromIndex);
} }
/** /**
* @dev function to reset the interest stream redirection and the user index, if the * @dev function to reset the interest stream redirection and the user index, if the
* user has no balance left. * user has no balance left.
* @param _user the address of the user * @param user the address of the user
* @return true if the user index has also been reset, false otherwise. useful to emit the proper user index value * @return true if the user index has also been reset, false otherwise. useful to emit the proper user index value
**/ **/
function resetDataOnZeroBalanceInternal(address _user) internal returns (bool) { function resetDataOnZeroBalanceInternal(address user) internal returns (bool) {
//if the user has 0 principal balance, the interest stream redirection gets reset //if the user has 0 principal balance, the interest stream redirection gets reset
interestRedirectionAddresses[_user] = address(0); _interestRedirectionAddresses[user] = address(0);
//emits a InterestStreamRedirected event to notify that the redirection has been reset //emits a InterestStreamRedirected event to notify that the redirection has been reset
emit InterestStreamRedirected(_user, address(0), 0, 0, 0); emit InterestStreamRedirected(user, address(0), 0, 0, 0);
//if the redirected balance is also 0, we clear up the user index //if the redirected balance is also 0, we clear up the user index
if (redirectedBalances[_user] == 0) { if (_redirectedBalances[user] == 0) {
userIndexes[_user] = 0; _userIndexes[user] = 0;
return true; return true;
} else { } else {
return false; return false;
@ -629,19 +625,19 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
/** /**
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer * @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
* assets in borrow(), redeem() and flashLoan() * assets in borrow(), redeem() and flashLoan()
* @param _target the target of the transfer * @param target the target of the transfer
* @param _amount the amount to transfer * @param amount the amount to transfer
* @return the amount transferred * @return the amount transferred
**/ **/
function transferUnderlyingTo(address _target, uint256 _amount) function transferUnderlyingTo(address target, uint256 amount)
external external
override override
onlyLendingPool onlyLendingPool
returns (uint256) returns (uint256)
{ {
ERC20(underlyingAssetAddress).safeTransfer(_target, _amount); ERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(target, amount);
return _amount; return amount;
} }
/** /**

View File

@ -31,48 +31,48 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
uint256 private avgStableRate; uint256 private avgStableRate;
mapping(address => UserData) usersData; mapping(address => UserData) private _usersData;
/** /**
* @dev emitted when new stable debt is minted * @dev emitted when new stable debt is minted
* @param _user the address of the user * @param user the address of the user
* @param _amount the amount minted * @param amount the amount minted
* @param _previousBalance the previous balance of the user * @param previousBalance the previous balance of the user
* @param _currentBalance the current balance of the user * @param currentBalance the current balance of the user
* @param _balanceIncrease the debt increase since the last update * @param balanceIncrease the debt increase since the last update
* @param _newRate the rate of the debt after the minting * @param newRate the rate of the debt after the minting
**/ **/
event MintDebt( event MintDebt(
address _user, address user,
uint256 _amount, uint256 amount,
uint256 _previousBalance, uint256 previousBalance,
uint256 _currentBalance, uint256 currentBalance,
uint256 _balanceIncrease, uint256 balanceIncrease,
uint256 _newRate uint256 newRate
); );
/** /**
* @dev emitted when new stable debt is burned * @dev emitted when new stable debt is burned
* @param _user the address of the user * @param user the address of the user
* @param _amount the amount minted * @param amount the amount minted
* @param _previousBalance the previous balance of the user * @param previousBalance the previous balance of the user
* @param _currentBalance the current balance of the user * @param currentBalance the current balance of the user
* @param _balanceIncrease the debt increase since the last update * @param balanceIncrease the debt increase since the last update
**/ **/
event BurnDebt( event BurnDebt(
address _user, address user,
uint256 _amount, uint256 amount,
uint256 _previousBalance, uint256 previousBalance,
uint256 _currentBalance, uint256 currentBalance,
uint256 _balanceIncrease uint256 balanceIncrease
); );
constructor( constructor(
address _pool, address pool,
address _underlyingAsset, address underlyingAsset,
string memory _name, string memory name,
string memory _symbol string memory symbol
) public DebtTokenBase(_pool, _underlyingAsset, _name, _symbol) {} ) public DebtTokenBase(pool, underlyingAsset, name, symbol) {}
/** /**
* @dev gets the revision of the stable debt token implementation * @dev gets the revision of the stable debt token implementation
@ -94,17 +94,17 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
* @dev returns the timestamp of the last user action * @dev returns the timestamp of the last user action
* @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 _usersData[user].lastUpdateTimestamp;
} }
/** /**
* @dev returns the stable rate of the user * @dev returns the stable rate of the user
* @param _user the address of the user * @param user the address of the user
* @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].currentRate;
} }
/** /**
@ -112,17 +112,18 @@ 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) {
if (balances[account] == 0) { uint256 accountBalance = _balances[account];
if (accountBalance == 0) {
return 0; return 0;
} }
UserData storage userData = usersData[account]; UserData storage userData = _usersData[account];
uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest( uint256 cumulatedInterest = MathUtils.calculateCompoundedInterest(
userData.currentRate, userData.currentRate,
userData.lastUpdateTimestamp userData.lastUpdateTimestamp
); );
return balances[account].wadToRay().rayMul(cumulatedInterest).rayToWad(); return accountBalance.wadToRay().rayMul(cumulatedInterest).rayToWad();
} }
struct MintLocalVars { struct MintLocalVars {
@ -135,14 +136,14 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
/** /**
* @dev mints debt token to the target user. The resulting rate is the weighted average * @dev mints debt token to the target user. The resulting rate is the weighted average
* between the rate of the new debt and the rate of the previous debt * between the rate of the new debt and the rate of the previous debt
* @param _user the address of the user * @param user the address of the user
* @param _amount the amount of debt tokens to mint * @param amount the amount of debt tokens to mint
* @param _rate the rate of the debt being minted. * @param rate the rate of the debt being minted.
**/ **/
function mint( function mint(
address _user, address user,
uint256 _amount, uint256 amount,
uint256 _rate uint256 rate
) external override onlyLendingPool { ) external override onlyLendingPool {
MintLocalVars memory vars; MintLocalVars memory vars;
@ -151,36 +152,36 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
uint256 previousBalance, uint256 previousBalance,
uint256 currentBalance, uint256 currentBalance,
uint256 balanceIncrease uint256 balanceIncrease
) = _calculateBalanceIncrease(_user); ) = _calculateBalanceIncrease(user);
vars.supplyBeforeMint = totalSupply.add(balanceIncrease); vars.supplyBeforeMint = _totalSupply.add(balanceIncrease);
vars.supplyAfterMint = vars.supplyBeforeMint.add(_amount); vars.supplyAfterMint = vars.supplyBeforeMint.add(amount);
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 = _usersData[user]
.currentRate .currentRate
.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; _usersData[user].currentRate = vars.newStableRate;
//solium-disable-next-line //solium-disable-next-line
usersData[_user].lastUpdateTimestamp = uint40(block.timestamp); _usersData[user].lastUpdateTimestamp = 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());
_mint(_user, _amount.add(balanceIncrease)); _mint(user, amount.add(balanceIncrease));
emit MintDebt( emit MintDebt(
_user, user,
_amount, amount,
previousBalance, previousBalance,
currentBalance, currentBalance,
balanceIncrease, balanceIncrease,
@ -190,42 +191,42 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
/** /**
* @dev burns debt of the target user. * @dev burns debt of the target user.
* @param _user the address of the user * @param user the address of the user
* @param _amount the amount of debt tokens to mint * @param amount the amount of debt tokens to mint
**/ **/
function burn(address _user, uint256 _amount) external override onlyLendingPool { function burn(address user, uint256 amount) external override onlyLendingPool {
( (
uint256 previousBalance, uint256 previousBalance,
uint256 currentBalance, uint256 currentBalance,
uint256 balanceIncrease uint256 balanceIncrease
) = _calculateBalanceIncrease(_user); ) = _calculateBalanceIncrease(user);
uint256 supplyBeforeBurn = totalSupply.add(balanceIncrease); uint256 supplyBeforeBurn = _totalSupply.add(balanceIncrease);
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(_usersData[user].currentRate.rayMul(amount.wadToRay()))
.rayDiv(supplyAfterBurn.wadToRay()); .rayDiv(supplyAfterBurn.wadToRay());
} }
if (_amount == currentBalance) { if (amount == currentBalance) {
usersData[_user].currentRate = 0; _usersData[user].currentRate = 0;
usersData[_user].lastUpdateTimestamp = 0; _usersData[user].lastUpdateTimestamp = 0;
} else { } else {
//solium-disable-next-line //solium-disable-next-line
usersData[_user].lastUpdateTimestamp = uint40(block.timestamp); _usersData[user].lastUpdateTimestamp = uint40(block.timestamp);
} }
if (balanceIncrease > _amount) { if (balanceIncrease > amount) {
_mint(_user, balanceIncrease.sub(_amount)); _mint(user, balanceIncrease.sub(amount));
} else { } else {
_burn(_user, _amount.sub(balanceIncrease)); _burn(user, amount.sub(balanceIncrease));
} }
emit BurnDebt(_user, _amount, previousBalance, currentBalance, balanceIncrease); emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease);
} }
} }

View File

@ -20,50 +20,50 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
uint256 public constant DEBT_TOKEN_REVISION = 0x1; uint256 public constant DEBT_TOKEN_REVISION = 0x1;
mapping(address => uint256) private userIndexes; mapping(address => uint256) private _userIndexes;
/** /**
* @dev emitted when new variable debt is minted * @dev emitted when new variable debt is minted
* @param _user the user receiving the debt * @param user the user receiving the debt
* @param _amount the amount of debt being minted * @param amount the amount of debt being minted
* @param _previousBalance the previous balance of the user * @param previousBalance the previous balance of the user
* @param _currentBalance the current balance of the user * @param currentBalance the current balance of the user
* @param _balanceIncrease the debt accumulated since the last action * @param balanceIncrease the debt accumulated since the last action
* @param _index the index of the user * @param index the index of the user
**/ **/
event MintDebt( event MintDebt(
address _user, address user,
uint256 _amount, uint256 amount,
uint256 _previousBalance, uint256 previousBalance,
uint256 _currentBalance, uint256 currentBalance,
uint256 _balanceIncrease, uint256 balanceIncrease,
uint256 _index uint256 index
); );
/** /**
* @dev emitted when variable debt is burnt * @dev emitted when variable debt is burnt
* @param _user the user which debt has been burned * @param user the user which debt has been burned
* @param _amount the amount of debt being burned * @param amount the amount of debt being burned
* @param _previousBalance the previous balance of the user * @param previousBalance the previous balance of the user
* @param _currentBalance the current balance of the user * @param currentBalance the current balance of the user
* @param _balanceIncrease the debt accumulated since the last action * @param balanceIncrease the debt accumulated since the last action
* @param _index the index of the user * @param index the index of the user
**/ **/
event BurnDebt( event BurnDebt(
address _user, address user,
uint256 _amount, uint256 amount,
uint256 _previousBalance, uint256 previousBalance,
uint256 _currentBalance, uint256 currentBalance,
uint256 _balanceIncrease, uint256 balanceIncrease,
uint256 _index uint256 index
); );
constructor( constructor(
address _pool, address pool,
address _underlyingAsset, address underlyingAsset,
string memory _name, string memory name,
string memory _symbol string memory symbol
) public DebtTokenBase(_pool, _underlyingAsset, _name, _symbol) {} ) public DebtTokenBase(pool, underlyingAsset, name, symbol) {}
/** /**
* @dev gets the revision of the stable debt token implementation * @dev gets the revision of the stable debt token implementation
@ -77,16 +77,17 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
* @dev calculates the accumulated debt balance of the user * @dev calculates the accumulated debt balance of the user
* @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) {
if (balances[_user] == 0) { uint256 userBalance = _balances[user];
if (userBalance == 0) {
return 0; return 0;
} }
return return
balances[_user] userBalance
.wadToRay() .wadToRay()
.rayMul(pool.getReserveNormalizedVariableDebt(underlyingAssetAddress)) .rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress))
.rayDiv(userIndexes[_user]) .rayDiv(_userIndexes[user])
.rayToWad(); .rayToWad();
} }
@ -95,55 +96,55 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
* @return the user index * @return the user index
**/ **/
function getUserIndex(address _user) external virtual override view returns (uint256) { function getUserIndex(address user) external virtual override view returns (uint256) {
return userIndexes[_user]; return _userIndexes[user];
} }
/** /**
* @dev mints new variable debt * @dev mints new variable debt
* @param _user the user receiving the debt * @param user the user receiving the debt
* @param _amount the amount of debt being minted * @param amount the amount of debt being minted
**/ **/
function mint(address _user, uint256 _amount) external override onlyLendingPool { function mint(address user, uint256 amount) external override onlyLendingPool {
( (
uint256 previousBalance, uint256 previousBalance,
uint256 currentBalance, uint256 currentBalance,
uint256 balanceIncrease uint256 balanceIncrease
) = _calculateBalanceIncrease(_user); ) = _calculateBalanceIncrease(user);
_mint(_user, _amount.add(balanceIncrease)); _mint(user, amount.add(balanceIncrease));
uint256 newUserIndex = pool.getReserveNormalizedVariableDebt(underlyingAssetAddress); uint256 newUserIndex = _pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress);
userIndexes[_user] = newUserIndex; _userIndexes[user] = newUserIndex;
emit MintDebt(_user, _amount, previousBalance, currentBalance, balanceIncrease, newUserIndex); emit MintDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
} }
/** /**
* @dev burns user variable debt * @dev burns user variable debt
* @param _user the user which debt is burnt * @param user the user which debt is burnt
* @param _amount the amount of debt being burned * @param amount the amount of debt being burned
**/ **/
function burn(address _user, uint256 _amount) external override onlyLendingPool { function burn(address user, uint256 amount) external override onlyLendingPool {
( (
uint256 previousBalance, uint256 previousBalance,
uint256 currentBalance, uint256 currentBalance,
uint256 balanceIncrease uint256 balanceIncrease
) = _calculateBalanceIncrease(_user); ) = _calculateBalanceIncrease(user);
if (balanceIncrease > _amount) { if (balanceIncrease > amount) {
_mint(_user, balanceIncrease.sub(_amount)); _mint(user, balanceIncrease.sub(amount));
} else { } else {
_burn(_user, _amount.sub(balanceIncrease)); _burn(user, amount.sub(balanceIncrease));
} }
uint256 newUserIndex = 0; uint256 newUserIndex = 0;
//if user not repaid everything //if user not repaid everything
if (currentBalance != _amount) { if (currentBalance != amount) {
newUserIndex = pool.getReserveNormalizedVariableDebt(underlyingAssetAddress); newUserIndex = _pool.getReserveNormalizedVariableDebt(_underlyingAssetAddress);
} }
userIndexes[_user] = newUserIndex; _userIndexes[user] = newUserIndex;
emit BurnDebt(_user, _amount, previousBalance, currentBalance, balanceIncrease, newUserIndex); emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease, newUserIndex);
} }
} }

View File

@ -2,13 +2,13 @@
pragma solidity ^0.6.8; pragma solidity ^0.6.8;
import {Context} from '@openzeppelin/contracts/GSN/Context.sol'; import {Context} from '@openzeppelin/contracts/GSN/Context.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol'; import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol'; import {ILendingPoolAddressesProvider} from '../../interfaces/ILendingPoolAddressesProvider.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol'; import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import { import {
VersionedInitializable VersionedInitializable
} from '../../libraries/openzeppelin-upgradeability/VersionedInitializable.sol'; } from '../../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
import {IERC20Detailed} from '../../interfaces/IERC20Detailed.sol';
/** /**
* @title contract DebtTokenBase * @title contract DebtTokenBase
@ -16,67 +16,87 @@ import {
* @notice base contract for StableDebtToken and VariableDebtToken * @notice base contract for StableDebtToken and VariableDebtToken
*/ */
abstract contract DebtTokenBase is IERC20, VersionedInitializable { abstract contract DebtTokenBase is IERC20Detailed, VersionedInitializable {
using SafeMath for uint256; using SafeMath for uint256;
uint256 public override totalSupply; uint256 internal _totalSupply;
string public name; string internal _name;
string public symbol; string internal _symbol;
uint8 public decimals; uint8 internal _decimals;
address public immutable underlyingAssetAddress; address internal immutable _underlyingAssetAddress;
ILendingPool internal immutable pool; ILendingPool internal immutable _pool;
mapping(address => uint256) internal balances; mapping(address => uint256) internal _balances;
/** /**
* @dev only lending pool can call functions marked by this modifier * @dev only lending pool can call functions marked by this modifier
**/ **/
modifier onlyLendingPool { modifier onlyLendingPool {
require(msg.sender == address(pool), 'The caller of this function must be a lending pool'); require(msg.sender == address(_pool), 'The caller of this function must be a lending pool');
_; _;
} }
constructor( constructor(
address _pool, address pool,
address _underlyingAssetAddress, address underlyingAssetAddress,
string memory _name, string memory name,
string memory _symbol string memory symbol
) public { ) public {
pool = ILendingPool(_pool); _pool = ILendingPool(pool);
underlyingAssetAddress = _underlyingAssetAddress; _underlyingAssetAddress = underlyingAssetAddress;
name = _name; _name = name;
symbol = _symbol; _symbol = symbol;
} }
/** /**
* @dev initializes the debt token. * @dev initializes the debt token.
* @param _name the name of the token * @param name the name of the token
* @param _symbol the symbol of the token * @param symbol the symbol of the token
* @param _decimals the decimals of the token * @param decimals the decimals of the token
*/ */
function initialize( function initialize(
uint8 _decimals, uint8 decimals,
string memory _name, string memory name,
string memory _symbol string memory symbol
) public initializer { ) public initializer {
name = _name; _name = name;
symbol = _symbol; _symbol = symbol;
decimals = _decimals; _decimals = decimals;
}
function name() public override view returns (string memory) {
return _name;
}
function symbol() public override view returns (string memory) {
return _symbol;
}
function decimals() public override view returns (uint8) {
return _decimals;
}
function totalSupply() public override view returns (uint256) {
return _totalSupply;
}
function underlyingAssetAddress() public view returns (address) {
return _underlyingAssetAddress;
} }
/** /**
* @dev calculates the accumulated debt balance of the user * @dev calculates the accumulated debt balance of the user
* @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);
/** /**
* @dev returns the principal debt balance of the user from * @dev returns the principal debt balance of the user from
* @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 _balances[user];
} }
/** /**
@ -84,9 +104,9 @@ abstract contract DebtTokenBase is IERC20, VersionedInitializable {
* @dev _user the target user of the minting action * @dev _user the target user of the minting action
* @dev _amount the amount to mint * @dev _amount the amount to mint
**/ **/
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); _balances[user] = _balances[user].add(amount);
} }
/** /**
@ -94,16 +114,16 @@ abstract contract DebtTokenBase is IERC20, VersionedInitializable {
* @dev _user the target user of the burning action * @dev _user the target user of the burning action
* @dev _amount the amount to burn * @dev _amount the amount to burn
**/ **/
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); _balances[user] = _balances[user].sub(amount);
} }
/** /**
* @dev being non transferrable, the debt token does not implement any of the * @dev being non transferrable, the debt token does not implement any of the
* standard ERC20 functions for transfer and allowance. * standard ERC20 functions for transfer and allowance.
**/ **/
function transfer(address recipient, uint256 _amount) external virtual override returns (bool) { function transfer(address recipient, uint256 amount) external virtual override returns (bool) {
revert('TRANSFER_NOT_SUPPORTED'); revert('TRANSFER_NOT_SUPPORTED');
} }
@ -117,14 +137,14 @@ abstract contract DebtTokenBase is IERC20, VersionedInitializable {
revert('ALLOWANCE_NOT_SUPPORTED'); revert('ALLOWANCE_NOT_SUPPORTED');
} }
function approve(address spender, uint256 _amount) external virtual override returns (bool) { function approve(address spender, uint256 amount) external virtual override returns (bool) {
revert('APPROVAL_NOT_SUPPORTED'); revert('APPROVAL_NOT_SUPPORTED');
} }
function transferFrom( function transferFrom(
address sender, address sender,
address recipient, address recipient,
uint256 _amount uint256 amount
) external virtual override returns (bool) { ) external virtual override returns (bool) {
revert('TRANSFER_NOT_SUPPORTED'); revert('TRANSFER_NOT_SUPPORTED');
} }
@ -143,11 +163,11 @@ abstract contract DebtTokenBase is IERC20, VersionedInitializable {
/** /**
* @dev calculates the increase in balance since the last user interaction * @dev calculates the increase in balance since the last user interaction
* @param _user the address of the user for which the interest is being accumulated * @param user the address of the user for which the interest is being accumulated
* @return the previous principal balance, the new principal balance, the balance increase * @return the previous principal balance, the new principal balance, the balance increase
* and the new user index * and the new user index
**/ **/
function _calculateBalanceIncrease(address _user) function _calculateBalanceIncrease(address user)
internal internal
view view
returns ( returns (
@ -156,14 +176,14 @@ abstract contract DebtTokenBase is IERC20, VersionedInitializable {
uint256 uint256
) )
{ {
uint256 previousPrincipalBalance = balances[_user]; uint256 previousPrincipalBalance = _balances[user];
if (previousPrincipalBalance == 0) { if (previousPrincipalBalance == 0) {
return (0, 0, 0); return (0, 0, 0);
} }
//calculate the accrued interest since the last accumulation //calculate the accrued interest since the last accumulation
uint256 balanceIncrease = balanceOf(_user).sub(previousPrincipalBalance); uint256 balanceIncrease = balanceOf(user).sub(previousPrincipalBalance);
return ( return (
previousPrincipalBalance, previousPrincipalBalance,

View File

@ -16,22 +16,22 @@ interface IStableDebtToken {
/** /**
* @dev mints debt token to the target user. The resulting rate is the weighted average * @dev mints debt token to the target user. The resulting rate is the weighted average
* between the rate of the new debt and the rate of the previous debt * between the rate of the new debt and the rate of the previous debt
* @param _user the address of the user * @param user the address of the user
* @param _amount the amount of debt tokens to mint * @param amount the amount of debt tokens to mint
* @param _rate the rate of the debt being minted. * @param rate the rate of the debt being minted.
**/ **/
function mint( function mint(
address _user, address user,
uint256 _amount, uint256 amount,
uint256 _rate uint256 rate
) external; ) external;
/** /**
* @dev burns debt of the target user. * @dev burns debt of the target user.
* @param _user the address of the user * @param user the address of the user
* @param _amount the amount of debt tokens to mint * @param amount the amount of debt tokens to mint
**/ **/
function burn(address _user, uint256 _amount) external; function burn(address user, uint256 amount) external;
/** /**
* @dev returns the average rate of all the stable rate loans. * @dev returns the average rate of all the stable rate loans.
@ -43,11 +43,11 @@ interface IStableDebtToken {
* @dev returns the stable rate of the user debt * @dev returns the stable rate of the user debt
* @return the stable rate of the user * @return the stable rate of the user
**/ **/
function getUserStableRate(address _user) external view returns (uint256); function getUserStableRate(address user) external view returns (uint256);
/** /**
* @dev returns the timestamp of the last update of the user * @dev returns the timestamp of the last update of the user
* @return the timestamp * @return the timestamp
**/ **/
function getUserLastUpdated(address _user) external view returns (uint40); function getUserLastUpdated(address user) external view returns (uint40);
} }

View File

@ -10,21 +10,21 @@ pragma solidity ^0.6.8;
interface IVariableDebtToken { interface IVariableDebtToken {
/** /**
* @dev mints new variable debt * @dev mints new variable debt
* @param _user the user receiving the debt * @param user the user receiving the debt
* @param _amount the amount of debt being minted * @param amount the amount of debt being minted
**/ **/
function mint(address _user, uint256 _amount) external; function mint(address user, uint256 amount) external;
/** /**
* @dev burns user variable debt * @dev burns user variable debt
* @param _user the user which debt is burnt * @param user the user which debt is burnt
* @param _amount the amount of debt being burned * @param amount the amount of debt being burned
**/ **/
function burn(address _user, uint256 _amount) external; function burn(address user, uint256 amount) external;
/** /**
* @dev returns the last index of the user * @dev returns the last index of the user
* @return the index of the user * @return the index of the user
**/ **/
function getUserIndex(address _user) external view returns (uint256); function getUserIndex(address user) external view returns (uint256);
} }

View File

@ -1,39 +1,38 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { import {
calcExpectedReserveDataAfterDeposit,
calcExpectedReserveDataAfterWithdraw,
calcExpectedUserDataAfterDeposit,
calcExpectedUserDataAfterWithdraw,
calcExpectedReserveDataAfterBorrow, calcExpectedReserveDataAfterBorrow,
calcExpectedUserDataAfterBorrow, calcExpectedReserveDataAfterDeposit,
calcExpectedReserveDataAfterRepay, calcExpectedReserveDataAfterRepay,
calcExpectedReserveDataAfterStableRateRebalance,
calcExpectedReserveDataAfterSwapRateMode,
calcExpectedReserveDataAfterWithdraw,
calcExpectedUserDataAfterBorrow,
calcExpectedUserDataAfterDeposit,
calcExpectedUserDataAfterRepay, calcExpectedUserDataAfterRepay,
calcExpectedUserDataAfterSetUseAsCollateral, calcExpectedUserDataAfterSetUseAsCollateral,
calcExpectedUserDataAfterSwapRateMode,
calcExpectedReserveDataAfterSwapRateMode,
calcExpectedReserveDataAfterStableRateRebalance,
calcExpectedUserDataAfterStableRateRebalance, calcExpectedUserDataAfterStableRateRebalance,
calcExpectedUserDataAfterSwapRateMode,
calcExpectedUserDataAfterWithdraw,
calcExpectedUsersDataAfterRedirectInterest, calcExpectedUsersDataAfterRedirectInterest,
} from './utils/calculations'; } from './utils/calculations';
import {getReserveAddressFromSymbol, getReserveData, getUserData} from './utils/helpers'; import {getReserveAddressFromSymbol, getReserveData, getUserData} from './utils/helpers';
import { import {
getMintableErc20,
convertToCurrencyDecimals, convertToCurrencyDecimals,
getAToken, getAToken,
getMintableErc20,
} from '../../helpers/contracts-helpers'; } from '../../helpers/contracts-helpers';
import {ONE_YEAR, MAX_UINT_AMOUNT} from '../../helpers/constants'; import {MAX_UINT_AMOUNT, ONE_YEAR} from '../../helpers/constants';
import {TestEnv, SignerWithAddress} from './make-suite'; import {SignerWithAddress, TestEnv} from './make-suite';
import {BRE, increaseTime, timeLatest} from '../../helpers/misc-utils'; import {BRE, increaseTime, timeLatest} from '../../helpers/misc-utils';
import chai from 'chai'; import chai from 'chai';
import {ReserveData, UserReserveData} from './utils/interfaces'; import {ReserveData, UserReserveData} from './utils/interfaces';
import {waitForTx} from '../__setup.spec'; import {waitForTx} from '../__setup.spec';
import {ContractReceipt} from 'ethers'; import {ContractReceipt} from 'ethers';
import {ethers} from 'ethers';
import {AToken} from '../../types/AToken'; import {AToken} from '../../types/AToken';
import {tEthereumAddress, RateMode} from '../../helpers/types'; import {RateMode, tEthereumAddress} from '../../helpers/types';
const {expect} = chai; const {expect} = chai;
@ -155,8 +154,7 @@ export const deposit = async (
); );
if (sendValue) { if (sendValue) {
const valueToSend = await convertToCurrencyDecimals(reserve, sendValue); txOptions.value = await convertToCurrencyDecimals(reserve, sendValue);
txOptions.value = valueToSend;
} }
if (expectedResult === 'success') { if (expectedResult === 'success') {
const txResult = await waitForTx( const txResult = await waitForTx(

View File

@ -0,0 +1,31 @@
import BigNumber from 'bignumber.js';
function almostEqualAssertion(this: any, expected: any, actual: any, message: string): any {
this.assert(
expected.plus(new BigNumber(1)).eq(actual) ||
expected.plus(new BigNumber(2)).eq(actual) ||
actual.plus(new BigNumber(1)).eq(expected) ||
actual.plus(new BigNumber(2)).eq(expected) ||
expected.eq(actual),
`${message} expected #{act} to be almost equal #{exp}`,
`${message} expected #{act} to be different from #{exp}`,
expected.toString(),
actual.toString()
);
}
export function almostEqual() {
return function (chai: any, utils: any) {
chai.Assertion.overwriteMethod('almostEqual', function (original: any) {
return function (this: any, value: any, message: string) {
if (utils.flag(this, 'bignumber')) {
var expected = new BigNumber(value);
var actual = new BigNumber(this._obj);
almostEqualAssertion.apply(this, [expected, actual, message]);
} else {
original.apply(this, arguments);
}
};
});
};
}

View File

@ -20,9 +20,11 @@ import {LendingPoolConfigurator} from '../../types/LendingPoolConfigurator';
import chai from 'chai'; import chai from 'chai';
// @ts-ignore // @ts-ignore
import bignumberChai from 'chai-bignumber'; import bignumberChai from 'chai-bignumber';
import {almostEqual} from './almost-equal';
import {PriceOracle} from '../../types/PriceOracle'; import {PriceOracle} from '../../types/PriceOracle';
import {LendingPoolAddressesProvider} from '../../types/LendingPoolAddressesProvider'; import {LendingPoolAddressesProvider} from '../../types/LendingPoolAddressesProvider';
chai.use(bignumberChai()); chai.use(bignumberChai());
chai.use(almostEqual());
export interface SignerWithAddress { export interface SignerWithAddress {
signer: Signer; signer: Signer;
@ -95,7 +97,6 @@ export async function initializeMakeSuite() {
const aDaiAddress = (await testEnv.helpersContract.getAllATokens()).find( const aDaiAddress = (await testEnv.helpersContract.getAllATokens()).find(
(aToken) => aToken.symbol === 'aDAI' (aToken) => aToken.symbol === 'aDAI'
)?.tokenAddress; )?.tokenAddress;
const aEthAddress = (await testEnv.helpersContract.getAllATokens()).find( const aEthAddress = (await testEnv.helpersContract.getAllATokens()).find(
(aToken) => aToken.symbol === 'aETH' (aToken) => aToken.symbol === 'aETH'
@ -112,7 +113,7 @@ export async function initializeMakeSuite() {
console.log(`atoken-modifiers.spec: aTokens not correctly initialized`); console.log(`atoken-modifiers.spec: aTokens not correctly initialized`);
process.exit(1); process.exit(1);
} }
if (!daiAddress || !usdcAddress || !lendAddress || ! wethAddress) { if (!daiAddress || !usdcAddress || !lendAddress || !wethAddress) {
console.log(`atoken-modifiers.spec: USDC or DAI not correctly initialized`); console.log(`atoken-modifiers.spec: USDC or DAI not correctly initialized`);
process.exit(1); process.exit(1);
} }

View File

@ -9,7 +9,6 @@ import {calcExpectedVariableDebtTokenBalance} from './helpers/utils/calculations
import {getUserData, getReserveData} from './helpers/utils/helpers'; import {getUserData, getReserveData} from './helpers/utils/helpers';
const chai = require('chai'); const chai = require('chai');
chai.use(require('chai-bignumber')());
const {expect} = chai; const {expect} = chai;
makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => { makeSuite('LendingPool liquidation - liquidator receiving aToken', (testEnv) => {

View File

@ -9,38 +9,9 @@ import {calcExpectedStableDebtTokenBalance} from './helpers/utils/calculations';
import {getUserData} from './helpers/utils/helpers'; import {getUserData} from './helpers/utils/helpers';
const chai = require('chai'); const chai = require('chai');
chai.use(require('chai-bignumber')());
const {expect} = chai; const {expect} = chai;
const almostEqual: any = function (this: any, expected: any, actual: any, message: string): any {
this.assert(
expected.plus(new BigNumber(1)).eq(actual) ||
expected.plus(new BigNumber(2)).eq(actual) ||
actual.plus(new BigNumber(1)).eq(expected) ||
actual.plus(new BigNumber(2)).eq(expected) ||
expected.eq(actual),
`${message} expected #{act} to be almost equal #{exp}`,
`${message} expected #{act} to be different from #{exp}`,
expected.toString(),
actual.toString()
);
};
chai.use(function (chai: any, utils: any) {
chai.Assertion.overwriteMethod('almostEqual', function (original: any) {
return function (this: any, value: any, message: string) {
if (utils.flag(this, 'bignumber')) {
var expected = new BigNumber(value);
var actual = new BigNumber(this._obj);
almostEqual.apply(this, [expected, actual, message]);
} else {
original.apply(this, arguments);
}
};
});
});
makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', (testEnv) => { makeSuite('LendingPool liquidation - liquidator receiving the underlying asset', (testEnv) => {
const { const {
HF_IS_NOT_BELLOW_THRESHOLD, HF_IS_NOT_BELLOW_THRESHOLD,