@ensuro/core 1.2.7 → 2.0.0-beta1

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 (92) hide show
  1. package/README.md +44 -17
  2. package/build/contracts/EToken.sol/EToken.json +122 -177
  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 -72
  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 -36
  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/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +353 -0
  36. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
  37. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +16 -3
  38. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +16 -3
  39. package/contracts/EToken.sol +188 -269
  40. package/contracts/FlightDelayRiskModule.sol +30 -21
  41. package/contracts/LPManualWhitelist.sol +3 -3
  42. package/contracts/Policy.sol +48 -44
  43. package/contracts/PolicyNFT.sol +2 -2
  44. package/contracts/PolicyPool.sol +114 -467
  45. package/contracts/PolicyPoolComponent.sol +8 -3
  46. package/contracts/PolicyPoolConfig.sol +30 -73
  47. package/contracts/PremiumsAccount.sol +274 -0
  48. package/contracts/Reserve.sol +34 -0
  49. package/contracts/RiskModule.sol +216 -164
  50. package/contracts/TimeScaled.sol +134 -0
  51. package/contracts/TrustfulRiskModule.sol +23 -21
  52. package/contracts/dependencies/ERC1967Proxy.sol +19 -0
  53. package/contracts/dependencies/IERC20Metadata.sol +19 -0
  54. package/contracts/interfaces/IEToken.sol +172 -0
  55. package/{interfaces → contracts/interfaces}/ILPWhitelist.sol +0 -0
  56. package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
  57. package/{interfaces → contracts/interfaces}/IPolicyNFT.sol +0 -0
  58. package/contracts/interfaces/IPolicyPool.sol +138 -0
  59. package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +0 -0
  60. package/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol +29 -20
  61. package/contracts/interfaces/IPremiumsAccount.sol +71 -0
  62. package/contracts/interfaces/IRiskModule.sol +60 -0
  63. package/contracts/mocks/ForwardProxy.sol +66 -0
  64. package/contracts/mocks/IMintableERC20.sol +13 -0
  65. package/contracts/mocks/LinkTokenMock.sol +30 -0
  66. package/contracts/mocks/PolicyHolderMock.sol +68 -0
  67. package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
  68. package/contracts/mocks/PolicyPoolMock.sol +122 -0
  69. package/contracts/mocks/TestCurrency.sol +35 -0
  70. package/contracts/mocks/TestNFT.sol +23 -0
  71. package/contracts/upgraded/PolicyNFTv1.sol +1 -1
  72. package/js/test-utils.js +278 -0
  73. package/package.json +2 -2
  74. package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -742
  75. package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
  76. package/build/contracts/Exchange.sol/Exchange.json +0 -591
  77. package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
  78. package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
  79. package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
  80. package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
  81. package/contracts/AaveAssetManager.sol +0 -298
  82. package/contracts/BaseAssetManager.sol +0 -301
  83. package/contracts/DataTypes.sol +0 -287
  84. package/contracts/Exchange.sol +0 -189
  85. package/contracts/extras/IPriceRiskModule.sol +0 -41
  86. package/contracts/extras/PriceRiskModule.sol +0 -243
  87. package/interfaces/IAssetManager.sol +0 -23
  88. package/interfaces/IEToken.sol +0 -48
  89. package/interfaces/IExchange.sol +0 -59
  90. package/interfaces/IInsolvencyHook.sol +0 -27
  91. package/interfaces/IPolicyPool.sol +0 -44
  92. 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,11 @@ 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 {ILPWhitelist} from "./interfaces/ILPWhitelist.sol";
11
+ import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
15
12
  import {WadRayMath} from "./WadRayMath.sol";
16
13
 
17
14
  /**
@@ -37,11 +34,8 @@ contract PolicyPoolConfig is
37
34
  uint256 public constant L2_RM_LIMIT = 5e16; // 5% in WAD
38
35
 
39
36
  address internal _treasury; // address of Ensuro treasury
40
- IAssetManager internal _assetManager; // asset manager
41
- IInsolvencyHook internal _insolvencyHook; // Contract that handles insolvency situations
42
37
  IPolicyPool internal _policyPool;
43
38
  ILPWhitelist internal _lpWhitelist; // Contract that handles whitelisting of Liquidity Providers
44
- IExchange internal _exchange; // Contract that handles exchange operations between assets
45
39
 
46
40
  mapping(IRiskModule => RiskModuleStatus) private _riskModules;
47
41
 
@@ -100,6 +94,26 @@ contract PolicyPoolConfig is
100
94
  // solhint-disable-next-line no-empty-blocks
101
95
  function _authorizeUpgrade(address) internal override onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
102
96
 
97
+ function getComponentRole(address component, bytes32 role) public pure returns (bytes32) {
98
+ return bytes32(bytes20(component)) ^ role;
99
+ }
100
+
101
+ function checkComponentRole(
102
+ address component,
103
+ bytes32 role,
104
+ address account
105
+ ) external view override {
106
+ _checkRole(getComponentRole(component, role), account);
107
+ }
108
+
109
+ function grantComponentRole(
110
+ address component,
111
+ bytes32 role,
112
+ address account
113
+ ) external onlyRole(getRoleAdmin(getComponentRole(component, role))) {
114
+ _grantRole(getComponentRole(component, role), account);
115
+ }
116
+
103
117
  function checkRole(bytes32 role, address account) external view override {
104
118
  _checkRole(role, account);
105
119
  }
@@ -112,21 +126,6 @@ contract PolicyPoolConfig is
112
126
  if (!hasRole(role1, account)) _checkRole(role2, account);
113
127
  }
114
128
 
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
129
  function setTreasury(address treasury_) external onlyRole(LEVEL1_ROLE) {
131
130
  _treasury = treasury_;
132
131
  emit ComponentChanged(GovernanceActions.setTreasury, _treasury);
@@ -136,23 +135,6 @@ contract PolicyPoolConfig is
136
135
  return _treasury;
137
136
  }
138
137
 
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
138
  function setLPWhitelist(ILPWhitelist lpWhitelist_)
157
139
  external
158
140
  onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
@@ -170,21 +152,7 @@ contract PolicyPoolConfig is
170
152
  return _lpWhitelist;
171
153
  }
172
154
 
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) {
155
+ function addRiskModule(IRiskModule riskModule) external onlyRole(LEVEL1_ROLE) {
188
156
  require(
189
157
  _riskModules[riskModule] == RiskModuleStatus.inactive,
190
158
  "Risk Module already in the pool"
@@ -194,26 +162,20 @@ contract PolicyPoolConfig is
194
162
  IPolicyPoolComponent(address(riskModule)).policyPool() == _policyPool,
195
163
  "RiskModule not linked to this pool"
196
164
  );
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
165
  _riskModules[riskModule] = RiskModuleStatus.active;
203
166
  emit RiskModuleStatusChanged(riskModule, RiskModuleStatus.active);
204
167
  }
205
168
 
206
169
  function removeRiskModule(IRiskModule riskModule) external onlyRole(LEVEL2_ROLE) {
207
170
  require(_riskModules[riskModule] != RiskModuleStatus.inactive, "Risk Module not found");
208
- require(riskModule.totalScr() == 0, "Can't remove a module with active policies");
171
+ require(riskModule.activeExposure() == 0, "Can't remove a module with active policies");
209
172
  delete _riskModules[riskModule];
210
173
  emit RiskModuleStatusChanged(riskModule, RiskModuleStatus.inactive);
211
174
  }
212
175
 
213
- // #if_succeeds_disabled _riskModules.get(riskModule) == newStatus;
214
176
  function changeRiskModuleStatus(IRiskModule riskModule, RiskModuleStatus newStatus)
215
177
  external
216
- onlyRole3(GUARDIAN_ROLE, LEVEL1_ROLE, LEVEL2_ROLE)
178
+ onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
217
179
  {
218
180
  require(_riskModules[riskModule] != RiskModuleStatus.inactive, "Risk Module not found");
219
181
  require(
@@ -221,13 +183,8 @@ contract PolicyPoolConfig is
221
183
  "Only GUARDIAN can suspend modules"
222
184
  );
223
185
  // 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
186
+ require(hasRole(LEVEL1_ROLE, msg.sender), "Only LEVEL1 can activate modules");
187
+ // Anyone (LEVEL1, GUARDIAN) can deprecate
231
188
  _riskModules[riskModule] = newStatus;
232
189
  emit RiskModuleStatusChanged(riskModule, newStatus);
233
190
  }
@@ -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
+ }