@ensuro/core 2.0.0-beta1 → 2.0.0-beta11

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 (84) hide show
  1. package/README.md +36 -14
  2. package/build/contracts/AccessManager.sol/AccessManager.json +564 -0
  3. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +238 -0
  4. package/build/contracts/EToken.sol/EToken.json +147 -46
  5. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +23 -4
  6. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +222 -0
  7. package/build/contracts/Policy.sol/Policy.json +2 -2
  8. package/build/contracts/PolicyPool.sol/PolicyPool.json +437 -61
  9. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +21 -2
  10. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +142 -16
  11. package/build/contracts/Reserve.sol/Reserve.json +85 -8
  12. package/build/contracts/RiskModule.sol/RiskModule.json +21 -2
  13. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +979 -0
  14. package/build/contracts/TimeScaled.sol/TimeScaled.json +3 -17
  15. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +24 -5
  16. package/build/contracts/{WadRayMath.sol → dependencies/WadRayMath.sol}/WadRayMath.json +3 -3
  17. package/build/contracts/interfaces/{IPolicyPoolConfig.sol/IPolicyPoolConfig.json → IAccessManager.sol/IAccessManager.json} +77 -59
  18. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +128 -0
  19. package/build/contracts/interfaces/IEToken.sol/IEToken.json +13 -0
  20. package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +40 -16
  21. package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +19 -0
  22. package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +13 -0
  23. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
  24. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
  25. package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +180 -0
  26. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +28 -2
  27. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +21 -2
  28. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +118 -19
  29. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +6 -6
  30. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +783 -0
  31. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
  32. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
  33. package/contracts/AccessManager.sol +132 -0
  34. package/contracts/ERC4626AssetManager.sol +55 -0
  35. package/contracts/EToken.sol +208 -102
  36. package/contracts/LPManualWhitelist.sol +19 -3
  37. package/contracts/LiquidityThresholdAssetManager.sol +175 -0
  38. package/contracts/Policy.sol +5 -3
  39. package/contracts/PolicyPool.sol +381 -116
  40. package/contracts/PolicyPoolComponent.sol +61 -44
  41. package/contracts/PremiumsAccount.sol +324 -86
  42. package/contracts/Reserve.sol +199 -4
  43. package/contracts/RiskModule.sol +62 -31
  44. package/contracts/SignedQuoteRiskModule.sol +248 -0
  45. package/contracts/TimeScaled.sol +19 -15
  46. package/contracts/TrustfulRiskModule.sol +69 -2
  47. package/contracts/dependencies/WadRayMath.sol +126 -0
  48. package/contracts/interfaces/IAccessManager.sol +148 -0
  49. package/contracts/interfaces/IAssetManager.sol +89 -0
  50. package/contracts/interfaces/IEToken.sol +25 -2
  51. package/contracts/interfaces/ILPWhitelist.sol +17 -0
  52. package/contracts/interfaces/IPolicyPool.sol +21 -14
  53. package/contracts/interfaces/IPolicyPoolComponent.sol +5 -1
  54. package/contracts/interfaces/IPremiumsAccount.sol +5 -0
  55. package/contracts/interfaces/IRiskModule.sol +67 -4
  56. package/contracts/mocks/FixedRateVault.sol +85 -0
  57. package/contracts/mocks/InterfaceIdCalculator.sol +32 -0
  58. package/contracts/mocks/PolicyHolderMock.sol +21 -0
  59. package/contracts/mocks/PolicyPoolComponentMock.sol +10 -0
  60. package/contracts/mocks/PolicyPoolMock.sol +41 -15
  61. package/contracts/mocks/RiskModuleMock.sol +75 -0
  62. package/js/deploy.js +704 -0
  63. package/js/test-utils.js +339 -159
  64. package/package.json +1 -1
  65. package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +0 -890
  66. package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -583
  67. package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +0 -691
  68. package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +0 -63
  69. package/build/contracts/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
  70. package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +0 -370
  71. package/build/contracts/mocks/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +0 -353
  72. package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +0 -322
  73. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +0 -584
  74. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +0 -615
  75. package/contracts/FlightDelayRiskModule.sol +0 -217
  76. package/contracts/PolicyNFT.sol +0 -96
  77. package/contracts/PolicyPoolConfig.sol +0 -204
  78. package/contracts/WadRayMath.sol +0 -135
  79. package/contracts/dependencies/ChainlinkClientUpgradeable.sol +0 -371
  80. package/contracts/interfaces/IPolicyNFT.sol +0 -15
  81. package/contracts/interfaces/IPolicyPoolConfig.sol +0 -96
  82. package/contracts/mocks/LinkTokenMock.sol +0 -30
  83. package/contracts/upgraded/IPolicyNFTv1.sol +0 -15
  84. package/contracts/upgraded/PolicyNFTv1.sol +0 -126
@@ -2,33 +2,228 @@
2
2
  pragma solidity ^0.8.0;
3
3
 
4
4
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5
+ import {Address} from "@openzeppelin/contracts/utils/Address.sol";
5
6
  import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
7
  import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
8
+ import {IAssetManager} from "./interfaces/IAssetManager.sol";
9
+ import {IAccessManager} from "./interfaces/IAccessManager.sol";
7
10
  import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
8
11
 
9
12
  /**
10
13
  * @title Base contract for Ensuro cash reserves
11
- * @dev This contract implements the methods related with management of the reserves and payments
14
+ * @dev This contract implements the methods related with management of the reserves and payments. {EToken} and
15
+ * {PremiumsAccount} inherit from this contract.
16
+ *
17
+ * These contracts have an asset manager {IAssetManager} that's a strategy contract that runs in the same context
18
+ * (called with delegatecall) that apply some strategy to reinvest the assets managed by the contract to generate
19
+ * additional returns.
20
+ *
12
21
  * @custom:security-contact security@ensuro.co
13
22
  * @author Ensuro
14
23
  */
15
24
  abstract contract Reserve is PolicyPoolComponent {
16
25
  using SafeERC20 for IERC20Metadata;
26
+ using Address for address;
17
27
 
18
28
  /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
19
29
  // solhint-disable-next-line var-name-mixedcase
20
- uint256 public immutable NEGLIGIBLE_AMOUNT; // init as 10**(decimals/2) == 0.001 USD
30
+ uint256 internal immutable NEGLIGIBLE_AMOUNT; // init as 10**(decimals/2) == 0.001 USD
21
31
 
32
+ /**
33
+ * @dev Reserve constructor. Calculates NEGLIGIBLE_AMOUNT to avoid rounding errors.
34
+ *
35
+ * @param policyPool_ The {PolicyPool} where this reserve will be plugged
36
+ */
22
37
  /// @custom:oz-upgrades-unsafe-allow constructor
23
38
  constructor(IPolicyPool policyPool_) PolicyPoolComponent(policyPool_) {
24
39
  NEGLIGIBLE_AMOUNT = 10**(policyPool_.currency().decimals() / 2);
25
40
  }
26
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
+
50
+ /**
51
+ * @dev Refills the reserve's balance, deinvesting from the asset manager to be able to make a payment
52
+ *
53
+ * @param amount The amount of the payment that needs to be made
54
+ * @return Returns the actual amount deinvested (how much the `currency().balanceof(this)` was increased). It might be
55
+ * more than `amount` because the asset manager might want to give more liquidity to the reserve to avoid further
56
+ * deinvestments. After the call, the `currency().balanceof(this)` should be greater than `amount` (unless unsolvency
57
+ * problem).
58
+ */
59
+ function _refillWallet(uint256 amount) internal returns (uint256) {
60
+ address am = address(assetManager());
61
+ if (am != address(0)) {
62
+ bytes memory result = am.functionDelegateCall(
63
+ abi.encodeWithSelector(IAssetManager.refillWallet.selector, amount),
64
+ "Error refilling wallet"
65
+ );
66
+ return abi.decode(result, (uint256));
67
+ }
68
+ return 0;
69
+ }
70
+
71
+ /**
72
+ * @dev Internal function that transfers money to a destination. It might need to call `_refillWallet` to deinvest
73
+ * some money to have enough liquidity for the payment.
74
+ *
75
+ * @param destination The destination of the transfer.
76
+ * @param amount The amount to be transferred.
77
+ */
27
78
  function _transferTo(address destination, uint256 amount) internal {
79
+ require(destination != address(0), "Reserve: transfer to the zero address");
28
80
  if (amount == 0) return;
29
81
  uint256 balance = currency().balanceOf(address(this));
30
- if (balance < amount && (amount - balance) < NEGLIGIBLE_AMOUNT) amount = balance;
31
- // TODO: asset management
82
+ if (balance < amount) {
83
+ balance += _refillWallet(amount);
84
+ if (amount > balance) {
85
+ if ((amount - balance) < NEGLIGIBLE_AMOUNT) {
86
+ amount = balance;
87
+ } // else - No need to do anything since safeTransfer will fail anyway
88
+ }
89
+ }
32
90
  currency().safeTransfer(destination, amount);
33
91
  }
92
+
93
+ /**
94
+ * @dev Returns the address of the asset manager for this reserve. The asset manager is the contract that manages the
95
+ * funds to generate additional yields. Can be `address(0)` if no asset manager has been set.
96
+ */
97
+ function assetManager() public view virtual returns (IAssetManager);
98
+
99
+ /**
100
+ * @dev Internal function that needs to be implemented by child contracts because they might store the asset manager
101
+ * address in a different way. This function just stores the value, doesn't do any validation (validations are done on
102
+ * `setAssetManager`.
103
+ *
104
+ * @param newAM The address of the new asset manager for the reserve.
105
+ */
106
+ function _setAssetManager(IAssetManager newAM) internal virtual;
107
+
108
+ /**
109
+ * @dev Internal function that needs to be implemented by child contracts to record the earnings (or losses if
110
+ * negative) generated by the asset management.
111
+ *
112
+ * @param earnings The amount of earnings (or losses if negative) generated since last time the earnings were
113
+ * recorded.
114
+ */
115
+ function _assetEarnings(int256 earnings) internal virtual;
116
+
117
+ /**
118
+ * @dev Sets the asset manager for this reserve. If the reserve had previously an asset manager, it will deinvest all
119
+ * the funds, making all of the liquid in the reserve balance.
120
+ *
121
+ * Requirements:
122
+ * - The caller must have been granted of global or component roles GUARDIAN_ROLE or LEVEL1_ROLE.
123
+ *
124
+ * Events:
125
+ * - Emits ComponentChanged with action setAssetManager or setAssetManagerForced
126
+ *
127
+ * @param newAM The address of the new asset manager to assign to the reserve. If is `address(0)` it means the reserve
128
+ * will not have an asset manager. If not `address(0)` it MUST be a contract following the IAssetManager interface.
129
+ * @param force When a previous asset manager exists, before setting the new one, the funds are deinvested. When
130
+ * `force` is true, an error in the deinvestAll() operation is ignored. When `force` is false, if `deinvestAll()`
131
+ * fails, it reverts.
132
+ */
133
+ function setAssetManager(IAssetManager newAM, bool force)
134
+ external
135
+ onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
136
+ {
137
+ require(
138
+ address(newAM) == address(0) || newAM.supportsInterface(type(IAssetManager).interfaceId),
139
+ "Reserve: asset manager doesn't implements the required interface"
140
+ );
141
+ address am = address(assetManager());
142
+ IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setAssetManager;
143
+ if (am != address(0)) {
144
+ if (force) {
145
+ // Ignores success or not
146
+ // solhint-disable-next-line avoid-low-level-calls
147
+ (bool success, bytes memory result) = am.delegatecall(
148
+ abi.encodeWithSelector(IAssetManager.deinvestAll.selector)
149
+ );
150
+ if (!success) {
151
+ action = IAccessManager.GovernanceActions.setAssetManagerForced;
152
+ } else {
153
+ _assetEarnings(abi.decode(result, (int256)));
154
+ }
155
+ } else {
156
+ bytes memory result = am.functionDelegateCall(
157
+ abi.encodeWithSelector(IAssetManager.deinvestAll.selector)
158
+ );
159
+ _assetEarnings(abi.decode(result, (int256)));
160
+ }
161
+ }
162
+ _setAssetManager(newAM);
163
+ am = address(assetManager());
164
+ if (am != address(0)) {
165
+ am.functionDelegateCall(abi.encodeWithSelector(IAssetManager.connect.selector));
166
+ }
167
+ _componentChanged(action, address(newAM));
168
+ }
169
+
170
+ /**
171
+ * @dev Calls {IAssetManager-rebalance} of the assigned asset manager (fails if no asset manager). This operation is
172
+ * intended to give the opportunity to rebalance the liquid and invested for better returns and/or gas optimization.
173
+ *
174
+ * - Emits {IAssetManager-MoneyInvested} or {IAssetManager-MoneyDeinvested}
175
+ */
176
+ function rebalance() public whenNotPaused {
177
+ address(assetManager()).functionDelegateCall(
178
+ abi.encodeWithSelector(IAssetManager.rebalance.selector)
179
+ );
180
+ }
181
+
182
+ /**
183
+ * @dev Calls {IAssetManager-recordEarnings} of the assigned asset manager (fails if no asset manager). The asset
184
+ * manager will return the earnings since last time the earnings where recorded. It then calls `_assetEarnings` to
185
+ * reflect the earnings in the way defined for each reserve.
186
+ *
187
+ * - Emits {IAssetManager-EarningsRecorded}
188
+ */
189
+ function recordEarnings() public whenNotPaused {
190
+ bytes memory result = address(assetManager()).functionDelegateCall(
191
+ abi.encodeWithSelector(IAssetManager.recordEarnings.selector)
192
+ );
193
+ _assetEarnings(abi.decode(result, (int256)));
194
+ }
195
+
196
+ /**
197
+ * @dev Function that calls both `recordEarnings()` and `rebalance()` (in that order). Usually scheduled to run once a
198
+ * day by a keeper or crontask.
199
+ */
200
+ function checkpoint() external whenNotPaused {
201
+ recordEarnings();
202
+ rebalance();
203
+ }
204
+
205
+ /**
206
+ * @dev This function allows to call custom functions of the asset manager (for example for setting parameters).
207
+ * This functions will be called with `delegatecall`, in the context of the reserve.
208
+ *
209
+ * Requirements:
210
+ * - The caller must have been granted of global or component roles LEVEL2_ROLE.
211
+ *
212
+ * @param functionCall Abi encoded function call to make.
213
+ * @return Returns the return value of the function called, to be decoded by the receiver.
214
+ */
215
+ function forwardToAssetManager(bytes memory functionCall)
216
+ external
217
+ onlyGlobalOrComponentRole(LEVEL2_ROLE)
218
+ returns (bytes memory)
219
+ {
220
+ return address(assetManager()).functionDelegateCall(functionCall);
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;
34
229
  }
@@ -1,12 +1,13 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.0;
3
3
 
4
- import {WadRayMath} from "./WadRayMath.sol";
4
+ import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
5
+ import {WadRayMath} from "./dependencies/WadRayMath.sol";
5
6
  import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
6
7
  import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
7
8
  import {IRiskModule} from "./interfaces/IRiskModule.sol";
8
9
  import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
9
- import {IPolicyPoolConfig} from "./interfaces/IPolicyPoolConfig.sol";
10
+ import {IAccessManager} from "./interfaces/IAccessManager.sol";
10
11
  import {Policy} from "./Policy.sol";
11
12
 
12
13
  /**
@@ -18,8 +19,15 @@ import {Policy} from "./Policy.sol";
18
19
  abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
19
20
  using Policy for Policy.PolicyData;
20
21
  using WadRayMath for uint256;
22
+ using SafeCast for uint256;
21
23
 
22
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;
23
31
 
24
32
  // For parameters that can be changed by the risk module provider
25
33
  bytes32 public constant RM_PROVIDER_ROLE = keccak256("RM_PROVIDER_ROLE");
@@ -78,7 +86,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
78
86
  uint256 maxPayoutPerPolicy_,
79
87
  uint256 exposureLimit_,
80
88
  address wallet_
81
- ) internal initializer {
89
+ ) internal onlyInitializing {
82
90
  __PolicyPoolComponent_init();
83
91
  __RiskModule_init_unchained(
84
92
  name_,
@@ -100,10 +108,10 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
100
108
  uint256 maxPayoutPerPolicy_,
101
109
  uint256 exposureLimit_,
102
110
  address wallet_
103
- ) internal initializer {
111
+ ) internal onlyInitializing {
104
112
  _name = name_;
105
113
  _params = PackedParams({
106
- moc: 1e4,
114
+ moc: HUNDRED_PERCENT,
107
115
  jrCollRatio: 0,
108
116
  collRatio: _wadTo4(collRatio_),
109
117
  ensuroPpFee: _wadTo4(ensuroPpFee_),
@@ -112,23 +120,33 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
112
120
  srRoc: _wadTo4(srRoc_),
113
121
  maxPayoutPerPolicy: _amountToX(2, maxPayoutPerPolicy_),
114
122
  exposureLimit: _amountToX(0, exposureLimit_),
115
- maxDuration: 24 * 365 // default = 1 year
123
+ maxDuration: HOURS_PER_YEAR
116
124
  });
117
125
  _activeExposure = 0;
118
126
  _wallet = wallet_;
119
127
  _validateParameters();
120
128
  }
121
129
 
130
+ /**
131
+ * @dev See {IERC165-supportsInterface}.
132
+ */
133
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
134
+ return super.supportsInterface(interfaceId) || interfaceId == type(IRiskModule).interfaceId;
135
+ }
136
+
122
137
  // runs validation on RiskModule parameters
123
138
  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");
139
+ require(_params.jrCollRatio <= HUNDRED_PERCENT, "Validation: jrCollRatio must be <=1");
140
+ require(
141
+ _params.collRatio <= HUNDRED_PERCENT && _params.collRatio > 0,
142
+ "Validation: collRatio must be <=1"
143
+ );
126
144
  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%)");
145
+ require(_params.moc <= MAX_MOC && _params.moc >= MIN_MOC, "Validation: moc must be [0.5, 4]");
146
+ require(_params.ensuroPpFee <= HUNDRED_PERCENT, "Validation: ensuroPpFee must be <= 1");
147
+ require(_params.ensuroCocFee <= HUNDRED_PERCENT, "Validation: ensuroCocFee must be <= 1");
148
+ require(_params.srRoc <= HUNDRED_PERCENT, "Validation: srRoc must be <= 1 (100%)");
149
+ require(_params.jrRoc <= HUNDRED_PERCENT, "Validation: jrRoc must be <= 1 (100%)");
132
150
  // _maxPayoutPerPolicy no limits
133
151
  require(
134
152
  exposureLimit() >= _activeExposure,
@@ -148,12 +166,12 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
148
166
  // solhint-disable-next-line func-name-mixedcase
149
167
  function _4toWad(uint16 value) internal pure returns (uint256) {
150
168
  // 4 decimals to Wad (18 decimals)
151
- return uint256(value) * 1e14;
169
+ return uint256(value) * FOUR_DECIMAL_TO_WAD;
152
170
  }
153
171
 
154
172
  function _wadTo4(uint256 value) internal pure returns (uint16) {
155
173
  // Wad to 4 decimals
156
- return uint16(value / 1e14);
174
+ return (value / FOUR_DECIMAL_TO_WAD).toUint16();
157
175
  }
158
176
 
159
177
  // solhint-disable-next-line func-name-mixedcase
@@ -164,7 +182,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
164
182
 
165
183
  function _amountToX(uint8 decimals, uint256 value) internal view returns (uint32) {
166
184
  // Wad to X decimals
167
- return uint32(value / 10**(currency().decimals() - decimals));
185
+ return (value / 10**(currency().decimals() - decimals)).toUint32();
168
186
  }
169
187
 
170
188
  function maxPayoutPerPolicy() public view override returns (uint256) {
@@ -189,7 +207,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
189
207
 
190
208
  function setParam(Parameter param, uint256 newValue)
191
209
  external
192
- onlyPoolRole3(LEVEL1_ROLE, LEVEL2_ROLE, LEVEL3_ROLE)
210
+ onlyGlobalOrComponentRole3(LEVEL1_ROLE, LEVEL2_ROLE, LEVEL3_ROLE)
193
211
  {
194
212
  bool tweak = !hasPoolRole(LEVEL2_ROLE) && !hasPoolRole(LEVEL1_ROLE);
195
213
  if (param == Parameter.moc) {
@@ -235,11 +253,11 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
235
253
  _params.exposureLimit = _amountToX(0, newValue);
236
254
  } else if (param == Parameter.maxDuration) {
237
255
  require(!tweak, "Tweak exceeded");
238
- _params.maxDuration = uint16(newValue);
256
+ _params.maxDuration = newValue.toUint16();
239
257
  }
240
258
  _parameterChanged(
241
- IPolicyPoolConfig.GovernanceActions(
242
- uint256(IPolicyPoolConfig.GovernanceActions.setMoc) + uint256(param)
259
+ IAccessManager.GovernanceActions(
260
+ uint256(IAccessManager.GovernanceActions.setMoc) + uint256(param)
243
261
  ),
244
262
  newValue,
245
263
  tweak
@@ -260,12 +278,9 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
260
278
  }
261
279
 
262
280
  function setWallet(address wallet_) external onlyComponentRole(RM_PROVIDER_ROLE) {
281
+ require(wallet_ != address(0), "RiskModule: wallet cannot be the zero address");
263
282
  _wallet = wallet_;
264
- _parameterChanged(
265
- IPolicyPoolConfig.GovernanceActions.setWallet,
266
- uint256(uint160(wallet_)),
267
- false
268
- );
283
+ _parameterChanged(IAccessManager.GovernanceActions.setWallet, uint256(uint160(wallet_)), false);
269
284
  }
270
285
 
271
286
  function getMinimumPremium(
@@ -304,8 +319,9 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
304
319
  * @param payout The exposure (maximum payout) of the policy
305
320
  * @param premium The premium that will be paid by the policyHolder
306
321
  * @param lossProb The probability of having to pay the maximum payout (wad)
322
+ * @param payer The account that pays for the premium
307
323
  * @param expiration The expiration of the policy (timestamp)
308
- * @param customer The policy holder
324
+ * @param onBehalfOf The policy holder
309
325
  * @param internalId An id that's unique within this module and it will be used to identify the policy
310
326
  */
311
327
  function _newPolicy(
@@ -313,18 +329,26 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
313
329
  uint256 premium,
314
330
  uint256 lossProb,
315
331
  uint40 expiration,
316
- address customer,
332
+ address payer,
333
+ address onBehalfOf,
317
334
  uint96 internalId
318
335
  ) internal whenNotPaused returns (Policy.PolicyData memory) {
336
+ if (premium == type(uint256).max) {
337
+ premium = getMinimumPremium(payout, lossProb, expiration);
338
+ }
319
339
  require(premium < payout, "Premium must be less than payout");
320
340
  uint40 now_ = uint40(block.timestamp);
321
341
  require(expiration > now_, "Expiration must be in the future");
322
342
  require(((expiration - now_) / 3600) < _params.maxDuration, "Policy exceeds max duration");
323
- require(customer != address(0), "Customer can't be zero address");
343
+ require(onBehalfOf != address(0), "Customer can't be zero address");
324
344
  require(
325
- _policyPool.currency().allowance(customer, address(_policyPool)) >= premium,
345
+ _policyPool.currency().allowance(payer, address(_policyPool)) >= premium,
326
346
  "You must allow ENSURO to transfer the premium"
327
347
  );
348
+ require(
349
+ payer == _msgSender() || _policyPool.currency().allowance(payer, _msgSender()) >= premium,
350
+ "Payer must allow caller to transfer the premium"
351
+ );
328
352
  require(payout <= maxPayoutPerPolicy(), "RiskModule: Payout is more than maximum per policy");
329
353
  Policy.PolicyData memory policy = Policy.initialize(
330
354
  this,
@@ -335,8 +359,8 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
335
359
  expiration
336
360
  );
337
361
  _activeExposure += policy.payout;
338
- require(_activeExposure <= exposureLimit(), "RiskModule: SCR limit exceeded");
339
- uint256 policyId = _policyPool.newPolicy(policy, customer, internalId);
362
+ require(_activeExposure <= exposureLimit(), "RiskModule: Exposure limit exceeded");
363
+ uint256 policyId = _policyPool.newPolicy(policy, payer, onBehalfOf, internalId);
340
364
  policy.id = policyId;
341
365
  return policy;
342
366
  }
@@ -351,4 +375,11 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
351
375
  function premiumsAccount() external view override returns (IPremiumsAccount) {
352
376
  return _premiumsAccount;
353
377
  }
378
+
379
+ /**
380
+ * @dev This empty reserved space is put in place to allow future versions to add new
381
+ * variables without shifting down storage in the inheritance chain.
382
+ * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
383
+ */
384
+ uint256[46] private __gap;
354
385
  }