@ensuro/core 2.0.0-beta1 → 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.
- package/README.md +23 -14
- package/build/contracts/AccessManager.sol/AccessManager.json +559 -0
- package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +219 -0
- package/build/contracts/EToken.sol/EToken.json +134 -52
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +4 -4
- package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +203 -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 +2 -2
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +123 -16
- package/build/contracts/Reserve.sol/Reserve.json +66 -8
- package/build/contracts/RiskModule.sol/RiskModule.json +2 -2
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +960 -0
- package/build/contracts/TimeScaled.sol/TimeScaled.json +3 -17
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +5 -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 +109 -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/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/PolicyHolderMock.sol/PolicyHolderMock.json +28 -2
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +2 -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 +764 -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 +103 -0
- package/contracts/ERC4626AssetManager.sol +52 -0
- package/contracts/EToken.sol +123 -87
- package/contracts/LPManualWhitelist.sol +1 -1
- package/contracts/LiquidityThresholdAssetManager.sol +160 -0
- package/contracts/Policy.sol +1 -1
- package/contracts/PolicyPool.sol +333 -115
- package/contracts/PolicyPoolComponent.sol +36 -41
- package/contracts/PremiumsAccount.sol +285 -79
- package/contracts/Reserve.sol +183 -4
- package/contracts/RiskModule.sol +26 -19
- package/contracts/SignedQuoteRiskModule.sol +241 -0
- package/contracts/TimeScaled.sol +19 -15
- package/contracts/TrustfulRiskModule.sol +62 -2
- package/contracts/dependencies/WadRayMath.sol +126 -0
- package/contracts/interfaces/IAccessManager.sol +148 -0
- package/contracts/interfaces/IAssetManager.sol +84 -0
- package/contracts/interfaces/IEToken.sol +25 -2
- package/contracts/interfaces/ILPWhitelist.sol +17 -0
- package/contracts/interfaces/IPolicyPool.sol +20 -13
- package/contracts/interfaces/IPolicyPoolComponent.sol +3 -0
- package/contracts/interfaces/IPremiumsAccount.sol +5 -0
- package/contracts/interfaces/IRiskModule.sol +67 -4
- package/contracts/mocks/FixedRateVault.sol +85 -0
- package/contracts/mocks/PolicyHolderMock.sol +21 -0
- package/contracts/mocks/PolicyPoolMock.sol +41 -15
- package/contracts/mocks/RiskModuleMock.sol +75 -0
- package/js/test-utils.js +227 -149
- 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
|
@@ -5,9 +5,9 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
|
|
|
5
5
|
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
6
6
|
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
7
7
|
import {IPolicyPoolComponent} from "./interfaces/IPolicyPoolComponent.sol";
|
|
8
|
-
import {
|
|
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,37 +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(
|
|
46
|
-
event ComponentChanged(
|
|
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
|
|
54
|
-
|
|
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
|
|
65
|
-
_policyPool.
|
|
58
|
+
modifier onlyGlobalOrComponentRole(bytes32 role) {
|
|
59
|
+
_policyPool.access().checkComponentRole(address(this), role, _msgSender(), true);
|
|
66
60
|
_;
|
|
67
61
|
}
|
|
68
62
|
|
|
69
|
-
modifier
|
|
70
|
-
_policyPool.
|
|
63
|
+
modifier onlyGlobalOrComponentRole2(bytes32 role1, bytes32 role2) {
|
|
64
|
+
_policyPool.access().checkComponentRole2(address(this), role1, role2, _msgSender(), true);
|
|
71
65
|
_;
|
|
72
66
|
}
|
|
73
67
|
|
|
74
|
-
modifier
|
|
75
|
-
|
|
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
|
+
}
|
|
76
77
|
_;
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -87,14 +88,23 @@ abstract contract PolicyPoolComponent is
|
|
|
87
88
|
__Pausable_init();
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
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
|
+
}
|
|
92
102
|
|
|
93
|
-
function pause() public
|
|
103
|
+
function pause() public onlyGlobalOrComponentRole(GUARDIAN_ROLE) {
|
|
94
104
|
_pause();
|
|
95
105
|
}
|
|
96
106
|
|
|
97
|
-
function unpause() public
|
|
107
|
+
function unpause() public onlyGlobalOrComponentRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
|
|
98
108
|
_unpause();
|
|
99
109
|
}
|
|
100
110
|
|
|
@@ -107,22 +117,7 @@ abstract contract PolicyPoolComponent is
|
|
|
107
117
|
}
|
|
108
118
|
|
|
109
119
|
function hasPoolRole(bytes32 role) internal view returns (bool) {
|
|
110
|
-
return _policyPool.
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function _isTweakRay(
|
|
114
|
-
uint256 oldValue,
|
|
115
|
-
uint256 newValue,
|
|
116
|
-
uint256 maxTweak
|
|
117
|
-
) internal pure returns (bool) {
|
|
118
|
-
if (oldValue == newValue) return true;
|
|
119
|
-
if (oldValue == 0) return maxTweak >= WadRayMath.RAY;
|
|
120
|
-
if (newValue == 0) return false;
|
|
121
|
-
if (oldValue < newValue) {
|
|
122
|
-
return (newValue.rayDiv(oldValue) - WadRayMath.RAY) <= maxTweak;
|
|
123
|
-
} else {
|
|
124
|
-
return (WadRayMath.RAY - newValue.rayDiv(oldValue)) <= maxTweak;
|
|
125
|
-
}
|
|
120
|
+
return _policyPool.access().hasComponentRole(address(this), role, _msgSender(), true);
|
|
126
121
|
}
|
|
127
122
|
|
|
128
123
|
function _isTweakWad(
|
|
@@ -144,7 +139,7 @@ abstract contract PolicyPoolComponent is
|
|
|
144
139
|
function _validateParameters() internal view virtual {} // Must be reimplemented with specific validations
|
|
145
140
|
|
|
146
141
|
function _parameterChanged(
|
|
147
|
-
|
|
142
|
+
IAccessManager.GovernanceActions action,
|
|
148
143
|
uint256 value,
|
|
149
144
|
bool tweak
|
|
150
145
|
) internal {
|
|
@@ -153,7 +148,7 @@ abstract contract PolicyPoolComponent is
|
|
|
153
148
|
emit GovernanceAction(action, value);
|
|
154
149
|
}
|
|
155
150
|
|
|
156
|
-
function _componentChanged(
|
|
151
|
+
function _componentChanged(IAccessManager.GovernanceActions action, address value) internal {
|
|
157
152
|
_validateParameters();
|
|
158
153
|
emit ComponentChanged(action, value);
|
|
159
154
|
}
|
|
@@ -162,7 +157,7 @@ abstract contract PolicyPoolComponent is
|
|
|
162
157
|
return (_lastTweakTimestamp, _lastTweakActions);
|
|
163
158
|
}
|
|
164
159
|
|
|
165
|
-
function _registerTweak(
|
|
160
|
+
function _registerTweak(IAccessManager.GovernanceActions action) internal {
|
|
166
161
|
uint56 actionBitMap = uint56(1 << (uint8(action) - 1));
|
|
167
162
|
if ((uint40(block.timestamp) - _lastTweakTimestamp) > TWEAK_EXPIRATION) {
|
|
168
163
|
_lastTweakTimestamp = uint40(block.timestamp);
|
|
@@ -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 enought to
|
|
26
|
+
* cover the losses.
|
|
27
|
+
*
|
|
18
28
|
* @custom:security-contact security@ensuro.co
|
|
19
29
|
* @author Ensuro
|
|
20
30
|
*/
|
|
@@ -22,26 +32,60 @@ 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");
|
|
27
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
|
+
*/
|
|
28
43
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
29
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
|
+
*/
|
|
30
50
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
31
51
|
IEToken internal immutable _seniorEtk;
|
|
32
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
|
+
*/
|
|
33
57
|
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
58
|
|
|
37
|
-
|
|
38
|
-
*
|
|
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.
|
|
39
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
|
|
40
79
|
*/
|
|
41
80
|
event WonPremiumsInOut(bool moneyIn, uint256 value);
|
|
42
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
|
+
*/
|
|
43
88
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
44
|
-
// solhint-disable-next-line no-empty-blocks
|
|
45
89
|
constructor(
|
|
46
90
|
IPolicyPool policyPool_,
|
|
47
91
|
IEToken juniorEtk_,
|
|
@@ -52,14 +96,14 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
52
96
|
}
|
|
53
97
|
|
|
54
98
|
/**
|
|
55
|
-
* @dev
|
|
99
|
+
* @dev Initializes the PremiumsAccount
|
|
56
100
|
*/
|
|
57
101
|
function initialize() public initializer {
|
|
58
102
|
__PremiumsAccount_init();
|
|
59
103
|
}
|
|
60
104
|
|
|
61
105
|
/**
|
|
62
|
-
* @dev Initializes the PremiumsAccount
|
|
106
|
+
* @dev Initializes the PremiumsAccount (to be called by subclasses)
|
|
63
107
|
*/
|
|
64
108
|
// solhint-disable-next-line func-name-mixedcase
|
|
65
109
|
function __PremiumsAccount_init() internal initializer {
|
|
@@ -67,37 +111,93 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
67
111
|
__PremiumsAccount_init_unchained();
|
|
68
112
|
}
|
|
69
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
|
+
*/
|
|
70
118
|
// solhint-disable-next-line func-name-mixedcase
|
|
71
119
|
function __PremiumsAccount_init_unchained() internal initializer {
|
|
72
120
|
/*
|
|
73
121
|
_activePurePremiums = 0;
|
|
74
|
-
_borrowedActivePP = 0;
|
|
75
|
-
_wonPurePremiums = 0;
|
|
76
122
|
*/
|
|
77
123
|
if (address(_juniorEtk) != address(0))
|
|
78
124
|
currency().approve(address(_juniorEtk), type(uint256).max);
|
|
79
125
|
if (address(_seniorEtk) != address(0))
|
|
80
126
|
currency().approve(address(_seniorEtk), type(uint256).max);
|
|
127
|
+
|
|
128
|
+
_params = PackedParams({deficitRatio: 1e4, assetManager: IAssetManager(address(0))});
|
|
81
129
|
_validateParameters();
|
|
82
130
|
}
|
|
83
131
|
|
|
84
|
-
|
|
85
|
-
|
|
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
|
+
}
|
|
86
158
|
|
|
87
|
-
function
|
|
88
|
-
|
|
159
|
+
function _validateParameters() internal view override {
|
|
160
|
+
require(
|
|
161
|
+
_params.deficitRatio <= 1e4 && _params.deficitRatio >= 0,
|
|
162
|
+
"Validation: deficitRatio must be <= 1"
|
|
163
|
+
);
|
|
89
164
|
}
|
|
90
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
|
+
*/
|
|
91
174
|
function activePurePremiums() external view returns (uint256) {
|
|
92
175
|
return _activePurePremiums;
|
|
93
176
|
}
|
|
94
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
|
+
*/
|
|
95
182
|
function wonPurePremiums() external view returns (uint256) {
|
|
96
|
-
return
|
|
183
|
+
return _surplus >= 0 ? uint256(_surplus) : 0;
|
|
97
184
|
}
|
|
98
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
|
+
*/
|
|
99
190
|
function borrowedActivePP() external view returns (uint256) {
|
|
100
|
-
return
|
|
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;
|
|
101
201
|
}
|
|
102
202
|
|
|
103
203
|
function seniorEtk() external view override returns (IEToken) {
|
|
@@ -108,40 +208,116 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
108
208
|
return _juniorEtk;
|
|
109
209
|
}
|
|
110
210
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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;
|
|
128
260
|
}
|
|
129
|
-
|
|
261
|
+
_params.deficitRatio = (newRatio / 1e14).toUint16();
|
|
262
|
+
_parameterChanged(action, newRatio, false);
|
|
130
263
|
}
|
|
131
264
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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);
|
|
138
283
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
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;
|
|
141
306
|
}
|
|
307
|
+
_surplus = maxDeficit;
|
|
308
|
+
return uint256(-newSurplus + maxDeficit);
|
|
142
309
|
}
|
|
143
310
|
|
|
144
|
-
|
|
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
|
+
}
|
|
145
321
|
|
|
146
322
|
/**
|
|
147
323
|
*
|
|
@@ -149,41 +325,61 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
149
325
|
*
|
|
150
326
|
* Can be used for example if the PolicyPool subscribes an excess loss policy with other company.
|
|
151
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.
|
|
152
335
|
*/
|
|
153
336
|
function receiveGrant(uint256 amount) external {
|
|
154
|
-
currency().safeTransferFrom(
|
|
337
|
+
currency().safeTransferFrom(_msgSender(), address(this), amount);
|
|
155
338
|
_storePurePremiumWon(amount);
|
|
156
339
|
emit WonPremiumsInOut(true, amount);
|
|
157
340
|
}
|
|
158
341
|
|
|
159
342
|
/**
|
|
160
343
|
*
|
|
161
|
-
* Withdraws excess premiums to
|
|
344
|
+
* Withdraws excess premiums (surplus) to the destination.
|
|
345
|
+
*
|
|
162
346
|
* This might be needed in some cases for example if we are deprecating the protocol or the excess premiums
|
|
163
347
|
* are needed to compensate something. Shouldn't be used. Can be disabled revoking role WITHDRAW_WON_PREMIUMS_ROLE
|
|
164
348
|
*
|
|
165
|
-
* returns The amount withdrawed
|
|
166
|
-
*
|
|
167
349
|
* Requirements:
|
|
350
|
+
* - onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
|
|
351
|
+
* - _surplus > 0
|
|
352
|
+
*
|
|
353
|
+
* Events:
|
|
354
|
+
* - Emits {WonPremiumsInOut} with moneyIn = false
|
|
168
355
|
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
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.
|
|
171
359
|
*/
|
|
172
|
-
function withdrawWonPremiums(uint256 amount)
|
|
360
|
+
function withdrawWonPremiums(uint256 amount, address destination)
|
|
173
361
|
external
|
|
174
|
-
|
|
362
|
+
onlyGlobalOrComponentRole(WITHDRAW_WON_PREMIUMS_ROLE)
|
|
175
363
|
returns (uint256)
|
|
176
364
|
{
|
|
177
|
-
if (
|
|
365
|
+
if (_surplus <= 0) {
|
|
366
|
+
amount = 0;
|
|
367
|
+
} else {
|
|
368
|
+
amount = Math.min(amount, uint256(_surplus));
|
|
369
|
+
}
|
|
178
370
|
require(amount > 0, "No premiums to withdraw");
|
|
179
|
-
|
|
180
|
-
_transferTo(
|
|
181
|
-
// TODO: see if this will be a component role
|
|
371
|
+
_surplus -= int256(amount);
|
|
372
|
+
_transferTo(destination, amount);
|
|
182
373
|
emit WonPremiumsInOut(false, amount);
|
|
183
374
|
return amount;
|
|
184
375
|
}
|
|
185
376
|
|
|
186
|
-
function policyCreated(Policy.PolicyData memory policy)
|
|
377
|
+
function policyCreated(Policy.PolicyData memory policy)
|
|
378
|
+
external
|
|
379
|
+
override
|
|
380
|
+
onlyPolicyPool
|
|
381
|
+
whenNotPaused
|
|
382
|
+
{
|
|
187
383
|
_activePurePremiums += policy.purePremium;
|
|
188
384
|
if (policy.jrScr > 0) _juniorEtk.lockScr(policy.jrScr, policy.jrInterestRate());
|
|
189
385
|
if (policy.srScr > 0) _seniorEtk.lockScr(policy.srScr, policy.srInterestRate());
|
|
@@ -193,7 +389,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
193
389
|
address policyHolder,
|
|
194
390
|
Policy.PolicyData memory policy,
|
|
195
391
|
uint256 payout
|
|
196
|
-
) external override onlyPolicyPool {
|
|
392
|
+
) external override onlyPolicyPool whenNotPaused {
|
|
197
393
|
_activePurePremiums -= policy.purePremium;
|
|
198
394
|
if (policy.purePremium >= payout) {
|
|
199
395
|
uint256 purePremiumWon = policy.purePremium - payout;
|
|
@@ -205,26 +401,20 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
205
401
|
_unlockScr(policy);
|
|
206
402
|
_transferTo(policyHolder, payout);
|
|
207
403
|
} else {
|
|
208
|
-
uint256 borrowFromScr =
|
|
404
|
+
uint256 borrowFromScr = _payFromPremiums(payout - policy.purePremium);
|
|
209
405
|
_unlockScr(policy);
|
|
210
406
|
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
|
-
}
|
|
407
|
+
_borrowFromEtk(borrowFromScr, policyHolder, policy.jrScr > 0);
|
|
223
408
|
}
|
|
224
409
|
_transferTo(policyHolder, payout - borrowFromScr);
|
|
225
410
|
}
|
|
226
411
|
}
|
|
227
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
|
+
*/
|
|
228
418
|
function _unlockScr(Policy.PolicyData memory policy) internal {
|
|
229
419
|
if (policy.jrScr > 0) {
|
|
230
420
|
_juniorEtk.unlockScr(
|
|
@@ -242,26 +432,42 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
242
432
|
}
|
|
243
433
|
}
|
|
244
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
|
+
*/
|
|
245
442
|
function _repayLoan(uint256 purePremiumWon, IEToken etk) internal returns (uint256) {
|
|
246
443
|
if (purePremiumWon < NEGLIGIBLE_AMOUNT) return purePremiumWon;
|
|
247
444
|
uint256 borrowedFromEtk = etk.getLoan(address(this));
|
|
248
445
|
if (borrowedFromEtk == 0) return purePremiumWon;
|
|
249
|
-
uint256 repayAmount =
|
|
250
|
-
|
|
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
|
+
}
|
|
251
452
|
etk.repayLoan(repayAmount, address(this));
|
|
252
453
|
return purePremiumWon - repayAmount;
|
|
253
454
|
}
|
|
254
455
|
|
|
255
|
-
function policyExpired(Policy.PolicyData memory policy)
|
|
256
|
-
|
|
456
|
+
function policyExpired(Policy.PolicyData memory policy)
|
|
457
|
+
external
|
|
458
|
+
override
|
|
459
|
+
onlyPolicyPool
|
|
460
|
+
whenNotPaused
|
|
461
|
+
{
|
|
257
462
|
uint256 purePremiumWon = policy.purePremium;
|
|
258
463
|
_activePurePremiums -= purePremiumWon;
|
|
259
464
|
|
|
260
465
|
// If negative _activePurePremiums, repay this first (shouldn't happen)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
purePremiumWon -=
|
|
466
|
+
int256 maxDeficit = _maxDeficit(deficitRatio());
|
|
467
|
+
if (_surplus < maxDeficit) {
|
|
468
|
+
// Covers the excess of deficit first
|
|
469
|
+
purePremiumWon -= uint256(-_surplus + maxDeficit);
|
|
470
|
+
_surplus = maxDeficit;
|
|
265
471
|
}
|
|
266
472
|
|
|
267
473
|
if (address(_seniorEtk) != address(0)) purePremiumWon = _repayLoan(purePremiumWon, _seniorEtk);
|