@ensuro/core 1.2.7 → 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 (109) hide show
  1. package/README.md +63 -27
  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 +217 -190
  5. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +17 -4
  6. package/build/contracts/{extras/IPriceRiskModule.sol/IPriceRiskModule.json → LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json} +81 -131
  7. package/build/contracts/Policy.sol/Policy.json +2 -2
  8. package/build/contracts/PolicyPool.sol/PolicyPool.json +425 -295
  9. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +15 -2
  10. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +868 -0
  11. package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +37 -166
  12. package/build/contracts/RiskModule.sol/RiskModule.json +85 -312
  13. package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +960 -0
  14. package/build/contracts/{DataTypes.sol/DataTypes.json → TimeScaled.sol/TimeScaled.json} +4 -4
  15. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +134 -336
  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/contracts/{WadRayMath.sol → dependencies/WadRayMath.sol}/WadRayMath.json +3 -3
  19. package/build/{interfaces/IPolicyPoolConfig.sol/IPolicyPoolConfig.json → contracts/interfaces/IAccessManager.sol/IAccessManager.json} +79 -77
  20. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +109 -0
  21. package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +39 -91
  22. package/build/{interfaces → contracts/interfaces}/ILPWhitelist.sol/ILPWhitelist.json +1 -1
  23. package/build/{interfaces → contracts/interfaces}/IPolicyHolder.sol/IPolicyHolder.json +1 -1
  24. package/build/{interfaces → contracts/interfaces}/IPolicyPool.sol/IPolicyPool.json +137 -100
  25. package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
  26. package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +315 -0
  27. package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
  28. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
  29. package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
  30. package/build/{interfaces/IInsolvencyHook.sol/IInsolvencyHook.json → contracts/mocks/IMintableERC20.sol/IMintableERC20.json} +13 -8
  31. package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +228 -0
  32. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
  33. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +702 -0
  34. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
  35. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +764 -0
  36. package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
  37. package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
  38. package/contracts/AccessManager.sol +103 -0
  39. package/contracts/ERC4626AssetManager.sol +52 -0
  40. package/contracts/EToken.sol +254 -299
  41. package/contracts/LPManualWhitelist.sol +4 -4
  42. package/contracts/LiquidityThresholdAssetManager.sol +160 -0
  43. package/contracts/Policy.sol +49 -45
  44. package/contracts/PolicyPool.sol +379 -514
  45. package/contracts/PolicyPoolComponent.sol +41 -41
  46. package/contracts/PremiumsAccount.sol +480 -0
  47. package/contracts/Reserve.sol +213 -0
  48. package/contracts/RiskModule.sol +233 -174
  49. package/contracts/SignedQuoteRiskModule.sol +241 -0
  50. package/contracts/TimeScaled.sol +138 -0
  51. package/contracts/TrustfulRiskModule.sol +85 -23
  52. package/contracts/dependencies/ERC1967Proxy.sol +19 -0
  53. package/contracts/dependencies/IERC20Metadata.sol +19 -0
  54. package/contracts/dependencies/WadRayMath.sol +126 -0
  55. package/contracts/interfaces/IAccessManager.sol +148 -0
  56. package/contracts/interfaces/IAssetManager.sol +84 -0
  57. package/contracts/interfaces/IEToken.sol +195 -0
  58. package/contracts/interfaces/ILPWhitelist.sol +40 -0
  59. package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
  60. package/contracts/interfaces/IPolicyPool.sol +145 -0
  61. package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +3 -0
  62. package/contracts/interfaces/IPremiumsAccount.sol +76 -0
  63. package/contracts/interfaces/IRiskModule.sol +123 -0
  64. package/contracts/mocks/FixedRateVault.sol +85 -0
  65. package/contracts/mocks/ForwardProxy.sol +66 -0
  66. package/contracts/mocks/IMintableERC20.sol +13 -0
  67. package/contracts/mocks/PolicyHolderMock.sol +89 -0
  68. package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
  69. package/contracts/mocks/PolicyPoolMock.sol +148 -0
  70. package/contracts/mocks/RiskModuleMock.sol +75 -0
  71. package/contracts/mocks/TestCurrency.sol +35 -0
  72. package/contracts/mocks/TestNFT.sol +23 -0
  73. package/js/test-utils.js +356 -0
  74. package/package.json +2 -2
  75. package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -742
  76. package/build/contracts/Exchange.sol/Exchange.json +0 -591
  77. package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +0 -1112
  78. package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -570
  79. package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +0 -686
  80. package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +0 -50
  81. package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
  82. package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +0 -322
  83. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +0 -571
  84. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +0 -602
  85. package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
  86. package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
  87. package/build/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
  88. package/contracts/AaveAssetManager.sol +0 -298
  89. package/contracts/BaseAssetManager.sol +0 -301
  90. package/contracts/DataTypes.sol +0 -287
  91. package/contracts/Exchange.sol +0 -189
  92. package/contracts/FlightDelayRiskModule.sol +0 -208
  93. package/contracts/PolicyNFT.sol +0 -96
  94. package/contracts/PolicyPoolConfig.sol +0 -247
  95. package/contracts/WadRayMath.sol +0 -135
  96. package/contracts/dependencies/ChainlinkClientUpgradeable.sol +0 -371
  97. package/contracts/extras/IPriceRiskModule.sol +0 -41
  98. package/contracts/extras/PriceRiskModule.sol +0 -243
  99. package/contracts/upgraded/IPolicyNFTv1.sol +0 -15
  100. package/contracts/upgraded/PolicyNFTv1.sol +0 -126
  101. package/interfaces/IAssetManager.sol +0 -23
  102. package/interfaces/IEToken.sol +0 -48
  103. package/interfaces/IExchange.sol +0 -59
  104. package/interfaces/IInsolvencyHook.sol +0 -27
  105. package/interfaces/ILPWhitelist.sol +0 -23
  106. package/interfaces/IPolicyNFT.sol +0 -15
  107. package/interfaces/IPolicyPool.sol +0 -44
  108. package/interfaces/IPolicyPoolConfig.sol +0 -87
  109. package/interfaces/IRiskModule.sol +0 -29
@@ -3,11 +3,11 @@ 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 {IAccessManager} from "./interfaces/IAccessManager.sol";
9
9
  import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
10
- import {WadRayMath} from "./WadRayMath.sol";
10
+ import {WadRayMath} from "./dependencies/WadRayMath.sol";
11
11
 
12
12
  /**
13
13
  * @title Base class for PolicyPool components
@@ -42,32 +42,38 @@ abstract contract PolicyPoolComponent is
42
42
  uint40 internal _lastTweakTimestamp;
43
43
  uint56 internal _lastTweakActions; // bitwise map of applied actions
44
44
 
45
- event GovernanceAction(IPolicyPoolConfig.GovernanceActions indexed action, uint256 value);
46
- event ComponentChanged(IPolicyPoolConfig.GovernanceActions indexed action, address value);
45
+ event GovernanceAction(IAccessManager.GovernanceActions indexed action, uint256 value);
46
+ event ComponentChanged(IAccessManager.GovernanceActions indexed action, address value);
47
47
 
48
48
  modifier onlyPolicyPool() {
49
49
  require(_msgSender() == address(_policyPool), "The caller must be the PolicyPool");
50
50
  _;
51
51
  }
52
52
 
53
- modifier onlyPoolRole3(
54
- bytes32 role1,
55
- bytes32 role2,
56
- bytes32 role3
57
- ) {
58
- if (!hasPoolRole(role1)) {
59
- _policyPool.config().checkRole2(role2, role3, msg.sender);
60
- }
53
+ modifier onlyComponentRole(bytes32 role) {
54
+ _policyPool.access().checkComponentRole(address(this), role, _msgSender(), false);
61
55
  _;
62
56
  }
63
57
 
64
- modifier onlyPoolRole2(bytes32 role1, bytes32 role2) {
65
- _policyPool.config().checkRole2(role1, role2, msg.sender);
58
+ modifier onlyGlobalOrComponentRole(bytes32 role) {
59
+ _policyPool.access().checkComponentRole(address(this), role, _msgSender(), true);
66
60
  _;
67
61
  }
68
62
 
69
- modifier onlyPoolRole(bytes32 role) {
70
- _policyPool.config().checkRole(role, msg.sender);
63
+ modifier onlyGlobalOrComponentRole2(bytes32 role1, bytes32 role2) {
64
+ _policyPool.access().checkComponentRole2(address(this), role1, role2, _msgSender(), true);
65
+ _;
66
+ }
67
+
68
+ modifier onlyGlobalOrComponentRole3(
69
+ bytes32 role1,
70
+ bytes32 role2,
71
+ bytes32 role3
72
+ ) {
73
+ IAccessManager access = _policyPool.access();
74
+ if (!access.hasComponentRole(address(this), role1, _msgSender(), true)) {
75
+ _policyPool.access().checkComponentRole2(address(this), role2, role3, _msgSender(), true);
76
+ }
71
77
  _;
72
78
  }
73
79
 
@@ -82,14 +88,23 @@ abstract contract PolicyPoolComponent is
82
88
  __Pausable_init();
83
89
  }
84
90
 
85
- // solhint-disable-next-line no-empty-blocks
86
- function _authorizeUpgrade(address) internal override onlyPoolRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
91
+ function _authorizeUpgrade(address newImpl)
92
+ internal
93
+ view
94
+ override
95
+ onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
96
+ {
97
+ require(
98
+ IPolicyPoolComponent(newImpl).policyPool() == _policyPool,
99
+ "Can't upgrade changing the PolicyPool!"
100
+ );
101
+ }
87
102
 
88
- function pause() public onlyPoolRole(GUARDIAN_ROLE) {
103
+ function pause() public onlyGlobalOrComponentRole(GUARDIAN_ROLE) {
89
104
  _pause();
90
105
  }
91
106
 
92
- function unpause() public onlyPoolRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
107
+ function unpause() public onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
93
108
  _unpause();
94
109
  }
95
110
 
@@ -102,22 +117,7 @@ abstract contract PolicyPoolComponent is
102
117
  }
103
118
 
104
119
  function hasPoolRole(bytes32 role) internal view returns (bool) {
105
- return _policyPool.config().hasRole(role, msg.sender);
106
- }
107
-
108
- function _isTweakRay(
109
- uint256 oldValue,
110
- uint256 newValue,
111
- uint256 maxTweak
112
- ) internal pure returns (bool) {
113
- if (oldValue == newValue) return true;
114
- if (oldValue == 0) return maxTweak >= WadRayMath.RAY;
115
- if (newValue == 0) return false;
116
- if (oldValue < newValue) {
117
- return (newValue.rayDiv(oldValue) - WadRayMath.RAY) <= maxTweak;
118
- } else {
119
- return (WadRayMath.RAY - newValue.rayDiv(oldValue)) <= maxTweak;
120
- }
120
+ return _policyPool.access().hasComponentRole(address(this), role, _msgSender(), true);
121
121
  }
122
122
 
123
123
  function _isTweakWad(
@@ -139,7 +139,7 @@ abstract contract PolicyPoolComponent is
139
139
  function _validateParameters() internal view virtual {} // Must be reimplemented with specific validations
140
140
 
141
141
  function _parameterChanged(
142
- IPolicyPoolConfig.GovernanceActions action,
142
+ IAccessManager.GovernanceActions action,
143
143
  uint256 value,
144
144
  bool tweak
145
145
  ) internal {
@@ -148,7 +148,7 @@ abstract contract PolicyPoolComponent is
148
148
  emit GovernanceAction(action, value);
149
149
  }
150
150
 
151
- function _componentChanged(IPolicyPoolConfig.GovernanceActions action, address value) internal {
151
+ function _componentChanged(IAccessManager.GovernanceActions action, address value) internal {
152
152
  _validateParameters();
153
153
  emit ComponentChanged(action, value);
154
154
  }
@@ -157,7 +157,7 @@ abstract contract PolicyPoolComponent is
157
157
  return (_lastTweakTimestamp, _lastTweakActions);
158
158
  }
159
159
 
160
- function _registerTweak(IPolicyPoolConfig.GovernanceActions action) internal {
160
+ function _registerTweak(IAccessManager.GovernanceActions action) internal {
161
161
  uint56 actionBitMap = uint56(1 << (uint8(action) - 1));
162
162
  if ((uint40(block.timestamp) - _lastTweakTimestamp) > TWEAK_EXPIRATION) {
163
163
  _lastTweakTimestamp = uint40(block.timestamp);
@@ -0,0 +1,480 @@
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 {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
8
+ import {WadRayMath} from "./dependencies/WadRayMath.sol";
9
+ import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
10
+ import {IEToken} from "./interfaces/IEToken.sol";
11
+ import {Reserve} from "./Reserve.sol";
12
+ import {IAccessManager} from "./interfaces/IAccessManager.sol";
13
+ import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
14
+ import {Policy} from "./Policy.sol";
15
+ import {IEToken} from "./interfaces/IEToken.sol";
16
+ import {IAssetManager} from "./interfaces/IAssetManager.sol";
17
+
18
+ /**
19
+ * @title Ensuro Premiums Account
20
+ * @dev This contract holds the pure premiums of a set of risk modules. The pure premiums is the part of the premium
21
+ * that is expected to cover the losses. The contract keeps track of the pure premiums of the active policies
22
+ * (_activePurePremiums) and the surplus or deficit generated by the finalized policies (pure premiums collected -
23
+ * losses).
24
+ *
25
+ * Collaborates with a junior {EToken} and a senior {EToken} that act as lenders when the premiums aren't enought to
26
+ * cover the losses.
27
+ *
28
+ * @custom:security-contact security@ensuro.co
29
+ * @author Ensuro
30
+ */
31
+ contract PremiumsAccount is IPremiumsAccount, Reserve {
32
+ using Policy for Policy.PolicyData;
33
+ using WadRayMath for uint256;
34
+ using SafeERC20 for IERC20Metadata;
35
+ using SafeCast for uint256;
36
+
37
+ bytes32 public constant WITHDRAW_WON_PREMIUMS_ROLE = keccak256("WITHDRAW_WON_PREMIUMS_ROLE");
38
+
39
+ /**
40
+ * @dev The Junior eToken is the first {EToken} to which the PremiumsAccount will go for credit when it runs out of
41
+ * money. Optional (address(0)).
42
+ */
43
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
44
+ IEToken internal immutable _juniorEtk;
45
+
46
+ /**
47
+ * @dev The Senior eToken is the second {EToken} to which the PremiumsAccount will go for credit, after trying before
48
+ * with the junior eToken, when it runs out of money. Optional (address(0)).
49
+ */
50
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
51
+ IEToken internal immutable _seniorEtk;
52
+
53
+ /**
54
+ * @dev The active pure premiums field keeps track of the pure premiums collected by the active policies of risk
55
+ * modules linked with this PremiumsAccount.
56
+ */
57
+ uint256 internal _activePurePremiums; // sum of pure-premiums of active policies - In Wad
58
+
59
+ /**
60
+ * @dev The surplus field keeps track of the surplus or deficit (when negative) of the actual payouts made by the
61
+ * PremiumsAccount versus the collected pure premiums. On the negative side, it has a limit defined by `_maxDeficit()`,
62
+ * after that limit, internal loans are taken from the eTokens.
63
+ */
64
+ int256 internal _surplus;
65
+
66
+ struct PackedParams {
67
+ uint16 deficitRatio;
68
+ IAssetManager assetManager;
69
+ }
70
+
71
+ PackedParams internal _params;
72
+
73
+ /**
74
+ * Premiums can come in (for "free", without liability) with receiveGrant.
75
+ * And can come out (withdrawed to treasury) with withdrawWonPremiums
76
+ *
77
+ * @param moneyIn Indicates if money came in or out (false).
78
+ * @param value The amount of money received or given
79
+ */
80
+ event WonPremiumsInOut(bool moneyIn, uint256 value);
81
+
82
+ /**
83
+ * @dev Constructor of the contract, sets the immutable fields.
84
+ *
85
+ * @param juniorEtk_ Address of the Junior EToken (first loss lender). `address(0)` if not present.
86
+ * @param seniorEtk_ Address of the Senior EToken (2nd loss lender). `address(0)` if not present.
87
+ */
88
+ /// @custom:oz-upgrades-unsafe-allow constructor
89
+ constructor(
90
+ IPolicyPool policyPool_,
91
+ IEToken juniorEtk_,
92
+ IEToken seniorEtk_
93
+ ) Reserve(policyPool_) {
94
+ _juniorEtk = juniorEtk_;
95
+ _seniorEtk = seniorEtk_;
96
+ }
97
+
98
+ /**
99
+ * @dev Initializes the PremiumsAccount
100
+ */
101
+ function initialize() public initializer {
102
+ __PremiumsAccount_init();
103
+ }
104
+
105
+ /**
106
+ * @dev Initializes the PremiumsAccount (to be called by subclasses)
107
+ */
108
+ // solhint-disable-next-line func-name-mixedcase
109
+ function __PremiumsAccount_init() internal initializer {
110
+ __PolicyPoolComponent_init();
111
+ __PremiumsAccount_init_unchained();
112
+ }
113
+
114
+ /**
115
+ * @dev In the initialization, besides settings the parameters, we approve the spending of funds by the eTokens
116
+ * so we don't need to do it on every repayment operation
117
+ */
118
+ // solhint-disable-next-line func-name-mixedcase
119
+ function __PremiumsAccount_init_unchained() internal initializer {
120
+ /*
121
+ _activePurePremiums = 0;
122
+ */
123
+ if (address(_juniorEtk) != address(0))
124
+ currency().approve(address(_juniorEtk), type(uint256).max);
125
+ if (address(_seniorEtk) != address(0))
126
+ currency().approve(address(_seniorEtk), type(uint256).max);
127
+
128
+ _params = PackedParams({deficitRatio: 1e4, assetManager: IAssetManager(address(0))});
129
+ _validateParameters();
130
+ }
131
+
132
+ function assetManager() public view override returns (IAssetManager) {
133
+ return _params.assetManager;
134
+ }
135
+
136
+ function _setAssetManager(IAssetManager newAM) internal override {
137
+ _params.assetManager = newAM;
138
+ }
139
+
140
+ /**
141
+ * @dev This is called by the {Reserve} base class to record the earnings generated by the asset management.
142
+ *
143
+ * @param earningsOrLosses Indicates the amount earned since last time earnings where recorded.
144
+ * - If positive, repays the lons and accumulates the rest in the surplus.
145
+ * - If negative (losses) substracts it from surplus. It never can exceed _maxDeficit and doesn't takes
146
+ * loans to cover asset losses.
147
+ */
148
+ function _assetEarnings(int256 earningsOrLosses) internal override {
149
+ if (earningsOrLosses > 0) {
150
+ uint256 earnings = uint256(earningsOrLosses);
151
+ if (address(_seniorEtk) != address(0)) earnings = _repayLoan(earnings, _seniorEtk);
152
+ if (address(_juniorEtk) != address(0)) earnings = _repayLoan(earnings, _juniorEtk);
153
+ _storePurePremiumWon(earnings);
154
+ } else {
155
+ require(_payFromPremiums(uint256(-earningsOrLosses)) == 0, "Losses can't exceed maxDeficit");
156
+ }
157
+ }
158
+
159
+ function _validateParameters() internal view override {
160
+ require(
161
+ _params.deficitRatio <= 1e4 && _params.deficitRatio >= 0,
162
+ "Validation: deficitRatio must be <= 1"
163
+ );
164
+ }
165
+
166
+ function purePremiums() external view override returns (uint256) {
167
+ return uint256(int256(_activePurePremiums) + _surplus);
168
+ }
169
+
170
+ /**
171
+ * @dev Returns the total amount of pure premiums that were collected by the active policies of the risk modules
172
+ * linked to this PremiumsAccount.
173
+ */
174
+ function activePurePremiums() external view returns (uint256) {
175
+ return _activePurePremiums;
176
+ }
177
+
178
+ /**
179
+ * @dev Returns the surplus between pure premiums collected and payouts of finalized policies. Returns 0 if no surplus
180
+ * or deficit.
181
+ */
182
+ function wonPurePremiums() external view returns (uint256) {
183
+ return _surplus >= 0 ? uint256(_surplus) : 0;
184
+ }
185
+
186
+ /**
187
+ * @dev Returns the amount of active pure premiums that was used to cover payouts of finalized policies (in excess of
188
+ * collected pure premiums). This is limited by `_maxDeficit()`
189
+ */
190
+ function borrowedActivePP() external view returns (uint256) {
191
+ return _surplus >= 0 ? 0 : uint256(-_surplus);
192
+ }
193
+
194
+ /**
195
+ * @dev Returns the surplus between pure premiums collected and payouts of finalized policies. Losses where more than
196
+ * premiums collected, returns a negative number that indicates the amount of the active pure premiums that was used
197
+ * to cover finalized premiums.
198
+ */
199
+ function surplus() external view returns (int256) {
200
+ return _surplus;
201
+ }
202
+
203
+ function seniorEtk() external view override returns (IEToken) {
204
+ return _seniorEtk;
205
+ }
206
+
207
+ function juniorEtk() external view override returns (IEToken) {
208
+ return _juniorEtk;
209
+ }
210
+
211
+ /**
212
+ * @dev Returns the maximum deficit that's supported by the PremiumsAccount. If more money is needed, it must take
213
+ * loans from the eTokens. The value is calculated as a fraction of the active pure premiums. The fraction is
214
+ * regulated by the `deficitRatio` parameter that indicates the percentage of the active pure premiums that can be
215
+ * used to cover payouts of finalized policies. In many cases is fine to use the active pure premiums to cover the
216
+ * losses because in most cases the policies with payout are triggered long time before the policies without payout.
217
+ * But this also can be dangerous because it can be postponing the losses that should impact on liquidity providers.
218
+ *
219
+ * @param ratio The ratio used in the calculation of the deficit. It's the deficitRatio parameter (whether the current
220
+ * one or the new one when it's being modified).
221
+ */
222
+ function _maxDeficit(uint256 ratio) internal view returns (int256) {
223
+ return -int256(_activePurePremiums.wadMul(ratio));
224
+ }
225
+
226
+ /**
227
+ * @dev Returns the percentage of the active pure premiums that can be used to cover losses of finalized policies.
228
+ */
229
+ function deficitRatio() public view returns (uint256) {
230
+ return uint256(_params.deficitRatio) * 1e14; // 4 -> 18 decimals
231
+ }
232
+
233
+ /**
234
+ * @dev Changes the `deficitRatio` parameter.
235
+ *
236
+ * Requirements:
237
+ * - onlyGlobalOrComponentRole(LEVEL2_ROLE)
238
+ *
239
+ * Events:
240
+ * - Emits GovernanceAction with action = setDeficitRatio or setDeficitRatioWithAdjustment if an adjustment was made.
241
+ *
242
+ * @param adjustment If true and the new ratio leaves `_surplus < -_maxDeficit()`, if adjusts the _surplus to the new
243
+ * `_maxDeficit()` and borrows the difference from the eTokens.
244
+ * If false and the new ratio leaves `_surplus < -_maxDeficit()`, the operation is reverted.
245
+ */
246
+ function setDeficitRatio(uint256 newRatio, bool adjustment)
247
+ external
248
+ onlyComponentRole(LEVEL2_ROLE)
249
+ {
250
+ require(newRatio <= 1e18 && newRatio >= 0, "Validation: deficitRatio must be <= 1");
251
+ int256 maxDeficit = _maxDeficit(newRatio);
252
+ require(adjustment || _surplus >= maxDeficit, "Validation: surplus must be >= maxDeficit");
253
+ IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setDeficitRatio;
254
+ if (_surplus < maxDeficit) {
255
+ // Do the adjustment
256
+ uint256 borrow = uint256(-_surplus + maxDeficit);
257
+ _surplus = maxDeficit;
258
+ _borrowFromEtk(borrow, address(this), address(_juniorEtk) != address(0));
259
+ action = IAccessManager.GovernanceActions.setDeficitRatioWithAdjustment;
260
+ }
261
+ _params.deficitRatio = (newRatio / 1e14).toUint16();
262
+ _parameterChanged(action, newRatio, false);
263
+ }
264
+
265
+ /**
266
+ * @dev Internal function called when money in the PremiumsAccount is not enought and we need to borrow from the
267
+ * eTokens.
268
+ *
269
+ * @param borrow The amount to borrow.
270
+ * @param receiver The address that will receive the money of the loan. Usually is the policy holder if this is called
271
+ * in the context of a policy payout.
272
+ * @param jrEtk If true it indicates that the loan is asked first from the junior eToken.
273
+ */
274
+ function _borrowFromEtk(
275
+ uint256 borrow,
276
+ address receiver,
277
+ bool jrEtk
278
+ ) internal {
279
+ uint256 left;
280
+ if (jrEtk) {
281
+ // Consume Junior Pool until exhausted
282
+ left = _juniorEtk.internalLoan(borrow, receiver, false);
283
+ } else {
284
+ left = borrow;
285
+ }
286
+ if (left > NEGLIGIBLE_AMOUNT) {
287
+ // Consume Senior Pool only up to SCR
288
+ left = _seniorEtk.internalLoan(left, receiver, true);
289
+ require(left <= NEGLIGIBLE_AMOUNT, "Don't know where to take the rest of the money");
290
+ }
291
+ }
292
+
293
+ /**
294
+ * @dev Updates the `_surplus` field with the payment made. Since the _surplus can never exceed `_maxDeficit()`,
295
+ * returns the remaining amount in case something can't be paid from the PremiumsAccount.
296
+ *
297
+ * @param toPay The amount to pay.
298
+ * @return The amount that couldn't be paid from the premiums account.
299
+ */
300
+ function _payFromPremiums(uint256 toPay) internal returns (uint256) {
301
+ int256 newSurplus = _surplus - int256(toPay);
302
+ int256 maxDeficit = _maxDeficit(deficitRatio());
303
+ if (newSurplus >= maxDeficit) {
304
+ _surplus = newSurplus;
305
+ return 0;
306
+ }
307
+ _surplus = maxDeficit;
308
+ return uint256(-newSurplus + maxDeficit);
309
+ }
310
+
311
+ /**
312
+ * @dev Stores an earned pure premium. Adds to the surplus, increasing the surplus if it was positive or reducing the
313
+ * deficit if it was negative.
314
+ *
315
+ * @param purePremiumWon The amount earned
316
+ */
317
+ function _storePurePremiumWon(uint256 purePremiumWon) internal {
318
+ if (purePremiumWon == 0) return;
319
+ _surplus += int256(purePremiumWon);
320
+ }
321
+
322
+ /**
323
+ *
324
+ * Endpoint to receive "free money" and inject that money into the premium pool.
325
+ *
326
+ * Can be used for example if the PolicyPool subscribes an excess loss policy with other company.
327
+ *
328
+ * Requirements:
329
+ * - The sender needs to approve the spending of `currency()` by this contract.
330
+ *
331
+ * Events:
332
+ * - Emits {WonPremiumsInOut} with moneyIn = true
333
+ *
334
+ * @param amount The amount to be transferred.
335
+ */
336
+ function receiveGrant(uint256 amount) external {
337
+ currency().safeTransferFrom(_msgSender(), address(this), amount);
338
+ _storePurePremiumWon(amount);
339
+ emit WonPremiumsInOut(true, amount);
340
+ }
341
+
342
+ /**
343
+ *
344
+ * Withdraws excess premiums (surplus) to the destination.
345
+ *
346
+ * This might be needed in some cases for example if we are deprecating the protocol or the excess premiums
347
+ * are needed to compensate something. Shouldn't be used. Can be disabled revoking role WITHDRAW_WON_PREMIUMS_ROLE
348
+ *
349
+ * Requirements:
350
+ * - onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
351
+ * - _surplus > 0
352
+ *
353
+ * Events:
354
+ * - Emits {WonPremiumsInOut} with moneyIn = false
355
+ *
356
+ * @param amount The amount to withdraw
357
+ * @param destination The address that will receive the transferred funds.
358
+ * @return Returns the actual amount withdrawn.
359
+ */
360
+ function withdrawWonPremiums(uint256 amount, address destination)
361
+ external
362
+ onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
363
+ returns (uint256)
364
+ {
365
+ if (_surplus <= 0) {
366
+ amount = 0;
367
+ } else {
368
+ amount = Math.min(amount, uint256(_surplus));
369
+ }
370
+ require(amount > 0, "No premiums to withdraw");
371
+ _surplus -= int256(amount);
372
+ _transferTo(destination, amount);
373
+ emit WonPremiumsInOut(false, amount);
374
+ return amount;
375
+ }
376
+
377
+ function policyCreated(Policy.PolicyData memory policy)
378
+ external
379
+ override
380
+ onlyPolicyPool
381
+ whenNotPaused
382
+ {
383
+ _activePurePremiums += policy.purePremium;
384
+ if (policy.jrScr > 0) _juniorEtk.lockScr(policy.jrScr, policy.jrInterestRate());
385
+ if (policy.srScr > 0) _seniorEtk.lockScr(policy.srScr, policy.srInterestRate());
386
+ }
387
+
388
+ function policyResolvedWithPayout(
389
+ address policyHolder,
390
+ Policy.PolicyData memory policy,
391
+ uint256 payout
392
+ ) external override onlyPolicyPool whenNotPaused {
393
+ _activePurePremiums -= policy.purePremium;
394
+ if (policy.purePremium >= payout) {
395
+ uint256 purePremiumWon = policy.purePremium - payout;
396
+ if (address(_seniorEtk) != address(0))
397
+ purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
398
+ if (address(_juniorEtk) != address(0))
399
+ purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
400
+ _storePurePremiumWon(purePremiumWon);
401
+ _unlockScr(policy);
402
+ _transferTo(policyHolder, payout);
403
+ } else {
404
+ uint256 borrowFromScr = _payFromPremiums(payout - policy.purePremium);
405
+ _unlockScr(policy);
406
+ if (borrowFromScr > 0) {
407
+ _borrowFromEtk(borrowFromScr, policyHolder, policy.jrScr > 0);
408
+ }
409
+ _transferTo(policyHolder, payout - borrowFromScr);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * @dev Internal function that calls the eTokens to lock the solvency capital when the policy is created.
415
+ *
416
+ * @param policy The policy created
417
+ */
418
+ function _unlockScr(Policy.PolicyData memory policy) internal {
419
+ if (policy.jrScr > 0) {
420
+ _juniorEtk.unlockScr(
421
+ policy.jrScr,
422
+ policy.jrInterestRate(),
423
+ int256(policy.jrCoc) - int256(policy.jrAccruedInterest())
424
+ );
425
+ }
426
+ if (policy.srScr > 0) {
427
+ _seniorEtk.unlockScr(
428
+ policy.srScr,
429
+ policy.srInterestRate(),
430
+ int256(policy.srCoc) - int256(policy.srAccruedInterest())
431
+ );
432
+ }
433
+ }
434
+
435
+ /**
436
+ * @dev Internal function that repays a loan taken (if any outstanding) from the an eToken
437
+ *
438
+ * @param purePremiumWon The amount earned and available for loan repayment.
439
+ * @param etk The eToken with the potential debt
440
+ * @return The excess amount of the purePremiumWon that wasn't used for the loan repayment.
441
+ */
442
+ function _repayLoan(uint256 purePremiumWon, IEToken etk) internal returns (uint256) {
443
+ if (purePremiumWon < NEGLIGIBLE_AMOUNT) return purePremiumWon;
444
+ uint256 borrowedFromEtk = etk.getLoan(address(this));
445
+ if (borrowedFromEtk == 0) return purePremiumWon;
446
+ uint256 repayAmount = Math.min(purePremiumWon, borrowedFromEtk);
447
+
448
+ // If not enought liquidity, it deinvests from the asset manager
449
+ if (currency().balanceOf(address(this)) < repayAmount) {
450
+ _refillWallet(repayAmount);
451
+ }
452
+ etk.repayLoan(repayAmount, address(this));
453
+ return purePremiumWon - repayAmount;
454
+ }
455
+
456
+ function policyExpired(Policy.PolicyData memory policy)
457
+ external
458
+ override
459
+ onlyPolicyPool
460
+ whenNotPaused
461
+ {
462
+ uint256 purePremiumWon = policy.purePremium;
463
+ _activePurePremiums -= purePremiumWon;
464
+
465
+ // If negative _activePurePremiums, repay this first (shouldn't happen)
466
+ int256 maxDeficit = _maxDeficit(deficitRatio());
467
+ if (_surplus < maxDeficit) {
468
+ // Covers the excess of deficit first
469
+ purePremiumWon -= uint256(-_surplus + maxDeficit);
470
+ _surplus = maxDeficit;
471
+ }
472
+
473
+ if (address(_seniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
474
+ if (address(_juniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _juniorEtk);
475
+
476
+ // Finally store purePremiumWon
477
+ _storePurePremiumWon(purePremiumWon);
478
+ _unlockScr(policy);
479
+ }
480
+ }