aave-protocol-v2/contracts/protocol/tokenization/AToken.sol

407 lines
13 KiB
Solidity
Raw Normal View History

// SPDX-License-Identifier: agpl-3.0
2020-11-20 10:45:20 +00:00
pragma solidity 0.6.12;
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {IAToken} from '../../interfaces/IAToken.sol';
2020-08-20 07:51:21 +00:00
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
2020-10-15 13:16:05 +00:00
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
import {IncentivizedERC20} from './IncentivizedERC20.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
2020-08-07 16:23:52 +00:00
/**
* @title Aave ERC20 AToken
* @dev Implementation of the interest bearing token for the Aave protocol
* @author Aave
*/
contract AToken is
VersionedInitializable,
IncentivizedERC20('ATOKEN_IMPL', 'ATOKEN_IMPL', 0),
IAToken
{
2020-07-13 08:54:08 +00:00
using WadRayMath for uint256;
2020-09-21 13:58:19 +00:00
using SafeERC20 for IERC20;
2020-07-13 08:54:08 +00:00
2020-09-14 17:59:00 +00:00
bytes public constant EIP712_REVISION = bytes('1');
bytes32 internal constant EIP712_DOMAIN =
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
bytes32 public constant PERMIT_TYPEHASH =
keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
2020-07-13 08:54:08 +00:00
2020-09-21 13:58:19 +00:00
uint256 public constant ATOKEN_REVISION = 0x1;
/// @dev owner => next valid nonce to submit with permit()
mapping(address => uint256) public _nonces;
2020-09-21 15:41:38 +00:00
2020-09-21 13:58:19 +00:00
bytes32 public DOMAIN_SEPARATOR;
2020-09-21 15:41:38 +00:00
ILendingPool internal _pool;
address internal _treasury;
address internal _underlyingAsset;
IAaveIncentivesController internal _incentivesController;
2020-07-13 08:54:08 +00:00
modifier onlyLendingPool {
require(_msgSender() == address(_pool), Errors.CT_CALLER_MUST_BE_LENDING_POOL);
2020-07-13 08:54:08 +00:00
_;
}
function getRevision() internal pure virtual override returns (uint256) {
2020-08-07 16:23:52 +00:00
return ATOKEN_REVISION;
}
/**
* @dev Initializes the aToken
* @param pool The address of the lending pool where this aToken will be used
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
*/
2020-08-07 16:23:52 +00:00
function initialize(
ILendingPool pool,
address treasury,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external override initializer {
2020-09-14 13:57:11 +00:00
uint256 chainId;
//solium-disable-next-line
assembly {
2020-09-14 17:59:00 +00:00
chainId := chainid()
2020-09-14 13:57:11 +00:00
}
2020-09-14 17:59:00 +00:00
DOMAIN_SEPARATOR = keccak256(
abi.encode(
2020-09-14 13:57:11 +00:00
EIP712_DOMAIN,
keccak256(bytes(aTokenName)),
2020-09-14 13:57:11 +00:00
keccak256(EIP712_REVISION),
chainId,
address(this)
2020-09-14 17:59:00 +00:00
)
);
2020-09-14 13:57:11 +00:00
_setName(aTokenName);
_setSymbol(aTokenSymbol);
_setDecimals(aTokenDecimals);
_pool = pool;
_treasury = treasury;
_underlyingAsset = underlyingAsset;
_incentivesController = incentivesController;
2021-03-01 17:33:48 +00:00
emit Initialized(
underlyingAsset,
address(pool),
treasury,
address(incentivesController),
aTokenDecimals,
aTokenName,
aTokenSymbol,
params
);
2020-07-13 08:54:08 +00:00
}
/**
* @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* - Only callable by the LendingPool, as extra state updates there need to be managed
* @param user The owner of the aTokens, getting them burned
* @param receiverOfUnderlying The address that will receive the underlying
* @param amount The amount being burned
* @param index The new liquidity index of the reserve
2020-07-13 08:54:08 +00:00
**/
function burn(
address user,
2020-09-07 15:55:47 +00:00
address receiverOfUnderlying,
2020-09-12 11:18:17 +00:00
uint256 amount,
uint256 index
) external override onlyLendingPool {
2020-09-30 15:40:47 +00:00
uint256 amountScaled = amount.rayDiv(index);
2020-11-12 12:54:23 +00:00
require(amountScaled != 0, Errors.CT_INVALID_BURN_AMOUNT);
2020-09-30 15:40:47 +00:00
_burn(user, amountScaled);
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
2020-09-07 15:55:47 +00:00
2020-09-15 12:36:02 +00:00
emit Transfer(user, address(0), amount);
2020-11-01 08:11:53 +00:00
emit Burn(user, receiverOfUnderlying, amount, index);
2020-07-13 08:54:08 +00:00
}
/**
* @dev Mints `amount` aTokens to `user`
* - Only callable by the LendingPool, as extra state updates there need to be managed
* @param user The address receiving the minted tokens
* @param amount The amount of tokens getting minted
* @param index The new liquidity index of the reserve
* @return `true` if the the previous balance of the user was 0
2020-07-13 08:54:08 +00:00
*/
function mint(
address user,
uint256 amount,
uint256 index
2020-10-15 12:13:46 +00:00
) external override onlyLendingPool returns (bool) {
uint256 previousBalance = super.balanceOf(user);
2020-09-30 15:40:47 +00:00
uint256 amountScaled = amount.rayDiv(index);
2020-11-12 12:54:23 +00:00
require(amountScaled != 0, Errors.CT_INVALID_MINT_AMOUNT);
2020-09-30 15:40:47 +00:00
_mint(user, amountScaled);
2020-07-13 08:54:08 +00:00
2020-09-15 12:36:02 +00:00
emit Transfer(address(0), user, amount);
2020-09-07 15:55:47 +00:00
emit Mint(user, amount, index);
2020-10-15 12:13:46 +00:00
return previousBalance == 0;
2020-07-13 08:54:08 +00:00
}
/**
* @dev Mints aTokens to the reserve treasury
* - Only callable by the LendingPool
* @param amount The amount of tokens getting minted
* @param index The new liquidity index of the reserve
*/
2020-09-14 13:09:16 +00:00
function mintToTreasury(uint256 amount, uint256 index) external override onlyLendingPool {
2020-10-12 13:19:27 +00:00
if (amount == 0) {
2020-10-05 11:11:53 +00:00
return;
}
address treasury = _treasury;
// Compared to the normal mint, we don't check for rounding errors.
// The amount to mint can easily be very small since it is a fraction of the interest ccrued.
// In that case, the treasury will experience a (very small) loss, but it
// wont cause potentially valid transactions to fail.
_mint(treasury, amount.rayDiv(index));
2020-09-21 15:58:02 +00:00
emit Transfer(address(0), treasury, amount);
emit Mint(treasury, amount, index);
2020-09-10 10:51:52 +00:00
}
2020-07-13 08:54:08 +00:00
/**
* @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* - Only callable by the LendingPool
* @param from The address getting liquidated, current owner of the aTokens
* @param to The recipient
* @param value The amount of tokens getting transferred
2020-07-13 08:54:08 +00:00
**/
function transferOnLiquidation(
address from,
address to,
uint256 value
) external override onlyLendingPool {
// Being a normal transfer, the Transfer() and BalanceTransfer() are emitted
// so no need to emit a specific event here
2020-09-07 15:55:47 +00:00
_transfer(from, to, value, false);
emit Transfer(from, to, value);
2020-07-13 08:54:08 +00:00
}
/**
* @dev Calculates the balance of the user: principal balance + interest generated by the principal
* @param user The user whose balance is calculated
* @return The balance of the user
2020-07-13 08:54:08 +00:00
**/
2020-09-15 15:08:28 +00:00
function balanceOf(address user)
public
view
override(IncentivizedERC20, IERC20)
2020-09-15 15:08:28 +00:00
returns (uint256)
{
return super.balanceOf(user).rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
2020-07-13 08:54:08 +00:00
}
/**
* @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
* updated stored balance divided by the reserve's liquidity index at the moment of the update
* @param user The user whose balance is calculated
* @return The scaled balance of the user
2020-07-13 08:54:08 +00:00
**/
function scaledBalanceOf(address user) external view override returns (uint256) {
return super.balanceOf(user);
2020-07-13 08:54:08 +00:00
}
2020-09-15 13:53:20 +00:00
/**
2020-11-26 09:37:04 +00:00
* @dev Returns the scaled balance of the user and the scaled total supply.
* @param user The address of the user
* @return The scaled balance of the user
* @return The scaled balance and the scaled total supply
2020-09-15 13:53:20 +00:00
**/
function getScaledUserBalanceAndSupply(address user)
external
view
override
2020-09-15 13:53:20 +00:00
returns (uint256, uint256)
{
return (super.balanceOf(user), super.totalSupply());
}
2020-07-13 08:54:08 +00:00
/**
* @dev calculates the total supply of the specific aToken
* since the balance of every single user increases over time, the total supply
* does that too.
* @return the current total supply
**/
function totalSupply() public view override(IncentivizedERC20, IERC20) returns (uint256) {
2020-09-07 15:55:47 +00:00
uint256 currentSupplyScaled = super.totalSupply();
2020-07-13 08:54:08 +00:00
2020-09-07 15:55:47 +00:00
if (currentSupplyScaled == 0) {
2020-07-13 08:54:08 +00:00
return 0;
}
return currentSupplyScaled.rayMul(_pool.getReserveNormalizedIncome(_underlyingAsset));
2020-07-13 08:54:08 +00:00
}
2020-09-21 15:41:38 +00:00
/**
* @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index)
2020-09-21 15:41:38 +00:00
* @return the scaled total supply
**/
function scaledTotalSupply() public view virtual override returns (uint256) {
2020-09-21 15:41:38 +00:00
return super.totalSupply();
}
/**
* @dev Returns the address of the Aave treasury, receiving the fees on this aToken
**/
function RESERVE_TREASURY_ADDRESS() public view returns (address) {
return _treasury;
}
/**
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
**/
2021-04-12 09:10:22 +00:00
function UNDERLYING_ASSET_ADDRESS() public override view returns (address) {
return _underlyingAsset;
}
/**
* @dev Returns the address of the lending pool where this aToken is used
**/
function POOL() public view returns (ILendingPool) {
return _pool;
}
/**
* @dev For internal usage in the logic of the parent contract IncentivizedERC20
**/
function _getIncentivesController() internal view override returns (IAaveIncentivesController) {
return _incentivesController;
}
/**
* @dev Returns the address of the incentives controller contract
**/
function getIncentivesController() external view override returns (IAaveIncentivesController) {
return _getIncentivesController();
}
2020-07-13 08:54:08 +00:00
/**
* @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
2020-11-26 09:29:53 +00:00
* assets in borrow(), withdraw() and flashLoan()
* @param target The recipient of the aTokens
* @param amount The amount getting transferred
* @return The amount transferred
**/
function transferUnderlyingTo(address target, uint256 amount)
2020-07-10 17:16:04 +00:00
external
override
2020-07-10 17:16:04 +00:00
onlyLendingPool
2020-07-13 08:54:08 +00:00
returns (uint256)
{
IERC20(_underlyingAsset).safeTransfer(target, amount);
return amount;
2020-07-13 08:54:08 +00:00
}
2021-03-01 16:47:27 +00:00
/**
* @dev Invoked to execute actions on the aToken side after a repayment.
* @param user The user executing the repayment
* @param amount The amount getting repaid
**/
function handleRepayment(address user, uint256 amount) external override onlyLendingPool {}
2020-09-14 13:57:11 +00:00
/**
* @dev implements the permit function as for
* https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
* @param owner The owner of the funds
* @param spender The spender
* @param value The amount
* @param deadline The deadline timestamp, type(uint256).max for max deadline
* @param v Signature param
* @param s Signature param
* @param r Signature param
2020-09-14 17:59:00 +00:00
*/
2020-09-14 13:57:11 +00:00
function permit(
2020-09-14 17:59:00 +00:00
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
2021-04-01 12:27:09 +00:00
) external override {
2020-09-14 17:59:00 +00:00
require(owner != address(0), 'INVALID_OWNER');
//solium-disable-next-line
require(block.timestamp <= deadline, 'INVALID_EXPIRATION');
uint256 currentValidNonce = _nonces[owner];
bytes32 digest =
keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
)
);
2020-09-14 17:59:00 +00:00
require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE');
_nonces[owner] = currentValidNonce.add(1);
_approve(owner, spender, value);
2020-09-14 13:57:11 +00:00
}
2020-09-21 15:58:02 +00:00
/**
* @dev Transfers the aTokens between two users. Validates the transfer
2020-09-21 15:58:02 +00:00
* (ie checks for valid HF after the transfer) if required
* @param from The source address
* @param to The destination address
* @param amount The amount getting transferred
* @param validate `true` if the transfer needs to be validated
2020-09-21 15:58:02 +00:00
**/
2020-09-08 11:45:24 +00:00
function _transfer(
address from,
address to,
2020-09-08 11:45:24 +00:00
uint256 amount,
bool validate
) internal {
address underlyingAsset = _underlyingAsset;
ILendingPool pool = _pool;
uint256 index = pool.getReserveNormalizedIncome(underlyingAsset);
2020-10-29 10:57:43 +00:00
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
2020-09-21 15:58:02 +00:00
super._transfer(from, to, amount.rayDiv(index));
2020-07-13 08:54:08 +00:00
2020-10-29 10:57:43 +00:00
if (validate) {
pool.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
2020-10-29 10:57:43 +00:00
}
2020-09-08 11:45:24 +00:00
emit BalanceTransfer(from, to, amount, index);
2020-07-13 08:54:08 +00:00
}
2020-09-21 15:58:02 +00:00
/**
* @dev Overrides the parent _transfer to force validated transfer() and transferFrom()
* @param from The source address
* @param to The destination address
* @param amount The amount getting transferred
2020-09-21 15:58:02 +00:00
**/
2020-09-09 08:03:19 +00:00
function _transfer(
address from,
address to,
uint256 amount
) internal override {
_transfer(from, to, amount, true);
2020-07-10 17:16:04 +00:00
}
}