@ensuro/core 1.2.7 → 2.0.0-beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +50 -17
  2. package/build/contracts/EToken.sol/EToken.json +144 -173
  3. package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +101 -323
  4. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +15 -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 +13 -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} +15 -202
  12. package/build/contracts/RiskModule.sol/RiskModule.json +83 -310
  13. package/build/contracts/TimeScaled.sol/TimeScaled.json +24 -0
  14. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +131 -333
  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 +8 -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 +29 -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 -742
  74. package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
  75. package/build/contracts/Exchange.sol/Exchange.json +0 -591
  76. package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
  77. package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
  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 -189
  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
@@ -3,9 +3,9 @@ pragma solidity ^0.8.0;
3
3
 
4
4
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5
5
  import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
- import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
7
- import {IPolicyPoolComponent} from "../interfaces/IPolicyPoolComponent.sol";
8
- import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
6
+ import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
7
+ import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
8
+ import {IPolicyPoolConfig} from "./interfaces/IPolicyPoolConfig.sol";
9
9
  import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
10
10
  import {WadRayMath} from "./WadRayMath.sol";
11
11
 
@@ -71,6 +71,11 @@ abstract contract PolicyPoolComponent is
71
71
  _;
72
72
  }
73
73
 
74
+ modifier onlyComponentRole(bytes32 role) {
75
+ _policyPool.config().checkComponentRole(address(this), role, msg.sender);
76
+ _;
77
+ }
78
+
74
79
  /// @custom:oz-upgrades-unsafe-allow constructor
75
80
  constructor(IPolicyPool policyPool_) {
76
81
  _policyPool = policyPool_;
@@ -4,14 +4,10 @@ pragma solidity ^0.8.0;
4
4
  import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
5
5
  import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
6
6
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
7
- import {IAssetManager} from "../interfaces/IAssetManager.sol";
8
- import {IInsolvencyHook} from "../interfaces/IInsolvencyHook.sol";
9
- import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
10
- import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
11
- import {IRiskModule} from "../interfaces/IRiskModule.sol";
12
- import {ILPWhitelist} from "../interfaces/ILPWhitelist.sol";
13
- import {IExchange} from "../interfaces/IExchange.sol";
14
- import {IPolicyPoolComponent} from "../interfaces/IPolicyPoolComponent.sol";
7
+ import {IPolicyPoolConfig} from "./interfaces/IPolicyPoolConfig.sol";
8
+ import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
9
+ import {IRiskModule} from "./interfaces/IRiskModule.sol";
10
+ import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
15
11
  import {WadRayMath} from "./WadRayMath.sol";
16
12
 
17
13
  /**
@@ -37,11 +33,7 @@ contract PolicyPoolConfig is
37
33
  uint256 public constant L2_RM_LIMIT = 5e16; // 5% in WAD
38
34
 
39
35
  address internal _treasury; // address of Ensuro treasury
40
- IAssetManager internal _assetManager; // asset manager
41
- IInsolvencyHook internal _insolvencyHook; // Contract that handles insolvency situations
42
36
  IPolicyPool internal _policyPool;
43
- ILPWhitelist internal _lpWhitelist; // Contract that handles whitelisting of Liquidity Providers
44
- IExchange internal _exchange; // Contract that handles exchange operations between assets
45
37
 
46
38
  mapping(IRiskModule => RiskModuleStatus) private _riskModules;
47
39
 
@@ -100,6 +92,26 @@ contract PolicyPoolConfig is
100
92
  // solhint-disable-next-line no-empty-blocks
101
93
  function _authorizeUpgrade(address) internal override onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
102
94
 
95
+ function getComponentRole(address component, bytes32 role) public pure returns (bytes32) {
96
+ return bytes32(bytes20(component)) ^ role;
97
+ }
98
+
99
+ function checkComponentRole(
100
+ address component,
101
+ bytes32 role,
102
+ address account
103
+ ) external view override {
104
+ _checkRole(getComponentRole(component, role), account);
105
+ }
106
+
107
+ function grantComponentRole(
108
+ address component,
109
+ bytes32 role,
110
+ address account
111
+ ) external onlyRole(getRoleAdmin(getComponentRole(component, role))) {
112
+ _grantRole(getComponentRole(component, role), account);
113
+ }
114
+
103
115
  function checkRole(bytes32 role, address account) external view override {
104
116
  _checkRole(role, account);
105
117
  }
@@ -112,21 +124,6 @@ contract PolicyPoolConfig is
112
124
  if (!hasRole(role1, account)) _checkRole(role2, account);
113
125
  }
114
126
 
115
- function setAssetManager(IAssetManager assetManager_) external onlyRole(LEVEL1_ROLE) {
116
- require(
117
- address(assetManager_) == address(0) ||
118
- IPolicyPoolComponent(address(assetManager_)).policyPool() == _policyPool,
119
- "Component not linked to this PolicyPool"
120
- );
121
- _policyPool.setAssetManager(assetManager_);
122
- _assetManager = assetManager_;
123
- emit ComponentChanged(GovernanceActions.setAssetManager, address(_assetManager));
124
- }
125
-
126
- function assetManager() external view virtual override returns (IAssetManager) {
127
- return _assetManager;
128
- }
129
-
130
127
  function setTreasury(address treasury_) external onlyRole(LEVEL1_ROLE) {
131
128
  _treasury = treasury_;
132
129
  emit ComponentChanged(GovernanceActions.setTreasury, _treasury);
@@ -136,55 +133,7 @@ contract PolicyPoolConfig is
136
133
  return _treasury;
137
134
  }
138
135
 
139
- function setInsolvencyHook(IInsolvencyHook insolvencyHook_)
140
- external
141
- onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
142
- {
143
- require(
144
- address(insolvencyHook_) == address(0) ||
145
- IPolicyPoolComponent(address(insolvencyHook_)).policyPool() == _policyPool,
146
- "Component not linked to this PolicyPool"
147
- );
148
- _insolvencyHook = insolvencyHook_;
149
- emit ComponentChanged(GovernanceActions.setInsolvencyHook, address(_insolvencyHook));
150
- }
151
-
152
- function insolvencyHook() external view override returns (IInsolvencyHook) {
153
- return _insolvencyHook;
154
- }
155
-
156
- function setLPWhitelist(ILPWhitelist lpWhitelist_)
157
- external
158
- onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
159
- {
160
- require(
161
- address(lpWhitelist_) == address(0) ||
162
- IPolicyPoolComponent(address(lpWhitelist_)).policyPool() == _policyPool,
163
- "Component not linked to this PolicyPool"
164
- );
165
- _lpWhitelist = lpWhitelist_;
166
- emit ComponentChanged(GovernanceActions.setLPWhitelist, address(_lpWhitelist));
167
- }
168
-
169
- function lpWhitelist() external view override returns (ILPWhitelist) {
170
- return _lpWhitelist;
171
- }
172
-
173
- function setExchange(IExchange exchange_) external onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
174
- require(
175
- address(exchange_) == address(0) ||
176
- IPolicyPoolComponent(address(exchange_)).policyPool() == _policyPool,
177
- "Component not linked to this PolicyPool"
178
- );
179
- _exchange = exchange_;
180
- emit ComponentChanged(GovernanceActions.setExchange, address(_exchange));
181
- }
182
-
183
- function exchange() external view override returns (IExchange) {
184
- return _exchange;
185
- }
186
-
187
- function addRiskModule(IRiskModule riskModule) external onlyRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
136
+ function addRiskModule(IRiskModule riskModule) external onlyRole(LEVEL1_ROLE) {
188
137
  require(
189
138
  _riskModules[riskModule] == RiskModuleStatus.inactive,
190
139
  "Risk Module already in the pool"
@@ -194,26 +143,20 @@ contract PolicyPoolConfig is
194
143
  IPolicyPoolComponent(address(riskModule)).policyPool() == _policyPool,
195
144
  "RiskModule not linked to this pool"
196
145
  );
197
- require(
198
- hasRole(LEVEL1_ROLE, msg.sender) ||
199
- _policyPool.totalETokenSupply() > (riskModule.scrLimit().wadMul(L2_RM_LIMIT)),
200
- "RiskModule SCR Limit exceeds the limit for LEVEL2 user"
201
- );
202
146
  _riskModules[riskModule] = RiskModuleStatus.active;
203
147
  emit RiskModuleStatusChanged(riskModule, RiskModuleStatus.active);
204
148
  }
205
149
 
206
150
  function removeRiskModule(IRiskModule riskModule) external onlyRole(LEVEL2_ROLE) {
207
151
  require(_riskModules[riskModule] != RiskModuleStatus.inactive, "Risk Module not found");
208
- require(riskModule.totalScr() == 0, "Can't remove a module with active policies");
152
+ require(riskModule.activeExposure() == 0, "Can't remove a module with active policies");
209
153
  delete _riskModules[riskModule];
210
154
  emit RiskModuleStatusChanged(riskModule, RiskModuleStatus.inactive);
211
155
  }
212
156
 
213
- // #if_succeeds_disabled _riskModules.get(riskModule) == newStatus;
214
157
  function changeRiskModuleStatus(IRiskModule riskModule, RiskModuleStatus newStatus)
215
158
  external
216
- onlyRole3(GUARDIAN_ROLE, LEVEL1_ROLE, LEVEL2_ROLE)
159
+ onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
217
160
  {
218
161
  require(_riskModules[riskModule] != RiskModuleStatus.inactive, "Risk Module not found");
219
162
  require(
@@ -221,13 +164,8 @@ contract PolicyPoolConfig is
221
164
  "Only GUARDIAN can suspend modules"
222
165
  );
223
166
  // To activate LEVEL1 required or LEVEL2 if <5% of total liquidity
224
- require(
225
- newStatus != RiskModuleStatus.active ||
226
- hasRole(LEVEL1_ROLE, msg.sender) ||
227
- _policyPool.totalETokenSupply() > (riskModule.scrLimit().wadMul(L2_RM_LIMIT)),
228
- "RiskModule SCR Limit exceeds the limit for LEVEL2 user"
229
- );
230
- // Anyone (LEVEL1, LEVEL2, GUARDIAN) can deprecate
167
+ require(hasRole(LEVEL1_ROLE, msg.sender), "Only LEVEL1 can activate modules");
168
+ // Anyone (LEVEL1, GUARDIAN) can deprecate
231
169
  _riskModules[riskModule] = newStatus;
232
170
  emit RiskModuleStatusChanged(riskModule, newStatus);
233
171
  }
@@ -0,0 +1,274 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
5
+ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
+ import {WadRayMath} from "./WadRayMath.sol";
8
+ import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
9
+ import {IEToken} from "./interfaces/IEToken.sol";
10
+ import {Reserve} from "./Reserve.sol";
11
+ import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
12
+ import {Policy} from "./Policy.sol";
13
+ import {IEToken} from "./interfaces/IEToken.sol";
14
+
15
+ /**
16
+ * @title Ensuro Premiums Account
17
+ * @dev This contract holds the premiums of a set of risk modules
18
+ * @custom:security-contact security@ensuro.co
19
+ * @author Ensuro
20
+ */
21
+ contract PremiumsAccount is IPremiumsAccount, Reserve {
22
+ using Policy for Policy.PolicyData;
23
+ using WadRayMath for uint256;
24
+ using SafeERC20 for IERC20Metadata;
25
+
26
+ bytes32 public constant WITHDRAW_WON_PREMIUMS_ROLE = keccak256("WITHDRAW_WON_PREMIUMS_ROLE");
27
+
28
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
29
+ IEToken internal immutable _juniorEtk;
30
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
31
+ IEToken internal immutable _seniorEtk;
32
+
33
+ uint256 internal _activePurePremiums; // sum of pure-premiums of active policies - In Wad
34
+ uint256 internal _borrowedActivePP; // amount borrowed from active pure premiums to pay defaulted policies
35
+ uint256 internal _wonPurePremiums; // amount of pure premiums won from non-defaulted policies
36
+
37
+ /*
38
+ * Premiums can come in (for free, without liability) with receiveGrant.
39
+ * And can come out (withdrawed to treasury) with withdrawWonPremiums
40
+ */
41
+ event WonPremiumsInOut(bool moneyIn, uint256 value);
42
+
43
+ /// @custom:oz-upgrades-unsafe-allow constructor
44
+ // solhint-disable-next-line no-empty-blocks
45
+ constructor(
46
+ IPolicyPool policyPool_,
47
+ IEToken juniorEtk_,
48
+ IEToken seniorEtk_
49
+ ) Reserve(policyPool_) {
50
+ _juniorEtk = juniorEtk_;
51
+ _seniorEtk = seniorEtk_;
52
+ }
53
+
54
+ /**
55
+ * @dev Public initialize Initializes the PremiumsAccount
56
+ */
57
+ function initialize() public initializer {
58
+ __PremiumsAccount_init();
59
+ }
60
+
61
+ /**
62
+ * @dev Initializes the PremiumsAccount
63
+ */
64
+ // solhint-disable-next-line func-name-mixedcase
65
+ function __PremiumsAccount_init() internal initializer {
66
+ __PolicyPoolComponent_init();
67
+ __PremiumsAccount_init_unchained();
68
+ }
69
+
70
+ // solhint-disable-next-line func-name-mixedcase
71
+ function __PremiumsAccount_init_unchained() internal initializer {
72
+ /*
73
+ _activePurePremiums = 0;
74
+ _borrowedActivePP = 0;
75
+ _wonPurePremiums = 0;
76
+ */
77
+ if (address(_juniorEtk) != address(0))
78
+ currency().approve(address(_juniorEtk), type(uint256).max);
79
+ if (address(_seniorEtk) != address(0))
80
+ currency().approve(address(_seniorEtk), type(uint256).max);
81
+ _validateParameters();
82
+ }
83
+
84
+ // solhint-disable-next-line no-empty-blocks
85
+ function _validateParameters() internal view override {}
86
+
87
+ function purePremiums() public view returns (uint256) {
88
+ return _activePurePremiums + _wonPurePremiums - _borrowedActivePP;
89
+ }
90
+
91
+ function activePurePremiums() external view returns (uint256) {
92
+ return _activePurePremiums;
93
+ }
94
+
95
+ function wonPurePremiums() external view returns (uint256) {
96
+ return _wonPurePremiums;
97
+ }
98
+
99
+ function borrowedActivePP() external view returns (uint256) {
100
+ return _borrowedActivePP;
101
+ }
102
+
103
+ function seniorEtk() external view override returns (IEToken) {
104
+ return _seniorEtk;
105
+ }
106
+
107
+ function juniorEtk() external view override returns (IEToken) {
108
+ return _juniorEtk;
109
+ }
110
+
111
+ function _payFromPool(uint256 toPay) internal returns (uint256) {
112
+ // 1. take from won_pure_premiums
113
+ if (toPay <= _wonPurePremiums) {
114
+ _wonPurePremiums -= toPay;
115
+ return 0;
116
+ }
117
+ toPay -= _wonPurePremiums;
118
+ _wonPurePremiums = 0;
119
+ // 2. borrow from active pure premiums
120
+ if (_activePurePremiums > _borrowedActivePP) {
121
+ if (toPay <= (_activePurePremiums - _borrowedActivePP)) {
122
+ _borrowedActivePP += toPay;
123
+ return 0;
124
+ } else {
125
+ toPay -= _activePurePremiums - _borrowedActivePP;
126
+ _borrowedActivePP = _activePurePremiums;
127
+ }
128
+ }
129
+ return toPay;
130
+ }
131
+
132
+ function _storePurePremiumWon(uint256 purePremiumWon) internal {
133
+ // TODO: merge _wonPurePremiums and _borrowedActivePP into single int256 variable
134
+ // and this will be just `_wonPurePremiums += purePremiumWon;`
135
+ if (purePremiumWon == 0) return;
136
+ if (_borrowedActivePP >= purePremiumWon) {
137
+ _borrowedActivePP -= purePremiumWon;
138
+ } else {
139
+ _wonPurePremiums += (purePremiumWon - _borrowedActivePP);
140
+ _borrowedActivePP = 0;
141
+ }
142
+ }
143
+
144
+ // TODO: restore repayETokenLoan?
145
+
146
+ /**
147
+ *
148
+ * Endpoint to receive "free money" and inject that money into the premium pool.
149
+ *
150
+ * Can be used for example if the PolicyPool subscribes an excess loss policy with other company.
151
+ *
152
+ */
153
+ function receiveGrant(uint256 amount) external {
154
+ currency().safeTransferFrom(msg.sender, address(this), amount);
155
+ _storePurePremiumWon(amount);
156
+ emit WonPremiumsInOut(true, amount);
157
+ }
158
+
159
+ /**
160
+ *
161
+ * Withdraws excess premiums to PolicyPool's treasury.
162
+ * This might be needed in some cases for example if we are deprecating the protocol or the excess premiums
163
+ * are needed to compensate something. Shouldn't be used. Can be disabled revoking role WITHDRAW_WON_PREMIUMS_ROLE
164
+ *
165
+ * returns The amount withdrawed
166
+ *
167
+ * Requirements:
168
+ *
169
+ * - onlyPoolRole(WITHDRAW_WON_PREMIUMS_ROLE)
170
+ * - _wonPurePremiums > 0
171
+ */
172
+ function withdrawWonPremiums(uint256 amount)
173
+ external
174
+ onlyPoolRole(WITHDRAW_WON_PREMIUMS_ROLE)
175
+ returns (uint256)
176
+ {
177
+ if (amount > _wonPurePremiums) amount = _wonPurePremiums;
178
+ require(amount > 0, "No premiums to withdraw");
179
+ _wonPurePremiums -= amount;
180
+ _transferTo(_policyPool.config().treasury(), amount); // TODO: discuss if destination shoud be msg.sender
181
+ // TODO: see if this will be a component role
182
+ emit WonPremiumsInOut(false, amount);
183
+ return amount;
184
+ }
185
+
186
+ function policyCreated(Policy.PolicyData memory policy) external override onlyPolicyPool {
187
+ _activePurePremiums += policy.purePremium;
188
+ if (policy.jrScr > 0) _juniorEtk.lockScr(policy.jrScr, policy.jrInterestRate());
189
+ if (policy.srScr > 0) _seniorEtk.lockScr(policy.srScr, policy.srInterestRate());
190
+ }
191
+
192
+ function policyResolvedWithPayout(
193
+ address policyHolder,
194
+ Policy.PolicyData memory policy,
195
+ uint256 payout
196
+ ) external override onlyPolicyPool {
197
+ _activePurePremiums -= policy.purePremium;
198
+ if (policy.purePremium >= payout) {
199
+ uint256 purePremiumWon = policy.purePremium - payout;
200
+ if (address(_seniorEtk) != address(0))
201
+ purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
202
+ if (address(_juniorEtk) != address(0))
203
+ purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
204
+ _storePurePremiumWon(purePremiumWon);
205
+ _unlockScr(policy);
206
+ _transferTo(policyHolder, payout);
207
+ } else {
208
+ uint256 borrowFromScr = _payFromPool(payout - policy.purePremium);
209
+ _unlockScr(policy);
210
+ if (borrowFromScr > 0) {
211
+ uint256 left;
212
+ if (policy.jrScr > 0) {
213
+ // Consume Junior Pool until exhausted
214
+ left = _juniorEtk.internalLoan(borrowFromScr, policyHolder, false);
215
+ } else {
216
+ left = borrowFromScr;
217
+ }
218
+ if (left > NEGLIGIBLE_AMOUNT) {
219
+ // Consume Senior Pool only up to SCR
220
+ left = _seniorEtk.internalLoan(left, policyHolder, true);
221
+ require(left <= NEGLIGIBLE_AMOUNT, "Don't know where to take the rest of the money");
222
+ }
223
+ }
224
+ _transferTo(policyHolder, payout - borrowFromScr);
225
+ }
226
+ }
227
+
228
+ function _unlockScr(Policy.PolicyData memory policy) internal {
229
+ if (policy.jrScr > 0) {
230
+ _juniorEtk.unlockScr(
231
+ policy.jrScr,
232
+ policy.jrInterestRate(),
233
+ int256(policy.jrCoc) - int256(policy.jrAccruedInterest())
234
+ );
235
+ }
236
+ if (policy.srScr > 0) {
237
+ _seniorEtk.unlockScr(
238
+ policy.srScr,
239
+ policy.srInterestRate(),
240
+ int256(policy.srCoc) - int256(policy.srAccruedInterest())
241
+ );
242
+ }
243
+ }
244
+
245
+ function _repayLoan(uint256 purePremiumWon, IEToken etk) internal returns (uint256) {
246
+ if (purePremiumWon < NEGLIGIBLE_AMOUNT) return purePremiumWon;
247
+ uint256 borrowedFromEtk = etk.getLoan(address(this));
248
+ if (borrowedFromEtk == 0) return purePremiumWon;
249
+ uint256 repayAmount = borrowedFromEtk > purePremiumWon ? purePremiumWon : borrowedFromEtk;
250
+ // TODO: make sure the balance is available or deinvest
251
+ etk.repayLoan(repayAmount, address(this));
252
+ return purePremiumWon - repayAmount;
253
+ }
254
+
255
+ function policyExpired(Policy.PolicyData memory policy) external override onlyPolicyPool {
256
+ uint256 aux;
257
+ uint256 purePremiumWon = policy.purePremium;
258
+ _activePurePremiums -= purePremiumWon;
259
+
260
+ // If negative _activePurePremiums, repay this first (shouldn't happen)
261
+ if (_borrowedActivePP > _activePurePremiums) {
262
+ aux = Math.min(_borrowedActivePP - _activePurePremiums, purePremiumWon);
263
+ _borrowedActivePP -= aux;
264
+ purePremiumWon -= aux;
265
+ }
266
+
267
+ if (address(_seniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
268
+ if (address(_juniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
269
+
270
+ // Finally store purePremiumWon
271
+ _storePurePremiumWon(purePremiumWon);
272
+ _unlockScr(policy);
273
+ }
274
+ }
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5
+ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
+ import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
7
+ import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
8
+
9
+ /**
10
+ * @title Base contract for Ensuro cash reserves
11
+ * @dev This contract implements the methods related with management of the reserves and payments
12
+ * @custom:security-contact security@ensuro.co
13
+ * @author Ensuro
14
+ */
15
+ abstract contract Reserve is PolicyPoolComponent {
16
+ using SafeERC20 for IERC20Metadata;
17
+
18
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
19
+ // solhint-disable-next-line var-name-mixedcase
20
+ uint256 public immutable NEGLIGIBLE_AMOUNT; // init as 10**(decimals/2) == 0.001 USD
21
+
22
+ /// @custom:oz-upgrades-unsafe-allow constructor
23
+ constructor(IPolicyPool policyPool_) PolicyPoolComponent(policyPool_) {
24
+ NEGLIGIBLE_AMOUNT = 10**(policyPool_.currency().decimals() / 2);
25
+ }
26
+
27
+ function _transferTo(address destination, uint256 amount) internal {
28
+ if (amount == 0) return;
29
+ uint256 balance = currency().balanceOf(address(this));
30
+ if (balance < amount && (amount - balance) < NEGLIGIBLE_AMOUNT) amount = balance;
31
+ // TODO: asset management
32
+ currency().safeTransfer(destination, amount);
33
+ }
34
+ }