@ensuro/core 1.2.6 → 2.0.0-beta2

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.
Files changed (91) hide show
  1. package/README.md +49 -17
  2. package/build/contracts/EToken.sol/EToken.json +163 -173
  3. package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +112 -315
  4. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +34 -2
  5. package/build/contracts/Policy.sol/Policy.json +2 -2
  6. package/build/contracts/PolicyNFT.sol/PolicyNFT.json +16 -3
  7. package/build/contracts/PolicyPool.sol/PolicyPool.json +105 -351
  8. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +32 -0
  9. package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +77 -98
  10. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +761 -0
  11. package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +23 -191
  12. package/build/contracts/RiskModule.sol/RiskModule.json +94 -302
  13. package/build/contracts/TimeScaled.sol/TimeScaled.json +24 -0
  14. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +142 -325
  15. package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +15 -2
  16. package/build/contracts/dependencies/ERC1967Proxy.sol/ERC1967Proxy.json +64 -0
  17. package/build/{interfaces/IExchange.sol/IExchange.json → contracts/dependencies/IERC20Metadata.sol/IERC20Metadata.json} +83 -79
  18. package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +32 -97
  19. package/build/{interfaces → contracts/interfaces}/ILPWhitelist.sol/ILPWhitelist.json +1 -1
  20. package/build/{interfaces → contracts/interfaces}/IPolicyHolder.sol/IPolicyHolder.json +1 -1
  21. package/build/{interfaces → contracts/interfaces}/IPolicyNFT.sol/IPolicyNFT.json +1 -1
  22. package/build/{interfaces → contracts/interfaces}/IPolicyPool.sol/IPolicyPool.json +121 -108
  23. package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
  24. package/build/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +20 -49
  25. package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +302 -0
  26. package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
  27. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
  28. package/build/{interfaces/IInsolvencyHook.sol/IInsolvencyHook.json → contracts/mocks/IMintableERC20.sol/IMintableERC20.json} +13 -8
  29. package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +370 -0
  30. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +202 -0
  31. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
  32. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +603 -0
  33. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
  34. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
  35. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
  36. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +16 -3
  37. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +16 -3
  38. package/contracts/EToken.sol +210 -267
  39. package/contracts/FlightDelayRiskModule.sol +30 -21
  40. package/contracts/LPManualWhitelist.sol +4 -4
  41. package/contracts/Policy.sol +48 -44
  42. package/contracts/PolicyNFT.sol +2 -2
  43. package/contracts/PolicyPool.sol +114 -467
  44. package/contracts/PolicyPoolComponent.sol +14 -3
  45. package/contracts/PolicyPoolConfig.sol +29 -91
  46. package/contracts/PremiumsAccount.sol +274 -0
  47. package/contracts/Reserve.sol +34 -0
  48. package/contracts/RiskModule.sol +216 -164
  49. package/contracts/TimeScaled.sol +134 -0
  50. package/contracts/TrustfulRiskModule.sol +23 -21
  51. package/contracts/dependencies/ERC1967Proxy.sol +19 -0
  52. package/contracts/dependencies/IERC20Metadata.sol +19 -0
  53. package/contracts/interfaces/IEToken.sol +172 -0
  54. package/{interfaces → contracts/interfaces}/ILPWhitelist.sol +0 -0
  55. package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
  56. package/{interfaces → contracts/interfaces}/IPolicyNFT.sol +0 -0
  57. package/contracts/interfaces/IPolicyPool.sol +138 -0
  58. package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +0 -0
  59. package/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol +31 -22
  60. package/contracts/interfaces/IPremiumsAccount.sol +71 -0
  61. package/contracts/interfaces/IRiskModule.sol +60 -0
  62. package/contracts/mocks/ForwardProxy.sol +66 -0
  63. package/contracts/mocks/IMintableERC20.sol +13 -0
  64. package/contracts/mocks/LinkTokenMock.sol +30 -0
  65. package/contracts/mocks/PolicyHolderMock.sol +68 -0
  66. package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
  67. package/contracts/mocks/PolicyPoolMock.sol +122 -0
  68. package/contracts/mocks/TestCurrency.sol +35 -0
  69. package/contracts/mocks/TestNFT.sol +23 -0
  70. package/contracts/upgraded/PolicyNFTv1.sol +1 -1
  71. package/js/test-utils.js +278 -0
  72. package/package.json +2 -2
  73. package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -723
  74. package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
  75. package/build/contracts/Exchange.sol/Exchange.json +0 -546
  76. package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
  77. package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1036
  78. package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
  79. package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
  80. package/contracts/AaveAssetManager.sol +0 -298
  81. package/contracts/BaseAssetManager.sol +0 -301
  82. package/contracts/DataTypes.sol +0 -287
  83. package/contracts/Exchange.sol +0 -173
  84. package/contracts/extras/IPriceRiskModule.sol +0 -41
  85. package/contracts/extras/PriceRiskModule.sol +0 -243
  86. package/interfaces/IAssetManager.sol +0 -23
  87. package/interfaces/IEToken.sol +0 -48
  88. package/interfaces/IExchange.sol +0 -59
  89. package/interfaces/IInsolvencyHook.sol +0 -27
  90. package/interfaces/IPolicyPool.sol +0 -44
  91. package/interfaces/IRiskModule.sol +0 -29
@@ -2,11 +2,11 @@
2
2
  pragma solidity ^0.8.0;
3
3
 
4
4
  import {WadRayMath} from "./WadRayMath.sol";
5
- import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
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 "../interfaces/IRiskModule.sol";
9
- import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
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, AccessControlUpgradeable, PolicyPoolComponent {
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 SECONDS_IN_YEAR_RAY = 31536000e27; /* 365 * 24 * 3600 * 10e27 */
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
- uint256 internal _scrPercentage; // in ray - Solvency Capital Requirement percentage, to calculate
29
- // capital requirement as % of (payout - premium)
30
- uint256 internal _moc; // in ray - Margin Of Conservativism - factor that multiplies lossProb
31
- // to calculate purePremium
32
- uint256 internal _ensuroFee; // in ray - % of pure premium that will go for Ensuro treasury
33
- uint256 internal _scrInterestRate; // in ray - % of interest to charge for the SCR
34
- uint256 internal _maxScrPerPolicy; // in wad - Max SCR per policy
35
- uint256 internal _scrLimit; // in wad - Max SCR to be allocated to this module
36
- uint256 internal _totalScr; // in wad - Current SCR allocated to this module
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
- // solhint-disable-next-line no-empty-blocks
42
- constructor(IPolicyPool policyPool_) PolicyPoolComponent(policyPool_) {}
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 scrPercentage_ Solvency Capital Requirement percentage, to calculate
48
- capital requirement as % of (payout - premium) (in ray)
49
- * @param ensuroFee_ % of pure premium that will go for Ensuro treasury (in ray)
50
- * @param scrInterestRate_ % of interest to charge for the SCR (in ray)
51
- * @param maxScrPerPolicy_ Max SCR to be allocated to this module (in wad)
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 scrPercentage_,
59
- uint256 ensuroFee_,
60
- uint256 scrInterestRate_,
61
- uint256 maxScrPerPolicy_,
62
- uint256 scrLimit_,
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
- scrPercentage_,
70
- ensuroFee_,
71
- scrInterestRate_,
72
- maxScrPerPolicy_,
73
- scrLimit_,
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 scrPercentage_,
82
- uint256 ensuroFee_,
83
- uint256 scrInterestRate_,
84
- uint256 maxScrPerPolicy_,
85
- uint256 scrLimit_,
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
- _scrPercentage = scrPercentage_;
90
- _moc = WadRayMath.RAY;
91
- _ensuroFee = ensuroFee_;
92
- _scrInterestRate = scrInterestRate_;
93
- _maxScrPerPolicy = maxScrPerPolicy_;
94
- _scrLimit = scrLimit_;
95
- _totalScr = 0;
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
- _scrPercentage <= WadRayMath.RAY && _scrPercentage > 0,
105
- "Validation: scrPercentage must be <=1"
134
+ exposureLimit() >= _activeExposure,
135
+ "Validation: exposureLimit can't be less than actual activeExposure"
106
136
  );
107
137
  require(
108
- _moc <= (2 * WadRayMath.RAY) && _moc >= (WadRayMath.RAY / 2),
109
- "Validation: moc must be [0.5, 2]"
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
- function scrPercentage() public view override returns (uint256) {
123
- return _scrPercentage;
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 scrInterestRate() public view override returns (uint256) {
135
- return _scrInterestRate;
154
+ function _wadTo4(uint256 value) internal pure returns (uint16) {
155
+ // Wad to 4 decimals
156
+ return uint16(value / 1e14);
136
157
  }
137
158
 
138
- function maxScrPerPolicy() public view override returns (uint256) {
139
- return _maxScrPerPolicy;
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 scrLimit() public view override returns (uint256) {
143
- return _scrLimit;
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 totalScr() public view override returns (uint256) {
147
- return _totalScr;
170
+ function maxPayoutPerPolicy() public view override returns (uint256) {
171
+ return _XtoAmount(2, _params.maxPayoutPerPolicy);
148
172
  }
149
173
 
150
- function wallet() public view override returns (address) {
151
- return _wallet;
174
+ function exposureLimit() public view override returns (uint256) {
175
+ return _XtoAmount(0, _params.exposureLimit);
152
176
  }
153
177
 
154
- function setScrPercentage(uint256 newScrPercentage)
155
- external
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 setMoc(uint256 newMoc) external onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE) {
172
- bool tweak = !hasPoolRole(LEVEL2_ROLE);
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 setScrInterestRate(uint256 newScrInterestRate)
179
- external
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 setMaxScrPerPolicy(uint256 newMaxScrPerPolicy)
190
+ function setParam(Parameter param, uint256 newValue)
206
191
  external
207
- onlyPoolRole2(LEVEL2_ROLE, LEVEL3_ROLE)
192
+ onlyPoolRole3(LEVEL1_ROLE, LEVEL2_ROLE, LEVEL3_ROLE)
208
193
  {
209
- bool tweak = !hasPoolRole(LEVEL2_ROLE);
210
- require(
211
- !tweak || _isTweakWad(_maxScrPerPolicy, newMaxScrPerPolicy, 3e17),
212
- "Tweak exceeded: maxScrPerPolicy tweaks only up to 30%"
213
- );
214
- _maxScrPerPolicy = newMaxScrPerPolicy;
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.setMaxScrPerPolicy,
217
- newMaxScrPerPolicy,
241
+ IPolicyPoolConfig.GovernanceActions(
242
+ uint256(IPolicyPoolConfig.GovernanceActions.setMoc) + uint256(param)
243
+ ),
244
+ newValue,
218
245
  tweak
219
246
  );
220
247
  }
221
248
 
222
- function setScrLimit(uint256 newScrLimit)
223
- external
224
- onlyPoolRole3(LEVEL1_ROLE, LEVEL2_ROLE, LEVEL3_ROLE)
225
- {
226
- bool tweak = !hasPoolRole(LEVEL2_ROLE) && !hasPoolRole(LEVEL1_ROLE);
227
- require(
228
- !tweak || _isTweakWad(_scrLimit, newScrLimit, 1e17),
229
- "Tweak exceeded: scrLimit tweaks only up to 10%"
230
- );
231
- require(
232
- newScrLimit <= _scrLimit ||
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 onlyRole(RM_PROVIDER_ROLE) {
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
- uint256 purePremium = payout.wadToRay().rayMul(lossProb.rayMul(moc())).rayToWad();
257
- uint256 scr = payout.wadMul(scrPercentage().rayToWad()) - purePremium;
258
- uint256 interestRate = (
259
- (scrInterestRate() * (expiration - block.timestamp)).rayDiv(SECONDS_IN_YEAR_RAY)
260
- ).rayToWad();
261
- uint256 premiumForLps = scr.wadMul(interestRate);
262
- uint256 premiumForEnsuro = (purePremium + premiumForLps).wadMul(ensuroFee().rayToWad());
263
- return purePremium + premiumForEnsuro + premiumForLps;
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
- require(expiration > uint40(block.timestamp), "Expiration must be in the future");
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
- require(policy.scr <= _maxScrPerPolicy, "RiskModule: SCR is more than maximum per policy");
289
- _totalScr += policy.scr;
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 releaseScr(uint256 scrAmount) external override onlyPolicyPool {
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 releaseScr
300
- _totalScr -= scrAmount;
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
+ }