@ensuro/core 2.0.0-beta10 → 2.0.0-beta12
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 +13 -0
- package/build/contracts/AccessManager.sol/AccessManager.json +7 -2
- package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +21 -2
- package/build/contracts/EToken.sol/EToken.json +21 -2
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +21 -2
- package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +19 -0
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyPool.sol/PolicyPool.json +21 -2
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +19 -0
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +21 -2
- package/build/contracts/Reserve.sol/Reserve.json +19 -0
- package/build/contracts/RiskModule.sol/RiskModule.json +19 -0
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +152 -2
- package/build/contracts/TimeScaled.sol/TimeScaled.json +2 -2
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +137 -2
- package/build/contracts/dependencies/WadRayMath.sol/WadRayMath.json +2 -2
- package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +19 -0
- package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +19 -0
- package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +19 -0
- package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +2 -2
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
- package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +180 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +2 -2
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +21 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +21 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +21 -2
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
- package/contracts/AccessManager.sol +30 -1
- package/contracts/ERC4626AssetManager.sol +3 -0
- package/contracts/EToken.sol +89 -19
- package/contracts/LPManualWhitelist.sol +18 -2
- package/contracts/LiquidityThresholdAssetManager.sol +17 -2
- package/contracts/Policy.sol +4 -2
- package/contracts/PolicyPool.sol +72 -13
- package/contracts/PolicyPoolComponent.sol +29 -3
- package/contracts/PremiumsAccount.sol +68 -23
- package/contracts/Reserve.sol +19 -3
- package/contracts/RiskModule.sol +46 -13
- package/contracts/SignedQuoteRiskModule.sol +120 -48
- package/contracts/TrustfulRiskModule.sol +59 -3
- package/contracts/interfaces/IAssetManager.sol +8 -3
- package/contracts/interfaces/IPolicyPool.sol +15 -4
- package/contracts/interfaces/IPolicyPoolComponent.sol +2 -1
- package/contracts/mocks/InterfaceIdCalculator.sol +32 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +10 -0
- package/contracts/mocks/PolicyPoolMock.sol +4 -0
- package/js/deploy.js +704 -0
- package/js/test-utils.js +139 -37
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
|
|
|
3
3
|
|
|
4
4
|
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
5
5
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
6
|
+
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
6
7
|
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
7
8
|
import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
|
|
8
9
|
import {IAccessManager} from "./interfaces/IAccessManager.sol";
|
|
@@ -14,8 +15,8 @@ import {WadRayMath} from "./dependencies/WadRayMath.sol";
|
|
|
14
15
|
* @dev This is the base class of all the components of the protocol that are linked to the PolicyPool and created
|
|
15
16
|
* after it.
|
|
16
17
|
* Holds the reference to _policyPool as immutable, also provides access to common admin roles:
|
|
17
|
-
* - LEVEL1_ROLE: High impact changes like upgrades or other critical operations
|
|
18
|
-
* - LEVEL2_ROLE: Mid-impact changes like
|
|
18
|
+
* - LEVEL1_ROLE: High impact changes like upgrades, adding or removing components or other critical operations
|
|
19
|
+
* - LEVEL2_ROLE: Mid-impact changes like changing some parameters
|
|
19
20
|
* - LEVEL3_ROLE: Low-impact changes like changing some parameters up to given percentage (tweaks)
|
|
20
21
|
* - GUARDIAN_ROLE: For emergency operations oriented to protect the protocol in case of attacks or hacking.
|
|
21
22
|
*
|
|
@@ -79,11 +80,16 @@ abstract contract PolicyPoolComponent is
|
|
|
79
80
|
|
|
80
81
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
81
82
|
constructor(IPolicyPool policyPool_) {
|
|
83
|
+
require(
|
|
84
|
+
address(policyPool_) != address(0),
|
|
85
|
+
"PolicyPoolComponent: policyPool cannot be zero address"
|
|
86
|
+
);
|
|
87
|
+
_disableInitializers();
|
|
82
88
|
_policyPool = policyPool_;
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
// solhint-disable-next-line func-name-mixedcase
|
|
86
|
-
function __PolicyPoolComponent_init() internal
|
|
92
|
+
function __PolicyPoolComponent_init() internal onlyInitializing {
|
|
87
93
|
__UUPSUpgradeable_init();
|
|
88
94
|
__Pausable_init();
|
|
89
95
|
}
|
|
@@ -94,12 +100,25 @@ abstract contract PolicyPoolComponent is
|
|
|
94
100
|
override
|
|
95
101
|
onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
|
|
96
102
|
{
|
|
103
|
+
_upgradeValidations(newImpl);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function _upgradeValidations(address newImpl) internal view virtual {
|
|
97
107
|
require(
|
|
98
108
|
IPolicyPoolComponent(newImpl).policyPool() == _policyPool,
|
|
99
109
|
"Can't upgrade changing the PolicyPool!"
|
|
100
110
|
);
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
/**
|
|
114
|
+
* @dev See {IERC165-supportsInterface}.
|
|
115
|
+
*/
|
|
116
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
117
|
+
return
|
|
118
|
+
interfaceId == type(IERC165).interfaceId ||
|
|
119
|
+
interfaceId == type(IPolicyPoolComponent).interfaceId;
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
function pause() public onlyGlobalOrComponentRole(GUARDIAN_ROLE) {
|
|
104
123
|
_pause();
|
|
105
124
|
}
|
|
@@ -171,4 +190,11 @@ abstract contract PolicyPoolComponent is
|
|
|
171
190
|
}
|
|
172
191
|
}
|
|
173
192
|
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
196
|
+
* variables without shifting down storage in the inheritance chain.
|
|
197
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
198
|
+
*/
|
|
199
|
+
uint256[49] private __gap;
|
|
174
200
|
}
|
|
@@ -22,7 +22,7 @@ import {IAssetManager} from "./interfaces/IAssetManager.sol";
|
|
|
22
22
|
* (_activePurePremiums) and the surplus or deficit generated by the finalized policies (pure premiums collected -
|
|
23
23
|
* losses).
|
|
24
24
|
*
|
|
25
|
-
* Collaborates with a junior {EToken} and a senior {EToken} that act as lenders when the premiums aren't
|
|
25
|
+
* Collaborates with a junior {EToken} and a senior {EToken} that act as lenders when the premiums aren't enough to
|
|
26
26
|
* cover the losses.
|
|
27
27
|
*
|
|
28
28
|
* @custom:security-contact security@ensuro.co
|
|
@@ -35,6 +35,8 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
35
35
|
using SafeCast for uint256;
|
|
36
36
|
|
|
37
37
|
bytes32 public constant WITHDRAW_WON_PREMIUMS_ROLE = keccak256("WITHDRAW_WON_PREMIUMS_ROLE");
|
|
38
|
+
uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
|
|
39
|
+
uint16 internal constant HUNDRED_PERCENT = 1e4;
|
|
38
40
|
|
|
39
41
|
/**
|
|
40
42
|
* @dev The Junior eToken is the first {EToken} to which the PremiumsAccount will go for credit when it runs out of
|
|
@@ -106,29 +108,44 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
106
108
|
* @dev Initializes the PremiumsAccount (to be called by subclasses)
|
|
107
109
|
*/
|
|
108
110
|
// solhint-disable-next-line func-name-mixedcase
|
|
109
|
-
function __PremiumsAccount_init() internal
|
|
110
|
-
|
|
111
|
+
function __PremiumsAccount_init() internal onlyInitializing {
|
|
112
|
+
__Reserve_init();
|
|
111
113
|
__PremiumsAccount_init_unchained();
|
|
112
114
|
}
|
|
113
115
|
|
|
114
|
-
/**
|
|
115
|
-
* @dev In the initialization, besides settings the parameters, we approve the spending of funds by the eTokens
|
|
116
|
-
* so we don't need to do it on every repayment operation
|
|
117
|
-
*/
|
|
118
116
|
// solhint-disable-next-line func-name-mixedcase
|
|
119
|
-
function __PremiumsAccount_init_unchained() internal
|
|
117
|
+
function __PremiumsAccount_init_unchained() internal onlyInitializing {
|
|
120
118
|
/*
|
|
121
119
|
_activePurePremiums = 0;
|
|
122
120
|
*/
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
_params = PackedParams({deficitRatio: 1e4, assetManager: IAssetManager(address(0))});
|
|
121
|
+
_params = PackedParams({
|
|
122
|
+
deficitRatio: HUNDRED_PERCENT,
|
|
123
|
+
assetManager: IAssetManager(address(0))
|
|
124
|
+
});
|
|
129
125
|
_validateParameters();
|
|
130
126
|
}
|
|
131
127
|
|
|
128
|
+
function _upgradeValidations(address newImpl) internal view virtual override {
|
|
129
|
+
super._upgradeValidations(newImpl);
|
|
130
|
+
IPremiumsAccount newPA = IPremiumsAccount(newImpl);
|
|
131
|
+
require(
|
|
132
|
+
newPA.juniorEtk() == _juniorEtk || address(_juniorEtk) == address(0),
|
|
133
|
+
"Can't upgrade changing the Junior ETK unless to non-zero"
|
|
134
|
+
);
|
|
135
|
+
require(
|
|
136
|
+
newPA.seniorEtk() == _seniorEtk || address(_seniorEtk) == address(0),
|
|
137
|
+
"Can't upgrade changing the Senior ETK unless to non-zero"
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @dev See {IERC165-supportsInterface}.
|
|
143
|
+
*/
|
|
144
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
145
|
+
return
|
|
146
|
+
super.supportsInterface(interfaceId) || interfaceId == type(IPremiumsAccount).interfaceId;
|
|
147
|
+
}
|
|
148
|
+
|
|
132
149
|
function assetManager() public view override returns (IAssetManager) {
|
|
133
150
|
return _params.assetManager;
|
|
134
151
|
}
|
|
@@ -141,7 +158,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
141
158
|
* @dev This is called by the {Reserve} base class to record the earnings generated by the asset management.
|
|
142
159
|
*
|
|
143
160
|
* @param earningsOrLosses Indicates the amount earned since last time earnings where recorded.
|
|
144
|
-
* - If positive, repays the
|
|
161
|
+
* - If positive, repays the loans and accumulates the rest in the surplus.
|
|
145
162
|
* - If negative (losses) substracts it from surplus. It never can exceed _maxDeficit and doesn't takes
|
|
146
163
|
* loans to cover asset losses.
|
|
147
164
|
*/
|
|
@@ -158,7 +175,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
158
175
|
|
|
159
176
|
function _validateParameters() internal view override {
|
|
160
177
|
require(
|
|
161
|
-
_params.deficitRatio <=
|
|
178
|
+
_params.deficitRatio <= HUNDRED_PERCENT && _params.deficitRatio >= 0,
|
|
162
179
|
"Validation: deficitRatio must be <= 1"
|
|
163
180
|
);
|
|
164
181
|
}
|
|
@@ -227,7 +244,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
227
244
|
* @dev Returns the percentage of the active pure premiums that can be used to cover losses of finalized policies.
|
|
228
245
|
*/
|
|
229
246
|
function deficitRatio() public view returns (uint256) {
|
|
230
|
-
return uint256(_params.deficitRatio) *
|
|
247
|
+
return uint256(_params.deficitRatio) * FOUR_DECIMAL_TO_WAD; // 4 -> 18 decimals
|
|
231
248
|
}
|
|
232
249
|
|
|
233
250
|
/**
|
|
@@ -239,7 +256,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
239
256
|
* Events:
|
|
240
257
|
* - Emits GovernanceAction with action = setDeficitRatio or setDeficitRatioWithAdjustment if an adjustment was made.
|
|
241
258
|
*
|
|
242
|
-
* @param adjustment If true and the new ratio leaves `_surplus < -_maxDeficit()`,
|
|
259
|
+
* @param adjustment If true and the new ratio leaves `_surplus < -_maxDeficit()`, it adjusts the _surplus to the new
|
|
243
260
|
* `_maxDeficit()` and borrows the difference from the eTokens.
|
|
244
261
|
* If false and the new ratio leaves `_surplus < -_maxDeficit()`, the operation is reverted.
|
|
245
262
|
*/
|
|
@@ -247,9 +264,17 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
247
264
|
external
|
|
248
265
|
onlyComponentRole(LEVEL2_ROLE)
|
|
249
266
|
{
|
|
250
|
-
require(newRatio <= 1e18
|
|
267
|
+
require(newRatio <= 1e18, "Validation: deficitRatio must be <= 1");
|
|
268
|
+
|
|
269
|
+
uint16 truncatedRatio = (newRatio / FOUR_DECIMAL_TO_WAD).toUint16();
|
|
270
|
+
require(
|
|
271
|
+
uint256(truncatedRatio) * FOUR_DECIMAL_TO_WAD == newRatio,
|
|
272
|
+
"Validation: only up to 4 decimals allowed"
|
|
273
|
+
);
|
|
274
|
+
|
|
251
275
|
int256 maxDeficit = _maxDeficit(newRatio);
|
|
252
276
|
require(adjustment || _surplus >= maxDeficit, "Validation: surplus must be >= maxDeficit");
|
|
277
|
+
|
|
253
278
|
IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setDeficitRatio;
|
|
254
279
|
if (_surplus < maxDeficit) {
|
|
255
280
|
// Do the adjustment
|
|
@@ -258,12 +283,12 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
258
283
|
_borrowFromEtk(borrow, address(this), address(_juniorEtk) != address(0));
|
|
259
284
|
action = IAccessManager.GovernanceActions.setDeficitRatioWithAdjustment;
|
|
260
285
|
}
|
|
261
|
-
_params.deficitRatio =
|
|
286
|
+
_params.deficitRatio = truncatedRatio;
|
|
262
287
|
_parameterChanged(action, newRatio, false);
|
|
263
288
|
}
|
|
264
289
|
|
|
265
290
|
/**
|
|
266
|
-
* @dev Internal function called when money in the PremiumsAccount is not
|
|
291
|
+
* @dev Internal function called when money in the PremiumsAccount is not enough and we need to borrow from the
|
|
267
292
|
* eTokens.
|
|
268
293
|
*
|
|
269
294
|
* @param borrow The amount to borrow.
|
|
@@ -276,6 +301,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
276
301
|
address receiver,
|
|
277
302
|
bool jrEtk
|
|
278
303
|
) internal {
|
|
304
|
+
require(receiver != address(0), "PremiumsAccount: receiver cannot be the zero address");
|
|
279
305
|
uint256 left;
|
|
280
306
|
if (jrEtk) {
|
|
281
307
|
// Consume Junior Pool until exhausted
|
|
@@ -334,9 +360,9 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
334
360
|
* @param amount The amount to be transferred.
|
|
335
361
|
*/
|
|
336
362
|
function receiveGrant(uint256 amount) external {
|
|
337
|
-
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
338
363
|
_storePurePremiumWon(amount);
|
|
339
364
|
emit WonPremiumsInOut(true, amount);
|
|
365
|
+
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
340
366
|
}
|
|
341
367
|
|
|
342
368
|
/**
|
|
@@ -362,6 +388,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
362
388
|
onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
|
|
363
389
|
returns (uint256)
|
|
364
390
|
{
|
|
391
|
+
require(destination != address(0), "PremiumsAccount: destination cannot be the zero address");
|
|
365
392
|
if (_surplus <= 0) {
|
|
366
393
|
amount = 0;
|
|
367
394
|
} else {
|
|
@@ -445,10 +472,21 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
445
472
|
if (borrowedFromEtk == 0) return purePremiumWon;
|
|
446
473
|
uint256 repayAmount = Math.min(purePremiumWon, borrowedFromEtk);
|
|
447
474
|
|
|
448
|
-
// If not
|
|
475
|
+
// If not enough liquidity, it deinvests from the asset manager
|
|
449
476
|
if (currency().balanceOf(address(this)) < repayAmount) {
|
|
477
|
+
/**
|
|
478
|
+
* I send `repayAmount` because the IAssetManager expects the full amount that's needed, not the missing one.
|
|
479
|
+
* It uses the value of the full amount to optimize the deinvestment leaving more liquidity if possible to avoid
|
|
480
|
+
* future deinvestment. It will only fail if it can't refill `repayAmount - currency().balanceOf(address(this))`
|
|
481
|
+
*/
|
|
450
482
|
_refillWallet(repayAmount);
|
|
451
483
|
}
|
|
484
|
+
// Checks the allowance before repayment
|
|
485
|
+
if (currency().allowance(address(this), address(etk)) < repayAmount) {
|
|
486
|
+
// If I have to approve, I approve for all the pending debt (not just repayAmount), this way I avoid some
|
|
487
|
+
// future approvals.
|
|
488
|
+
currency().approve(address(etk), borrowedFromEtk);
|
|
489
|
+
}
|
|
452
490
|
etk.repayLoan(repayAmount, address(this));
|
|
453
491
|
return purePremiumWon - repayAmount;
|
|
454
492
|
}
|
|
@@ -477,4 +515,11 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
477
515
|
_storePurePremiumWon(purePremiumWon);
|
|
478
516
|
_unlockScr(policy);
|
|
479
517
|
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
521
|
+
* variables without shifting down storage in the inheritance chain.
|
|
522
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
523
|
+
*/
|
|
524
|
+
uint256[47] private __gap;
|
|
480
525
|
}
|
package/contracts/Reserve.sol
CHANGED
|
@@ -39,6 +39,14 @@ abstract contract Reserve is PolicyPoolComponent {
|
|
|
39
39
|
NEGLIGIBLE_AMOUNT = 10**(policyPool_.currency().decimals() / 2);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @dev Initializes the Reserve (to be called by subclasses)
|
|
44
|
+
*/
|
|
45
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
46
|
+
function __Reserve_init() internal onlyInitializing {
|
|
47
|
+
__PolicyPoolComponent_init();
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
/**
|
|
43
51
|
* @dev Refills the reserve's balance, deinvesting from the asset manager to be able to make a payment
|
|
44
52
|
*
|
|
@@ -62,12 +70,13 @@ abstract contract Reserve is PolicyPoolComponent {
|
|
|
62
70
|
|
|
63
71
|
/**
|
|
64
72
|
* @dev Internal function that transfers money to a destination. It might need to call `_refillWallet` to deinvest
|
|
65
|
-
* some money to have
|
|
73
|
+
* some money to have enough liquidity for the payment.
|
|
66
74
|
*
|
|
67
75
|
* @param destination The destination of the transfer.
|
|
68
76
|
* @param amount The amount to be transferred.
|
|
69
77
|
*/
|
|
70
78
|
function _transferTo(address destination, uint256 amount) internal {
|
|
79
|
+
require(destination != address(0), "Reserve: transfer to the zero address");
|
|
71
80
|
if (amount == 0) return;
|
|
72
81
|
uint256 balance = currency().balanceOf(address(this));
|
|
73
82
|
if (balance < amount) {
|
|
@@ -126,8 +135,8 @@ abstract contract Reserve is PolicyPoolComponent {
|
|
|
126
135
|
onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
|
|
127
136
|
{
|
|
128
137
|
require(
|
|
129
|
-
address(newAM) == address(0) ||
|
|
130
|
-
"
|
|
138
|
+
address(newAM) == address(0) || newAM.supportsInterface(type(IAssetManager).interfaceId),
|
|
139
|
+
"Reserve: asset manager doesn't implements the required interface"
|
|
131
140
|
);
|
|
132
141
|
address am = address(assetManager());
|
|
133
142
|
IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setAssetManager;
|
|
@@ -210,4 +219,11 @@ abstract contract Reserve is PolicyPoolComponent {
|
|
|
210
219
|
{
|
|
211
220
|
return address(assetManager()).functionDelegateCall(functionCall);
|
|
212
221
|
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
225
|
+
* variables without shifting down storage in the inheritance chain.
|
|
226
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
227
|
+
*/
|
|
228
|
+
uint256[50] private __gap;
|
|
213
229
|
}
|
package/contracts/RiskModule.sol
CHANGED
|
@@ -22,6 +22,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
22
22
|
using SafeCast for uint256;
|
|
23
23
|
|
|
24
24
|
uint256 internal constant SECONDS_IN_YEAR_WAD = 31536000e18; /* 365 * 24 * 3600 * 10e18 */
|
|
25
|
+
uint16 internal constant HOURS_PER_YEAR = 8760; /* 24 * 365 */
|
|
26
|
+
|
|
27
|
+
uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
|
|
28
|
+
uint16 internal constant HUNDRED_PERCENT = 1e4;
|
|
29
|
+
uint16 internal constant MIN_MOC = 5e3;
|
|
30
|
+
uint16 internal constant MAX_MOC = 4e4;
|
|
25
31
|
|
|
26
32
|
// For parameters that can be changed by the risk module provider
|
|
27
33
|
bytes32 public constant RM_PROVIDER_ROLE = keccak256("RM_PROVIDER_ROLE");
|
|
@@ -80,7 +86,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
80
86
|
uint256 maxPayoutPerPolicy_,
|
|
81
87
|
uint256 exposureLimit_,
|
|
82
88
|
address wallet_
|
|
83
|
-
) internal
|
|
89
|
+
) internal onlyInitializing {
|
|
84
90
|
__PolicyPoolComponent_init();
|
|
85
91
|
__RiskModule_init_unchained(
|
|
86
92
|
name_,
|
|
@@ -102,10 +108,10 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
102
108
|
uint256 maxPayoutPerPolicy_,
|
|
103
109
|
uint256 exposureLimit_,
|
|
104
110
|
address wallet_
|
|
105
|
-
) internal
|
|
111
|
+
) internal onlyInitializing {
|
|
106
112
|
_name = name_;
|
|
107
113
|
_params = PackedParams({
|
|
108
|
-
moc:
|
|
114
|
+
moc: HUNDRED_PERCENT,
|
|
109
115
|
jrCollRatio: 0,
|
|
110
116
|
collRatio: _wadTo4(collRatio_),
|
|
111
117
|
ensuroPpFee: _wadTo4(ensuroPpFee_),
|
|
@@ -114,23 +120,42 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
114
120
|
srRoc: _wadTo4(srRoc_),
|
|
115
121
|
maxPayoutPerPolicy: _amountToX(2, maxPayoutPerPolicy_),
|
|
116
122
|
exposureLimit: _amountToX(0, exposureLimit_),
|
|
117
|
-
maxDuration:
|
|
123
|
+
maxDuration: HOURS_PER_YEAR
|
|
118
124
|
});
|
|
119
125
|
_activeExposure = 0;
|
|
120
126
|
_wallet = wallet_;
|
|
121
127
|
_validateParameters();
|
|
122
128
|
}
|
|
123
129
|
|
|
130
|
+
function _upgradeValidations(address newImpl) internal view virtual override {
|
|
131
|
+
super._upgradeValidations(newImpl);
|
|
132
|
+
IRiskModule newRM = IRiskModule(newImpl);
|
|
133
|
+
require(
|
|
134
|
+
newRM.premiumsAccount() == _premiumsAccount,
|
|
135
|
+
"Can't upgrade changing the PremiumsAccount"
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @dev See {IERC165-supportsInterface}.
|
|
141
|
+
*/
|
|
142
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
143
|
+
return super.supportsInterface(interfaceId) || interfaceId == type(IRiskModule).interfaceId;
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
// runs validation on RiskModule parameters
|
|
125
147
|
function _validateParameters() internal view override {
|
|
126
|
-
require(_params.jrCollRatio <=
|
|
127
|
-
require(
|
|
148
|
+
require(_params.jrCollRatio <= HUNDRED_PERCENT, "Validation: jrCollRatio must be <=1");
|
|
149
|
+
require(
|
|
150
|
+
_params.collRatio <= HUNDRED_PERCENT && _params.collRatio > 0,
|
|
151
|
+
"Validation: collRatio must be <=1"
|
|
152
|
+
);
|
|
128
153
|
require(_params.collRatio >= _params.jrCollRatio, "Validation: collRatio >= jrCollRatio");
|
|
129
|
-
require(_params.moc <=
|
|
130
|
-
require(_params.ensuroPpFee <=
|
|
131
|
-
require(_params.ensuroCocFee <=
|
|
132
|
-
require(_params.srRoc <=
|
|
133
|
-
require(_params.jrRoc <=
|
|
154
|
+
require(_params.moc <= MAX_MOC && _params.moc >= MIN_MOC, "Validation: moc must be [0.5, 4]");
|
|
155
|
+
require(_params.ensuroPpFee <= HUNDRED_PERCENT, "Validation: ensuroPpFee must be <= 1");
|
|
156
|
+
require(_params.ensuroCocFee <= HUNDRED_PERCENT, "Validation: ensuroCocFee must be <= 1");
|
|
157
|
+
require(_params.srRoc <= HUNDRED_PERCENT, "Validation: srRoc must be <= 1 (100%)");
|
|
158
|
+
require(_params.jrRoc <= HUNDRED_PERCENT, "Validation: jrRoc must be <= 1 (100%)");
|
|
134
159
|
// _maxPayoutPerPolicy no limits
|
|
135
160
|
require(
|
|
136
161
|
exposureLimit() >= _activeExposure,
|
|
@@ -150,12 +175,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
150
175
|
// solhint-disable-next-line func-name-mixedcase
|
|
151
176
|
function _4toWad(uint16 value) internal pure returns (uint256) {
|
|
152
177
|
// 4 decimals to Wad (18 decimals)
|
|
153
|
-
return uint256(value) *
|
|
178
|
+
return uint256(value) * FOUR_DECIMAL_TO_WAD;
|
|
154
179
|
}
|
|
155
180
|
|
|
156
181
|
function _wadTo4(uint256 value) internal pure returns (uint16) {
|
|
157
182
|
// Wad to 4 decimals
|
|
158
|
-
return (value /
|
|
183
|
+
return (value / FOUR_DECIMAL_TO_WAD).toUint16();
|
|
159
184
|
}
|
|
160
185
|
|
|
161
186
|
// solhint-disable-next-line func-name-mixedcase
|
|
@@ -262,6 +287,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
262
287
|
}
|
|
263
288
|
|
|
264
289
|
function setWallet(address wallet_) external onlyComponentRole(RM_PROVIDER_ROLE) {
|
|
290
|
+
require(wallet_ != address(0), "RiskModule: wallet cannot be the zero address");
|
|
265
291
|
_wallet = wallet_;
|
|
266
292
|
_parameterChanged(IAccessManager.GovernanceActions.setWallet, uint256(uint160(wallet_)), false);
|
|
267
293
|
}
|
|
@@ -358,4 +384,11 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
358
384
|
function premiumsAccount() external view override returns (IPremiumsAccount) {
|
|
359
385
|
return _premiumsAccount;
|
|
360
386
|
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
390
|
+
* variables without shifting down storage in the inheritance chain.
|
|
391
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
392
|
+
*/
|
|
393
|
+
uint256[46] private __gap;
|
|
361
394
|
}
|
|
@@ -22,6 +22,12 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
22
22
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
23
23
|
bool internal immutable _creationIsOpen;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @dev Event emitted every time a new policy is created. It allows to link the policyData with a particular policy
|
|
27
|
+
*
|
|
28
|
+
* @param policyId The id of the policy
|
|
29
|
+
* @param policyData The value sent in `policyData` parameter that's the hash of the off-chain stored data.
|
|
30
|
+
*/
|
|
25
31
|
event NewSignedPolicy(uint256 indexed policyId, bytes32 policyData);
|
|
26
32
|
|
|
27
33
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
@@ -74,7 +80,7 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
74
80
|
uint40 quoteValidUntil,
|
|
75
81
|
address payer,
|
|
76
82
|
address onBehalfOf
|
|
77
|
-
) internal returns (
|
|
83
|
+
) internal returns (Policy.PolicyData memory createdPolicy) {
|
|
78
84
|
if (!_creationIsOpen)
|
|
79
85
|
_policyPool.access().checkComponentRole(
|
|
80
86
|
address(this),
|
|
@@ -108,33 +114,92 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
108
114
|
_policyPool.access().checkComponentRole(address(this), PRICER_ROLE, signer, false);
|
|
109
115
|
uint96 internalId = uint96(uint256(policyData) % 2**96);
|
|
110
116
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
createdPolicy = _newPolicy(
|
|
118
|
+
payout,
|
|
119
|
+
premium,
|
|
120
|
+
lossProb,
|
|
121
|
+
expiration,
|
|
122
|
+
payer,
|
|
123
|
+
onBehalfOf,
|
|
124
|
+
internalId
|
|
125
|
+
);
|
|
126
|
+
emit NewSignedPolicy(createdPolicy.id, policyData);
|
|
127
|
+
return createdPolicy;
|
|
114
128
|
}
|
|
115
129
|
|
|
116
130
|
/**
|
|
117
|
-

|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-

|
|
122
|
-

|
|
123
|
-

|
|
124
|
-

|
|
125
|
-

|
|
126
|
-

|
|
127
|
-

|
|
128
|
-

|
|
129
|
-

|
|
130
|
-

|
|
131
|
-

|
|
132
|
-

|
|
133
|
-

|
|
134
|
-

|
|
135
|
-

|
|
136
|
-

|
|
137
|
-

|
|
131
|
+
 * @dev Creates a new Policy using a signed quote. The caller is the payer of the policy. Returns all the struct, not
|
|
132
|
+
* just the id.
|
|
133
|
+
*
|
|
134
|
+
* Same as {newPolicy} but returns all the PolicyData struct, usefull if the PolicyData needs to be stored on-chain.
|
|
135
|
+
 *
|
|
136
|
+
 * Requirements:
|
|
137
|
+
 * - The caller approved the spending of the premium to the PolicyPool
|
|
138
|
+
 * - The quote has been signed by an address with the component role PRICER_ROLE
|
|
139
|
+
 *
|
|
140
|
+
 * Emits:
|
|
141
|
+
 * - {PolicyPool.NewPolicy}
|
|
142
|
+
 * - {NewSignedPolicy}
|
|
143
|
+
 *
|
|
144
|
+
 * @param payout The exposure (maximum payout) of the policy
|
|
145
|
+
 * @param premium The premium that will be paid by the payer
|
|
146
|
+
 * @param lossProb The probability of having to pay the maximum payout (wad)
|
|
147
|
+
 * @param expiration The expiration of the policy (timestamp)
|
|
148
|
+
 * @param onBehalfOf The policy holder
|
|
149
|
+
 * @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
150
|
+
 * @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
151
|
+
 * @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
152
|
+
 * @param quoteValidUntil The expiration of the quote
|
|
153
|
+
 * @return createdPolicy Returns the created policy
|
|
154
|
+
 */
|
|
155
|
+
function newPolicyFull(
|
|
156
|
+
uint256 payout,
|
|
157
|
+
uint256 premium,
|
|
158
|
+
uint256 lossProb,
|
|
159
|
+
uint40 expiration,
|
|
160
|
+
address onBehalfOf,
|
|
161
|
+
bytes32 policyData,
|
|
162
|
+
bytes32 quoteSignatureR,
|
|
163
|
+
bytes32 quoteSignatureVS,
|
|
164
|
+
uint40 quoteValidUntil
|
|
165
|
+
) external returns (Policy.PolicyData memory createdPolicy) {
|
|
166
|
+
return
|
|
167
|
+
_newPolicySigned(
|
|
168
|
+
payout,
|
|
169
|
+
premium,
|
|
170
|
+
lossProb,
|
|
171
|
+
expiration,
|
|
172
|
+
policyData,
|
|
173
|
+
quoteSignatureR,
|
|
174
|
+
quoteSignatureVS,
|
|
175
|
+
quoteValidUntil,
|
|
176
|
+
_msgSender(),
|
|
177
|
+
onBehalfOf
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
 * @dev Creates a new Policy using a signed quote. The caller is the payer of the policy.
|
|
183
|
+
 *
|
|
184
|
+
 * Requirements:
|
|
185
|
+
 * - The caller approved the spending of the premium to the PolicyPool
|
|
186
|
+
 * - The quote has been signed by an address with the component role PRICER_ROLE
|
|
187
|
+
 *
|
|
188
|
+
 * Emits:
|
|
189
|
+
 * - {PolicyPool.NewPolicy}
|
|
190
|
+
 * - {NewSignedPolicy}
|
|
191
|
+
 *
|
|
192
|
+
 * @param payout The exposure (maximum payout) of the policy
|
|
193
|
+
 * @param premium The premium that will be paid by the payer
|
|
194
|
+
 * @param lossProb The probability of having to pay the maximum payout (wad)
|
|
195
|
+
 * @param expiration The expiration of the policy (timestamp)
|
|
196
|
+
 * @param onBehalfOf The policy holder
|
|
197
|
+
 * @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
198
|
+
 * @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
199
|
+
 * @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
200
|
+
 * @param quoteValidUntil The expiration of the quote
|
|
201
|
+
 * @return Returns the id of the created policy
|
|
202
|
+
 */
|
|
138
203
|
function newPolicy(
|
|
139
204
|
uint256 payout,
|
|
140
205
|
uint256 premium,
|
|
@@ -158,31 +223,31 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
158
223
|
quoteValidUntil,
|
|
159
224
|
_msgSender(),
|
|
160
225
|
onBehalfOf
|
|
161
|
-
);
|
|
226
|
+
).id;
|
|
162
227
|
}
|
|
163
228
|
|
|
164
229
|
/**
|
|
165
|
-

|
|
166
|
-

|
|
167
|
-

|
|
168
|
-

|
|
169
|
-

|
|
170
|
-

|
|
171
|
-

|
|
172
|
-

|
|
173
|
-

|
|
174
|
-

|
|
175
|
-

|
|
176
|
-

|
|
177
|
-

|
|
178
|
-

|
|
179
|
-

|
|
180
|
-

|
|
181
|
-

|
|
182
|
-

|
|
183
|
-

|
|
184
|
-

|
|
185
|
-

|
|
230
|
+
 * @dev Creates a new Policy using a signed quote. The payer is the policy holder
|
|
231
|
+
 *
|
|
232
|
+
 * Requirements:
|
|
233
|
+
 * - currency().allowance(onBehalfOf, _msgSender()) > 0
|
|
234
|
+
 * - The quote has been signed by an address with the component role PRICER_ROLE
|
|
235
|
+
 *
|
|
236
|
+
 * Emits:
|
|
237
|
+
 * - {PolicyPool.NewPolicy}
|
|
238
|
+
 * - {NewSignedPolicy}
|
|
239
|
+
 *
|
|
240
|
+
 * @param payout The exposure (maximum payout) of the policy
|
|
241
|
+
 * @param premium The premium that will be paid by the payer
|
|
242
|
+
 * @param lossProb The probability of having to pay the maximum payout (wad)
|
|
243
|
+
 * @param expiration The expiration of the policy (timestamp)
|
|
244
|
+
 * @param onBehalfOf The policy holder
|
|
245
|
+
 * @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
246
|
+
 * @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
247
|
+
 * @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
248
|
+
 * @param quoteValidUntil The expiration of the quote
|
|
249
|
+
 * @return Returns the id of the created policy
|
|
250
|
+
 */
|
|
186
251
|
function newPolicyPaidByHolder(
|
|
187
252
|
uint256 payout,
|
|
188
253
|
uint256 premium,
|
|
@@ -220,7 +285,7 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
220
285
|
quoteValidUntil,
|
|
221
286
|
onBehalfOf,
|
|
222
287
|
onBehalfOf
|
|
223
|
-
);
|
|
288
|
+
).id;
|
|
224
289
|
}
|
|
225
290
|
|
|
226
291
|
function resolvePolicy(Policy.PolicyData calldata policy, uint256 payout)
|
|
@@ -238,4 +303,11 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
238
303
|
{
|
|
239
304
|
_policyPool.resolvePolicyFullPayout(policy, customerWon);
|
|
240
305
|
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
309
|
+
* variables without shifting down storage in the inheritance chain.
|
|
310
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
311
|
+
*/
|
|
312
|
+
uint256[50] private __gap;
|
|
241
313
|
}
|