@ensuro/core 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -0
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +772 -0
- package/build/contracts/BaseAssetManager.sol/BaseAssetManager.json +494 -0
- package/build/contracts/DataTypes.sol/DataTypes.json +10 -0
- package/build/contracts/EToken.sol/EToken.json +1148 -0
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +1093 -0
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +412 -0
- package/build/contracts/Policy.sol/Policy.json +10 -0
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +570 -0
- package/build/contracts/PolicyPool.sol/PolicyPool.json +1257 -0
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +281 -0
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +660 -0
- package/build/contracts/RiskModule.sol/RiskModule.json +748 -0
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +1032 -0
- package/build/contracts/WadRayMath.sol/WadRayMath.json +10 -0
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +50 -0
- package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +322 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +571 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +602 -0
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +31 -0
- package/build/interfaces/IEToken.sol/IEToken.json +491 -0
- package/build/interfaces/IInsolvencyHook.sol/IInsolvencyHook.json +42 -0
- package/build/interfaces/ILPWhitelist.sol/ILPWhitelist.json +74 -0
- package/build/interfaces/IPolicyNFT.sol/IPolicyNFT.json +321 -0
- package/build/interfaces/IPolicyPool.sol/IPolicyPool.json +445 -0
- package/build/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +24 -0
- package/build/interfaces/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +328 -0
- package/build/interfaces/IRiskModule.sol/IRiskModule.json +141 -0
- package/contracts/AaveAssetManager.sol +326 -0
- package/contracts/BaseAssetManager.sol +283 -0
- package/contracts/DataTypes.sol +287 -0
- package/contracts/EToken.sol +773 -0
- package/contracts/FlightDelayRiskModule.sol +208 -0
- package/contracts/LPManualWhitelist.sol +57 -0
- package/contracts/Policy.sol +104 -0
- package/contracts/PolicyNFT.sol +96 -0
- package/contracts/PolicyPool.sol +716 -0
- package/contracts/PolicyPoolComponent.sol +164 -0
- package/contracts/PolicyPoolConfig.sol +231 -0
- package/contracts/RiskModule.sol +323 -0
- package/contracts/TrustfulRiskModule.sol +81 -0
- package/contracts/WadRayMath.sol +135 -0
- package/contracts/dependencies/ChainlinkClientUpgradeable.sol +371 -0
- package/contracts/upgraded/IPolicyNFTv1.sol +15 -0
- package/contracts/upgraded/PolicyNFTv1.sol +126 -0
- package/interfaces/IAssetManager.sol +23 -0
- package/interfaces/IEToken.sol +44 -0
- package/interfaces/IInsolvencyHook.sol +27 -0
- package/interfaces/ILPWhitelist.sol +23 -0
- package/interfaces/IPolicyNFT.sol +15 -0
- package/interfaces/IPolicyPool.sol +44 -0
- package/interfaces/IPolicyPoolComponent.sol +13 -0
- package/interfaces/IPolicyPoolConfig.sol +81 -0
- package/interfaces/IRiskModule.sol +29 -0
- package/package.json +30 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
5
|
+
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
6
|
+
import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
|
|
7
|
+
import {IEToken} from "../interfaces/IEToken.sol";
|
|
8
|
+
import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
|
|
9
|
+
import {IInsolvencyHook} from "../interfaces/IInsolvencyHook.sol";
|
|
10
|
+
import {WadRayMath} from "./WadRayMath.sol";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @title Ensuro ERC20 EToken - interest-bearing token
|
|
14
|
+
* @dev Implementation of the interest/earnings bearing token for the Ensuro protocol.
|
|
15
|
+
* The _scaleFactor scales the balances stored in _balances. _scaleFactor grows continuoulsly at
|
|
16
|
+
* _tokenInterestRate.
|
|
17
|
+
* Every operation that changes the utilization rate (_scr/totalSupply) or the _scrInterestRate, updates
|
|
18
|
+
* first the _scaleFactor accumulating the interest accrued since _lastScaleUpdate.
|
|
19
|
+
* @custom:security-contact security@ensuro.co
|
|
20
|
+
* @author Ensuro
|
|
21
|
+
*/
|
|
22
|
+
contract EToken is PolicyPoolComponent, IERC20Metadata, IEToken {
|
|
23
|
+
uint256 public constant MIN_SCALE = 1e17; // 0.0000000001 == 1e-10 in ray
|
|
24
|
+
|
|
25
|
+
using WadRayMath for uint256;
|
|
26
|
+
|
|
27
|
+
uint256 internal constant SECONDS_PER_YEAR = 365 days;
|
|
28
|
+
|
|
29
|
+
// Attributes taken from ERC20
|
|
30
|
+
mapping(address => uint256) private _balances;
|
|
31
|
+
mapping(address => mapping(address => uint256)) private _allowances;
|
|
32
|
+
uint256 private _totalSupply; // non-scaled totalSupply
|
|
33
|
+
|
|
34
|
+
string private _name;
|
|
35
|
+
string private _symbol;
|
|
36
|
+
|
|
37
|
+
uint40 internal _expirationPeriod; // in seconds, the maximum duration of policies this eToken can back up
|
|
38
|
+
uint256 internal _scaleFactor; // in Ray
|
|
39
|
+
uint40 internal _lastScaleUpdate;
|
|
40
|
+
|
|
41
|
+
uint256 internal _scr; // in Wad - Capital locked as Solvency Capital Requirement of backed up policies
|
|
42
|
+
uint256 internal _scrInterestRate; // in Ray - Interest rate received in exchange of solvency capital
|
|
43
|
+
uint256 internal _tokenInterestRate; // in Ray - Overall interest rate of the token
|
|
44
|
+
uint256 internal _liquidityRequirement; // in Ray - Liquidity requirement to lock more than SCR
|
|
45
|
+
uint256 internal _maxUtilizationRate; // in Ray - Maximum SCR/totalSupply rate for backup up new policies
|
|
46
|
+
|
|
47
|
+
uint256 internal _poolLoan; // in Wad - Capital that was used to pay defaults of the premium pool. Took as a loan.
|
|
48
|
+
uint256 internal _poolLoanInterestRate; // in Ray
|
|
49
|
+
uint256 internal _poolLoanScale; // in Ray
|
|
50
|
+
uint40 internal _poolLoanLastUpdate;
|
|
51
|
+
|
|
52
|
+
bool internal _acceptAllRMs; // By defaults, accepts (backs up) any RiskModule;
|
|
53
|
+
// Exceptions to the accept all or accept none policy defined before
|
|
54
|
+
mapping(address => bool) internal _acceptExceptions;
|
|
55
|
+
|
|
56
|
+
event PoolLoan(uint256 value);
|
|
57
|
+
event PoolLoanRepaid(uint256 value);
|
|
58
|
+
|
|
59
|
+
modifier onlyAssetManager() {
|
|
60
|
+
require(
|
|
61
|
+
_msgSender() == address(_policyPool.config().assetManager()),
|
|
62
|
+
"The caller must be the PolicyPool's AssetManager"
|
|
63
|
+
);
|
|
64
|
+
_;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
modifier validateParamsAfterChange() {
|
|
68
|
+
_;
|
|
69
|
+
_validateParameters();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
73
|
+
// solhint-disable-next-line no-empty-blocks
|
|
74
|
+
constructor(IPolicyPool policyPool_) PolicyPoolComponent(policyPool_) {}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @dev Initializes the eToken
|
|
78
|
+
* @param expirationPeriod_ Maximum expirationPeriod (from block.timestamp) of policies to be accepted
|
|
79
|
+
* @param liquidityRequirement_ Liquidity requirement to allow withdrawal (in Ray - default=1 Ray)
|
|
80
|
+
* @param maxUtilizationRate_ Max utilization rate (scr/totalSupply) (in Ray - default=1 Ray)
|
|
81
|
+
* @param poolLoanInterestRate_ Rate of loans givencrto the policy pool (in Ray)
|
|
82
|
+
* @param name_ Name of the eToken
|
|
83
|
+
* @param symbol_ Symbol of the eToken
|
|
84
|
+
*/
|
|
85
|
+
function initialize(
|
|
86
|
+
string memory name_,
|
|
87
|
+
string memory symbol_,
|
|
88
|
+
uint40 expirationPeriod_,
|
|
89
|
+
uint256 liquidityRequirement_,
|
|
90
|
+
uint256 maxUtilizationRate_,
|
|
91
|
+
uint256 poolLoanInterestRate_
|
|
92
|
+
) public initializer {
|
|
93
|
+
__PolicyPoolComponent_init();
|
|
94
|
+
__EToken_init_unchained(
|
|
95
|
+
name_,
|
|
96
|
+
symbol_,
|
|
97
|
+
expirationPeriod_,
|
|
98
|
+
liquidityRequirement_,
|
|
99
|
+
maxUtilizationRate_,
|
|
100
|
+
poolLoanInterestRate_
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
105
|
+
function __EToken_init_unchained(
|
|
106
|
+
string memory name_,
|
|
107
|
+
string memory symbol_,
|
|
108
|
+
uint40 expirationPeriod_,
|
|
109
|
+
uint256 liquidityRequirement_,
|
|
110
|
+
uint256 maxUtilizationRate_,
|
|
111
|
+
uint256 poolLoanInterestRate_
|
|
112
|
+
) internal initializer {
|
|
113
|
+
_name = name_;
|
|
114
|
+
_symbol = symbol_;
|
|
115
|
+
_expirationPeriod = expirationPeriod_;
|
|
116
|
+
_scaleFactor = WadRayMath.ray();
|
|
117
|
+
_lastScaleUpdate = uint40(block.timestamp);
|
|
118
|
+
_scr = 0;
|
|
119
|
+
_scrInterestRate = 0;
|
|
120
|
+
_tokenInterestRate = 0;
|
|
121
|
+
_liquidityRequirement = liquidityRequirement_;
|
|
122
|
+
_maxUtilizationRate = maxUtilizationRate_;
|
|
123
|
+
_acceptAllRMs = true;
|
|
124
|
+
|
|
125
|
+
_poolLoan = 0;
|
|
126
|
+
_poolLoanInterestRate = poolLoanInterestRate_;
|
|
127
|
+
_poolLoanScale = WadRayMath.ray();
|
|
128
|
+
_poolLoanLastUpdate = uint40(block.timestamp);
|
|
129
|
+
_validateParameters();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// runs validation on EToken parameters
|
|
133
|
+
function _validateParameters() internal view {
|
|
134
|
+
require(
|
|
135
|
+
_liquidityRequirement >= 8e26 && _liquidityRequirement <= 13e26,
|
|
136
|
+
"Validation: liquidityRequirement must be [0.8, 1.3]"
|
|
137
|
+
);
|
|
138
|
+
require(
|
|
139
|
+
_maxUtilizationRate >= 5e26 && _maxUtilizationRate <= WadRayMath.RAY,
|
|
140
|
+
"Validation: maxUtilizationRate must be [0.5, 1]"
|
|
141
|
+
);
|
|
142
|
+
require(_poolLoanInterestRate <= 5e26, "Validation: poolLoanInterestRate must be <= 50%");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/*** BEGIN ERC20 methods - mainly copied from OpenZeppelin but changes in events and scaledAmount */
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* @dev Returns the name of the token.
|
|
149
|
+
*/
|
|
150
|
+
function name() public view virtual override returns (string memory) {
|
|
151
|
+
return _name;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @dev Returns the symbol of the token, usually a shorter version of the
|
|
156
|
+
* name.
|
|
157
|
+
*/
|
|
158
|
+
function symbol() public view virtual override returns (string memory) {
|
|
159
|
+
return _symbol;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @dev Returns the number of decimals used to get its user representation.
|
|
164
|
+
* For example, if `decimals` equals `2`, a balance of `505` tokens should
|
|
165
|
+
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
|
|
166
|
+
*
|
|
167
|
+
* Tokens usually opt for a value of 18, imitating the relationship between
|
|
168
|
+
* Ether and Wei. This is the value {ERC20} uses, unless this function is
|
|
169
|
+
* overloaded;
|
|
170
|
+
*
|
|
171
|
+
* NOTE: This information is only used for _display_ purposes: it in
|
|
172
|
+
* no way affects any of the arithmetic of the contract, including
|
|
173
|
+
* {IERC20-balanceOf} and {IERC20-transfer}.
|
|
174
|
+
*/
|
|
175
|
+
function decimals() public view virtual override returns (uint8) {
|
|
176
|
+
return _policyPool.currency().decimals();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @dev See {IERC20-totalSupply}.
|
|
181
|
+
*/
|
|
182
|
+
function totalSupply() public view virtual override returns (uint256) {
|
|
183
|
+
return _totalSupply.wadToRay().rayMul(_calculateCurrentScale()).rayToWad();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @dev See {IERC20-balanceOf}.
|
|
188
|
+
*/
|
|
189
|
+
function balanceOf(address account) public view virtual override returns (uint256) {
|
|
190
|
+
uint256 principalBalance = _balances[account];
|
|
191
|
+
if (principalBalance == 0) return 0;
|
|
192
|
+
return principalBalance.wadToRay().rayMul(_calculateCurrentScale()).rayToWad();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @dev See {IERC20-transfer}.
|
|
197
|
+
*
|
|
198
|
+
* Requirements:
|
|
199
|
+
*
|
|
200
|
+
* - `recipient` cannot be the zero address.
|
|
201
|
+
* - the caller must have a balance of at least `amount`.
|
|
202
|
+
*/
|
|
203
|
+
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
|
|
204
|
+
_transfer(_msgSender(), recipient, amount);
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @dev See {IERC20-allowance}.
|
|
210
|
+
*/
|
|
211
|
+
function allowance(address owner, address spender)
|
|
212
|
+
public
|
|
213
|
+
view
|
|
214
|
+
virtual
|
|
215
|
+
override
|
|
216
|
+
returns (uint256)
|
|
217
|
+
{
|
|
218
|
+
return _allowances[owner][spender];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @dev See {IERC20-approve}.
|
|
223
|
+
*
|
|
224
|
+
* Requirements:
|
|
225
|
+
*
|
|
226
|
+
* - `spender` cannot be the zero address.
|
|
227
|
+
*/
|
|
228
|
+
function approve(address spender, uint256 amount) public virtual override returns (bool) {
|
|
229
|
+
_approve(_msgSender(), spender, amount);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @dev See {IERC20-transferFrom}.
|
|
235
|
+
*
|
|
236
|
+
* Emits an {Approval} event indicating the updated allowance. This is not
|
|
237
|
+
* required by the EIP. See the note at the beginning of {ERC20}.
|
|
238
|
+
*
|
|
239
|
+
* Requirements:
|
|
240
|
+
*
|
|
241
|
+
* - `sender` and `recipient` cannot be the zero address.
|
|
242
|
+
* - `sender` must have a balance of at least `amount`.
|
|
243
|
+
* - the caller must have allowance for ``sender``'s tokens of at least
|
|
244
|
+
* `amount`.
|
|
245
|
+
*/
|
|
246
|
+
function transferFrom(
|
|
247
|
+
address sender,
|
|
248
|
+
address recipient,
|
|
249
|
+
uint256 amount
|
|
250
|
+
) public virtual override returns (bool) {
|
|
251
|
+
_transfer(sender, recipient, amount);
|
|
252
|
+
|
|
253
|
+
uint256 currentAllowance = _allowances[sender][_msgSender()];
|
|
254
|
+
require(currentAllowance >= amount, "EToken: transfer amount exceeds allowance");
|
|
255
|
+
_approve(sender, _msgSender(), currentAllowance - amount);
|
|
256
|
+
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* @dev Atomically increases the allowance granted to `spender` by the caller.
|
|
262
|
+
*
|
|
263
|
+
* This is an alternative to {approve} that can be used as a mitigation for
|
|
264
|
+
* problems described in {IERC20-approve}.
|
|
265
|
+
*
|
|
266
|
+
* Emits an {Approval} event indicating the updated allowance.
|
|
267
|
+
*
|
|
268
|
+
* Requirements:
|
|
269
|
+
*
|
|
270
|
+
* - `spender` cannot be the zero address.
|
|
271
|
+
*/
|
|
272
|
+
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
|
|
273
|
+
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @dev Atomically decreases the allowance granted to `spender` by the caller.
|
|
279
|
+
*
|
|
280
|
+
* This is an alternative to {approve} that can be used as a mitigation for
|
|
281
|
+
* problems described in {IERC20-approve}.
|
|
282
|
+
*
|
|
283
|
+
* Emits an {Approval} event indicating the updated allowance.
|
|
284
|
+
*
|
|
285
|
+
* Requirements:
|
|
286
|
+
*
|
|
287
|
+
* - `spender` cannot be the zero address.
|
|
288
|
+
* - `spender` must have allowance for the caller of at least
|
|
289
|
+
* `subtractedValue`.
|
|
290
|
+
*/
|
|
291
|
+
function decreaseAllowance(address spender, uint256 subtractedValue)
|
|
292
|
+
public
|
|
293
|
+
virtual
|
|
294
|
+
returns (bool)
|
|
295
|
+
{
|
|
296
|
+
uint256 currentAllowance = _allowances[_msgSender()][spender];
|
|
297
|
+
require(currentAllowance >= subtractedValue, "EToken: decreased allowance below zero");
|
|
298
|
+
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
|
|
299
|
+
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function _scaleAmount(uint256 amount) internal view returns (uint256) {
|
|
304
|
+
return amount.wadToRay().rayDiv(_calculateCurrentScale()).rayToWad();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @dev Moves tokens `amount` from `sender` to `recipient`.
|
|
309
|
+
*
|
|
310
|
+
* This is internal function is equivalent to {transfer}, and can be used to
|
|
311
|
+
* e.g. implement automatic token fees, slashing mechanisms, etc.
|
|
312
|
+
*
|
|
313
|
+
* Emits a {Transfer} event.
|
|
314
|
+
*
|
|
315
|
+
* Requirements:
|
|
316
|
+
*
|
|
317
|
+
* - `sender` cannot be the zero address.
|
|
318
|
+
* - `recipient` cannot be the zero address.
|
|
319
|
+
* - `sender` must have a balance of at least `amount`.
|
|
320
|
+
*/
|
|
321
|
+
function _transfer(
|
|
322
|
+
address sender,
|
|
323
|
+
address recipient,
|
|
324
|
+
uint256 amount
|
|
325
|
+
) internal virtual {
|
|
326
|
+
require(sender != address(0), "EToken: transfer from the zero address");
|
|
327
|
+
require(recipient != address(0), "EToken: transfer to the zero address");
|
|
328
|
+
|
|
329
|
+
_beforeTokenTransfer(sender, recipient, amount);
|
|
330
|
+
uint256 scaledAmount = _scaleAmount(amount);
|
|
331
|
+
|
|
332
|
+
uint256 senderBalance = _balances[sender];
|
|
333
|
+
require(senderBalance >= scaledAmount, "EToken: transfer amount exceeds balance");
|
|
334
|
+
_balances[sender] = senderBalance - scaledAmount;
|
|
335
|
+
_balances[recipient] += scaledAmount;
|
|
336
|
+
|
|
337
|
+
emit Transfer(sender, recipient, amount);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
|
|
341
|
+
* the total supply.
|
|
342
|
+
*
|
|
343
|
+
* Emits a {Transfer} event with `from` set to the zero address.
|
|
344
|
+
*
|
|
345
|
+
* Requirements:
|
|
346
|
+
*
|
|
347
|
+
* - `to` cannot be the zero address.
|
|
348
|
+
*/
|
|
349
|
+
function _mint(address account, uint256 amount) internal virtual {
|
|
350
|
+
require(account != address(0), "EToken: mint to the zero address");
|
|
351
|
+
|
|
352
|
+
_beforeTokenTransfer(address(0), account, amount);
|
|
353
|
+
uint256 scaledAmount = _scaleAmount(amount);
|
|
354
|
+
|
|
355
|
+
_totalSupply += scaledAmount;
|
|
356
|
+
_balances[account] += scaledAmount;
|
|
357
|
+
emit Transfer(address(0), account, amount);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* @dev Destroys `amount` tokens from `account`, reducing the
|
|
362
|
+
* total supply.
|
|
363
|
+
*
|
|
364
|
+
* Emits a {Transfer} event with `to` set to the zero address.
|
|
365
|
+
*
|
|
366
|
+
* Requirements:
|
|
367
|
+
*
|
|
368
|
+
* - `account` cannot be the zero address.
|
|
369
|
+
* - `account` must have at least `amount` tokens.
|
|
370
|
+
*/
|
|
371
|
+
function _burn(address account, uint256 amount) internal virtual {
|
|
372
|
+
require(account != address(0), "EToken: burn from the zero address");
|
|
373
|
+
_beforeTokenTransfer(account, address(0), amount);
|
|
374
|
+
|
|
375
|
+
uint256 scaledAmount = _scaleAmount(amount);
|
|
376
|
+
uint256 accountBalance = _balances[account];
|
|
377
|
+
require(accountBalance >= scaledAmount, "EToken: burn amount exceeds balance");
|
|
378
|
+
_balances[account] = accountBalance - scaledAmount;
|
|
379
|
+
_totalSupply -= scaledAmount;
|
|
380
|
+
|
|
381
|
+
emit Transfer(account, address(0), amount);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
|
|
386
|
+
*
|
|
387
|
+
* This internal function is equivalent to `approve`, and can be used to
|
|
388
|
+
* e.g. set automatic allowances for certain subsystems, etc.
|
|
389
|
+
*
|
|
390
|
+
* Emits an {Approval} event.
|
|
391
|
+
*
|
|
392
|
+
* Requirements:
|
|
393
|
+
*
|
|
394
|
+
* - `owner` cannot be the zero address.
|
|
395
|
+
* - `spender` cannot be the zero address.
|
|
396
|
+
*/
|
|
397
|
+
function _approve(
|
|
398
|
+
address owner,
|
|
399
|
+
address spender,
|
|
400
|
+
uint256 amount
|
|
401
|
+
) internal virtual {
|
|
402
|
+
require(owner != address(0), "EToken: approve from the zero address");
|
|
403
|
+
require(spender != address(0), "EToken: approve to the zero address");
|
|
404
|
+
|
|
405
|
+
_allowances[owner][spender] = amount;
|
|
406
|
+
emit Approval(owner, spender, amount);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* @dev Hook that is called before any transfer of tokens. This includes
|
|
411
|
+
* minting and burning.
|
|
412
|
+
*
|
|
413
|
+
* Calling conditions:
|
|
414
|
+
*
|
|
415
|
+
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
|
|
416
|
+
* will be to transferred to `to`.
|
|
417
|
+
* - when `from` is zero, `amount` tokens will be minted for `to`.
|
|
418
|
+
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
|
|
419
|
+
* - `from` and `to` are never both zero.
|
|
420
|
+
*
|
|
421
|
+
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
|
|
422
|
+
*/
|
|
423
|
+
function _beforeTokenTransfer(
|
|
424
|
+
address from,
|
|
425
|
+
address to,
|
|
426
|
+
uint256 amount
|
|
427
|
+
) internal virtual {
|
|
428
|
+
require(
|
|
429
|
+
from == address(0) ||
|
|
430
|
+
to == address(0) ||
|
|
431
|
+
address(policyPool().config().lpWhitelist()) == address(0) ||
|
|
432
|
+
policyPool().config().lpWhitelist().acceptsTransfer(this, from, to, amount),
|
|
433
|
+
"Transfer not allowed - Liquidity Provider not whitelisted"
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/*** END ERC20 methods - mainly copied from OpenZeppelin but changes in events and scaledAmount */
|
|
438
|
+
|
|
439
|
+
function _updateCurrentScale() internal {
|
|
440
|
+
if (uint40(block.timestamp) == _lastScaleUpdate) return;
|
|
441
|
+
_scaleFactor = _calculateCurrentScale();
|
|
442
|
+
require(_scaleFactor >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
443
|
+
_lastScaleUpdate = uint40(block.timestamp);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function _updateTokenInterestRate() internal {
|
|
447
|
+
uint256 totalSupply_ = this.totalSupply().wadToRay();
|
|
448
|
+
if (totalSupply_ == 0) _tokenInterestRate = 0;
|
|
449
|
+
else _tokenInterestRate = _scrInterestRate.rayMul(_scr.wadToRay()).rayDiv(totalSupply_);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function _calculateCurrentScale() internal view returns (uint256) {
|
|
453
|
+
if (uint40(block.timestamp) <= _lastScaleUpdate) return _scaleFactor;
|
|
454
|
+
uint256 timeDifference = block.timestamp - _lastScaleUpdate;
|
|
455
|
+
return
|
|
456
|
+
_scaleFactor.rayMul(
|
|
457
|
+
((_tokenInterestRate * timeDifference) / SECONDS_PER_YEAR) + WadRayMath.ray()
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function getCurrentScale(bool updated) public view returns (uint256) {
|
|
462
|
+
if (updated) return _calculateCurrentScale();
|
|
463
|
+
else return _scaleFactor;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function ocean() public view virtual override returns (uint256) {
|
|
467
|
+
uint256 totalSupply_ = this.totalSupply();
|
|
468
|
+
if (totalSupply_ > _scr) return totalSupply_ - _scr;
|
|
469
|
+
else return 0;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function oceanForNewScr() public view virtual override returns (uint256) {
|
|
473
|
+
uint256 totalSupply_ = this.totalSupply();
|
|
474
|
+
if (totalSupply_ > _scr) return (totalSupply_ - _scr).wadMul(_maxUtilizationRate.rayToWad());
|
|
475
|
+
else return 0;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function scr() public view virtual override returns (uint256) {
|
|
479
|
+
return _scr;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function scrInterestRate() public view returns (uint256) {
|
|
483
|
+
return _scrInterestRate;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function tokenInterestRate() public view returns (uint256) {
|
|
487
|
+
return _tokenInterestRate;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function liquidityRequirement() public view returns (uint256) {
|
|
491
|
+
return _liquidityRequirement;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function maxUtilizationRate() public view returns (uint256) {
|
|
495
|
+
return _maxUtilizationRate;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function expirationPeriod() public view returns (uint40) {
|
|
499
|
+
return _expirationPeriod;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function utilizationRate() public view returns (uint256) {
|
|
503
|
+
return _scr.wadDiv(this.totalSupply()).wadToRay();
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function lockScr(uint256 policyInterestRate, uint256 scrAmount) external override onlyPolicyPool {
|
|
507
|
+
require(scrAmount <= this.ocean(), "Not enought OCEAN to cover the SCR");
|
|
508
|
+
_updateCurrentScale();
|
|
509
|
+
if (_scr == 0) {
|
|
510
|
+
_scr = scrAmount;
|
|
511
|
+
_scrInterestRate = policyInterestRate;
|
|
512
|
+
} else {
|
|
513
|
+
uint256 origScr = _scr.wadToRay();
|
|
514
|
+
_scr += scrAmount;
|
|
515
|
+
_scrInterestRate = (_scrInterestRate.rayMul(origScr) +
|
|
516
|
+
policyInterestRate.rayMul(scrAmount.wadToRay())).rayDiv(_scr.wadToRay());
|
|
517
|
+
}
|
|
518
|
+
emit SCRLocked(policyInterestRate, scrAmount);
|
|
519
|
+
_updateTokenInterestRate();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function unlockScr(uint256 policyInterestRate, uint256 scrAmount)
|
|
523
|
+
external
|
|
524
|
+
override
|
|
525
|
+
onlyPolicyPool
|
|
526
|
+
{
|
|
527
|
+
require(scrAmount <= _scr, "Current SCR less than the amount you want to unlock");
|
|
528
|
+
_updateCurrentScale();
|
|
529
|
+
|
|
530
|
+
if (_scr == scrAmount) {
|
|
531
|
+
_scr = 0;
|
|
532
|
+
_scrInterestRate = 0;
|
|
533
|
+
} else {
|
|
534
|
+
uint256 origScr = _scr.wadToRay();
|
|
535
|
+
_scr -= scrAmount;
|
|
536
|
+
_scrInterestRate = (_scrInterestRate.rayMul(origScr) -
|
|
537
|
+
policyInterestRate.rayMul(scrAmount.wadToRay())).rayDiv(_scr.wadToRay());
|
|
538
|
+
}
|
|
539
|
+
emit SCRUnlocked(policyInterestRate, scrAmount);
|
|
540
|
+
_updateTokenInterestRate();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function _discreteChange(uint256 amount, bool positive) internal {
|
|
544
|
+
uint256 newTotalSupply = positive ? (totalSupply() + amount) : (totalSupply() - amount);
|
|
545
|
+
_scaleFactor = newTotalSupply.wadToRay().rayDiv(_totalSupply.wadToRay());
|
|
546
|
+
require(_scaleFactor >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
547
|
+
_updateTokenInterestRate();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function discreteEarning(uint256 amount, bool positive) external override onlyPolicyPool {
|
|
551
|
+
_updateCurrentScale();
|
|
552
|
+
_discreteChange(amount, positive);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function assetEarnings(uint256 amount, bool positive) external override onlyAssetManager {
|
|
556
|
+
_updateCurrentScale();
|
|
557
|
+
_discreteChange(amount, positive);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function deposit(address provider, uint256 amount)
|
|
561
|
+
external
|
|
562
|
+
override
|
|
563
|
+
onlyPolicyPool
|
|
564
|
+
whenNotPaused
|
|
565
|
+
returns (uint256)
|
|
566
|
+
{
|
|
567
|
+
require(
|
|
568
|
+
address(policyPool().config().lpWhitelist()) == address(0) ||
|
|
569
|
+
policyPool().config().lpWhitelist().acceptsDeposit(this, provider, amount),
|
|
570
|
+
"Liquidity Provider not whitelisted"
|
|
571
|
+
);
|
|
572
|
+
_updateCurrentScale();
|
|
573
|
+
_mint(provider, amount);
|
|
574
|
+
_updateTokenInterestRate();
|
|
575
|
+
return balanceOf(provider);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function totalWithdrawable() public view virtual override returns (uint256) {
|
|
579
|
+
uint256 locked = _scr
|
|
580
|
+
.wadToRay()
|
|
581
|
+
.rayMul(WadRayMath.ray() + _scrInterestRate)
|
|
582
|
+
.rayMul(_liquidityRequirement)
|
|
583
|
+
.rayToWad();
|
|
584
|
+
uint256 totalSupply_ = totalSupply();
|
|
585
|
+
if (totalSupply_ >= locked) return totalSupply_ - locked;
|
|
586
|
+
else return 0;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function withdraw(address provider, uint256 amount)
|
|
590
|
+
external
|
|
591
|
+
override
|
|
592
|
+
onlyPolicyPool
|
|
593
|
+
whenNotPaused
|
|
594
|
+
returns (uint256)
|
|
595
|
+
{
|
|
596
|
+
_updateCurrentScale();
|
|
597
|
+
uint256 balance = balanceOf(provider);
|
|
598
|
+
if (balance == 0) return 0;
|
|
599
|
+
if (amount > balance) amount = balance;
|
|
600
|
+
uint256 withdrawable = totalWithdrawable();
|
|
601
|
+
if (amount > withdrawable) amount = withdrawable;
|
|
602
|
+
if (amount == 0) return 0;
|
|
603
|
+
_burn(provider, amount);
|
|
604
|
+
_updateTokenInterestRate();
|
|
605
|
+
return amount;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function accepts(address riskModule, uint40 policyExpiration)
|
|
609
|
+
public
|
|
610
|
+
view
|
|
611
|
+
virtual
|
|
612
|
+
override
|
|
613
|
+
returns (bool)
|
|
614
|
+
{
|
|
615
|
+
if (paused()) return false;
|
|
616
|
+
if (_acceptAllRMs == _acceptExceptions[riskModule]) {
|
|
617
|
+
// all accepted except this one or all rejected and this one is not an exception
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
return policyExpiration < (uint40(block.timestamp) + _expirationPeriod);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function _updatePoolLoanScale() internal {
|
|
624
|
+
if (uint40(block.timestamp) == _poolLoanLastUpdate) return;
|
|
625
|
+
_poolLoanScale = _getPoolLoanScale();
|
|
626
|
+
_poolLoanLastUpdate = uint40(block.timestamp);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function _maxNegativeAdjustment() internal view returns (uint256) {
|
|
630
|
+
uint256 ts = totalSupply();
|
|
631
|
+
uint256 minTs = _totalSupply.wadToRay().rayMul(MIN_SCALE * 10).rayToWad();
|
|
632
|
+
if (ts > minTs) return ts - minTs;
|
|
633
|
+
else return 0;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function lendToPool(uint256 amount, bool fromOcean)
|
|
637
|
+
external
|
|
638
|
+
override
|
|
639
|
+
onlyPolicyPool
|
|
640
|
+
returns (uint256)
|
|
641
|
+
{
|
|
642
|
+
if (fromOcean && amount > ocean()) amount = ocean();
|
|
643
|
+
if (!fromOcean && amount > totalSupply()) amount = totalSupply();
|
|
644
|
+
if (amount > _maxNegativeAdjustment()) {
|
|
645
|
+
amount = _maxNegativeAdjustment();
|
|
646
|
+
if (amount == 0) return amount;
|
|
647
|
+
}
|
|
648
|
+
if (_poolLoan == 0) {
|
|
649
|
+
_poolLoan = amount;
|
|
650
|
+
_poolLoanScale = WadRayMath.ray();
|
|
651
|
+
_poolLoanLastUpdate = uint40(block.timestamp);
|
|
652
|
+
} else {
|
|
653
|
+
_updatePoolLoanScale();
|
|
654
|
+
_poolLoan += amount.wadToRay().rayDiv(_poolLoanScale).rayToWad();
|
|
655
|
+
}
|
|
656
|
+
_updateCurrentScale(); // shouldn't do anything because lendToPool is after unlock_scr but doing anyway
|
|
657
|
+
_discreteChange(amount, false);
|
|
658
|
+
emit PoolLoan(amount);
|
|
659
|
+
if (!fromOcean && _scr > totalSupply()) {
|
|
660
|
+
// Notify insolvency_hook - Insuficient solvency
|
|
661
|
+
IInsolvencyHook hook = _policyPool.config().insolvencyHook();
|
|
662
|
+
if (address(hook) != address(0)) {
|
|
663
|
+
hook.insolventEToken(this, _scr - totalSupply());
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return amount;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function repayPoolLoan(uint256 amount) external override onlyPolicyPool {
|
|
670
|
+
_updatePoolLoanScale();
|
|
671
|
+
_poolLoan = (getPoolLoan() - amount).wadToRay().rayDiv(_poolLoanScale).rayToWad();
|
|
672
|
+
_updateCurrentScale(); // shouldn't do anything because lendToPool is after unlock_scr but doing anyway
|
|
673
|
+
_discreteChange(amount, true);
|
|
674
|
+
emit PoolLoanRepaid(amount);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function _getPoolLoanScale() internal view returns (uint256) {
|
|
678
|
+
if (uint40(block.timestamp) <= _poolLoanLastUpdate) return _poolLoanScale;
|
|
679
|
+
uint256 timeDifference = block.timestamp - _poolLoanLastUpdate;
|
|
680
|
+
return
|
|
681
|
+
_poolLoanScale.rayMul(
|
|
682
|
+
((_poolLoanInterestRate * timeDifference) / SECONDS_PER_YEAR) + WadRayMath.ray()
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function getPoolLoan() public view virtual override returns (uint256) {
|
|
687
|
+
if (_poolLoan == 0) return 0;
|
|
688
|
+
return _poolLoan.wadToRay().rayMul(_getPoolLoanScale()).rayToWad();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function poolLoanInterestRate() public view returns (uint256) {
|
|
692
|
+
return _poolLoanInterestRate;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function acceptAllRMs() public view returns (bool) {
|
|
696
|
+
return _acceptAllRMs;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
function isAcceptException(address riskModule) public view returns (bool) {
|
|
700
|
+
return _acceptExceptions[riskModule];
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function setPoolLoanInterestRate(uint256 newRate)
|
|
704
|
+
external
|
|
705
|
+
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
706
|
+
validateParamsAfterChange
|
|
707
|
+
{
|
|
708
|
+
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
709
|
+
require(
|
|
710
|
+
!tweak || _isTweakRay(_poolLoanInterestRate, newRate, 3e26),
|
|
711
|
+
"Tweak exceeded: poolLoanInterestRate tweaks only up to 30%"
|
|
712
|
+
);
|
|
713
|
+
_updatePoolLoanScale();
|
|
714
|
+
_poolLoanInterestRate = newRate;
|
|
715
|
+
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setPoolLoanInterestRate, newRate, tweak);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
function setLiquidityRequirement(uint256 newRate)
|
|
719
|
+
external
|
|
720
|
+
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
721
|
+
validateParamsAfterChange
|
|
722
|
+
{
|
|
723
|
+
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
724
|
+
require(
|
|
725
|
+
!tweak || _isTweakRay(_liquidityRequirement, newRate, 1e26),
|
|
726
|
+
"Tweak exceeded: liquidityRequirement tweaks only up to 10%"
|
|
727
|
+
);
|
|
728
|
+
_liquidityRequirement = newRate;
|
|
729
|
+
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setLiquidityRequirement, newRate, tweak);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
function setMaxUtilizationRate(uint256 newRate)
|
|
733
|
+
external
|
|
734
|
+
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
735
|
+
validateParamsAfterChange
|
|
736
|
+
{
|
|
737
|
+
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
738
|
+
require(
|
|
739
|
+
!tweak || _isTweakRay(_maxUtilizationRate, newRate, 3e26),
|
|
740
|
+
"Tweak exceeded: maxUtilizationRate tweaks only up to 30%"
|
|
741
|
+
);
|
|
742
|
+
_maxUtilizationRate = newRate;
|
|
743
|
+
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setMaxUtilizationRate, newRate, tweak);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function setAcceptAllRMs(bool acceptAllRMs_)
|
|
747
|
+
external
|
|
748
|
+
onlyPoolRole(LEVEL2_ROLE)
|
|
749
|
+
validateParamsAfterChange
|
|
750
|
+
{
|
|
751
|
+
_acceptAllRMs = acceptAllRMs_;
|
|
752
|
+
_parameterChanged(
|
|
753
|
+
IPolicyPoolConfig.GovernanceActions.setAcceptAllRMs,
|
|
754
|
+
acceptAllRMs_ ? 1 : 0,
|
|
755
|
+
false
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
function setAcceptException(address riskModule, bool isException)
|
|
760
|
+
external
|
|
761
|
+
onlyPoolRole(LEVEL2_ROLE)
|
|
762
|
+
validateParamsAfterChange
|
|
763
|
+
{
|
|
764
|
+
_acceptExceptions[riskModule] = isException;
|
|
765
|
+
uint256 value = uint160(riskModule);
|
|
766
|
+
if (!isException) value |= (1 << 255); // if changed to NOT exception activate first bit
|
|
767
|
+
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setAcceptException, value, false);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function getInvestable() public view virtual override returns (uint256) {
|
|
771
|
+
return _scr + ocean() + getPoolLoan();
|
|
772
|
+
}
|
|
773
|
+
}
|