Transaction Hash:
Block:
12884643 at Jul-23-2021 08:00:27 PM +UTC
Transaction Fee:
0.003462405 ETH
$6.68
Gas Used:
230,827 Gas / 15 Gwei
Emitted Events:
| 303 |
InitializableAdminUpgradeabilityProxy.0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f( 0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f, 0x000000000000000000000000dbf5e9c5206d0db70a90108bf936da60221dc080, 000000000000000000000000000000000000000000000003a7014707f8922000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 304 |
InitializableAdminUpgradeabilityProxy.0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f( 0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f, 0x0000000000000000000000002734dea73c715a2a537b6772e09d23db93d009f3, 000000000000000000000000000000000000000000000000006a94d74f430000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
| 305 |
InitializableAdminUpgradeabilityProxy.0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f( 0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f, 0x000000000000000000000000dbf5e9c5206d0db70a90108bf936da60221dc080, 000000000000000000000000000000000000000000000003a7014707f8922000, 0000000000000000000000000000000000000000000000000000000000000001 )
|
| 306 |
InitializableAdminUpgradeabilityProxy.0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f( 0xa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f, 0x0000000000000000000000002734dea73c715a2a537b6772e09d23db93d009f3, 000000000000000000000000000000000000000000000000006a94d74f430000, 0000000000000000000000000000000000000000000000000000000000000001 )
|
| 307 |
InitializableAdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000dbf5e9c5206d0db70a90108bf936da60221dc080, 0x0000000000000000000000002734dea73c715a2a537b6772e09d23db93d009f3, 000000000000000000000000000000000000000000000000006a94d74f430000 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x7Fc66500...33E2DDaE9 | |||||
| 0xDBF5E9c5...0221dC080 | (Wintermute: 0xdbf...080) |
24.858102299200872036 Eth
Nonce: 213
|
24.854639894200872036 Eth
Nonce: 214
| 0.003462405 | |
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,983.484549285765584716 Eth | 1,983.488011690765584716 Eth | 0.003462405 |
Execution Trace
InitializableAdminUpgradeabilityProxy.a9059cbb( )
-
AaveTokenV2.transfer( recipient=0x2734DeA73C715A2a537B6772E09D23DB93D009f3, amount=30000000000000000 ) => ( True )
transfer[ERC20 (ln:513)]
_transfer[ERC20 (ln:514)]_beforeTokenTransfer[ERC20 (ln:609)]sub[ERC20 (ln:611)]add[ERC20 (ln:612)]Transfer[ERC20 (ln:613)]
_msgSender[ERC20 (ln:514)]
File 1 of 2: InitializableAdminUpgradeabilityProxy
File 2 of 2: AaveTokenV2
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
import {IERC20} from "./IERC20.sol";
interface IERC20Detailed is IERC20 {
function name() external view returns(string memory);
function symbol() external view returns(string memory);
function decimals() external view returns(uint8);
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
interface ITransferHook {
function onTransfer(address from, address to, uint256 amount) external;
}pragma solidity ^0.6.2;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}pragma solidity ^0.6.0;
import './UpgradeabilityProxy.sol';
/**
* @title BaseAdminUpgradeabilityProxy
* @dev This contract combines an upgradeability proxy with an authorization
* mechanism for administrative tasks.
* All external functions in this contract must be guarded by the
* `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
* feature proposal that would enable this to be done automatically.
*/
contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
/**
* @dev Emitted when the administration has been transferred.
* @param previousAdmin Address of the previous admin.
* @param newAdmin Address of the new admin.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Modifier to check whether the `msg.sender` is the admin.
* If it is, it will run the function. Otherwise, it will delegate the call
* to the implementation.
*/
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
/**
* @return The address of the proxy admin.
*/
function admin() external ifAdmin returns (address) {
return _admin();
}
/**
* @return The address of the implementation.
*/
function implementation() external ifAdmin returns (address) {
return _implementation();
}
/**
* @dev Changes the admin of the proxy.
* Only the current admin can call this function.
* @param newAdmin Address to transfer proxy administration to.
*/
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev Upgrade the backing implementation of the proxy.
* Only the admin can call this function.
* @param newImplementation Address of the new implementation.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
/**
* @dev Upgrade the backing implementation of the proxy and call a function
* on the new implementation.
* This is useful to initialize the proxied contract.
* @param newImplementation Address of the new implementation.
* @param data Data to send as msg.data in the low level call.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
_upgradeTo(newImplementation);
(bool success,) = newImplementation.delegatecall(data);
require(success);
}
/**
* @return adm The admin slot.
*/
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
/**
* @dev Sets the address of the proxy admin.
* @param newAdmin Address of the new proxy admin.
*/
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
/**
* @dev Only fall back when the sender is not the admin.
*/
function _willFallback() internal override virtual {
require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
super._willFallback();
}
}pragma solidity ^0.6.0;
import './BaseUpgradeabilityProxy.sol';
/**
* @title UpgradeabilityProxy
* @dev Extends BaseUpgradeabilityProxy with a constructor for initializing
* implementation and init data.
*/
contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
/**
* @dev Contract constructor.
* @param _logic Address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(address _logic, bytes memory _data) public payable {
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
_setImplementation(_logic);
if(_data.length > 0) {
(bool success,) = _logic.delegatecall(_data);
require(success);
}
}
}pragma solidity ^0.6.0;
import './Proxy.sol';
import './Address.sol';
/**
* @title BaseUpgradeabilityProxy
* @dev This contract implements a proxy that allows to change the
* implementation address to which it will delegate.
* Such a change is called an implementation upgrade.
*/
contract BaseUpgradeabilityProxy is Proxy {
/**
* @dev Emitted when the implementation is upgraded.
* @param implementation Address of the new implementation.
*/
event Upgraded(address indexed implementation);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation.
* @return impl Address of the current implementation
*/
function _implementation() internal override view returns (address impl) {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
impl := sload(slot)
}
}
/**
* @dev Upgrades the proxy to a new implementation.
* @param newImplementation Address of the new implementation.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Sets the implementation address of the proxy.
* @param newImplementation Address of the new implementation.
*/
function _setImplementation(address newImplementation) internal {
require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
}pragma solidity ^0.6.0;
/**
* @title Proxy
* @dev Implements delegation of calls to other contracts, with proper
* forwarding of return values and bubbling of failures.
* It defines a fallback function that delegates all calls to the address
* returned by the abstract _implementation() internal function.
*/
abstract contract Proxy {
/**
* @dev Fallback function.
* Implemented entirely in `_fallback`.
*/
fallback () payable external {
_fallback();
}
/**
* @return The Address of the implementation.
*/
function _implementation() internal virtual view returns (address);
/**
* @dev Delegates execution to an implementation contract.
* This is a low level function that doesn't return to its internal call site.
* It will return to the external caller whatever the implementation returns.
* @param implementation Address to delegate.
*/
function _delegate(address implementation) internal {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
/**
* @dev Function that is run as the first thing in the fallback function.
* Can be redefined in derived contracts to add functionality.
* Redefinitions must call super._willFallback().
*/
function _willFallback() internal virtual {
}
/**
* @dev fallback implementation.
* Extracted to enable manual triggering.
*/
function _fallback() internal {
_willFallback();
_delegate(_implementation());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "./Context.sol";
import "../interfaces/IERC20.sol";
import "./SafeMath.sol";
import "./Address.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
using Address for address;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string internal _name;
string internal _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with
* a default value of 18.
*
* To select a different value for {decimals}, use {_setupDecimals}.
*
* All three of these values are immutable: they can only be set once during
* construction.
*/
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20};
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
*
* This is internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Sets {decimals} to a value other than the default one of 18.
*
* WARNING: This function should only be called from the constructor. Most
* applications that interact with token contracts will not expect
* {decimals} to ever change, and may work incorrectly if it does.
*/
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}pragma solidity ^0.6.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.10;
import "./BaseAdminUpgradeabilityProxy.sol";
import "./InitializableUpgradeabilityProxy.sol";
/**
* @title InitializableAdminUpgradeabilityProxy
* @dev Extends from BaseAdminUpgradeabilityProxy with an initializer for
* initializing the implementation, admin, and init data.
*/
contract InitializableAdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, InitializableUpgradeabilityProxy {
/**
* Contract initializer.
* @param _logic address of the initial implementation.
* @param _admin Address of the proxy administrator.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
function initialize(address _logic, address _admin, bytes memory _data) public payable {
require(_implementation() == address(0));
InitializableUpgradeabilityProxy.initialize(_logic, _data);
assert(ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_setAdmin(_admin);
}
/**
* @dev Only fall back when the sender is not the admin.
*/
function _willFallback() internal override(BaseAdminUpgradeabilityProxy, Proxy) {
BaseAdminUpgradeabilityProxy._willFallback();
}
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.10;
import "./BaseUpgradeabilityProxy.sol";
/**
* @title InitializableUpgradeabilityProxy
* @dev Extends BaseUpgradeabilityProxy with an initializer for initializing
* implementation and init data.
*/
contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
/**
* @dev Contract initializer.
* @param _logic Address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
function initialize(address _logic, bytes memory _data) public payable {
require(_implementation() == address(0));
assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_setImplementation(_logic);
if (_data.length > 0) {
(bool success, ) = _logic.delegatecall(_data);
require(success);
}
}
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
import {ERC20} from "../open-zeppelin/ERC20.sol";
import {ITransferHook} from "../interfaces/ITransferHook.sol";
import {VersionedInitializable} from "../utils/VersionedInitializable.sol";
/**
* @notice implementation of the AAVE token contract
* @author Aave
*/
contract AaveToken is ERC20, VersionedInitializable {
/// @dev snapshot of a value on a specific block, used for balances
struct Snapshot {
uint128 blockNumber;
uint128 value;
}
string internal constant NAME = "Aave Token";
string internal constant SYMBOL = "AAVE";
uint8 internal constant DECIMALS = 18;
/// @dev the amount being distributed for the LEND -> AAVE migration
uint256 internal constant MIGRATION_AMOUNT = 13000000 ether;
/// @dev the amount being distributed for the PSI and PEI
uint256 internal constant DISTRIBUTION_AMOUNT = 3000000 ether;
uint256 public constant REVISION = 1;
/// @dev owner => next valid nonce to submit with permit()
mapping (address => uint256) public _nonces;
mapping (address => mapping (uint256 => Snapshot)) public _snapshots;
mapping (address => uint256) public _countsSnapshots;
/// @dev reference to the Aave governance contract to call (if initialized) on _beforeTokenTransfer
/// !!! IMPORTANT The Aave governance is considered a trustable contract, being its responsibility
/// to control all potential reentrancies by calling back the AaveToken
ITransferHook public _aaveGovernance;
bytes32 public DOMAIN_SEPARATOR;
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)");
event SnapshotDone(address owner, uint128 oldValue, uint128 newValue);
constructor() ERC20(NAME, SYMBOL) public {}
/**
* @dev initializes the contract upon assignment to the InitializableAdminUpgradeabilityProxy
* @param migrator the address of the LEND -> AAVE migration contract
* @param distributor the address of the AAVE distribution contract
*/
function initialize(
address migrator,
address distributor,
ITransferHook aaveGovernance
) external initializer {
uint256 chainId;
//solium-disable-next-line
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(abi.encode(
EIP712_DOMAIN,
keccak256(bytes(NAME)),
keccak256(EIP712_REVISION),
chainId,
address(this)
));
_name = NAME;
_symbol = SYMBOL;
_setupDecimals(DECIMALS);
_aaveGovernance = aaveGovernance;
_mint(migrator, MIGRATION_AMOUNT);
_mint(distributor, DISTRIBUTION_AMOUNT);
}
/**
* @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 no deadline
* @param v signature param
* @param s signature param
* @param r signature param
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
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))
)
);
require(owner == ecrecover(digest, v, r, s), "INVALID_SIGNATURE");
_nonces[owner] = currentValidNonce.add(1);
_approve(owner, spender, value);
}
/**
* @dev returns the revision of the implementation contract
*/
function getRevision() internal pure override returns (uint256) {
return REVISION;
}
/**
* @dev Writes a snapshot for an owner of tokens
* @param owner The owner of the tokens
* @param oldValue The value before the operation that is gonna be executed after the snapshot
* @param newValue The value after the operation
*/
function _writeSnapshot(address owner, uint128 oldValue, uint128 newValue) internal {
uint128 currentBlock = uint128(block.number);
uint256 ownerCountOfSnapshots = _countsSnapshots[owner];
mapping (uint256 => Snapshot) storage snapshotsOwner = _snapshots[owner];
// Doing multiple operations in the same block
if (ownerCountOfSnapshots != 0 && snapshotsOwner[ownerCountOfSnapshots.sub(1)].blockNumber == currentBlock) {
snapshotsOwner[ownerCountOfSnapshots.sub(1)].value = newValue;
} else {
snapshotsOwner[ownerCountOfSnapshots] = Snapshot(currentBlock, newValue);
_countsSnapshots[owner] = ownerCountOfSnapshots.add(1);
}
emit SnapshotDone(owner, oldValue, newValue);
}
/**
* @dev Writes a snapshot before any operation involving transfer of value: _transfer, _mint and _burn
* - On _transfer, it writes snapshots for both "from" and "to"
* - On _mint, only for _to
* - On _burn, only for _from
* @param from the from address
* @param to the to address
* @param amount the amount to transfer
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
if (from == to) {
return;
}
if (from != address(0)) {
uint256 fromBalance = balanceOf(from);
_writeSnapshot(from, uint128(fromBalance), uint128(fromBalance.sub(amount)));
}
if (to != address(0)) {
uint256 toBalance = balanceOf(to);
_writeSnapshot(to, uint128(toBalance), uint128(toBalance.add(amount)));
}
// caching the aave governance address to avoid multiple state loads
ITransferHook aaveGovernance = _aaveGovernance;
if (aaveGovernance != ITransferHook(0)) {
aaveGovernance.onTransfer(from, to, amount);
}
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
/**
* @title VersionedInitializable
*
* @dev Helper contract to support initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*
* @author Aave, inspired by the OpenZeppelin Initializable contract
*/
abstract contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized.
*/
uint256 internal lastInitializedRevision = 0;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
uint256 revision = getRevision();
require(revision > lastInitializedRevision, "Contract instance has already been initialized");
lastInitializedRevision = revision;
_;
}
/// @dev returns the revision number of the contract.
/// Needs to be defined in the inherited class as a constant.
function getRevision() internal pure virtual returns(uint256);
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
import {IERC20} from "../interfaces/IERC20.sol";
import {SafeMath} from "../open-zeppelin/SafeMath.sol";
import {VersionedInitializable} from "../utils/VersionedInitializable.sol";
/**
* @title LendToAaveMigrator
* @notice This contract implements the migration from LEND to AAVE token
* @author Aave
*/
contract LendToAaveMigrator is VersionedInitializable {
using SafeMath for uint256;
IERC20 public immutable AAVE;
IERC20 public immutable LEND;
uint256 public immutable LEND_AAVE_RATIO;
uint256 public constant REVISION = 1;
uint256 public _totalLendMigrated;
/**
* @dev emitted on migration
* @param sender the caller of the migration
* @param amount the amount being migrated
*/
event LendMigrated(address indexed sender, uint256 indexed amount);
/**
* @param aave the address of the AAVE token
* @param lend the address of the LEND token
* @param lendAaveRatio the exchange rate between LEND and AAVE
*/
constructor(IERC20 aave, IERC20 lend, uint256 lendAaveRatio) public {
AAVE = aave;
LEND = lend;
LEND_AAVE_RATIO = lendAaveRatio;
}
/**
* @dev initializes the implementation
*/
function initialize() public initializer {
}
/**
* @dev returns true if the migration started
*/
function migrationStarted() external view returns(bool) {
return lastInitializedRevision != 0;
}
/**
* @dev executes the migration from LEND to AAVE. Users need to give allowance to this contract to transfer LEND before executing
* this transaction.
* @param amount the amount of LEND to be migrated
*/
function migrateFromLEND(uint256 amount) external {
require(lastInitializedRevision != 0, "MIGRATION_NOT_STARTED");
_totalLendMigrated = _totalLendMigrated.add(amount);
LEND.transferFrom(msg.sender, address(this), amount);
AAVE.transfer(msg.sender, amount.div(LEND_AAVE_RATIO));
emit LendMigrated(msg.sender, amount);
}
/**
* @dev returns the implementation revision
* @return the implementation revision
*/
function getRevision() internal pure override returns (uint256) {
return REVISION;
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
import "../interfaces/IERC20.sol";
contract DoubleTransferHelper {
IERC20 public immutable AAVE;
constructor(IERC20 aave) public {
AAVE = aave;
}
function doubleSend(address to, uint256 amount1, uint256 amount2) external {
AAVE.transfer(to, amount1);
AAVE.transfer(to, amount2);
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
import "../open-zeppelin/ERC20.sol";
/**
* @title ERC20Mintable
* @dev ERC20 minting logic
*/
contract MintableErc20 is ERC20 {
constructor(string memory name, string memory symbol, uint8 decimals) ERC20(name, symbol) public {
_setupDecimals(decimals);
}
/**
* @dev Function to mint tokens
* @param value The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(uint256 value) public returns (bool) {
_mint(msg.sender, value);
return true;
}
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.10;
import {ITransferHook} from "../interfaces/ITransferHook.sol";
contract MockTransferHook is ITransferHook {
event MockHookEvent();
function onTransfer(address from, address to, uint256 amount) external override {
emit MockHookEvent();
}
}File 2 of 2: AaveTokenV2
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.7.5;
pragma experimental ABIEncoderV2;
interface IGovernancePowerDelegationToken {
enum DelegationType {VOTING_POWER, PROPOSITION_POWER}
/**
* @dev emitted when a user delegates to another
* @param delegator the delegator
* @param delegatee the delegatee
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
**/
event DelegateChanged(
address indexed delegator,
address indexed delegatee,
DelegationType delegationType
);
/**
* @dev emitted when an action changes the delegated power of a user
* @param user the user which delegated power has changed
* @param amount the amount of delegated power for the user
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
**/
event DelegatedPowerChanged(address indexed user, uint256 amount, DelegationType delegationType);
/**
* @dev delegates the specific power to a delegatee
* @param delegatee the user which delegated power has changed
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
**/
function delegateByType(address delegatee, DelegationType delegationType) external virtual;
/**
* @dev delegates all the powers to a specific user
* @param delegatee the user to which the power will be delegated
**/
function delegate(address delegatee) external virtual;
/**
* @dev returns the delegatee of an user
* @param delegator the address of the delegator
**/
function getDelegateeByType(address delegator, DelegationType delegationType)
external
virtual
view
returns (address);
/**
* @dev returns the current delegated power of a user. The current power is the
* power delegated at the time of the last snapshot
* @param user the user
**/
function getPowerCurrent(address user, DelegationType delegationType)
external
virtual
view
returns (uint256);
/**
* @dev returns the delegated power of a user at a certain block
* @param user the user
**/
function getPowerAtBlock(
address user,
uint256 blockNumber,
DelegationType delegationType
) external virtual view returns (uint256);
/**
* @dev returns the total supply at a certain block number
**/
function totalSupplyAt(uint256 blockNumber) external virtual view returns (uint256);
}
/**
* @dev From https://github.com/OpenZeppelin/openzeppelin-contracts
* Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
* From https://github.com/OpenZeppelin/openzeppelin-contracts
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @dev From https://github.com/OpenZeppelin/openzeppelin-contracts
* Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'SafeMath: addition overflow');
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, 'SafeMath: subtraction overflow');
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, 'SafeMath: division by zero');
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, 'SafeMath: modulo by zero');
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
/**
* @dev Collection of functions related to the address type
* From https://github.com/OpenZeppelin/openzeppelin-contracts
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, 'Address: insufficient balance');
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{value: amount}('');
require(success, 'Address: unable to send value, recipient may have reverted');
}
}
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
using Address for address;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string internal _name;
string internal _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with
* a default value of 18.
*
* To select a different value for {decimals}, use {_setupDecimals}.
*
* All three of these values are immutable: they can only be set once during
* construction.
*/
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20};
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
*
* This is internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Sets {decimals} to a value other than the default one of 18.
*
* WARNING: This function should only be called from the constructor. Most
* applications that interact with token contracts will not expect
* {decimals} to ever change, and may work incorrectly if it does.
*/
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
interface ITransferHook {
function onTransfer(
address from,
address to,
uint256 amount
) external;
}
/**
* @title SafeERC20
* @dev From https://github.com/OpenZeppelin/openzeppelin-contracts
* Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
'SafeERC20: approve from non-zero to non-zero allowance'
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), 'SafeERC20: call to non-contract');
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, 'SafeERC20: low-level call failed');
if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
}
}
}
/**
* @title VersionedInitializable
*
* @dev Helper contract to support initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*
* @author Aave, inspired by the OpenZeppelin Initializable contract
*/
abstract contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized.
*/
uint256 internal lastInitializedRevision = 0;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
uint256 revision = getRevision();
require(revision > lastInitializedRevision, 'Contract instance has already been initialized');
lastInitializedRevision = revision;
_;
}
/// @dev returns the revision number of the contract.
/// Needs to be defined in the inherited class as a constant.
function getRevision() internal pure virtual returns (uint256);
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
/**
* @notice implementation of the AAVE token contract
* @author Aave
*/
abstract contract GovernancePowerDelegationERC20 is ERC20, IGovernancePowerDelegationToken {
using SafeMath for uint256;
/// @notice The EIP-712 typehash for the delegation struct used by the contract
bytes32 public constant DELEGATE_BY_TYPE_TYPEHASH = keccak256(
'DelegateByType(address delegatee,uint256 type,uint256 nonce,uint256 expiry)'
);
bytes32 public constant DELEGATE_TYPEHASH = keccak256(
'Delegate(address delegatee,uint256 nonce,uint256 expiry)'
);
/// @dev snapshot of a value on a specific block, used for votes
struct Snapshot {
uint128 blockNumber;
uint128 value;
}
/**
* @dev delegates one specific power to a delegatee
* @param delegatee the user which delegated power has changed
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
**/
function delegateByType(address delegatee, DelegationType delegationType) external override {
_delegateByType(msg.sender, delegatee, delegationType);
}
/**
* @dev delegates all the powers to a specific user
* @param delegatee the user to which the power will be delegated
**/
function delegate(address delegatee) external override {
_delegateByType(msg.sender, delegatee, DelegationType.VOTING_POWER);
_delegateByType(msg.sender, delegatee, DelegationType.PROPOSITION_POWER);
}
/**
* @dev returns the delegatee of an user
* @param delegator the address of the delegator
**/
function getDelegateeByType(address delegator, DelegationType delegationType)
external
override
view
returns (address)
{
(, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
return _getDelegatee(delegator, delegates);
}
/**
* @dev returns the current delegated power of a user. The current power is the
* power delegated at the time of the last snapshot
* @param user the user
**/
function getPowerCurrent(address user, DelegationType delegationType)
external
override
view
returns (uint256)
{
(
mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
mapping(address => uint256) storage snapshotsCounts,
) = _getDelegationDataByType(delegationType);
return _searchByBlockNumber(snapshots, snapshotsCounts, user, block.number);
}
/**
* @dev returns the delegated power of a user at a certain block
* @param user the user
**/
function getPowerAtBlock(
address user,
uint256 blockNumber,
DelegationType delegationType
) external override view returns (uint256) {
(
mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
mapping(address => uint256) storage snapshotsCounts,
) = _getDelegationDataByType(delegationType);
return _searchByBlockNumber(snapshots, snapshotsCounts, user, blockNumber);
}
/**
* @dev returns the total supply at a certain block number
* used by the voting strategy contracts to calculate the total votes needed for threshold/quorum
* In this initial implementation with no AAVE minting, simply returns the current supply
* A snapshots mapping will need to be added in case a mint function is added to the AAVE token in the future
**/
function totalSupplyAt(uint256 blockNumber) external override view returns (uint256) {
return super.totalSupply();
}
/**
* @dev delegates the specific power to a delegatee
* @param delegatee the user which delegated power has changed
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
**/
function _delegateByType(
address delegator,
address delegatee,
DelegationType delegationType
) internal {
require(delegatee != address(0), 'INVALID_DELEGATEE');
(, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
uint256 delegatorBalance = balanceOf(delegator);
address previousDelegatee = _getDelegatee(delegator, delegates);
delegates[delegator] = delegatee;
_moveDelegatesByType(previousDelegatee, delegatee, delegatorBalance, delegationType);
emit DelegateChanged(delegator, delegatee, delegationType);
}
/**
* @dev moves delegated power from one user to another
* @param from the user from which delegated power is moved
* @param to the user that will receive the delegated power
* @param amount the amount of delegated power to be moved
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
**/
function _moveDelegatesByType(
address from,
address to,
uint256 amount,
DelegationType delegationType
) internal {
if (from == to) {
return;
}
(
mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
mapping(address => uint256) storage snapshotsCounts,
) = _getDelegationDataByType(delegationType);
if (from != address(0)) {
uint256 previous = 0;
uint256 fromSnapshotsCount = snapshotsCounts[from];
if (fromSnapshotsCount != 0) {
previous = snapshots[from][fromSnapshotsCount - 1].value;
} else {
previous = balanceOf(from);
}
_writeSnapshot(
snapshots,
snapshotsCounts,
from,
uint128(previous),
uint128(previous.sub(amount))
);
emit DelegatedPowerChanged(from, previous.sub(amount), delegationType);
}
if (to != address(0)) {
uint256 previous = 0;
uint256 toSnapshotsCount = snapshotsCounts[to];
if (toSnapshotsCount != 0) {
previous = snapshots[to][toSnapshotsCount - 1].value;
} else {
previous = balanceOf(to);
}
_writeSnapshot(
snapshots,
snapshotsCounts,
to,
uint128(previous),
uint128(previous.add(amount))
);
emit DelegatedPowerChanged(to, previous.add(amount), delegationType);
}
}
/**
* @dev searches a snapshot by block number. Uses binary search.
* @param snapshots the snapshots mapping
* @param snapshotsCounts the number of snapshots
* @param user the user for which the snapshot is being searched
* @param blockNumber the block number being searched
**/
function _searchByBlockNumber(
mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
mapping(address => uint256) storage snapshotsCounts,
address user,
uint256 blockNumber
) internal view returns (uint256) {
require(blockNumber <= block.number, 'INVALID_BLOCK_NUMBER');
uint256 snapshotsCount = snapshotsCounts[user];
if (snapshotsCount == 0) {
return balanceOf(user);
}
// First check most recent balance
if (snapshots[user][snapshotsCount - 1].blockNumber <= blockNumber) {
return snapshots[user][snapshotsCount - 1].value;
}
// Next check implicit zero balance
if (snapshots[user][0].blockNumber > blockNumber) {
return 0;
}
uint256 lower = 0;
uint256 upper = snapshotsCount - 1;
while (upper > lower) {
uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
Snapshot memory snapshot = snapshots[user][center];
if (snapshot.blockNumber == blockNumber) {
return snapshot.value;
} else if (snapshot.blockNumber < blockNumber) {
lower = center;
} else {
upper = center - 1;
}
}
return snapshots[user][lower].value;
}
/**
* @dev returns the delegation data (snapshot, snapshotsCount, list of delegates) by delegation type
* NOTE: Ideal implementation would have mapped this in a struct by delegation type. Unfortunately,
* the AAVE token and StakeToken already include a mapping for the snapshots, so we require contracts
* who inherit from this to provide access to the delegation data by overriding this method.
* @param delegationType the type of delegation
**/
function _getDelegationDataByType(DelegationType delegationType)
internal
virtual
view
returns (
mapping(address => mapping(uint256 => Snapshot)) storage, //snapshots
mapping(address => uint256) storage, //snapshots count
mapping(address => address) storage //delegatees list
);
/**
* @dev Writes a snapshot for an owner of tokens
* @param owner The owner of the tokens
* @param oldValue The value before the operation that is gonna be executed after the snapshot
* @param newValue The value after the operation
*/
function _writeSnapshot(
mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
mapping(address => uint256) storage snapshotsCounts,
address owner,
uint128 oldValue,
uint128 newValue
) internal {
uint128 currentBlock = uint128(block.number);
uint256 ownerSnapshotsCount = snapshotsCounts[owner];
mapping(uint256 => Snapshot) storage snapshotsOwner = snapshots[owner];
// Doing multiple operations in the same block
if (
ownerSnapshotsCount != 0 &&
snapshotsOwner[ownerSnapshotsCount - 1].blockNumber == currentBlock
) {
snapshotsOwner[ownerSnapshotsCount - 1].value = newValue;
} else {
snapshotsOwner[ownerSnapshotsCount] = Snapshot(currentBlock, newValue);
snapshotsCounts[owner] = ownerSnapshotsCount + 1;
}
}
/**
* @dev returns the user delegatee. If a user never performed any delegation,
* his delegated address will be 0x0. In that case we simply return the user itself
* @param delegator the address of the user for which return the delegatee
* @param delegates the array of delegates for a particular type of delegation
**/
function _getDelegatee(address delegator, mapping(address => address) storage delegates)
internal
view
returns (address)
{
address previousDelegatee = delegates[delegator];
if (previousDelegatee == address(0)) {
return delegator;
}
return previousDelegatee;
}
}
/**
* @notice implementation of the AAVE token contract
* @author Aave
*/
contract AaveTokenV2 is GovernancePowerDelegationERC20, VersionedInitializable {
using SafeMath for uint256;
string internal constant NAME = 'Aave Token';
string internal constant SYMBOL = 'AAVE';
uint8 internal constant DECIMALS = 18;
uint256 public constant REVISION = 2;
/// @dev owner => next valid nonce to submit with permit()
mapping(address => uint256) public _nonces;
mapping(address => mapping(uint256 => Snapshot)) public _votingSnapshots;
mapping(address => uint256) public _votingSnapshotsCounts;
/// @dev reference to the Aave governance contract to call (if initialized) on _beforeTokenTransfer
/// !!! IMPORTANT The Aave governance is considered a trustable contract, being its responsibility
/// to control all potential reentrancies by calling back the AaveToken
ITransferHook public _aaveGovernance;
bytes32 public DOMAIN_SEPARATOR;
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)'
);
mapping(address => address) internal _votingDelegates;
mapping(address => mapping(uint256 => Snapshot)) internal _propositionPowerSnapshots;
mapping(address => uint256) internal _propositionPowerSnapshotsCounts;
mapping(address => address) internal _propositionPowerDelegates;
constructor() public ERC20(NAME, SYMBOL) {}
/**
* @dev initializes the contract upon assignment to the InitializableAdminUpgradeabilityProxy
*/
function initialize() external initializer {}
/**
* @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 no deadline
* @param v signature param
* @param s signature param
* @param r signature param
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
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))
)
);
require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE');
_nonces[owner] = currentValidNonce.add(1);
_approve(owner, spender, value);
}
/**
* @dev returns the revision of the implementation contract
*/
function getRevision() internal override pure returns (uint256) {
return REVISION;
}
/**
* @dev Writes a snapshot before any operation involving transfer of value: _transfer, _mint and _burn
* - On _transfer, it writes snapshots for both "from" and "to"
* - On _mint, only for _to
* - On _burn, only for _from
* @param from the from address
* @param to the to address
* @param amount the amount to transfer
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override {
address votingFromDelegatee = _getDelegatee(from, _votingDelegates);
address votingToDelegatee = _getDelegatee(to, _votingDelegates);
_moveDelegatesByType(
votingFromDelegatee,
votingToDelegatee,
amount,
DelegationType.VOTING_POWER
);
address propPowerFromDelegatee = _getDelegatee(from, _propositionPowerDelegates);
address propPowerToDelegatee = _getDelegatee(to, _propositionPowerDelegates);
_moveDelegatesByType(
propPowerFromDelegatee,
propPowerToDelegatee,
amount,
DelegationType.PROPOSITION_POWER
);
// caching the aave governance address to avoid multiple state loads
ITransferHook aaveGovernance = _aaveGovernance;
if (aaveGovernance != ITransferHook(0)) {
aaveGovernance.onTransfer(from, to, amount);
}
}
function _getDelegationDataByType(DelegationType delegationType)
internal
override
view
returns (
mapping(address => mapping(uint256 => Snapshot)) storage, //snapshots
mapping(address => uint256) storage, //snapshots count
mapping(address => address) storage //delegatees list
)
{
if (delegationType == DelegationType.VOTING_POWER) {
return (_votingSnapshots, _votingSnapshotsCounts, _votingDelegates);
} else {
return (
_propositionPowerSnapshots,
_propositionPowerSnapshotsCounts,
_propositionPowerDelegates
);
}
}
/**
* @dev Delegates power from signatory to `delegatee`
* @param delegatee The address to delegate votes to
* @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
* @param nonce The contract state required to match the signature
* @param expiry The time at which to expire the signature
* @param v The recovery byte of the signature
* @param r Half of the ECDSA signature pair
* @param s Half of the ECDSA signature pair
*/
function delegateByTypeBySig(
address delegatee,
DelegationType delegationType,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public {
bytes32 structHash = keccak256(
abi.encode(DELEGATE_BY_TYPE_TYPEHASH, delegatee, uint256(delegationType), nonce, expiry)
);
bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR, structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), 'INVALID_SIGNATURE');
require(nonce == _nonces[signatory]++, 'INVALID_NONCE');
require(block.timestamp <= expiry, 'INVALID_EXPIRATION');
_delegateByType(signatory, delegatee, delegationType);
}
/**
* @dev Delegates power from signatory to `delegatee`
* @param delegatee The address to delegate votes to
* @param nonce The contract state required to match the signature
* @param expiry The time at which to expire the signature
* @param v The recovery byte of the signature
* @param r Half of the ECDSA signature pair
* @param s Half of the ECDSA signature pair
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public {
bytes32 structHash = keccak256(abi.encode(DELEGATE_TYPEHASH, delegatee, nonce, expiry));
bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR, structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), 'INVALID_SIGNATURE');
require(nonce == _nonces[signatory]++, 'INVALID_NONCE');
require(block.timestamp <= expiry, 'INVALID_EXPIRATION');
_delegateByType(signatory, delegatee, DelegationType.VOTING_POWER);
_delegateByType(signatory, delegatee, DelegationType.PROPOSITION_POWER);
}
}