@ensuro/core 2.0.0-beta1 → 2.0.0-beta11
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 +36 -14
- package/build/contracts/AccessManager.sol/AccessManager.json +564 -0
- package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +238 -0
- package/build/contracts/EToken.sol/EToken.json +147 -46
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +23 -4
- package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +222 -0
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyPool.sol/PolicyPool.json +437 -61
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +21 -2
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +142 -16
- package/build/contracts/Reserve.sol/Reserve.json +85 -8
- package/build/contracts/RiskModule.sol/RiskModule.json +21 -2
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +979 -0
- package/build/contracts/TimeScaled.sol/TimeScaled.json +3 -17
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +24 -5
- package/build/contracts/{WadRayMath.sol → dependencies/WadRayMath.sol}/WadRayMath.json +3 -3
- package/build/contracts/interfaces/{IPolicyPoolConfig.sol/IPolicyPoolConfig.json → IAccessManager.sol/IAccessManager.json} +77 -59
- package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +128 -0
- package/build/contracts/interfaces/IEToken.sol/IEToken.json +13 -0
- package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +40 -16
- package/build/contracts/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +19 -0
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +13 -0
- package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
- package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +180 -0
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +28 -2
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +21 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +118 -19
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +6 -6
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +783 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +2 -2
- package/contracts/AccessManager.sol +132 -0
- package/contracts/ERC4626AssetManager.sol +55 -0
- package/contracts/EToken.sol +208 -102
- package/contracts/LPManualWhitelist.sol +19 -3
- package/contracts/LiquidityThresholdAssetManager.sol +175 -0
- package/contracts/Policy.sol +5 -3
- package/contracts/PolicyPool.sol +381 -116
- package/contracts/PolicyPoolComponent.sol +61 -44
- package/contracts/PremiumsAccount.sol +324 -86
- package/contracts/Reserve.sol +199 -4
- package/contracts/RiskModule.sol +62 -31
- package/contracts/SignedQuoteRiskModule.sol +248 -0
- package/contracts/TimeScaled.sol +19 -15
- package/contracts/TrustfulRiskModule.sol +69 -2
- package/contracts/dependencies/WadRayMath.sol +126 -0
- package/contracts/interfaces/IAccessManager.sol +148 -0
- package/contracts/interfaces/IAssetManager.sol +89 -0
- package/contracts/interfaces/IEToken.sol +25 -2
- package/contracts/interfaces/ILPWhitelist.sol +17 -0
- package/contracts/interfaces/IPolicyPool.sol +21 -14
- package/contracts/interfaces/IPolicyPoolComponent.sol +5 -1
- package/contracts/interfaces/IPremiumsAccount.sol +5 -0
- package/contracts/interfaces/IRiskModule.sol +67 -4
- package/contracts/mocks/FixedRateVault.sol +85 -0
- package/contracts/mocks/InterfaceIdCalculator.sol +32 -0
- package/contracts/mocks/PolicyHolderMock.sol +21 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +10 -0
- package/contracts/mocks/PolicyPoolMock.sol +41 -15
- package/contracts/mocks/RiskModuleMock.sol +75 -0
- package/js/deploy.js +704 -0
- package/js/test-utils.js +339 -159
- package/package.json +1 -1
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +0 -890
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -583
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +0 -691
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +0 -63
- package/build/contracts/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
- package/build/contracts/mocks/LinkTokenMock.sol/LinkTokenMock.json +0 -370
- package/build/contracts/mocks/TestCurrencyUUPS.sol/TestCurrencyUUPS.json +0 -353
- package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +0 -322
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +0 -584
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +0 -615
- package/contracts/FlightDelayRiskModule.sol +0 -217
- package/contracts/PolicyNFT.sol +0 -96
- package/contracts/PolicyPoolConfig.sol +0 -204
- package/contracts/WadRayMath.sol +0 -135
- package/contracts/dependencies/ChainlinkClientUpgradeable.sol +0 -371
- package/contracts/interfaces/IPolicyNFT.sol +0 -15
- package/contracts/interfaces/IPolicyPoolConfig.sol +0 -96
- package/contracts/mocks/LinkTokenMock.sol +0 -30
- package/contracts/upgraded/IPolicyNFTv1.sol +0 -15
- package/contracts/upgraded/PolicyNFTv1.sol +0 -126
|
@@ -4,17 +4,27 @@ pragma solidity ^0.8.0;
|
|
|
4
4
|
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
|
|
5
5
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
6
6
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
7
|
-
import {
|
|
7
|
+
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
|
|
8
|
+
import {WadRayMath} from "./dependencies/WadRayMath.sol";
|
|
8
9
|
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
9
10
|
import {IEToken} from "./interfaces/IEToken.sol";
|
|
10
11
|
import {Reserve} from "./Reserve.sol";
|
|
12
|
+
import {IAccessManager} from "./interfaces/IAccessManager.sol";
|
|
11
13
|
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
12
14
|
import {Policy} from "./Policy.sol";
|
|
13
15
|
import {IEToken} from "./interfaces/IEToken.sol";
|
|
16
|
+
import {IAssetManager} from "./interfaces/IAssetManager.sol";
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* @title Ensuro Premiums Account
|
|
17
|
-
* @dev This contract holds the premiums of a set of risk modules
|
|
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 enough to
|
|
26
|
+
* cover the losses.
|
|
27
|
+
*
|
|
18
28
|
* @custom:security-contact security@ensuro.co
|
|
19
29
|
* @author Ensuro
|
|
20
30
|
*/
|
|
@@ -22,26 +32,62 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
22
32
|
using Policy for Policy.PolicyData;
|
|
23
33
|
using WadRayMath for uint256;
|
|
24
34
|
using SafeERC20 for IERC20Metadata;
|
|
35
|
+
using SafeCast for uint256;
|
|
25
36
|
|
|
26
37
|
bytes32 public constant WITHDRAW_WON_PREMIUMS_ROLE = keccak256("WITHDRAW_WON_PREMIUMS_ROLE");
|
|
38
|
+
uint256 internal constant FOUR_DECIMAL_TO_WAD = 1e14;
|
|
39
|
+
uint16 internal constant HUNDRED_PERCENT = 1e4;
|
|
27
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @dev The Junior eToken is the first {EToken} to which the PremiumsAccount will go for credit when it runs out of
|
|
43
|
+
* money. Optional (address(0)).
|
|
44
|
+
*/
|
|
28
45
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
29
46
|
IEToken internal immutable _juniorEtk;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @dev The Senior eToken is the second {EToken} to which the PremiumsAccount will go for credit, after trying before
|
|
50
|
+
* with the junior eToken, when it runs out of money. Optional (address(0)).
|
|
51
|
+
*/
|
|
30
52
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
31
53
|
IEToken internal immutable _seniorEtk;
|
|
32
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @dev The active pure premiums field keeps track of the pure premiums collected by the active policies of risk
|
|
57
|
+
* modules linked with this PremiumsAccount.
|
|
58
|
+
*/
|
|
33
59
|
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
60
|
|
|
37
|
-
|
|
38
|
-
*
|
|
61
|
+
/**
|
|
62
|
+
* @dev The surplus field keeps track of the surplus or deficit (when negative) of the actual payouts made by the
|
|
63
|
+
* PremiumsAccount versus the collected pure premiums. On the negative side, it has a limit defined by `_maxDeficit()`,
|
|
64
|
+
* after that limit, internal loans are taken from the eTokens.
|
|
65
|
+
*/
|
|
66
|
+
int256 internal _surplus;
|
|
67
|
+
|
|
68
|
+
struct PackedParams {
|
|
69
|
+
uint16 deficitRatio;
|
|
70
|
+
IAssetManager assetManager;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
PackedParams internal _params;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Premiums can come in (for "free", without liability) with receiveGrant.
|
|
39
77
|
* And can come out (withdrawed to treasury) with withdrawWonPremiums
|
|
78
|
+
*
|
|
79
|
+
* @param moneyIn Indicates if money came in or out (false).
|
|
80
|
+
* @param value The amount of money received or given
|
|
40
81
|
*/
|
|
41
82
|
event WonPremiumsInOut(bool moneyIn, uint256 value);
|
|
42
83
|
|
|
84
|
+
/**
|
|
85
|
+
* @dev Constructor of the contract, sets the immutable fields.
|
|
86
|
+
*
|
|
87
|
+
* @param juniorEtk_ Address of the Junior EToken (first loss lender). `address(0)` if not present.
|
|
88
|
+
* @param seniorEtk_ Address of the Senior EToken (2nd loss lender). `address(0)` if not present.
|
|
89
|
+
*/
|
|
43
90
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
44
|
-
// solhint-disable-next-line no-empty-blocks
|
|
45
91
|
constructor(
|
|
46
92
|
IPolicyPool policyPool_,
|
|
47
93
|
IEToken juniorEtk_,
|
|
@@ -52,52 +98,110 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
52
98
|
}
|
|
53
99
|
|
|
54
100
|
/**
|
|
55
|
-
* @dev
|
|
101
|
+
* @dev Initializes the PremiumsAccount
|
|
56
102
|
*/
|
|
57
103
|
function initialize() public initializer {
|
|
58
104
|
__PremiumsAccount_init();
|
|
59
105
|
}
|
|
60
106
|
|
|
61
107
|
/**
|
|
62
|
-
* @dev Initializes the PremiumsAccount
|
|
108
|
+
* @dev Initializes the PremiumsAccount (to be called by subclasses)
|
|
63
109
|
*/
|
|
64
110
|
// solhint-disable-next-line func-name-mixedcase
|
|
65
|
-
function __PremiumsAccount_init() internal
|
|
66
|
-
|
|
111
|
+
function __PremiumsAccount_init() internal onlyInitializing {
|
|
112
|
+
__Reserve_init();
|
|
67
113
|
__PremiumsAccount_init_unchained();
|
|
68
114
|
}
|
|
69
115
|
|
|
70
116
|
// solhint-disable-next-line func-name-mixedcase
|
|
71
|
-
function __PremiumsAccount_init_unchained() internal
|
|
117
|
+
function __PremiumsAccount_init_unchained() internal onlyInitializing {
|
|
72
118
|
/*
|
|
73
119
|
_activePurePremiums = 0;
|
|
74
|
-
_borrowedActivePP = 0;
|
|
75
|
-
_wonPurePremiums = 0;
|
|
76
120
|
*/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
121
|
+
_params = PackedParams({
|
|
122
|
+
deficitRatio: HUNDRED_PERCENT,
|
|
123
|
+
assetManager: IAssetManager(address(0))
|
|
124
|
+
});
|
|
81
125
|
_validateParameters();
|
|
82
126
|
}
|
|
83
127
|
|
|
84
|
-
|
|
85
|
-
|
|
128
|
+
/**
|
|
129
|
+
* @dev See {IERC165-supportsInterface}.
|
|
130
|
+
*/
|
|
131
|
+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
|
|
132
|
+
return
|
|
133
|
+
super.supportsInterface(interfaceId) || interfaceId == type(IPremiumsAccount).interfaceId;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function assetManager() public view override returns (IAssetManager) {
|
|
137
|
+
return _params.assetManager;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function _setAssetManager(IAssetManager newAM) internal override {
|
|
141
|
+
_params.assetManager = newAM;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @dev This is called by the {Reserve} base class to record the earnings generated by the asset management.
|
|
146
|
+
*
|
|
147
|
+
* @param earningsOrLosses Indicates the amount earned since last time earnings where recorded.
|
|
148
|
+
* - If positive, repays the loans and accumulates the rest in the surplus.
|
|
149
|
+
* - If negative (losses) substracts it from surplus. It never can exceed _maxDeficit and doesn't takes
|
|
150
|
+
* loans to cover asset losses.
|
|
151
|
+
*/
|
|
152
|
+
function _assetEarnings(int256 earningsOrLosses) internal override {
|
|
153
|
+
if (earningsOrLosses > 0) {
|
|
154
|
+
uint256 earnings = uint256(earningsOrLosses);
|
|
155
|
+
if (address(_seniorEtk) != address(0)) earnings = _repayLoan(earnings, _seniorEtk);
|
|
156
|
+
if (address(_juniorEtk) != address(0)) earnings = _repayLoan(earnings, _juniorEtk);
|
|
157
|
+
_storePurePremiumWon(earnings);
|
|
158
|
+
} else {
|
|
159
|
+
require(_payFromPremiums(uint256(-earningsOrLosses)) == 0, "Losses can't exceed maxDeficit");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function _validateParameters() internal view override {
|
|
164
|
+
require(
|
|
165
|
+
_params.deficitRatio <= HUNDRED_PERCENT && _params.deficitRatio >= 0,
|
|
166
|
+
"Validation: deficitRatio must be <= 1"
|
|
167
|
+
);
|
|
168
|
+
}
|
|
86
169
|
|
|
87
|
-
function purePremiums()
|
|
88
|
-
return _activePurePremiums +
|
|
170
|
+
function purePremiums() external view override returns (uint256) {
|
|
171
|
+
return uint256(int256(_activePurePremiums) + _surplus);
|
|
89
172
|
}
|
|
90
173
|
|
|
174
|
+
/**
|
|
175
|
+
* @dev Returns the total amount of pure premiums that were collected by the active policies of the risk modules
|
|
176
|
+
* linked to this PremiumsAccount.
|
|
177
|
+
*/
|
|
91
178
|
function activePurePremiums() external view returns (uint256) {
|
|
92
179
|
return _activePurePremiums;
|
|
93
180
|
}
|
|
94
181
|
|
|
182
|
+
/**
|
|
183
|
+
* @dev Returns the surplus between pure premiums collected and payouts of finalized policies. Returns 0 if no surplus
|
|
184
|
+
* or deficit.
|
|
185
|
+
*/
|
|
95
186
|
function wonPurePremiums() external view returns (uint256) {
|
|
96
|
-
return
|
|
187
|
+
return _surplus >= 0 ? uint256(_surplus) : 0;
|
|
97
188
|
}
|
|
98
189
|
|
|
190
|
+
/**
|
|
191
|
+
* @dev Returns the amount of active pure premiums that was used to cover payouts of finalized policies (in excess of
|
|
192
|
+
* collected pure premiums). This is limited by `_maxDeficit()`
|
|
193
|
+
*/
|
|
99
194
|
function borrowedActivePP() external view returns (uint256) {
|
|
100
|
-
return
|
|
195
|
+
return _surplus >= 0 ? 0 : uint256(-_surplus);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @dev Returns the surplus between pure premiums collected and payouts of finalized policies. Losses where more than
|
|
200
|
+
* premiums collected, returns a negative number that indicates the amount of the active pure premiums that was used
|
|
201
|
+
* to cover finalized premiums.
|
|
202
|
+
*/
|
|
203
|
+
function surplus() external view returns (int256) {
|
|
204
|
+
return _surplus;
|
|
101
205
|
}
|
|
102
206
|
|
|
103
207
|
function seniorEtk() external view override returns (IEToken) {
|
|
@@ -108,40 +212,125 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
108
212
|
return _juniorEtk;
|
|
109
213
|
}
|
|
110
214
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
215
|
+
/**
|
|
216
|
+
* @dev Returns the maximum deficit that's supported by the PremiumsAccount. If more money is needed, it must take
|
|
217
|
+
* loans from the eTokens. The value is calculated as a fraction of the active pure premiums. The fraction is
|
|
218
|
+
* regulated by the `deficitRatio` parameter that indicates the percentage of the active pure premiums that can be
|
|
219
|
+
* used to cover payouts of finalized policies. In many cases is fine to use the active pure premiums to cover the
|
|
220
|
+
* losses because in most cases the policies with payout are triggered long time before the policies without payout.
|
|
221
|
+
* But this also can be dangerous because it can be postponing the losses that should impact on liquidity providers.
|
|
222
|
+
*
|
|
223
|
+
* @param ratio The ratio used in the calculation of the deficit. It's the deficitRatio parameter (whether the current
|
|
224
|
+
* one or the new one when it's being modified).
|
|
225
|
+
*/
|
|
226
|
+
function _maxDeficit(uint256 ratio) internal view returns (int256) {
|
|
227
|
+
return -int256(_activePurePremiums.wadMul(ratio));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @dev Returns the percentage of the active pure premiums that can be used to cover losses of finalized policies.
|
|
232
|
+
*/
|
|
233
|
+
function deficitRatio() public view returns (uint256) {
|
|
234
|
+
return uint256(_params.deficitRatio) * FOUR_DECIMAL_TO_WAD; // 4 -> 18 decimals
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @dev Changes the `deficitRatio` parameter.
|
|
239
|
+
*
|
|
240
|
+
* Requirements:
|
|
241
|
+
* - onlyGlobalOrComponentRole(LEVEL2_ROLE)
|
|
242
|
+
*
|
|
243
|
+
* Events:
|
|
244
|
+
* - Emits GovernanceAction with action = setDeficitRatio or setDeficitRatioWithAdjustment if an adjustment was made.
|
|
245
|
+
*
|
|
246
|
+
* @param adjustment If true and the new ratio leaves `_surplus < -_maxDeficit()`, it adjusts the _surplus to the new
|
|
247
|
+
* `_maxDeficit()` and borrows the difference from the eTokens.
|
|
248
|
+
* If false and the new ratio leaves `_surplus < -_maxDeficit()`, the operation is reverted.
|
|
249
|
+
*/
|
|
250
|
+
function setDeficitRatio(uint256 newRatio, bool adjustment)
|
|
251
|
+
external
|
|
252
|
+
onlyComponentRole(LEVEL2_ROLE)
|
|
253
|
+
{
|
|
254
|
+
require(newRatio <= 1e18, "Validation: deficitRatio must be <= 1");
|
|
255
|
+
|
|
256
|
+
uint16 truncatedRatio = (newRatio / FOUR_DECIMAL_TO_WAD).toUint16();
|
|
257
|
+
require(
|
|
258
|
+
uint256(truncatedRatio) * FOUR_DECIMAL_TO_WAD == newRatio,
|
|
259
|
+
"Validation: only up to 4 decimals allowed"
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
int256 maxDeficit = _maxDeficit(newRatio);
|
|
263
|
+
require(adjustment || _surplus >= maxDeficit, "Validation: surplus must be >= maxDeficit");
|
|
264
|
+
|
|
265
|
+
IAccessManager.GovernanceActions action = IAccessManager.GovernanceActions.setDeficitRatio;
|
|
266
|
+
if (_surplus < maxDeficit) {
|
|
267
|
+
// Do the adjustment
|
|
268
|
+
uint256 borrow = uint256(-_surplus + maxDeficit);
|
|
269
|
+
_surplus = maxDeficit;
|
|
270
|
+
_borrowFromEtk(borrow, address(this), address(_juniorEtk) != address(0));
|
|
271
|
+
action = IAccessManager.GovernanceActions.setDeficitRatioWithAdjustment;
|
|
128
272
|
}
|
|
129
|
-
|
|
273
|
+
_params.deficitRatio = truncatedRatio;
|
|
274
|
+
_parameterChanged(action, newRatio, false);
|
|
130
275
|
}
|
|
131
276
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
277
|
+
/**
|
|
278
|
+
* @dev Internal function called when money in the PremiumsAccount is not enough and we need to borrow from the
|
|
279
|
+
* eTokens.
|
|
280
|
+
*
|
|
281
|
+
* @param borrow The amount to borrow.
|
|
282
|
+
* @param receiver The address that will receive the money of the loan. Usually is the policy holder if this is called
|
|
283
|
+
* in the context of a policy payout.
|
|
284
|
+
* @param jrEtk If true it indicates that the loan is asked first from the junior eToken.
|
|
285
|
+
*/
|
|
286
|
+
function _borrowFromEtk(
|
|
287
|
+
uint256 borrow,
|
|
288
|
+
address receiver,
|
|
289
|
+
bool jrEtk
|
|
290
|
+
) internal {
|
|
291
|
+
require(receiver != address(0), "PremiumsAccount: receiver cannot be the zero address");
|
|
292
|
+
uint256 left;
|
|
293
|
+
if (jrEtk) {
|
|
294
|
+
// Consume Junior Pool until exhausted
|
|
295
|
+
left = _juniorEtk.internalLoan(borrow, receiver, false);
|
|
138
296
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
297
|
+
left = borrow;
|
|
298
|
+
}
|
|
299
|
+
if (left > NEGLIGIBLE_AMOUNT) {
|
|
300
|
+
// Consume Senior Pool only up to SCR
|
|
301
|
+
left = _seniorEtk.internalLoan(left, receiver, true);
|
|
302
|
+
require(left <= NEGLIGIBLE_AMOUNT, "Don't know where to take the rest of the money");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @dev Updates the `_surplus` field with the payment made. Since the _surplus can never exceed `_maxDeficit()`,
|
|
308
|
+
* returns the remaining amount in case something can't be paid from the PremiumsAccount.
|
|
309
|
+
*
|
|
310
|
+
* @param toPay The amount to pay.
|
|
311
|
+
* @return The amount that couldn't be paid from the premiums account.
|
|
312
|
+
*/
|
|
313
|
+
function _payFromPremiums(uint256 toPay) internal returns (uint256) {
|
|
314
|
+
int256 newSurplus = _surplus - int256(toPay);
|
|
315
|
+
int256 maxDeficit = _maxDeficit(deficitRatio());
|
|
316
|
+
if (newSurplus >= maxDeficit) {
|
|
317
|
+
_surplus = newSurplus;
|
|
318
|
+
return 0;
|
|
141
319
|
}
|
|
320
|
+
_surplus = maxDeficit;
|
|
321
|
+
return uint256(-newSurplus + maxDeficit);
|
|
142
322
|
}
|
|
143
323
|
|
|
144
|
-
|
|
324
|
+
/**
|
|
325
|
+
* @dev Stores an earned pure premium. Adds to the surplus, increasing the surplus if it was positive or reducing the
|
|
326
|
+
* deficit if it was negative.
|
|
327
|
+
*
|
|
328
|
+
* @param purePremiumWon The amount earned
|
|
329
|
+
*/
|
|
330
|
+
function _storePurePremiumWon(uint256 purePremiumWon) internal {
|
|
331
|
+
if (purePremiumWon == 0) return;
|
|
332
|
+
_surplus += int256(purePremiumWon);
|
|
333
|
+
}
|
|
145
334
|
|
|
146
335
|
/**
|
|
147
336
|
*
|
|
@@ -149,41 +338,62 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
149
338
|
*
|
|
150
339
|
* Can be used for example if the PolicyPool subscribes an excess loss policy with other company.
|
|
151
340
|
*
|
|
341
|
+
* Requirements:
|
|
342
|
+
* - The sender needs to approve the spending of `currency()` by this contract.
|
|
343
|
+
*
|
|
344
|
+
* Events:
|
|
345
|
+
* - Emits {WonPremiumsInOut} with moneyIn = true
|
|
346
|
+
*
|
|
347
|
+
* @param amount The amount to be transferred.
|
|
152
348
|
*/
|
|
153
349
|
function receiveGrant(uint256 amount) external {
|
|
154
|
-
currency().safeTransferFrom(msg.sender, address(this), amount);
|
|
155
350
|
_storePurePremiumWon(amount);
|
|
156
351
|
emit WonPremiumsInOut(true, amount);
|
|
352
|
+
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
157
353
|
}
|
|
158
354
|
|
|
159
355
|
/**
|
|
160
356
|
*
|
|
161
|
-
* Withdraws excess premiums to
|
|
357
|
+
* Withdraws excess premiums (surplus) to the destination.
|
|
358
|
+
*
|
|
162
359
|
* This might be needed in some cases for example if we are deprecating the protocol or the excess premiums
|
|
163
360
|
* are needed to compensate something. Shouldn't be used. Can be disabled revoking role WITHDRAW_WON_PREMIUMS_ROLE
|
|
164
361
|
*
|
|
165
|
-
* returns The amount withdrawed
|
|
166
|
-
*
|
|
167
362
|
* Requirements:
|
|
363
|
+
* - onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
|
|
364
|
+
* - _surplus > 0
|
|
168
365
|
*
|
|
169
|
-
*
|
|
170
|
-
* -
|
|
366
|
+
* Events:
|
|
367
|
+
* - Emits {WonPremiumsInOut} with moneyIn = false
|
|
368
|
+
*
|
|
369
|
+
* @param amount The amount to withdraw
|
|
370
|
+
* @param destination The address that will receive the transferred funds.
|
|
371
|
+
* @return Returns the actual amount withdrawn.
|
|
171
372
|
*/
|
|
172
|
-
function withdrawWonPremiums(uint256 amount)
|
|
373
|
+
function withdrawWonPremiums(uint256 amount, address destination)
|
|
173
374
|
external
|
|
174
|
-
|
|
375
|
+
onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
|
|
175
376
|
returns (uint256)
|
|
176
377
|
{
|
|
177
|
-
|
|
378
|
+
require(destination != address(0), "PremiumsAccount: destination cannot be the zero address");
|
|
379
|
+
if (_surplus <= 0) {
|
|
380
|
+
amount = 0;
|
|
381
|
+
} else {
|
|
382
|
+
amount = Math.min(amount, uint256(_surplus));
|
|
383
|
+
}
|
|
178
384
|
require(amount > 0, "No premiums to withdraw");
|
|
179
|
-
|
|
180
|
-
_transferTo(
|
|
181
|
-
// TODO: see if this will be a component role
|
|
385
|
+
_surplus -= int256(amount);
|
|
386
|
+
_transferTo(destination, amount);
|
|
182
387
|
emit WonPremiumsInOut(false, amount);
|
|
183
388
|
return amount;
|
|
184
389
|
}
|
|
185
390
|
|
|
186
|
-
function policyCreated(Policy.PolicyData memory policy)
|
|
391
|
+
function policyCreated(Policy.PolicyData memory policy)
|
|
392
|
+
external
|
|
393
|
+
override
|
|
394
|
+
onlyPolicyPool
|
|
395
|
+
whenNotPaused
|
|
396
|
+
{
|
|
187
397
|
_activePurePremiums += policy.purePremium;
|
|
188
398
|
if (policy.jrScr > 0) _juniorEtk.lockScr(policy.jrScr, policy.jrInterestRate());
|
|
189
399
|
if (policy.srScr > 0) _seniorEtk.lockScr(policy.srScr, policy.srInterestRate());
|
|
@@ -193,7 +403,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
193
403
|
address policyHolder,
|
|
194
404
|
Policy.PolicyData memory policy,
|
|
195
405
|
uint256 payout
|
|
196
|
-
) external override onlyPolicyPool {
|
|
406
|
+
) external override onlyPolicyPool whenNotPaused {
|
|
197
407
|
_activePurePremiums -= policy.purePremium;
|
|
198
408
|
if (policy.purePremium >= payout) {
|
|
199
409
|
uint256 purePremiumWon = policy.purePremium - payout;
|
|
@@ -205,26 +415,20 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
205
415
|
_unlockScr(policy);
|
|
206
416
|
_transferTo(policyHolder, payout);
|
|
207
417
|
} else {
|
|
208
|
-
uint256 borrowFromScr =
|
|
418
|
+
uint256 borrowFromScr = _payFromPremiums(payout - policy.purePremium);
|
|
209
419
|
_unlockScr(policy);
|
|
210
420
|
if (borrowFromScr > 0) {
|
|
211
|
-
|
|
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
|
-
}
|
|
421
|
+
_borrowFromEtk(borrowFromScr, policyHolder, policy.jrScr > 0);
|
|
223
422
|
}
|
|
224
423
|
_transferTo(policyHolder, payout - borrowFromScr);
|
|
225
424
|
}
|
|
226
425
|
}
|
|
227
426
|
|
|
427
|
+
/**
|
|
428
|
+
* @dev Internal function that calls the eTokens to lock the solvency capital when the policy is created.
|
|
429
|
+
*
|
|
430
|
+
* @param policy The policy created
|
|
431
|
+
*/
|
|
228
432
|
function _unlockScr(Policy.PolicyData memory policy) internal {
|
|
229
433
|
if (policy.jrScr > 0) {
|
|
230
434
|
_juniorEtk.unlockScr(
|
|
@@ -242,26 +446,53 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
242
446
|
}
|
|
243
447
|
}
|
|
244
448
|
|
|
449
|
+
/**
|
|
450
|
+
* @dev Internal function that repays a loan taken (if any outstanding) from the an eToken
|
|
451
|
+
*
|
|
452
|
+
* @param purePremiumWon The amount earned and available for loan repayment.
|
|
453
|
+
* @param etk The eToken with the potential debt
|
|
454
|
+
* @return The excess amount of the purePremiumWon that wasn't used for the loan repayment.
|
|
455
|
+
*/
|
|
245
456
|
function _repayLoan(uint256 purePremiumWon, IEToken etk) internal returns (uint256) {
|
|
246
457
|
if (purePremiumWon < NEGLIGIBLE_AMOUNT) return purePremiumWon;
|
|
247
458
|
uint256 borrowedFromEtk = etk.getLoan(address(this));
|
|
248
459
|
if (borrowedFromEtk == 0) return purePremiumWon;
|
|
249
|
-
uint256 repayAmount =
|
|
250
|
-
|
|
460
|
+
uint256 repayAmount = Math.min(purePremiumWon, borrowedFromEtk);
|
|
461
|
+
|
|
462
|
+
// If not enough liquidity, it deinvests from the asset manager
|
|
463
|
+
if (currency().balanceOf(address(this)) < repayAmount) {
|
|
464
|
+
/**
|
|
465
|
+
* I send `repayAmount` because the IAssetManager expects the full amount that's needed, not the missing one.
|
|
466
|
+
* It uses the value of the full amount to optimize the deinvestment leaving more liquidity if possible to avoid
|
|
467
|
+
* future deinvestment. It will only fail if it can't refill `repayAmount - currency().balanceOf(address(this))`
|
|
468
|
+
*/
|
|
469
|
+
_refillWallet(repayAmount);
|
|
470
|
+
}
|
|
471
|
+
// Checks the allowance before repayment
|
|
472
|
+
if (currency().allowance(address(this), address(etk)) < repayAmount) {
|
|
473
|
+
// If I have to approve, I approve for all the pending debt (not just repayAmount), this way I avoid some
|
|
474
|
+
// future approvals.
|
|
475
|
+
currency().approve(address(etk), borrowedFromEtk);
|
|
476
|
+
}
|
|
251
477
|
etk.repayLoan(repayAmount, address(this));
|
|
252
478
|
return purePremiumWon - repayAmount;
|
|
253
479
|
}
|
|
254
480
|
|
|
255
|
-
function policyExpired(Policy.PolicyData memory policy)
|
|
256
|
-
|
|
481
|
+
function policyExpired(Policy.PolicyData memory policy)
|
|
482
|
+
external
|
|
483
|
+
override
|
|
484
|
+
onlyPolicyPool
|
|
485
|
+
whenNotPaused
|
|
486
|
+
{
|
|
257
487
|
uint256 purePremiumWon = policy.purePremium;
|
|
258
488
|
_activePurePremiums -= purePremiumWon;
|
|
259
489
|
|
|
260
490
|
// If negative _activePurePremiums, repay this first (shouldn't happen)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
purePremiumWon -=
|
|
491
|
+
int256 maxDeficit = _maxDeficit(deficitRatio());
|
|
492
|
+
if (_surplus < maxDeficit) {
|
|
493
|
+
// Covers the excess of deficit first
|
|
494
|
+
purePremiumWon -= uint256(-_surplus + maxDeficit);
|
|
495
|
+
_surplus = maxDeficit;
|
|
265
496
|
}
|
|
266
497
|
|
|
267
498
|
if (address(_seniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
|
|
@@ -271,4 +502,11 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
271
502
|
_storePurePremiumWon(purePremiumWon);
|
|
272
503
|
_unlockScr(policy);
|
|
273
504
|
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
508
|
+
* variables without shifting down storage in the inheritance chain.
|
|
509
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
510
|
+
*/
|
|
511
|
+
uint256[47] private __gap;
|
|
274
512
|
}
|