-
Notifications
You must be signed in to change notification settings - Fork 587
/
Copy pathAToken.sol
272 lines (236 loc) · 8.15 KB
/
AToken.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.10;
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
import {GPv2SafeERC20} from '../../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {SafeCast} from '../../dependencies/openzeppelin/contracts/SafeCast.sol';
import {VersionedInitializable} from '../libraries/aave-upgradeability/VersionedInitializable.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {WadRayMath} from '../libraries/math/WadRayMath.sol';
import {IPool} from '../../interfaces/IPool.sol';
import {IAToken} from '../../interfaces/IAToken.sol';
import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesController.sol';
import {IInitializableAToken} from '../../interfaces/IInitializableAToken.sol';
import {ScaledBalanceTokenBase} from './base/ScaledBalanceTokenBase.sol';
import {IncentivizedERC20} from './base/IncentivizedERC20.sol';
import {EIP712Base} from './base/EIP712Base.sol';
/**
* @title Aave ERC20 AToken
* @author Aave
* @notice Implementation of the interest bearing token for the Aave protocol
*/
contract AToken is VersionedInitializable, ScaledBalanceTokenBase, EIP712Base, IAToken {
using WadRayMath for uint256;
using SafeCast for uint256;
using GPv2SafeERC20 for IERC20;
bytes32 public constant PERMIT_TYPEHASH =
keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
uint256 public constant ATOKEN_REVISION = 0x1;
address internal _treasury;
address internal _underlyingAsset;
/// @inheritdoc VersionedInitializable
function getRevision() internal pure virtual override returns (uint256) {
return ATOKEN_REVISION;
}
/**
* @dev Constructor.
* @param pool The address of the Pool contract
*/
constructor(IPool pool)
ScaledBalanceTokenBase(pool, 'ATOKEN_IMPL', 'ATOKEN_IMPL', 0)
EIP712Base()
{
// Intentionally left blank
}
/// @inheritdoc IInitializableAToken
function initialize(
IPool initializingPool,
address treasury,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external override initializer {
require(initializingPool == POOL, Errors.POOL_ADDRESSES_DO_NOT_MATCH);
_setName(aTokenName);
_setSymbol(aTokenSymbol);
_setDecimals(aTokenDecimals);
_treasury = treasury;
_underlyingAsset = underlyingAsset;
_incentivesController = incentivesController;
_domainSeparator = _calculateDomainSeparator();
emit Initialized(
underlyingAsset,
address(POOL),
treasury,
address(incentivesController),
aTokenDecimals,
aTokenName,
aTokenSymbol,
params
);
}
/// @inheritdoc IAToken
function mint(
address caller,
address onBehalfOf,
uint256 amount,
uint256 index
) external virtual override onlyPool returns (bool) {
return _mintScaled(caller, onBehalfOf, amount, index);
}
/// @inheritdoc IAToken
function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external virtual override onlyPool {
_burnScaled(from, receiverOfUnderlying, amount, index);
if (receiverOfUnderlying != address(this)) {
IERC20(_underlyingAsset).safeTransfer(receiverOfUnderlying, amount);
}
}
/// @inheritdoc IAToken
function mintToTreasury(uint256 amount, uint256 index) external override onlyPool {
if (amount == 0) {
return;
}
_mintScaled(address(POOL), _treasury, amount, index);
}
/// @inheritdoc IAToken
function transferOnLiquidation(
address from,
address to,
uint256 value
) external override onlyPool {
// Being a normal transfer, the Transfer() and BalanceTransfer() are emitted
// so no need to emit a specific event here
_transfer(from, to, value, false);
emit Transfer(from, to, value);
}
/// @inheritdoc IERC20
function balanceOf(address user)
public
view
virtual
override(IncentivizedERC20, IERC20)
returns (uint256)
{
return super.balanceOf(user).rayMul(POOL.getReserveNormalizedIncome(_underlyingAsset));
}
/// @inheritdoc IERC20
function totalSupply() public view virtual override(IncentivizedERC20, IERC20) returns (uint256) {
uint256 currentSupplyScaled = super.totalSupply();
if (currentSupplyScaled == 0) {
return 0;
}
return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(_underlyingAsset));
}
/// @inheritdoc IAToken
function RESERVE_TREASURY_ADDRESS() external view override returns (address) {
return _treasury;
}
/// @inheritdoc IAToken
function UNDERLYING_ASSET_ADDRESS() external view override returns (address) {
return _underlyingAsset;
}
/// @inheritdoc IAToken
function transferUnderlyingTo(address target, uint256 amount) external virtual override onlyPool {
IERC20(_underlyingAsset).safeTransfer(target, amount);
}
/// @inheritdoc IAToken
function handleRepayment(address user, uint256 amount) external virtual override onlyPool {
// Intentionally left blank
}
/// @inheritdoc IAToken
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
require(owner != address(0), Errors.ZERO_ADDRESS_NOT_VALID);
//solium-disable-next-line
require(block.timestamp <= deadline, Errors.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), Errors.INVALID_SIGNATURE);
_nonces[owner] = currentValidNonce + 1;
_approve(owner, spender, value);
}
/**
* @notice Transfers the aTokens between two users. Validates the transfer
* (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, false otherwise
**/
function _transfer(
address from,
address to,
uint256 amount,
bool validate
) internal {
address underlyingAsset = _underlyingAsset;
uint256 index = POOL.getReserveNormalizedIncome(underlyingAsset);
uint256 fromBalanceBefore = super.balanceOf(from).rayMul(index);
uint256 toBalanceBefore = super.balanceOf(to).rayMul(index);
super._transfer(from, to, amount.rayDiv(index).toUint128());
if (validate) {
POOL.finalizeTransfer(underlyingAsset, from, to, amount, fromBalanceBefore, toBalanceBefore);
}
emit BalanceTransfer(from, to, amount, index);
}
/**
* @notice 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
**/
function _transfer(
address from,
address to,
uint128 amount
) internal override {
_transfer(from, to, amount, true);
}
/**
* @dev Overrides the base function to fully implement IAToken
* @dev see `IncentivizedERC20.DOMAIN_SEPARATOR()` for more detailed documentation
*/
function DOMAIN_SEPARATOR() public view override(IAToken, EIP712Base) returns (bytes32) {
return super.DOMAIN_SEPARATOR();
}
/**
* @dev Overrides the base function to fully implement IAToken
* @dev see `IncentivizedERC20.nonces()` for more detailed documentation
*/
function nonces(address owner) public view override(IAToken, EIP712Base) returns (uint256) {
return super.nonces(owner);
}
/// @inheritdoc EIP712Base
function _EIP712BaseId() internal view override returns (string memory) {
return name();
}
/// @inheritdoc IAToken
function rescueTokens(
address token,
address to,
uint256 amount
) external override onlyPoolAdmin {
require(token != _underlyingAsset, Errors.UNDERLYING_CANNOT_BE_RESCUED);
IERC20(token).safeTransfer(to, amount);
}
}