@ensuro/core 1.2.7 → 2.0.0-beta3
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 +50 -17
- package/build/contracts/EToken.sol/EToken.json +144 -173
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +101 -323
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +15 -2
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +16 -3
- package/build/contracts/PolicyPool.sol/PolicyPool.json +105 -351
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +13 -0
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +77 -98
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +761 -0
- package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +15 -202
- package/build/contracts/RiskModule.sol/RiskModule.json +83 -310
- package/build/contracts/TimeScaled.sol/TimeScaled.json +24 -0
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +131 -333
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +15 -2
- package/build/contracts/dependencies/ERC1967Proxy.sol/ERC1967Proxy.json +64 -0
- package/build/{interfaces/IExchange.sol/IExchange.json → contracts/dependencies/IERC20Metadata.sol/IERC20Metadata.json} +83 -79
- package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +32 -97
- package/build/{interfaces → contracts/interfaces}/ILPWhitelist.sol/ILPWhitelist.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyHolder.sol/IPolicyHolder.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyNFT.sol/IPolicyNFT.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPool.sol/IPolicyPool.json +121 -108
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +20 -49
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +302 -0
- package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
- package/build/{interfaces/IInsolvencyHook.sol/IInsolvencyHook.json → contracts/mocks/IMintableERC20.sol/IMintableERC20.json} +13 -8
- package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +370 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +202 -0
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +603 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +16 -3
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +16 -3
- package/contracts/EToken.sol +210 -267
- package/contracts/FlightDelayRiskModule.sol +30 -21
- package/contracts/LPManualWhitelist.sol +4 -4
- package/contracts/Policy.sol +48 -44
- package/contracts/PolicyNFT.sol +2 -2
- package/contracts/PolicyPool.sol +114 -467
- package/contracts/PolicyPoolComponent.sol +8 -3
- package/contracts/PolicyPoolConfig.sol +29 -91
- package/contracts/PremiumsAccount.sol +274 -0
- package/contracts/Reserve.sol +34 -0
- package/contracts/RiskModule.sol +216 -164
- package/contracts/TimeScaled.sol +134 -0
- package/contracts/TrustfulRiskModule.sol +23 -21
- package/contracts/dependencies/ERC1967Proxy.sol +19 -0
- package/contracts/dependencies/IERC20Metadata.sol +19 -0
- package/contracts/interfaces/IEToken.sol +172 -0
- package/{interfaces → contracts/interfaces}/ILPWhitelist.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyNFT.sol +0 -0
- package/contracts/interfaces/IPolicyPool.sol +138 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol +29 -22
- package/contracts/interfaces/IPremiumsAccount.sol +71 -0
- package/contracts/interfaces/IRiskModule.sol +60 -0
- package/contracts/mocks/ForwardProxy.sol +66 -0
- package/contracts/mocks/IMintableERC20.sol +13 -0
- package/contracts/mocks/LinkTokenMock.sol +30 -0
- package/contracts/mocks/PolicyHolderMock.sol +68 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
- package/contracts/mocks/PolicyPoolMock.sol +122 -0
- package/contracts/mocks/TestCurrency.sol +35 -0
- package/contracts/mocks/TestNFT.sol +23 -0
- package/contracts/upgraded/PolicyNFTv1.sol +1 -1
- package/js/test-utils.js +278 -0
- package/package.json +2 -2
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -742
- package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
- package/build/contracts/Exchange.sol/Exchange.json +0 -591
- package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
- package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
- package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
- package/contracts/AaveAssetManager.sol +0 -298
- package/contracts/BaseAssetManager.sol +0 -301
- package/contracts/DataTypes.sol +0 -287
- package/contracts/Exchange.sol +0 -189
- package/contracts/extras/IPriceRiskModule.sol +0 -41
- package/contracts/extras/PriceRiskModule.sol +0 -243
- package/interfaces/IAssetManager.sol +0 -23
- package/interfaces/IEToken.sol +0 -48
- package/interfaces/IExchange.sol +0 -59
- package/interfaces/IInsolvencyHook.sol +0 -27
- package/interfaces/IPolicyPool.sol +0 -44
- package/interfaces/IRiskModule.sol +0 -29
package/contracts/RiskModule.sol
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
4
|
import {WadRayMath} from "./WadRayMath.sol";
|
|
5
|
-
import {
|
|
6
|
-
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
5
|
+
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
7
6
|
import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
|
|
8
|
-
import {IRiskModule} from "
|
|
9
|
-
import {
|
|
7
|
+
import {IRiskModule} from "./interfaces/IRiskModule.sol";
|
|
8
|
+
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
9
|
+
import {IPolicyPoolConfig} from "./interfaces/IPolicyPoolConfig.sol";
|
|
10
10
|
import {Policy} from "./Policy.sol";
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -15,62 +15,78 @@ import {Policy} from "./Policy.sol";
|
|
|
15
15
|
* @custom:security-contact security@ensuro.co
|
|
16
16
|
* @author Ensuro
|
|
17
17
|
*/
|
|
18
|
-
abstract contract RiskModule is IRiskModule,
|
|
18
|
+
abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
19
19
|
using Policy for Policy.PolicyData;
|
|
20
20
|
using WadRayMath for uint256;
|
|
21
21
|
|
|
22
|
-
uint256 internal constant
|
|
22
|
+
uint256 internal constant SECONDS_IN_YEAR_WAD = 31536000e18; /* 365 * 24 * 3600 * 10e18 */
|
|
23
23
|
|
|
24
24
|
// For parameters that can be changed by the risk module provider
|
|
25
25
|
bytes32 public constant RM_PROVIDER_ROLE = keccak256("RM_PROVIDER_ROLE");
|
|
26
26
|
|
|
27
|
+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
28
|
+
IPremiumsAccount internal immutable _premiumsAccount;
|
|
29
|
+
|
|
27
30
|
string private _name;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
|
|
32
|
+
struct PackedParams {
|
|
33
|
+
uint16 moc; // Margin Of Conservativism - factor that multiplies lossProb - 4 decimals
|
|
34
|
+
uint16 jrCollRatio; // Collateralization Ratio to compute Junior solvency as % of payout - 4 decimals
|
|
35
|
+
uint16 collRatio; // Collateralization Ratio to compute solvency requirement as % of payout - 4 decimals
|
|
36
|
+
uint16 ensuroPpFee; // % of pure premium that will go for Ensuro treasury - 4 decimals
|
|
37
|
+
uint16 ensuroCocFee; // % of CoC that will go for Ensuro treasury - 4 decimals
|
|
38
|
+
uint16 jrRoc; // Return on Capital paid to Junior LPs - Annualized Percentage - 4 decimals
|
|
39
|
+
uint16 srRoc; // Return on Capital paid to Senior LPs - Annualized Percentage - 4 decimals
|
|
40
|
+
uint32 maxPayoutPerPolicy; // Max Payout per Policy - 2 decimals
|
|
41
|
+
uint32 exposureLimit; // Max exposure (sum of payouts) to be allocated to this module - 0 decimals
|
|
42
|
+
uint16 maxDuration; // Max policy duration (in hours)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
PackedParams internal _params;
|
|
46
|
+
|
|
47
|
+
uint256 internal _activeExposure; // in wad - Current exposure of active policies
|
|
37
48
|
|
|
38
49
|
address internal _wallet; // Address of the RiskModule provider
|
|
39
50
|
|
|
40
51
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
constructor(IPolicyPool policyPool_, IPremiumsAccount premiumsAccount_)
|
|
53
|
+
PolicyPoolComponent(policyPool_)
|
|
54
|
+
{
|
|
55
|
+
require(
|
|
56
|
+
PolicyPoolComponent(address(premiumsAccount_)).policyPool() == policyPool_,
|
|
57
|
+
"The PremiumsAccount must be part of the Pool"
|
|
58
|
+
);
|
|
59
|
+
_premiumsAccount = premiumsAccount_;
|
|
60
|
+
}
|
|
43
61
|
|
|
44
62
|
/**
|
|
45
63
|
* @dev Initializes the RiskModule
|
|
46
64
|
* @param name_ Name of the Risk Module
|
|
47
|
-
* @param
|
|
48
|
-
|
|
49
|
-
* @param
|
|
50
|
-
* @param
|
|
51
|
-
* @param
|
|
52
|
-
* @param scrLimit_ Max SCR to be allocated to this module (in wad)
|
|
65
|
+
* @param collRatio_ Collateralization ratio to compute solvency requirement as % of payout (in wad)
|
|
66
|
+
* @param ensuroPpFee_ % of pure premium that will go for Ensuro treasury (in wad)
|
|
67
|
+
* @param srRoc_ return on capital paid to LPs (annualized percentage - in wad)
|
|
68
|
+
* @param maxPayoutPerPolicy_ Maximum payout per policy (in wad)
|
|
69
|
+
* @param exposureLimit_ Max exposure (sum of payouts) to be allocated to this module (in wad)
|
|
53
70
|
* @param wallet_ Address of the RiskModule provider
|
|
54
71
|
*/
|
|
55
72
|
// solhint-disable-next-line func-name-mixedcase
|
|
56
73
|
function __RiskModule_init(
|
|
57
74
|
string memory name_,
|
|
58
|
-
uint256
|
|
59
|
-
uint256
|
|
60
|
-
uint256
|
|
61
|
-
uint256
|
|
62
|
-
uint256
|
|
75
|
+
uint256 collRatio_,
|
|
76
|
+
uint256 ensuroPpFee_,
|
|
77
|
+
uint256 srRoc_,
|
|
78
|
+
uint256 maxPayoutPerPolicy_,
|
|
79
|
+
uint256 exposureLimit_,
|
|
63
80
|
address wallet_
|
|
64
81
|
) internal initializer {
|
|
65
|
-
__AccessControl_init();
|
|
66
82
|
__PolicyPoolComponent_init();
|
|
67
83
|
__RiskModule_init_unchained(
|
|
68
84
|
name_,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
collRatio_,
|
|
86
|
+
ensuroPpFee_,
|
|
87
|
+
srRoc_,
|
|
88
|
+
maxPayoutPerPolicy_,
|
|
89
|
+
exposureLimit_,
|
|
74
90
|
wallet_
|
|
75
91
|
);
|
|
76
92
|
}
|
|
@@ -78,40 +94,50 @@ abstract contract RiskModule is IRiskModule, AccessControlUpgradeable, PolicyPoo
|
|
|
78
94
|
// solhint-disable-next-line func-name-mixedcase
|
|
79
95
|
function __RiskModule_init_unchained(
|
|
80
96
|
string memory name_,
|
|
81
|
-
uint256
|
|
82
|
-
uint256
|
|
83
|
-
uint256
|
|
84
|
-
uint256
|
|
85
|
-
uint256
|
|
97
|
+
uint256 collRatio_,
|
|
98
|
+
uint256 ensuroPpFee_,
|
|
99
|
+
uint256 srRoc_,
|
|
100
|
+
uint256 maxPayoutPerPolicy_,
|
|
101
|
+
uint256 exposureLimit_,
|
|
86
102
|
address wallet_
|
|
87
103
|
) internal initializer {
|
|
88
104
|
_name = name_;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
_params = PackedParams({
|
|
106
|
+
moc: 1e4,
|
|
107
|
+
jrCollRatio: 0,
|
|
108
|
+
collRatio: _wadTo4(collRatio_),
|
|
109
|
+
ensuroPpFee: _wadTo4(ensuroPpFee_),
|
|
110
|
+
ensuroCocFee: 0,
|
|
111
|
+
jrRoc: 0,
|
|
112
|
+
srRoc: _wadTo4(srRoc_),
|
|
113
|
+
maxPayoutPerPolicy: _amountToX(2, maxPayoutPerPolicy_),
|
|
114
|
+
exposureLimit: _amountToX(0, exposureLimit_),
|
|
115
|
+
maxDuration: 24 * 365 // default = 1 year
|
|
116
|
+
});
|
|
117
|
+
_activeExposure = 0;
|
|
96
118
|
_wallet = wallet_;
|
|
97
|
-
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
|
|
98
119
|
_validateParameters();
|
|
99
120
|
}
|
|
100
121
|
|
|
101
122
|
// runs validation on RiskModule parameters
|
|
102
123
|
function _validateParameters() internal view override {
|
|
124
|
+
require(_params.jrCollRatio <= 1e4, "Validation: jrCollRatio must be <=1");
|
|
125
|
+
require(_params.collRatio <= 1e4 && _params.collRatio > 0, "Validation: collRatio must be <=1");
|
|
126
|
+
require(_params.collRatio >= _params.jrCollRatio, "Validation: collRatio >= jrCollRatio");
|
|
127
|
+
require(_params.moc <= 4e4 && _params.moc >= 5e3, "Validation: moc must be [0.5, 4]");
|
|
128
|
+
require(_params.ensuroPpFee <= 1e4, "Validation: ensuroPpFee must be <= 1");
|
|
129
|
+
require(_params.ensuroCocFee <= 1e4, "Validation: ensuroCocFee must be <= 1");
|
|
130
|
+
require(_params.srRoc <= 1e4, "Validation: srRoc must be <= 1 (100%)");
|
|
131
|
+
require(_params.jrRoc <= 1e4, "Validation: jrRoc must be <= 1 (100%)");
|
|
132
|
+
// _maxPayoutPerPolicy no limits
|
|
103
133
|
require(
|
|
104
|
-
|
|
105
|
-
"Validation:
|
|
134
|
+
exposureLimit() >= _activeExposure,
|
|
135
|
+
"Validation: exposureLimit can't be less than actual activeExposure"
|
|
106
136
|
);
|
|
107
137
|
require(
|
|
108
|
-
|
|
109
|
-
"
|
|
138
|
+
_params.exposureLimit > 0 && _params.maxPayoutPerPolicy > 0,
|
|
139
|
+
"Exposure and MaxPayout must be >0"
|
|
110
140
|
);
|
|
111
|
-
require(_ensuroFee <= WadRayMath.RAY, "Validation: ensuroFee must be <= 1");
|
|
112
|
-
require(_scrInterestRate <= WadRayMath.RAY, "Validation: scrInterestRate must be <= 1 (100%)");
|
|
113
|
-
// _maxScrPerPolicy no limits
|
|
114
|
-
require(_scrLimit >= _totalScr, "Validation: scrLimit can't be less than actual totalScr");
|
|
115
141
|
require(_wallet != address(0), "Validation: Wallet can't be zero address");
|
|
116
142
|
}
|
|
117
143
|
|
|
@@ -119,127 +145,121 @@ abstract contract RiskModule is IRiskModule, AccessControlUpgradeable, PolicyPoo
|
|
|
119
145
|
return _name;
|
|
120
146
|
}
|
|
121
147
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
function moc() public view override returns (uint256) {
|
|
127
|
-
return _moc;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function ensuroFee() public view override returns (uint256) {
|
|
131
|
-
return _ensuroFee;
|
|
148
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
149
|
+
function _4toWad(uint16 value) internal pure returns (uint256) {
|
|
150
|
+
// 4 decimals to Wad (18 decimals)
|
|
151
|
+
return uint256(value) * 1e14;
|
|
132
152
|
}
|
|
133
153
|
|
|
134
|
-
function
|
|
135
|
-
|
|
154
|
+
function _wadTo4(uint256 value) internal pure returns (uint16) {
|
|
155
|
+
// Wad to 4 decimals
|
|
156
|
+
return uint16(value / 1e14);
|
|
136
157
|
}
|
|
137
158
|
|
|
138
|
-
|
|
139
|
-
|
|
159
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
160
|
+
function _XtoAmount(uint8 decimals, uint32 value) internal view returns (uint256) {
|
|
161
|
+
// X decimals to Wad (18 decimals)
|
|
162
|
+
return uint256(value) * 10**(currency().decimals() - decimals);
|
|
140
163
|
}
|
|
141
164
|
|
|
142
|
-
function
|
|
143
|
-
|
|
165
|
+
function _amountToX(uint8 decimals, uint256 value) internal view returns (uint32) {
|
|
166
|
+
// Wad to X decimals
|
|
167
|
+
return uint32(value / 10**(currency().decimals() - decimals));
|
|
144
168
|
}
|
|
145
169
|
|
|
146
|
-
function
|
|
147
|
-
return
|
|
170
|
+
function maxPayoutPerPolicy() public view override returns (uint256) {
|
|
171
|
+
return _XtoAmount(2, _params.maxPayoutPerPolicy);
|
|
148
172
|
}
|
|
149
173
|
|
|
150
|
-
function
|
|
151
|
-
return
|
|
174
|
+
function exposureLimit() public view override returns (uint256) {
|
|
175
|
+
return _XtoAmount(0, _params.exposureLimit);
|
|
152
176
|
}
|
|
153
177
|
|
|
154
|
-
function
|
|
155
|
-
|
|
156
|
-
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
157
|
-
{
|
|
158
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
159
|
-
require(
|
|
160
|
-
!tweak || _isTweakRay(_scrPercentage, newScrPercentage, 1e26),
|
|
161
|
-
"Tweak exceeded: scrPercentage tweaks only up to 10%"
|
|
162
|
-
);
|
|
163
|
-
_scrPercentage = newScrPercentage;
|
|
164
|
-
_parameterChanged(
|
|
165
|
-
IPolicyPoolConfig.GovernanceActions.setScrPercentage,
|
|
166
|
-
newScrPercentage,
|
|
167
|
-
tweak
|
|
168
|
-
);
|
|
178
|
+
function maxDuration() public view override returns (uint256) {
|
|
179
|
+
return _params.maxDuration;
|
|
169
180
|
}
|
|
170
181
|
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
require(!tweak || _isTweakRay(_moc, newMoc, 1e26), "Tweak exceeded: moc tweaks only up to 10%");
|
|
174
|
-
_moc = newMoc;
|
|
175
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setMoc, newMoc, tweak);
|
|
182
|
+
function activeExposure() public view override returns (uint256) {
|
|
183
|
+
return _activeExposure;
|
|
176
184
|
}
|
|
177
185
|
|
|
178
|
-
function
|
|
179
|
-
|
|
180
|
-
onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
|
|
181
|
-
{
|
|
182
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
183
|
-
require(
|
|
184
|
-
!tweak || _isTweakRay(_scrInterestRate, newScrInterestRate, 3e26),
|
|
185
|
-
"Tweak exceeded: scrInterestRate tweaks only up to 30%"
|
|
186
|
-
);
|
|
187
|
-
_scrInterestRate = newScrInterestRate;
|
|
188
|
-
_parameterChanged(
|
|
189
|
-
IPolicyPoolConfig.GovernanceActions.setScrInterestRate,
|
|
190
|
-
newScrInterestRate,
|
|
191
|
-
tweak
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function setEnsuroFee(uint256 newEnsuroFee) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
196
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
197
|
-
require(
|
|
198
|
-
!tweak || _isTweakRay(_ensuroFee, newEnsuroFee, 3e26),
|
|
199
|
-
"Tweak exceeded: ensuroFee tweaks only up to 30%"
|
|
200
|
-
);
|
|
201
|
-
_ensuroFee = newEnsuroFee;
|
|
202
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setEnsuroFee, newEnsuroFee, tweak);
|
|
186
|
+
function wallet() public view override returns (address) {
|
|
187
|
+
return _wallet;
|
|
203
188
|
}
|
|
204
189
|
|
|
205
|
-
function
|
|
190
|
+
function setParam(Parameter param, uint256 newValue)
|
|
206
191
|
external
|
|
207
|
-
|
|
192
|
+
onlyPoolRole3(LEVEL1_ROLE, LEVEL2_ROLE, LEVEL3_ROLE)
|
|
208
193
|
{
|
|
209
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
210
|
-
|
|
211
|
-
!tweak || _isTweakWad(
|
|
212
|
-
|
|
213
|
-
)
|
|
214
|
-
|
|
194
|
+
bool tweak = !hasPoolRole(LEVEL2_ROLE) && !hasPoolRole(LEVEL1_ROLE);
|
|
195
|
+
if (param == Parameter.moc) {
|
|
196
|
+
require(!tweak || _isTweakWad(_4toWad(_params.moc), newValue, 1e17), "Tweak exceeded");
|
|
197
|
+
_params.moc = _wadTo4(newValue);
|
|
198
|
+
} else if (param == Parameter.jrCollRatio) {
|
|
199
|
+
require(
|
|
200
|
+
!tweak || _isTweakWad(_4toWad(_params.jrCollRatio), newValue, 1e17),
|
|
201
|
+
"Tweak exceeded"
|
|
202
|
+
);
|
|
203
|
+
_params.jrCollRatio = _wadTo4(newValue);
|
|
204
|
+
} else if (param == Parameter.collRatio) {
|
|
205
|
+
require(!tweak || _isTweakWad(_4toWad(_params.collRatio), newValue, 1e17), "Tweak exceeded");
|
|
206
|
+
_params.collRatio = _wadTo4(newValue);
|
|
207
|
+
} else if (param == Parameter.ensuroPpFee) {
|
|
208
|
+
require(
|
|
209
|
+
!tweak || _isTweakWad(_4toWad(_params.ensuroPpFee), newValue, 1e17),
|
|
210
|
+
"Tweak exceeded"
|
|
211
|
+
);
|
|
212
|
+
_params.ensuroPpFee = _wadTo4(newValue);
|
|
213
|
+
} else if (param == Parameter.ensuroCocFee) {
|
|
214
|
+
require(
|
|
215
|
+
!tweak || _isTweakWad(_4toWad(_params.ensuroCocFee), newValue, 1e17),
|
|
216
|
+
"Tweak exceeded"
|
|
217
|
+
);
|
|
218
|
+
_params.ensuroCocFee = _wadTo4(newValue);
|
|
219
|
+
} else if (param == Parameter.jrRoc) {
|
|
220
|
+
require(!tweak || _isTweakWad(_4toWad(_params.jrRoc), newValue, 1e17), "Tweak exceeded");
|
|
221
|
+
_params.jrRoc = _wadTo4(newValue);
|
|
222
|
+
} else if (param == Parameter.srRoc) {
|
|
223
|
+
require(!tweak || _isTweakWad(_4toWad(_params.srRoc), newValue, 1e17), "Tweak exceeded");
|
|
224
|
+
_params.srRoc = _wadTo4(newValue);
|
|
225
|
+
} else if (param == Parameter.maxPayoutPerPolicy) {
|
|
226
|
+
require(!tweak || _isTweakWad(maxPayoutPerPolicy(), newValue, 1e17), "Tweak exceeded");
|
|
227
|
+
_params.maxPayoutPerPolicy = _amountToX(2, newValue);
|
|
228
|
+
} else if (param == Parameter.exposureLimit) {
|
|
229
|
+
require(newValue >= _activeExposure, "Can't set exposureLimit less than active exposure");
|
|
230
|
+
require(!tweak || _isTweakWad(exposureLimit(), newValue, 1e17), "Tweak exceeded");
|
|
231
|
+
require(
|
|
232
|
+
newValue <= exposureLimit() || hasPoolRole(LEVEL1_ROLE),
|
|
233
|
+
"Tweak exceeded: Increase requires LEVEL1_ROLE"
|
|
234
|
+
);
|
|
235
|
+
_params.exposureLimit = _amountToX(0, newValue);
|
|
236
|
+
} else if (param == Parameter.maxDuration) {
|
|
237
|
+
require(!tweak, "Tweak exceeded");
|
|
238
|
+
_params.maxDuration = uint16(newValue);
|
|
239
|
+
}
|
|
215
240
|
_parameterChanged(
|
|
216
|
-
IPolicyPoolConfig.GovernanceActions
|
|
217
|
-
|
|
241
|
+
IPolicyPoolConfig.GovernanceActions(
|
|
242
|
+
uint256(IPolicyPoolConfig.GovernanceActions.setMoc) + uint256(param)
|
|
243
|
+
),
|
|
244
|
+
newValue,
|
|
218
245
|
tweak
|
|
219
246
|
);
|
|
220
247
|
}
|
|
221
248
|
|
|
222
|
-
function
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
hasPoolRole(LEVEL1_ROLE) ||
|
|
234
|
-
_policyPool.totalETokenSupply().wadMul(1e17) > newScrLimit,
|
|
235
|
-
"Tweak exceeded: Increase, >=10% of the total liquidity, requires LEVEL1_ROLE"
|
|
236
|
-
);
|
|
237
|
-
require(newScrLimit >= _totalScr, "Can't set SCR less than current SCR allocation");
|
|
238
|
-
_scrLimit = newScrLimit;
|
|
239
|
-
_parameterChanged(IPolicyPoolConfig.GovernanceActions.setScrLimit, newScrLimit, tweak);
|
|
249
|
+
function params() public view override returns (Params memory ret) {
|
|
250
|
+
return
|
|
251
|
+
Params({
|
|
252
|
+
moc: _4toWad(_params.moc),
|
|
253
|
+
jrCollRatio: _4toWad(_params.jrCollRatio),
|
|
254
|
+
collRatio: _4toWad(_params.collRatio),
|
|
255
|
+
ensuroPpFee: _4toWad(_params.ensuroPpFee),
|
|
256
|
+
ensuroCocFee: _4toWad(_params.ensuroCocFee),
|
|
257
|
+
jrRoc: _4toWad(_params.jrRoc),
|
|
258
|
+
srRoc: _4toWad(_params.srRoc)
|
|
259
|
+
});
|
|
240
260
|
}
|
|
241
261
|
|
|
242
|
-
function setWallet(address wallet_) external
|
|
262
|
+
function setWallet(address wallet_) external onlyComponentRole(RM_PROVIDER_ROLE) {
|
|
243
263
|
_wallet = wallet_;
|
|
244
264
|
_parameterChanged(
|
|
245
265
|
IPolicyPoolConfig.GovernanceActions.setWallet,
|
|
@@ -253,16 +273,41 @@ abstract contract RiskModule is IRiskModule, AccessControlUpgradeable, PolicyPoo
|
|
|
253
273
|
uint256 lossProb,
|
|
254
274
|
uint40 expiration
|
|
255
275
|
) public view returns (uint256) {
|
|
256
|
-
|
|
257
|
-
uint256
|
|
258
|
-
uint256
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
276
|
+
Params memory p = params();
|
|
277
|
+
uint256 purePremium = payout.wadMul(lossProb.wadMul(p.moc));
|
|
278
|
+
uint256 jrScr = payout.wadMul(p.jrCollRatio);
|
|
279
|
+
if (jrScr > purePremium) {
|
|
280
|
+
jrScr -= purePremium;
|
|
281
|
+
} else {
|
|
282
|
+
jrScr = 0;
|
|
283
|
+
}
|
|
284
|
+
uint256 srScr = payout.wadMul(p.collRatio);
|
|
285
|
+
if (srScr > (purePremium + jrScr)) {
|
|
286
|
+
srScr -= purePremium + jrScr;
|
|
287
|
+
} else {
|
|
288
|
+
srScr = 0;
|
|
289
|
+
}
|
|
290
|
+
uint256 jrCoc = jrScr.wadMul(
|
|
291
|
+
(p.jrRoc * (expiration - block.timestamp)).wadDiv(SECONDS_IN_YEAR_WAD)
|
|
292
|
+
);
|
|
293
|
+
uint256 srCoc = srScr.wadMul(
|
|
294
|
+
(p.srRoc * (expiration - block.timestamp)).wadDiv(SECONDS_IN_YEAR_WAD)
|
|
295
|
+
);
|
|
296
|
+
uint256 ensuroCommission = purePremium.wadMul(p.ensuroPpFee) +
|
|
297
|
+
(jrCoc + srCoc).wadMul(p.ensuroCocFee);
|
|
298
|
+
return purePremium + ensuroCommission + (jrCoc + srCoc);
|
|
264
299
|
}
|
|
265
300
|
|
|
301
|
+
/**
|
|
302
|
+
* @dev Called from child contracts to create policies (after they validated the pricing)
|
|
303
|
+
*
|
|
304
|
+
* @param payout The exposure (maximum payout) of the policy
|
|
305
|
+
* @param premium The premium that will be paid by the policyHolder
|
|
306
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
307
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
308
|
+
* @param customer The policy holder
|
|
309
|
+
* @param internalId An id that's unique within this module and it will be used to identify the policy
|
|
310
|
+
*/
|
|
266
311
|
function _newPolicy(
|
|
267
312
|
uint256 payout,
|
|
268
313
|
uint256 premium,
|
|
@@ -272,31 +317,38 @@ abstract contract RiskModule is IRiskModule, AccessControlUpgradeable, PolicyPoo
|
|
|
272
317
|
uint96 internalId
|
|
273
318
|
) internal whenNotPaused returns (Policy.PolicyData memory) {
|
|
274
319
|
require(premium < payout, "Premium must be less than payout");
|
|
275
|
-
|
|
320
|
+
uint40 now_ = uint40(block.timestamp);
|
|
321
|
+
require(expiration > now_, "Expiration must be in the future");
|
|
322
|
+
require(((expiration - now_) / 3600) < _params.maxDuration, "Policy exceeds max duration");
|
|
276
323
|
require(customer != address(0), "Customer can't be zero address");
|
|
277
324
|
require(
|
|
278
325
|
_policyPool.currency().allowance(customer, address(_policyPool)) >= premium,
|
|
279
326
|
"You must allow ENSURO to transfer the premium"
|
|
280
327
|
);
|
|
328
|
+
require(payout <= maxPayoutPerPolicy(), "RiskModule: Payout is more than maximum per policy");
|
|
281
329
|
Policy.PolicyData memory policy = Policy.initialize(
|
|
282
330
|
this,
|
|
331
|
+
params(),
|
|
283
332
|
premium,
|
|
284
333
|
payout,
|
|
285
334
|
lossProb,
|
|
286
335
|
expiration
|
|
287
336
|
);
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
require(_totalScr <= _scrLimit, "RiskModule: SCR limit exceeded");
|
|
337
|
+
_activeExposure += policy.payout;
|
|
338
|
+
require(_activeExposure <= exposureLimit(), "RiskModule: SCR limit exceeded");
|
|
291
339
|
uint256 policyId = _policyPool.newPolicy(policy, customer, internalId);
|
|
292
340
|
policy.id = policyId;
|
|
293
341
|
return policy;
|
|
294
342
|
}
|
|
295
343
|
|
|
296
|
-
function
|
|
344
|
+
function releaseExposure(uint256 payout) external override onlyPolicyPool {
|
|
297
345
|
// In the Python protype this function is called `remove_policy` and receives
|
|
298
346
|
// all the policy. Since we just need the amount, for performance reasons
|
|
299
|
-
// we just send the amount and the method is called
|
|
300
|
-
|
|
347
|
+
// we just send the amount and the method is called releaseExposure
|
|
348
|
+
_activeExposure -= payout;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function premiumsAccount() external view override returns (IPremiumsAccount) {
|
|
352
|
+
return _premiumsAccount;
|
|
301
353
|
}
|
|
302
354
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.0;
|
|
4
|
+
|
|
5
|
+
import {WadRayMath} from "./WadRayMath.sol";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @title TimeScaled
|
|
9
|
+
* @dev Library for packed amounts that increase continuoulsly with a scale factor
|
|
10
|
+
* @custom:security-contact security@ensuro.co
|
|
11
|
+
* @author Ensuro
|
|
12
|
+
*/
|
|
13
|
+
library TimeScaled {
|
|
14
|
+
using WadRayMath for uint256;
|
|
15
|
+
|
|
16
|
+
uint256 internal constant SECONDS_PER_YEAR = 365 days;
|
|
17
|
+
uint128 public constant MIN_SCALE = 1e17; // 0.0000000001 == 1e-10 in ray
|
|
18
|
+
|
|
19
|
+
struct ScaledAmount {
|
|
20
|
+
uint128 scale;
|
|
21
|
+
uint96 amount;
|
|
22
|
+
uint32 lastUpdate;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function updateScale(ScaledAmount storage scaledAmount, uint256 interestRate) internal {
|
|
26
|
+
if (scaledAmount.lastUpdate >= uint32(block.timestamp)) return;
|
|
27
|
+
if (scaledAmount.amount == 0) {
|
|
28
|
+
scaledAmount.lastUpdate = uint32(block.timestamp);
|
|
29
|
+
} else {
|
|
30
|
+
scaledAmount.scale = uint128(getScale(scaledAmount, interestRate));
|
|
31
|
+
scaledAmount.lastUpdate = uint32(block.timestamp);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getScale(ScaledAmount storage scaledAmount, uint256 interestRate)
|
|
36
|
+
internal
|
|
37
|
+
view
|
|
38
|
+
returns (uint256)
|
|
39
|
+
{
|
|
40
|
+
uint32 now_ = uint32(block.timestamp);
|
|
41
|
+
if (scaledAmount.lastUpdate >= now_) {
|
|
42
|
+
return scaledAmount.scale;
|
|
43
|
+
}
|
|
44
|
+
uint256 timeDifference = uint256(now_ - scaledAmount.lastUpdate);
|
|
45
|
+
return
|
|
46
|
+
uint256(scaledAmount.scale).rayMul(
|
|
47
|
+
((interestRate.wadToRay() * timeDifference) / SECONDS_PER_YEAR) + WadRayMath.ray()
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getScaledAmount(ScaledAmount storage scaledAmount, uint256 interestRate)
|
|
52
|
+
internal
|
|
53
|
+
view
|
|
54
|
+
returns (uint256)
|
|
55
|
+
{
|
|
56
|
+
return
|
|
57
|
+
uint256(scaledAmount.amount)
|
|
58
|
+
.wadToRay()
|
|
59
|
+
.rayMul(getScale(scaledAmount, interestRate))
|
|
60
|
+
.rayToWad();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function init(ScaledAmount storage scaledAmount) internal {
|
|
64
|
+
scaledAmount.scale = uint128(WadRayMath.ray());
|
|
65
|
+
scaledAmount.amount = 0;
|
|
66
|
+
scaledAmount.lastUpdate = uint32(block.timestamp);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function scaleAmount(ScaledAmount storage scaledAmount, uint256 toScale)
|
|
70
|
+
internal
|
|
71
|
+
view
|
|
72
|
+
returns (uint256)
|
|
73
|
+
{
|
|
74
|
+
return toScale.wadToRay().rayDiv(uint256(scaledAmount.scale)).rayToWad();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function scaleAmountNow(
|
|
78
|
+
ScaledAmount storage scaledAmount,
|
|
79
|
+
uint256 interestRate,
|
|
80
|
+
uint256 toScale
|
|
81
|
+
) internal view returns (uint256) {
|
|
82
|
+
return toScale.wadToRay().rayDiv(getScale(scaledAmount, interestRate)).rayToWad();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function add(
|
|
86
|
+
ScaledAmount storage scaledAmount,
|
|
87
|
+
uint256 amount,
|
|
88
|
+
uint256 interestRate
|
|
89
|
+
) internal returns (uint256) {
|
|
90
|
+
updateScale(scaledAmount, interestRate);
|
|
91
|
+
uint256 scaledAdd = scaleAmount(scaledAmount, amount);
|
|
92
|
+
scaledAmount.amount += uint96(scaledAdd);
|
|
93
|
+
return scaledAdd;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function sub(
|
|
97
|
+
ScaledAmount storage scaledAmount,
|
|
98
|
+
uint256 amount,
|
|
99
|
+
uint256 interestRate
|
|
100
|
+
) internal returns (uint256) {
|
|
101
|
+
updateScale(scaledAmount, interestRate);
|
|
102
|
+
uint256 scaledSub = scaleAmount(scaledAmount, amount);
|
|
103
|
+
scaledAmount.amount -= uint96(scaledSub);
|
|
104
|
+
if (scaledAmount.amount == 0) {
|
|
105
|
+
// Reset scale if amount == 0
|
|
106
|
+
scaledAmount.scale = uint128(WadRayMath.ray());
|
|
107
|
+
}
|
|
108
|
+
return scaledSub;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function discreteChange(
|
|
112
|
+
ScaledAmount storage scaledAmount,
|
|
113
|
+
int256 amount,
|
|
114
|
+
uint256 interestRate
|
|
115
|
+
) internal {
|
|
116
|
+
updateScale(scaledAmount, interestRate);
|
|
117
|
+
uint256 newScaledAmount = uint256(int256(getScaledAmount(scaledAmount, interestRate)) + amount);
|
|
118
|
+
scaledAmount.scale = uint128(
|
|
119
|
+
newScaledAmount.wadToRay().rayDiv(uint256(scaledAmount.amount).wadToRay())
|
|
120
|
+
);
|
|
121
|
+
require(scaledAmount.scale >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function maxNegativeAdjustment(ScaledAmount storage scaledAmount, uint256 interestRate)
|
|
125
|
+
internal
|
|
126
|
+
view
|
|
127
|
+
returns (uint256)
|
|
128
|
+
{
|
|
129
|
+
uint256 ts = getScaledAmount(scaledAmount, interestRate);
|
|
130
|
+
uint256 minTs = uint256(scaledAmount.amount).wadToRay().rayMul(MIN_SCALE * 10).rayToWad();
|
|
131
|
+
if (ts > minTs) return ts - minTs;
|
|
132
|
+
else return 0;
|
|
133
|
+
}
|
|
134
|
+
}
|