@ensuro/core 2.0.0-beta1 → 2.0.0-beta10

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 (79) hide show
  1. package/README.md +23 -14
  2. package/build/contracts/AccessManager.sol/AccessManager.json +559 -0
  3. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +219 -0
  4. package/build/contracts/EToken.sol/EToken.json +134 -52
  5. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +4 -4
  6. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +203 -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 +2 -2
  10. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +123 -16
  11. package/build/contracts/Reserve.sol/Reserve.json +66 -8
  12. package/build/contracts/RiskModule.sol/RiskModule.json +2 -2
  13. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +960 -0
  14. package/build/contracts/TimeScaled.sol/TimeScaled.json +3 -17
  15. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +5 -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 +109 -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/IPremiumsAccount.sol/IPremiumsAccount.json +13 -0
  22. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
  23. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
  24. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +28 -2
  25. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +2 -2
  26. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +118 -19
  27. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +6 -6
  28. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +764 -0
  29. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
  30. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
  31. package/contracts/AccessManager.sol +103 -0
  32. package/contracts/ERC4626AssetManager.sol +52 -0
  33. package/contracts/EToken.sol +123 -87
  34. package/contracts/LPManualWhitelist.sol +1 -1
  35. package/contracts/LiquidityThresholdAssetManager.sol +160 -0
  36. package/contracts/Policy.sol +1 -1
  37. package/contracts/PolicyPool.sol +333 -115
  38. package/contracts/PolicyPoolComponent.sol +36 -41
  39. package/contracts/PremiumsAccount.sol +285 -79
  40. package/contracts/Reserve.sol +183 -4
  41. package/contracts/RiskModule.sol +26 -19
  42. package/contracts/SignedQuoteRiskModule.sol +241 -0
  43. package/contracts/TimeScaled.sol +19 -15
  44. package/contracts/TrustfulRiskModule.sol +62 -2
  45. package/contracts/dependencies/WadRayMath.sol +126 -0
  46. package/contracts/interfaces/IAccessManager.sol +148 -0
  47. package/contracts/interfaces/IAssetManager.sol +84 -0
  48. package/contracts/interfaces/IEToken.sol +25 -2
  49. package/contracts/interfaces/ILPWhitelist.sol +17 -0
  50. package/contracts/interfaces/IPolicyPool.sol +20 -13
  51. package/contracts/interfaces/IPolicyPoolComponent.sol +3 -0
  52. package/contracts/interfaces/IPremiumsAccount.sol +5 -0
  53. package/contracts/interfaces/IRiskModule.sol +67 -4
  54. package/contracts/mocks/FixedRateVault.sol +85 -0
  55. package/contracts/mocks/PolicyHolderMock.sol +21 -0
  56. package/contracts/mocks/PolicyPoolMock.sol +41 -15
  57. package/contracts/mocks/RiskModuleMock.sol +75 -0
  58. package/js/test-utils.js +227 -149
  59. package/package.json +1 -1
  60. package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +0 -890
  61. package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -583
  62. package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +0 -691
  63. package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +0 -63
  64. package/build/contracts/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
  65. package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +0 -370
  66. package/build/contracts/mocks/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +0 -353
  67. package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +0 -322
  68. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +0 -584
  69. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +0 -615
  70. package/contracts/FlightDelayRiskModule.sol +0 -217
  71. package/contracts/PolicyNFT.sol +0 -96
  72. package/contracts/PolicyPoolConfig.sol +0 -204
  73. package/contracts/WadRayMath.sol +0 -135
  74. package/contracts/dependencies/ChainlinkClientUpgradeable.sol +0 -371
  75. package/contracts/interfaces/IPolicyNFT.sol +0 -15
  76. package/contracts/interfaces/IPolicyPoolConfig.sol +0 -96
  77. package/contracts/mocks/LinkTokenMock.sol +0 -30
  78. package/contracts/upgraded/IPolicyNFTv1.sol +0 -15
  79. package/contracts/upgraded/PolicyNFTv1.sol +0 -126
@@ -4,33 +4,33 @@ pragma solidity ^0.8.0;
4
4
  import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
5
5
  import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
6
6
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
7
+ import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
7
8
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
8
- import {IPolicyPoolConfig} from "./interfaces/IPolicyPoolConfig.sol";
9
+ import {IAccessManager} from "./interfaces/IAccessManager.sol";
9
10
  import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
10
- import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
11
11
  import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
12
12
  import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
13
13
  import {IRiskModule} from "./interfaces/IRiskModule.sol";
14
14
  import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
15
15
  import {IEToken} from "./interfaces/IEToken.sol";
16
- import {IPolicyNFT} from "./interfaces/IPolicyNFT.sol";
17
16
  import {IPolicyHolder} from "./interfaces/IPolicyHolder.sol";
18
17
  import {Policy} from "./Policy.sol";
19
- import {WadRayMath} from "./WadRayMath.sol";
18
+ import {WadRayMath} from "./dependencies/WadRayMath.sol";
20
19
 
21
20
  /**
22
21
  * @title Ensuro PolicyPool contract
23
22
  * @dev This is the main contract of the protocol, it stores the eTokens (liquidity pools) and has the operations
24
- * to interact with them. This is also the contract that receives and sends the underlying asset.
23
+ * to interact with them. This is also the contract that receives and sends the underlying asset (currency).
25
24
  * Also this contract keeps track of accumulated premiums in different stages:
26
25
  * - activePurePremiums
27
26
  * - wonPurePremiums (surplus)
28
27
  * - borrowedActivePP (deficit borrowed from activePurePremiums)
28
+ * This contract also implements the ERC721 standard, because it mints and NFT for each policy created. The
29
+ * property of the NFT represents the one that will receive the payout.
29
30
  * @custom:security-contact security@ensuro.co
30
31
  * @author Ensuro
31
32
  */
32
- contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
33
- using EnumerableSet for EnumerableSet.AddressSet;
33
+ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721Upgradeable {
34
34
  using WadRayMath for uint256;
35
35
  using Policy for Policy.PolicyData;
36
36
  using SafeERC20 for IERC20Metadata;
@@ -40,25 +40,76 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
40
40
  bytes32 public constant LEVEL2_ROLE = keccak256("LEVEL2_ROLE");
41
41
  bytes32 public constant LEVEL3_ROLE = keccak256("LEVEL3_ROLE");
42
42
 
43
+ /**
44
+ * @dev {AccessManager} that handles the access permissions for the PolicyPool and its components.
45
+ */
43
46
  /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
44
- IPolicyPoolConfig internal immutable _config;
47
+ IAccessManager internal immutable _access;
48
+
49
+ /**
50
+ * @dev {ERC20} token used in PolicyPool as currency. Usually it will be a stablecoin such as USDC.
51
+ */
45
52
  /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
46
53
  IERC20Metadata internal immutable _currency;
47
- /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
48
- IPolicyNFT internal immutable _policyNFT;
49
54
 
50
- enum ETokenStatus {
51
- inactive, // doesn't exists - All operations rejected
52
- active, // deposit / withdraw / lockScr / unlockScr OK
53
- deprecated, // withdraw OK, unlockScr OK, deposit rejected, no new policies
54
- suspended // all operations temporarily rejected
55
+ /**
56
+ * @dev Address of Ensuro's treasury that receives the protocol fees.
57
+ */
58
+ address internal _treasury; // address of Ensuro treasury
59
+
60
+ /**
61
+ * @dev This enum tracks the different status that a component ({PremiumsAccount}, {EToken} or {RiskModule} can have.
62
+ */
63
+ enum ComponentStatus {
64
+ /**
65
+ * @dev inactive status = 0 means the component doesn't exists - All operations rejected
66
+ */
67
+ inactive,
68
+ /**
69
+ * @dev active means the component is fully functional, all the component operations are allowed.
70
+ * deposit / withdraw for eTokens
71
+ * newPolicy / resolvePolicy for riskModules
72
+ * policyCreated / policyExpired / policyResolvedWithPayout for premiumsAccount
73
+ */
74
+ active,
75
+ /**
76
+ * @dev deprecated means the component is in process of being deactivated. Only some operations are allowed:
77
+ * withdraw for eTokens
78
+ * resolvePolicy / expirePolicy for riskModules
79
+ * policyExpired / policyResolvedWithPayout for premiumsAccount
80
+ */
81
+ deprecated,
82
+ /**
83
+ * @dev suspended means the component is temporarily deactivated. All the operations are rejected. Only GUARDIAN
84
+ * can suspend.
85
+ */
86
+ suspended
55
87
  }
56
88
 
57
89
  /**
58
- * @dev Mapping of installed eTokens (see {EToken}) in the PolicyPool. For each one it keep an state
59
- * {ETokenStatus}.
90
+ * @dev Enum of the different kind of top level components that can be plugged into the pool. Each one corresponds
91
+ * with the {EToken}, {RiskModule} and {PremiumsAccount} respectively.
60
92
  */
61
- mapping(IEToken => ETokenStatus) private _eTokens;
93
+ enum ComponentKind {
94
+ unknown,
95
+ eToken,
96
+ riskModule,
97
+ premiumsAccount
98
+ }
99
+
100
+ /**
101
+ * @dev Struct to keep the state and type of the components installed. The `kind` never changes. The `status`
102
+ * initially is `active` and can be changes with {PolicyPool-changeComponentStatus} and {PolicyPool-removeComponent}.
103
+ */
104
+ struct Component {
105
+ ComponentStatus status;
106
+ ComponentKind kind;
107
+ }
108
+
109
+ /**
110
+ * @dev Mapping of installed components (see {EToken}, {RiskModule}, {PremiumsAccount}) in the PolicyPool.
111
+ */
112
+ mapping(IPolicyPoolComponent => Component) private _components;
62
113
 
63
114
  /**
64
115
  * @dev Mapping that stores the active policies (the policyId is the key). It just saves the hash of the policies,
@@ -69,148 +120,294 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
69
120
  /**
70
121
  * @dev Event emitted every time a new policy is added to the pool. Contains all the data about the policy that is
71
122
  * later required for doing operations with the policy like resolution or expiration.
123
+ *
124
+ * @param riskModule The risk module that created the policy
125
+ * @param policy The {Policy-PolicyData} struct with all the immutable fields of the policy.
72
126
  */
73
127
  event NewPolicy(IRiskModule indexed riskModule, Policy.PolicyData policy);
74
128
 
75
129
  /**
76
130
  * @dev Event emitted every time a policy is removed from the pool. If the policy expired, the `payout` is 0,
77
131
  * otherwise is the amount transferred to the policyholder.
132
+ *
133
+ * @param riskModule The risk module where that created the policy initially.
134
+ * @param policyId The unique id of the policy
135
+ * @param payout The payout that has been paid to the policy holder. 0 when the policy expired.
78
136
  */
79
137
  event PolicyResolved(IRiskModule indexed riskModule, uint256 indexed policyId, uint256 payout);
80
138
 
81
139
  /**
82
- * @dev Event emitted when a new eToken is added to the pool or the status changes. See {ETokenStatus}.
140
+ * @dev Event emitted when the treasury changes
141
+ *
142
+ * @param action The type of governance action (just setTreasury in this contract for now)
143
+ * @param value The address of the new treasury
83
144
  */
84
- event ETokenStatusChanged(IEToken indexed eToken, ETokenStatus newStatus);
145
+ event ComponentChanged(IAccessManager.GovernanceActions indexed action, address value);
85
146
 
86
147
  /**
87
- * @dev Event emitted when a new PremiumsAccount is added to the pool or the status changes. TODO
148
+ * @dev Event emitted when a new component added/removed to the pool or the status changes.
149
+ *
150
+ * @param component The address of the component, it can be an {EToken}, {RiskModule} or {PremiumsAccount}
151
+ * @param kind Value indicating the kind of component. See {ComponentKind}
152
+ * @param newStatus The status of the component after the operation. See {ComponentStatus}
88
153
  */
89
- event PremiumsAccountStatusChanged(
90
- IPremiumsAccount indexed premiumsAccount,
91
- ETokenStatus newStatus
154
+ event ComponentStatusChanged(
155
+ IPolicyPoolComponent indexed component,
156
+ ComponentKind kind,
157
+ ComponentStatus newStatus
92
158
  );
93
159
 
160
+ /**
161
+ * @dev Modifier that checks the caller has a given role
162
+ */
94
163
  modifier onlyRole(bytes32 role) {
95
- _config.checkRole(role, msg.sender);
164
+ _access.checkRole(role, _msgSender());
96
165
  _;
97
166
  }
98
167
 
168
+ /**
169
+ * @dev Modifier that checks the caller has any of the given rolea
170
+ */
99
171
  modifier onlyRole2(bytes32 role1, bytes32 role2) {
100
- _config.checkRole2(role1, role2, msg.sender);
172
+ _access.checkRole2(role1, role2, _msgSender());
101
173
  _;
102
174
  }
103
175
 
176
+ /**
177
+ * @dev Instantiates a Policy Pool. Sets immutable fields.
178
+ *
179
+ * @param access_ The address of the {AccessManager} that manages the access permissions for the pool governance
180
+ * operations.
181
+ * @param currency_ The {ERC20} token that's used as a currency in the protocol. Usually a stablecoin such as USDC.
182
+ */
104
183
  /// @custom:oz-upgrades-unsafe-allow constructor
105
- constructor(
106
- IPolicyPoolConfig config_,
107
- IPolicyNFT policyNFT_,
108
- IERC20Metadata currency_
109
- ) {
110
- _config = config_;
111
- _policyNFT = policyNFT_;
184
+ constructor(IAccessManager access_, IERC20Metadata currency_) {
185
+ _access = access_;
112
186
  _currency = currency_;
113
187
  }
114
188
 
115
- function initialize() public initializer {
189
+ /**
190
+ * @dev Initializes a Policy Pool
191
+ *
192
+ * @param name_ The name of the ERC721 token.
193
+ * @param symbol_ The symbol of the ERC721 token.
194
+ * @param treasury_ The address of the treasury that will receive the protocol fees.
195
+ */
196
+ function initialize(
197
+ string memory name_,
198
+ string memory symbol_,
199
+ address treasury_
200
+ ) public initializer {
116
201
  __UUPSUpgradeable_init();
202
+ __ERC721_init(name_, symbol_);
117
203
  __Pausable_init();
118
- __PolicyPool_init_unchained();
204
+ __PolicyPool_init_unchained(treasury_);
119
205
  }
120
206
 
121
207
  // solhint-disable-next-line func-name-mixedcase
122
- function __PolicyPool_init_unchained() internal initializer {
123
- _config.connect();
124
- _policyNFT.connect();
208
+ function __PolicyPool_init_unchained(address treasury_) internal initializer {
209
+ _treasury = treasury_;
125
210
  }
126
211
 
127
212
  // solhint-disable-next-line no-empty-blocks
128
213
  function _authorizeUpgrade(address) internal override onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
129
214
 
215
+ /**
216
+ * @dev Pauses the contract. When the contract is paused, several operations are rejected: deposits, withdrawals, new
217
+ * policies, policy resolution and expiration, nft transfers.
218
+ *
219
+ * Requirements:
220
+ * - Must be executed by a user with the {GUARDIAN_ROLE}.
221
+ */
130
222
  function pause() public onlyRole(GUARDIAN_ROLE) {
131
223
  _pause();
132
224
  }
133
225
 
226
+ /**
227
+ * @dev Unpauses the contract. All the operations disabled when the contract was paused are re-enabled.
228
+ *
229
+ * Requirements:
230
+ * - Must be called by a user with either the {GUARDIAN_ROLE} or a {LEVEL1_ROLE}.
231
+ */
134
232
  function unpause() public onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
135
233
  _unpause();
136
234
  }
137
235
 
138
- function config() external view virtual override returns (IPolicyPoolConfig) {
139
- return _config;
236
+ function access() external view virtual override returns (IAccessManager) {
237
+ return _access;
140
238
  }
141
239
 
142
240
  function currency() external view virtual override returns (IERC20Metadata) {
143
241
  return _currency;
144
242
  }
145
243
 
146
- function policyNFT() external view virtual override returns (address) {
147
- return address(_policyNFT);
244
+ /**
245
+ * @dev Changes the address of the treasury, the one that receives the protocol fees.
246
+ *
247
+ * Requirements:
248
+ * - Must be called by a user with the {LEVEL1_ROLE}.
249
+ *
250
+ * Events:
251
+ * - Emits {ComponentChanged} with action = setTreasury and the address of the new treasury.
252
+ */
253
+ function setTreasury(address treasury_) external onlyRole(LEVEL1_ROLE) {
254
+ _treasury = treasury_;
255
+ emit ComponentChanged(IAccessManager.GovernanceActions.setTreasury, _treasury);
148
256
  }
149
257
 
150
- function addEToken(IEToken eToken) external onlyRole(LEVEL1_ROLE) {
151
- ETokenStatus status = _eTokens[eToken];
152
- require(status == ETokenStatus.inactive, "eToken already in the pool");
153
- require(address(eToken) != address(0), "eToken can't be zero");
154
- require(
155
- IPolicyPoolComponent(address(eToken)).policyPool() == this,
156
- "EToken not linked to this pool"
157
- );
258
+ /**
259
+ * @dev Returns the address of the treasury, the one that receives the protocol fees.
260
+ */
261
+ function treasury() external view override returns (address) {
262
+ return _treasury;
263
+ }
158
264
 
159
- _eTokens[eToken] = ETokenStatus.active;
160
- emit ETokenStatusChanged(eToken, ETokenStatus.active);
265
+ /**
266
+ * @dev Adds a new component (either an {EToken}, {RiskModule} or {PremiumsAccount}) to the protocol. The component
267
+ * status will be `active`.
268
+ *
269
+ * Requirements:
270
+ * - Must be called by a user with the {LEVEL1_ROLE}
271
+ * - The component wasn't added before.
272
+ *
273
+ * Events:
274
+ * - Emits {ComponentStatusChanged} with status active.
275
+ *
276
+ * @param component The address of component contract. Must be an {EToken}, {RiskModule} or {PremiumsAccount} linked
277
+ * to this specific {PolicyPool} and matching the `kind` specified in the next paramter.
278
+ * @param kind The type of component to be added.
279
+ */
280
+ function addComponent(IPolicyPoolComponent component, ComponentKind kind)
281
+ external
282
+ onlyRole(LEVEL1_ROLE)
283
+ {
284
+ Component storage comp = _components[component];
285
+ require(comp.status == ComponentStatus.inactive, "Component already in the pool");
286
+ require(component.policyPool() == this, "Component not linked to this pool");
287
+
288
+ comp.status = ComponentStatus.active;
289
+ comp.kind = kind;
290
+ if (kind == ComponentKind.premiumsAccount) {
291
+ IPremiumsAccount pa = IPremiumsAccount(address(component));
292
+ IEToken etk = pa.juniorEtk();
293
+ if (address(etk) != address(0)) {
294
+ etk.addBorrower(address(pa));
295
+ }
296
+ etk = pa.seniorEtk();
297
+ if (address(etk) != address(0)) {
298
+ etk.addBorrower(address(pa));
299
+ }
300
+ }
301
+ emit ComponentStatusChanged(component, kind, ComponentStatus.active);
161
302
  }
162
303
 
163
- function removeEToken(IEToken eToken) external onlyRole(LEVEL3_ROLE) {
164
- ETokenStatus status = _eTokens[eToken];
165
- require(status == ETokenStatus.deprecated, "EToken not deprecated");
166
- require(eToken.totalSupply() == 0, "EToken has liquidity, can't be removed");
167
- delete _eTokens[eToken];
168
- emit ETokenStatusChanged(eToken, ETokenStatus.inactive);
304
+ /**
305
+ * @dev Removes a component from the protocol. The component needs to be in `deprecated` status before doing this
306
+ * operation.
307
+ *
308
+ * Requirements:
309
+ * - Must be called by a user with the {LEVEL1_ROLE}
310
+ * - The component status is `deprecated`.
311
+ *
312
+ * Events:
313
+ * - Emits {ComponentStatusChanged} with status inactive.
314
+ *
315
+ * @param component The address of component contract. Must be a component added before.
316
+ */
317
+ function removeComponent(IPolicyPoolComponent component) external onlyRole(LEVEL1_ROLE) {
318
+ Component storage comp = _components[component];
319
+ require(comp.status == ComponentStatus.deprecated, "Component not deprecated");
320
+ if (comp.kind == ComponentKind.eToken) {
321
+ require(
322
+ IEToken(address(component)).totalSupply() == 0,
323
+ "EToken has liquidity, can't be removed"
324
+ );
325
+ } else if (comp.kind == ComponentKind.riskModule) {
326
+ require(
327
+ IRiskModule(address(component)).activeExposure() == 0,
328
+ "Can't remove a module with active policies"
329
+ );
330
+ } else if (comp.kind == ComponentKind.premiumsAccount) {
331
+ IPremiumsAccount pa = IPremiumsAccount(address(component));
332
+ require(pa.purePremiums() == 0, "Can't remove a PremiumsAccount with premiums");
333
+ IEToken etk = pa.juniorEtk();
334
+ if (address(etk) != address(0)) {
335
+ etk.removeBorrower(address(pa));
336
+ }
337
+ etk = pa.seniorEtk();
338
+ if (address(etk) != address(0)) {
339
+ etk.removeBorrower(address(pa));
340
+ }
341
+ }
342
+ emit ComponentStatusChanged(component, comp.kind, ComponentStatus.inactive);
343
+ delete _components[component];
169
344
  }
170
345
 
171
- function changeETokenStatus(IEToken eToken, ETokenStatus newStatus)
346
+ /**
347
+ * @dev Changes the status of a component.
348
+ *
349
+ * Requirements:
350
+ * - Must be called by a user with the {LEVEL1_ROLE} if the new status is `active` or `deprecated`.
351
+ * - Must be called by a user with the {GUARDIAN_ROLE} if the new status is `suspended`.
352
+ *
353
+ * Events:
354
+ * - Emits {ComponentStatusChanged} with the new status.
355
+ *
356
+ * @param component The address of component contract. Must be a component added before.
357
+ * @param newStatus The new status, must be either `active`, `deprecated` or `suspended`.
358
+ */
359
+ function changeComponentStatus(IPolicyPoolComponent component, ComponentStatus newStatus)
172
360
  external
173
361
  onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
174
362
  {
175
- ETokenStatus status = _eTokens[eToken];
176
- require(status != ETokenStatus.inactive, "EToken not found");
363
+ Component storage comp = _components[component];
364
+ require(comp.status != ComponentStatus.inactive, "Component not found");
177
365
  require(
178
- newStatus != ETokenStatus.suspended || _config.hasRole(GUARDIAN_ROLE, msg.sender),
179
- "Only GUARDIAN can suspend eTokens"
366
+ (newStatus == ComponentStatus.active && _access.hasRole(LEVEL1_ROLE, _msgSender())) ||
367
+ (newStatus == ComponentStatus.suspended && _access.hasRole(GUARDIAN_ROLE, _msgSender())) ||
368
+ (newStatus == ComponentStatus.deprecated && _access.hasRole(LEVEL1_ROLE, _msgSender())),
369
+ "Only GUARDIAN can suspend / Only LEVEL1 can activate/deprecate"
180
370
  );
181
- _eTokens[eToken] = newStatus;
182
- emit ETokenStatusChanged(eToken, newStatus);
371
+ comp.status = newStatus;
372
+ emit ComponentStatusChanged(component, comp.kind, newStatus);
183
373
  }
184
374
 
185
- function getETokenStatus(IEToken eToken) external view returns (ETokenStatus) {
186
- return _eTokens[eToken];
375
+ /**
376
+ * @dev Returns the status of a component.
377
+ *
378
+ * @param component The address of the component
379
+ * @return The status of the component. See {ComponentStatus}
380
+ */
381
+ function getComponentStatus(IPolicyPoolComponent component)
382
+ external
383
+ view
384
+ returns (ComponentStatus)
385
+ {
386
+ return _components[component].status;
187
387
  }
188
388
 
189
- function addPremiumsAccount(IPremiumsAccount pa) external onlyRole(LEVEL1_ROLE) {
190
- // TODO: limit in # of PremiumsAccount?
191
- // TODO: keep PremiumsAccount status?
192
- require(address(pa) != address(0), "PremiumsAccount can't be zero");
193
- require(
194
- IPolicyPoolComponent(address(pa)).policyPool() == this,
195
- "PremiumsAccount not linked to this pool"
196
- );
197
- IEToken etk = pa.juniorEtk();
198
- if (address(etk) != address(0)) {
199
- etk.addBorrower(address(pa));
200
- }
201
- etk = pa.seniorEtk();
202
- if (address(etk) != address(0)) {
203
- etk.addBorrower(address(pa));
204
- }
205
- emit PremiumsAccountStatusChanged(pa, ETokenStatus.active);
206
- // TODO: functions for deactivating premiumsAccount (and remove them as borrower)
389
+ function _etkStatus(IEToken eToken) internal view returns (ComponentStatus) {
390
+ Component storage comp = _components[IPolicyPoolComponent(address(eToken))];
391
+ require(comp.kind == ComponentKind.eToken, "Component is not an eToken");
392
+ return comp.status;
393
+ }
394
+
395
+ function _rmStatus(IRiskModule riskModule) internal view returns (ComponentStatus) {
396
+ Component storage comp = _components[IPolicyPoolComponent(address(riskModule))];
397
+ require(comp.kind == ComponentKind.riskModule, "Component is not a RiskModule");
398
+ return comp.status;
399
+ }
400
+
401
+ function _paStatus(IPremiumsAccount premiumsAccount) internal view returns (ComponentStatus) {
402
+ Component storage comp = _components[IPolicyPoolComponent(address(premiumsAccount))];
403
+ require(comp.kind == ComponentKind.premiumsAccount, "Component is not a PremiumsAccount");
404
+ return comp.status;
207
405
  }
208
406
 
209
407
  function deposit(IEToken eToken, uint256 amount) external override whenNotPaused {
210
- ETokenStatus etkStatus = _eTokens[eToken];
211
- require(etkStatus == ETokenStatus.active, "eToken is not active");
212
- _currency.safeTransferFrom(msg.sender, address(eToken), amount);
213
- eToken.deposit(msg.sender, amount);
408
+ require(_etkStatus(eToken) == ComponentStatus.active, "eToken is not active");
409
+ _currency.safeTransferFrom(_msgSender(), address(eToken), amount);
410
+ eToken.deposit(_msgSender(), amount);
214
411
  }
215
412
 
216
413
  function withdraw(IEToken eToken, uint256 amount)
@@ -219,48 +416,44 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
219
416
  whenNotPaused
220
417
  returns (uint256)
221
418
  {
222
- ETokenStatus etkStatus = _eTokens[eToken];
419
+ ComponentStatus etkStatus = _etkStatus(eToken);
223
420
  require(
224
- etkStatus == ETokenStatus.active || etkStatus == ETokenStatus.deprecated,
421
+ etkStatus == ComponentStatus.active || etkStatus == ComponentStatus.deprecated,
225
422
  "eToken not found or withdraws not allowed"
226
423
  );
227
- address provider = msg.sender;
424
+ address provider = _msgSender();
228
425
  return eToken.withdraw(provider, amount);
229
426
  }
230
427
 
231
428
  function newPolicy(
232
429
  Policy.PolicyData memory policy,
233
- address customer,
430
+ address payer,
431
+ address policyHolder,
234
432
  uint96 internalId
235
433
  ) external override whenNotPaused returns (uint256) {
236
434
  IRiskModule rm = policy.riskModule;
237
- require(address(rm) == msg.sender, "Only the RM can create new policies");
238
- _config.checkAcceptsNewPolicy(rm);
435
+ require(address(rm) == _msgSender(), "Only the RM can create new policies");
436
+ require(_rmStatus(rm) == ComponentStatus.active, "RM module not found or not active");
239
437
  policy.id = (uint256(uint160(address(rm))) << 96) + internalId;
240
438
  _policies[policy.id] = policy.hash();
241
439
  IPremiumsAccount pa = rm.premiumsAccount();
440
+ require(_paStatus(pa) == ComponentStatus.active, "PremiumsAccount not found or not active");
242
441
  pa.policyCreated(policy);
243
- _policyNFT.safeMint(customer, policy.id);
442
+ _safeMint(policyHolder, policy.id, "");
244
443
 
245
444
  // Distribute the premium
246
- _currency.safeTransferFrom(customer, address(pa), policy.purePremium);
247
- if (policy.srCoc > 0)
248
- _currency.safeTransferFrom(customer, address(pa.seniorEtk()), policy.srCoc);
249
- if (policy.jrCoc > 0)
250
- _currency.safeTransferFrom(customer, address(pa.juniorEtk()), policy.jrCoc);
251
- _currency.safeTransferFrom(customer, _config.treasury(), policy.ensuroCommission);
252
- if (policy.partnerCommission > 0 && customer != rm.wallet())
253
- _currency.safeTransferFrom(customer, rm.wallet(), policy.partnerCommission);
445
+ _currency.safeTransferFrom(payer, address(pa), policy.purePremium);
446
+ if (policy.srCoc > 0) _currency.safeTransferFrom(payer, address(pa.seniorEtk()), policy.srCoc);
447
+ if (policy.jrCoc > 0) _currency.safeTransferFrom(payer, address(pa.juniorEtk()), policy.jrCoc);
448
+ _currency.safeTransferFrom(payer, _treasury, policy.ensuroCommission);
449
+ if (policy.partnerCommission > 0 && payer != rm.wallet())
450
+ _currency.safeTransferFrom(payer, rm.wallet(), policy.partnerCommission);
254
451
  // TODO: this code does up to 5 ERC20 transfers. How we can avoid this? Delayed transfers?
255
452
 
256
453
  emit NewPolicy(rm, policy);
257
454
  return policy.id;
258
455
  }
259
456
 
260
- function _balance() internal view returns (uint256) {
261
- return _currency.balanceOf(address(this));
262
- }
263
-
264
457
  function _validatePolicy(Policy.PolicyData memory policy) internal view {
265
458
  require(policy.id != 0 && policy.hash() == _policies[policy.id], "Policy not found");
266
459
  }
@@ -286,10 +479,17 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
286
479
  return _resolvePolicy(policy, customerWon ? policy.payout : 0, false);
287
480
  }
288
481
 
482
+ function isActive(uint256 policyId) external view override returns (bool) {
483
+ return _policies[policyId] != bytes32(0);
484
+ }
485
+
289
486
  /**
290
487
  * @dev Internal function that handles the different alternative resolutions for a policy, with or without payout and
291
488
  * expiration.
292
489
  *
490
+ * Events:
491
+ * - Emits {PolicyResolved} with the payout
492
+ *
293
493
  * @param policy A policy created with {Policy-initialize}
294
494
  * @param payout The amount to paid to the policyholder
295
495
  * @param expired True for expiration resolution (`payout` must be 0)
@@ -301,18 +501,28 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
301
501
  ) internal {
302
502
  _validatePolicy(policy);
303
503
  IRiskModule rm = policy.riskModule;
304
- require(expired || address(rm) == msg.sender, "Only the RM can resolve policies");
504
+ require(expired || address(rm) == _msgSender(), "Only the RM can resolve policies");
305
505
  require(payout == 0 || policy.expiration > block.timestamp, "Can't pay expired policy");
306
- _config.checkAcceptsResolvePolicy(rm);
506
+ ComponentStatus compStatus = _rmStatus(rm);
507
+ require(
508
+ compStatus == ComponentStatus.active || compStatus == ComponentStatus.deprecated,
509
+ "Module must be active or deprecated to process resolutions"
510
+ );
307
511
  require(payout <= policy.payout, "payout > policy.payout");
308
512
 
309
513
  bool customerWon = payout > 0;
310
514
 
515
+ IPremiumsAccount pa = rm.premiumsAccount();
516
+ compStatus = _paStatus(pa);
517
+ require(
518
+ compStatus == ComponentStatus.active || compStatus == ComponentStatus.deprecated,
519
+ "PremiumsAccount must be active or deprecated to process resolutions"
520
+ );
311
521
  if (customerWon) {
312
- address policyOwner = _policyNFT.ownerOf(policy.id);
313
- rm.premiumsAccount().policyResolvedWithPayout(policyOwner, policy, payout);
522
+ address policyOwner = ownerOf(policy.id);
523
+ pa.policyResolvedWithPayout(policyOwner, policy, payout);
314
524
  } else {
315
- rm.premiumsAccount().policyExpired(policy);
525
+ pa.policyExpired(policy);
316
526
  }
317
527
 
318
528
  rm.releaseExposure(policy.payout);
@@ -331,7 +541,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
331
541
  * contract explicitly reverts. Doesn't reverts is the callback is not implemented.
332
542
  */
333
543
  function _notifyPayout(uint256 policyId, uint256 payout) internal {
334
- address customer = _policyNFT.ownerOf(policyId);
544
+ address customer = ownerOf(policyId);
335
545
  if (!AddressUpgradeable.isContract(customer)) return;
336
546
  try
337
547
  IPolicyHolder(customer).onPayoutReceived(_msgSender(), address(this), policyId, payout)
@@ -356,7 +566,7 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
356
566
  * @dev Notifies the expiration with a callback if the policyholder is a contract. Never reverts.
357
567
  */
358
568
  function _notifyExpiration(uint256 policyId) internal {
359
- address customer = _policyNFT.ownerOf(policyId);
569
+ address customer = ownerOf(policyId);
360
570
  if (!AddressUpgradeable.isContract(customer)) return;
361
571
  try IPolicyHolder(customer).onPolicyExpired(_msgSender(), address(this), policyId) returns (
362
572
  bytes4
@@ -366,4 +576,12 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
366
576
  return;
367
577
  }
368
578
  }
579
+
580
+ function _beforeTokenTransfer(
581
+ address from,
582
+ address to,
583
+ uint256 tokenId
584
+ ) internal override whenNotPaused {
585
+ super._beforeTokenTransfer(from, to, tokenId);
586
+ }
369
587
  }