@ensuro/core 1.2.6 → 2.0.0-beta2
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.
- package/README.md +49 -17
- package/build/contracts/EToken.sol/EToken.json +163 -173
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +112 -315
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +34 -2
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +16 -3
- package/build/contracts/PolicyPool.sol/PolicyPool.json +105 -351
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +32 -0
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +77 -98
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +761 -0
- package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +23 -191
- package/build/contracts/RiskModule.sol/RiskModule.json +94 -302
- package/build/contracts/TimeScaled.sol/TimeScaled.json +24 -0
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +142 -325
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +15 -2
- package/build/contracts/dependencies/ERC1967Proxy.sol/ERC1967Proxy.json +64 -0
- package/build/{interfaces/IExchange.sol/IExchange.json → contracts/dependencies/IERC20Metadata.sol/IERC20Metadata.json} +83 -79
- package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +32 -97
- package/build/{interfaces → contracts/interfaces}/ILPWhitelist.sol/ILPWhitelist.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyHolder.sol/IPolicyHolder.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyNFT.sol/IPolicyNFT.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPool.sol/IPolicyPool.json +121 -108
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +20 -49
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +302 -0
- package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +43 -0
- package/build/{interfaces/IInsolvencyHook.sol/IInsolvencyHook.json → contracts/mocks/IMintableERC20.sol/IMintableERC20.json} +13 -8
- package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +370 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +202 -0
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +603 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +16 -3
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +16 -3
- package/contracts/EToken.sol +210 -267
- package/contracts/FlightDelayRiskModule.sol +30 -21
- package/contracts/LPManualWhitelist.sol +4 -4
- package/contracts/Policy.sol +48 -44
- package/contracts/PolicyNFT.sol +2 -2
- package/contracts/PolicyPool.sol +114 -467
- package/contracts/PolicyPoolComponent.sol +14 -3
- package/contracts/PolicyPoolConfig.sol +29 -91
- package/contracts/PremiumsAccount.sol +274 -0
- package/contracts/Reserve.sol +34 -0
- package/contracts/RiskModule.sol +216 -164
- package/contracts/TimeScaled.sol +134 -0
- package/contracts/TrustfulRiskModule.sol +23 -21
- package/contracts/dependencies/ERC1967Proxy.sol +19 -0
- package/contracts/dependencies/IERC20Metadata.sol +19 -0
- package/contracts/interfaces/IEToken.sol +172 -0
- package/{interfaces → contracts/interfaces}/ILPWhitelist.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyNFT.sol +0 -0
- package/contracts/interfaces/IPolicyPool.sol +138 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +0 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolConfig.sol +31 -22
- package/contracts/interfaces/IPremiumsAccount.sol +71 -0
- package/contracts/interfaces/IRiskModule.sol +60 -0
- package/contracts/mocks/ForwardProxy.sol +66 -0
- package/contracts/mocks/IMintableERC20.sol +13 -0
- package/contracts/mocks/LinkTokenMock.sol +30 -0
- package/contracts/mocks/PolicyHolderMock.sol +68 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
- package/contracts/mocks/PolicyPoolMock.sol +122 -0
- package/contracts/mocks/TestCurrency.sol +35 -0
- package/contracts/mocks/TestNFT.sol +23 -0
- package/contracts/upgraded/PolicyNFTv1.sol +1 -1
- package/js/test-utils.js +278 -0
- package/package.json +2 -2
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -723
- package/build/contracts/DataTypes.sol/DataTypes.json +0 -10
- package/build/contracts/Exchange.sol/Exchange.json +0 -546
- package/build/contracts/extras/IPriceRiskModule.sol/IPriceRiskModule.json +0 -253
- package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1036
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
- package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
- package/contracts/AaveAssetManager.sol +0 -298
- package/contracts/BaseAssetManager.sol +0 -301
- package/contracts/DataTypes.sol +0 -287
- package/contracts/Exchange.sol +0 -173
- package/contracts/extras/IPriceRiskModule.sol +0 -41
- package/contracts/extras/PriceRiskModule.sol +0 -243
- package/interfaces/IAssetManager.sol +0 -23
- package/interfaces/IEToken.sol +0 -48
- package/interfaces/IExchange.sol +0 -59
- package/interfaces/IInsolvencyHook.sol +0 -27
- package/interfaces/IPolicyPool.sol +0 -44
- 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 "
|
|
7
|
-
import {IPolicyPoolComponent} from "
|
|
8
|
-
import {IPolicyPoolConfig} from "
|
|
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
|
|
|
@@ -43,6 +43,7 @@ abstract contract PolicyPoolComponent is
|
|
|
43
43
|
uint56 internal _lastTweakActions; // bitwise map of applied actions
|
|
44
44
|
|
|
45
45
|
event GovernanceAction(IPolicyPoolConfig.GovernanceActions indexed action, uint256 value);
|
|
46
|
+
event ComponentChanged(IPolicyPoolConfig.GovernanceActions indexed action, address value);
|
|
46
47
|
|
|
47
48
|
modifier onlyPolicyPool() {
|
|
48
49
|
require(_msgSender() == address(_policyPool), "The caller must be the PolicyPool");
|
|
@@ -70,6 +71,11 @@ abstract contract PolicyPoolComponent is
|
|
|
70
71
|
_;
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
modifier onlyComponentRole(bytes32 role) {
|
|
75
|
+
_policyPool.config().checkComponentRole(address(this), role, msg.sender);
|
|
76
|
+
_;
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
74
80
|
constructor(IPolicyPool policyPool_) {
|
|
75
81
|
_policyPool = policyPool_;
|
|
@@ -147,6 +153,11 @@ abstract contract PolicyPoolComponent is
|
|
|
147
153
|
emit GovernanceAction(action, value);
|
|
148
154
|
}
|
|
149
155
|
|
|
156
|
+
function _componentChanged(IPolicyPoolConfig.GovernanceActions action, address value) internal {
|
|
157
|
+
_validateParameters();
|
|
158
|
+
emit ComponentChanged(action, value);
|
|
159
|
+
}
|
|
160
|
+
|
|
150
161
|
function lastTweak() external view returns (uint40, uint56) {
|
|
151
162
|
return (_lastTweakTimestamp, _lastTweakActions);
|
|
152
163
|
}
|
|
@@ -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 {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|