@ensuro/core 1.2.7 → 2.0.0-beta10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -27
- 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 +217 -190
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +17 -4
- package/build/contracts/{extras/IPriceRiskModule.sol/IPriceRiskModule.json → LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json} +81 -131
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyPool.sol/PolicyPool.json +425 -295
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +15 -2
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +868 -0
- package/build/contracts/{BaseAssetManager.sol/BaseAssetManager.json → Reserve.sol/Reserve.json} +37 -166
- package/build/contracts/RiskModule.sol/RiskModule.json +85 -312
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +960 -0
- package/build/contracts/{DataTypes.sol/DataTypes.json → TimeScaled.sol/TimeScaled.json} +4 -4
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +134 -336
- 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/contracts/{WadRayMath.sol → dependencies/WadRayMath.sol}/WadRayMath.json +3 -3
- package/build/{interfaces/IPolicyPoolConfig.sol/IPolicyPoolConfig.json → contracts/interfaces/IAccessManager.sol/IAccessManager.json} +79 -77
- package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +109 -0
- package/build/{interfaces → contracts/interfaces}/IEToken.sol/IEToken.json +39 -91
- 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}/IPolicyPool.sol/IPolicyPool.json +137 -100
- package/build/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +1 -1
- package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +315 -0
- package/build/{interfaces → contracts/interfaces}/IRiskModule.sol/IRiskModule.json +58 -34
- package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
- 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/PolicyHolderMock.sol/PolicyHolderMock.json +228 -0
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +35 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +702 -0
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +92 -0
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +764 -0
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +343 -0
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +388 -0
- package/contracts/AccessManager.sol +103 -0
- package/contracts/ERC4626AssetManager.sol +52 -0
- package/contracts/EToken.sol +254 -299
- package/contracts/LPManualWhitelist.sol +4 -4
- package/contracts/LiquidityThresholdAssetManager.sol +160 -0
- package/contracts/Policy.sol +49 -45
- package/contracts/PolicyPool.sol +379 -514
- package/contracts/PolicyPoolComponent.sol +41 -41
- package/contracts/PremiumsAccount.sol +480 -0
- package/contracts/Reserve.sol +213 -0
- package/contracts/RiskModule.sol +233 -174
- package/contracts/SignedQuoteRiskModule.sol +241 -0
- package/contracts/TimeScaled.sol +138 -0
- package/contracts/TrustfulRiskModule.sol +85 -23
- package/contracts/dependencies/ERC1967Proxy.sol +19 -0
- package/contracts/dependencies/IERC20Metadata.sol +19 -0
- 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 +195 -0
- package/contracts/interfaces/ILPWhitelist.sol +40 -0
- package/{interfaces → contracts/interfaces}/IPolicyHolder.sol +0 -0
- package/contracts/interfaces/IPolicyPool.sol +145 -0
- package/{interfaces → contracts/interfaces}/IPolicyPoolComponent.sol +3 -0
- package/contracts/interfaces/IPremiumsAccount.sol +76 -0
- package/contracts/interfaces/IRiskModule.sol +123 -0
- package/contracts/mocks/FixedRateVault.sol +85 -0
- package/contracts/mocks/ForwardProxy.sol +66 -0
- package/contracts/mocks/IMintableERC20.sol +13 -0
- package/contracts/mocks/PolicyHolderMock.sol +89 -0
- package/contracts/mocks/PolicyPoolComponentMock.sol +17 -0
- package/contracts/mocks/PolicyPoolMock.sol +148 -0
- package/contracts/mocks/RiskModuleMock.sol +75 -0
- package/contracts/mocks/TestCurrency.sol +35 -0
- package/contracts/mocks/TestNFT.sol +23 -0
- package/js/test-utils.js +356 -0
- package/package.json +2 -2
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +0 -742
- package/build/contracts/Exchange.sol/Exchange.json +0 -591
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +0 -1112
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -570
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +0 -686
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +0 -50
- package/build/contracts/extras/PriceRiskModule.sol/PriceRiskModule.json +0 -1055
- package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +0 -322
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +0 -571
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +0 -602
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +0 -31
- package/build/interfaces/IExchange.sol/IPriceOracle.json +0 -30
- package/build/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
- package/contracts/AaveAssetManager.sol +0 -298
- package/contracts/BaseAssetManager.sol +0 -301
- package/contracts/DataTypes.sol +0 -287
- package/contracts/Exchange.sol +0 -189
- package/contracts/FlightDelayRiskModule.sol +0 -208
- package/contracts/PolicyNFT.sol +0 -96
- package/contracts/PolicyPoolConfig.sol +0 -247
- package/contracts/WadRayMath.sol +0 -135
- package/contracts/dependencies/ChainlinkClientUpgradeable.sol +0 -371
- package/contracts/extras/IPriceRiskModule.sol +0 -41
- package/contracts/extras/PriceRiskModule.sol +0 -243
- package/contracts/upgraded/IPolicyNFTv1.sol +0 -15
- package/contracts/upgraded/PolicyNFTv1.sol +0 -126
- 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/ILPWhitelist.sol +0 -23
- package/interfaces/IPolicyNFT.sol +0 -15
- package/interfaces/IPolicyPool.sol +0 -44
- package/interfaces/IPolicyPoolConfig.sol +0 -87
- package/interfaces/IRiskModule.sol +0 -29
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
|
5
|
+
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
6
|
+
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
7
|
+
import {RiskModule} from "./RiskModule.sol";
|
|
8
|
+
import {Policy} from "./Policy.sol";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @title SignedQuote Risk Module
|
|
12
|
+
* @dev Risk Module that for policy creation verifies the different components of the price have been signed by a
|
|
13
|
+
trusted account (PRICER_ROLE). For the resolution (resolvePolicy), it has to be called by an authorized user
|
|
14
|
+
* @custom:security-contact security@ensuro.co
|
|
15
|
+
* @author Ensuro
|
|
16
|
+
*/
|
|
17
|
+
contract SignedQuoteRiskModule is RiskModule {
|
|
18
|
+
bytes32 public constant POLICY_CREATOR_ROLE = keccak256("POLICY_CREATOR_ROLE");
|
|
19
|
+
bytes32 public constant PRICER_ROLE = keccak256("PRICER_ROLE");
|
|
20
|
+
bytes32 public constant RESOLVER_ROLE = keccak256("RESOLVER_ROLE");
|
|
21
|
+
|
|
22
|
+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
23
|
+
bool internal immutable _creationIsOpen;
|
|
24
|
+
|
|
25
|
+
event NewSignedPolicy(uint256 indexed policyId, bytes32 policyData);
|
|
26
|
+
|
|
27
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
28
|
+
constructor(
|
|
29
|
+
IPolicyPool policyPool_,
|
|
30
|
+
IPremiumsAccount premiumsAccount_,
|
|
31
|
+
bool creationIsOpen_
|
|
32
|
+
) RiskModule(policyPool_, premiumsAccount_) {
|
|
33
|
+
_creationIsOpen = creationIsOpen_;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @dev Initializes the RiskModule
|
|
38
|
+
* @param name_ Name of the Risk Module
|
|
39
|
+
* @param collRatio_ Collateralization ratio to compute solvency requirement as % of payout (in ray)
|
|
40
|
+
* @param ensuroPpFee_ % of pure premium that will go for Ensuro treasury (in ray)
|
|
41
|
+
* @param srRoc_ return on capital paid to Senior LPs (annualized percentage - in ray)
|
|
42
|
+
* @param maxPayoutPerPolicy_ Maximum payout per policy (in wad)
|
|
43
|
+
* @param exposureLimit_ Max exposure (sum of payouts) to be allocated to this module (in wad)
|
|
44
|
+
* @param wallet_ Address of the RiskModule provider
|
|
45
|
+
*/
|
|
46
|
+
function initialize(
|
|
47
|
+
string memory name_,
|
|
48
|
+
uint256 collRatio_,
|
|
49
|
+
uint256 ensuroPpFee_,
|
|
50
|
+
uint256 srRoc_,
|
|
51
|
+
uint256 maxPayoutPerPolicy_,
|
|
52
|
+
uint256 exposureLimit_,
|
|
53
|
+
address wallet_
|
|
54
|
+
) public initializer {
|
|
55
|
+
__RiskModule_init(
|
|
56
|
+
name_,
|
|
57
|
+
collRatio_,
|
|
58
|
+
ensuroPpFee_,
|
|
59
|
+
srRoc_,
|
|
60
|
+
maxPayoutPerPolicy_,
|
|
61
|
+
exposureLimit_,
|
|
62
|
+
wallet_
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function _newPolicySigned(
|
|
67
|
+
uint256 payout,
|
|
68
|
+
uint256 premium,
|
|
69
|
+
uint256 lossProb,
|
|
70
|
+
uint40 expiration,
|
|
71
|
+
bytes32 policyData,
|
|
72
|
+
bytes32 quoteSignatureR,
|
|
73
|
+
bytes32 quoteSignatureVS,
|
|
74
|
+
uint40 quoteValidUntil,
|
|
75
|
+
address payer,
|
|
76
|
+
address onBehalfOf
|
|
77
|
+
) internal returns (uint256 policyId) {
|
|
78
|
+
if (!_creationIsOpen)
|
|
79
|
+
_policyPool.access().checkComponentRole(
|
|
80
|
+
address(this),
|
|
81
|
+
POLICY_CREATOR_ROLE,
|
|
82
|
+
_msgSender(),
|
|
83
|
+
false
|
|
84
|
+
);
|
|
85
|
+
require(quoteValidUntil >= block.timestamp, "Quote expired");
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Checks the quote has been signed by an authorized user
|
|
89
|
+
* The "quote" is computed as hash of the following fields (encodePacked):
|
|
90
|
+
* - address(this): the address of this RiskModule
|
|
91
|
+
* - payout, premium, lossProb, expiration: the base parameters of the policy
|
|
92
|
+
* - policyData: a hash of the private details of the policy. The calculation should include some
|
|
93
|
+
* unique id (quoteId), so each policyData identifies a policy.
|
|
94
|
+
* - quoteValidUntil: the maximum validity of the quote
|
|
95
|
+
*/
|
|
96
|
+
bytes32 quoteHash = ECDSA.toEthSignedMessageHash(
|
|
97
|
+
abi.encodePacked(
|
|
98
|
+
address(this),
|
|
99
|
+
payout,
|
|
100
|
+
premium,
|
|
101
|
+
lossProb,
|
|
102
|
+
expiration,
|
|
103
|
+
policyData,
|
|
104
|
+
quoteValidUntil
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
address signer = ECDSA.recover(quoteHash, quoteSignatureR, quoteSignatureVS);
|
|
108
|
+
_policyPool.access().checkComponentRole(address(this), PRICER_ROLE, signer, false);
|
|
109
|
+
uint96 internalId = uint96(uint256(policyData) % 2**96);
|
|
110
|
+
|
|
111
|
+
policyId = _newPolicy(payout, premium, lossProb, expiration, payer, onBehalfOf, internalId).id;
|
|
112
|
+
emit NewSignedPolicy(policyId, policyData);
|
|
113
|
+
return policyId;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
 * @dev Creates a new Policy using a signed quote. The caller is the payer of the policy.
|
|
118
|
+
 *
|
|
119
|
+
 * Requirements:
|
|
120
|
+
 * - The caller approved the spending of the premium to the PolicyPool
|
|
121
|
+
 * - The quote has been signed by an address with the component role PRICER_ROLE
|
|
122
|
+
 *
|
|
123
|
+
 * Emits:
|
|
124
|
+
 * - {PolicyPool.NewPolicy}
|
|
125
|
+
 * - {NewSignedPolicy}
|
|
126
|
+
 *
|
|
127
|
+
 * @param payout The exposure (maximum payout) of the policy
|
|
128
|
+
 * @param premium The premium that will be paid by the payer
|
|
129
|
+
 * @param lossProb The probability of having to pay the maximum payout (wad)
|
|
130
|
+
 * @param expiration The expiration of the policy (timestamp)
|
|
131
|
+
 * @param onBehalfOf The policy holder
|
|
132
|
+
 * @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
133
|
+
 * @param quoteSignatureR The signature of the "quote". R component (EIP-2098 signature)
|
|
134
|
+
 * @param quoteSignatureVS The signature of the "quote". VS component (EIP-2098 signature)
|
|
135
|
+
 * @param quoteValidUntil The expiration of the quote
|
|
136
|
+
 * @return Returns the id of the created policy
|
|
137
|
+
 */
|
|
138
|
+
function newPolicy(
|
|
139
|
+
uint256 payout,
|
|
140
|
+
uint256 premium,
|
|
141
|
+
uint256 lossProb,
|
|
142
|
+
uint40 expiration,
|
|
143
|
+
address onBehalfOf,
|
|
144
|
+
bytes32 policyData,
|
|
145
|
+
bytes32 quoteSignatureR,
|
|
146
|
+
bytes32 quoteSignatureVS,
|
|
147
|
+
uint40 quoteValidUntil
|
|
148
|
+
) external returns (uint256) {
|
|
149
|
+
return
|
|
150
|
+
_newPolicySigned(
|
|
151
|
+
payout,
|
|
152
|
+
premium,
|
|
153
|
+
lossProb,
|
|
154
|
+
expiration,
|
|
155
|
+
policyData,
|
|
156
|
+
quoteSignatureR,
|
|
157
|
+
quoteSignatureVS,
|
|
158
|
+
quoteValidUntil,
|
|
159
|
+
_msgSender(),
|
|
160
|
+
onBehalfOf
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
 * @dev Creates a new Policy using a signed quote. The payer is the policy holder
|
|
166
|
+
 *
|
|
167
|
+
 * Requirements:
|
|
168
|
+
 * - currency().allowance(onBehalfOf, _msgSender()) > 0
|
|
169
|
+
 * - The quote has been signed by an address with the component role PRICER_ROLE
|
|
170
|
+
 *
|
|
171
|
+
 * Emits:
|
|
172
|
+
 * - {PolicyPool.NewPolicy}
|
|
173
|
+
 * - {NewSignedPolicy}
|
|
174
|
+
 *
|
|
175
|
+
 * @param payout The exposure (maximum payout) of the policy
|
|
176
|
+
 * @param premium The premium that will be paid by the payer
|
|
177
|
+
 * @param lossProb The probability of having to pay the maximum payout (wad)
|
|
178
|
+
 * @param expiration The expiration of the policy (timestamp)
|
|
179
|
+
 * @param onBehalfOf The policy holder
|
|
180
|
+
 * @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
181
|
+
 * @param quoteSignatureR The signature of the "quote". R component (EIP-2098 signature)
|
|
182
|
+
 * @param quoteSignatureVS The signature of the "quote". VS component (EIP-2098 signature)
|
|
183
|
+
 * @param quoteValidUntil The expiration of the quote
|
|
184
|
+
 * @return Returns the id of the created policy
|
|
185
|
+
 */
|
|
186
|
+
function newPolicyPaidByHolder(
|
|
187
|
+
uint256 payout,
|
|
188
|
+
uint256 premium,
|
|
189
|
+
uint256 lossProb,
|
|
190
|
+
uint40 expiration,
|
|
191
|
+
address onBehalfOf,
|
|
192
|
+
bytes32 policyData,
|
|
193
|
+
bytes32 quoteSignatureR,
|
|
194
|
+
bytes32 quoteSignatureVS,
|
|
195
|
+
uint40 quoteValidUntil
|
|
196
|
+
) external returns (uint256) {
|
|
197
|
+
require(
|
|
198
|
+
onBehalfOf == _msgSender() || currency().allowance(onBehalfOf, _msgSender()) > 0,
|
|
199
|
+
"Sender is not authorized to create policies onBehalfOf"
|
|
200
|
+
);
|
|
201
|
+
/**
|
|
202
|
+
* The standard is the payer should be the _msgSender() but usually, in this type of module,
|
|
203
|
+
* the sender is an operative account managed by software, where the onBehalfOf is a more
|
|
204
|
+
* secure account (hardware wallet) that does the cash movements.
|
|
205
|
+
* This non standard behaviour allows for a more secure setup, where the sender never manages
|
|
206
|
+
* cash.
|
|
207
|
+
* We leverage the currency's allowance mechanism to allow the sender access to the payer's
|
|
208
|
+
* funds.
|
|
209
|
+
* Note that this allowance won't be spent, so anything above 0 is accepted.
|
|
210
|
+
*/
|
|
211
|
+
return
|
|
212
|
+
_newPolicySigned(
|
|
213
|
+
payout,
|
|
214
|
+
premium,
|
|
215
|
+
lossProb,
|
|
216
|
+
expiration,
|
|
217
|
+
policyData,
|
|
218
|
+
quoteSignatureR,
|
|
219
|
+
quoteSignatureVS,
|
|
220
|
+
quoteValidUntil,
|
|
221
|
+
onBehalfOf,
|
|
222
|
+
onBehalfOf
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function resolvePolicy(Policy.PolicyData calldata policy, uint256 payout)
|
|
227
|
+
external
|
|
228
|
+
onlyComponentRole(RESOLVER_ROLE)
|
|
229
|
+
whenNotPaused
|
|
230
|
+
{
|
|
231
|
+
_policyPool.resolvePolicy(policy, payout);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function resolvePolicyFullPayout(Policy.PolicyData calldata policy, bool customerWon)
|
|
235
|
+
external
|
|
236
|
+
onlyComponentRole(RESOLVER_ROLE)
|
|
237
|
+
whenNotPaused
|
|
238
|
+
{
|
|
239
|
+
_policyPool.resolvePolicyFullPayout(policy, customerWon);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.0;
|
|
4
|
+
|
|
5
|
+
import {WadRayMath} from "./dependencies/WadRayMath.sol";
|
|
6
|
+
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @title TimeScaled
|
|
10
|
+
* @dev Library for packed amounts that increase continuoulsly with a scale factor
|
|
11
|
+
* @custom:security-contact security@ensuro.co
|
|
12
|
+
* @author Ensuro
|
|
13
|
+
*/
|
|
14
|
+
library TimeScaled {
|
|
15
|
+
using WadRayMath for uint256;
|
|
16
|
+
using SafeCast for uint256;
|
|
17
|
+
|
|
18
|
+
uint256 private constant SECONDS_PER_YEAR = 365 days;
|
|
19
|
+
uint112 private constant MIN_SCALE = 1e17; // 0.0000000001 == 1e-10 in ray
|
|
20
|
+
uint112 private constant RAY112 = 1e27;
|
|
21
|
+
|
|
22
|
+
struct ScaledAmount {
|
|
23
|
+
uint112 scale;
|
|
24
|
+
uint112 amount;
|
|
25
|
+
uint32 lastUpdate;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function updateScale(ScaledAmount storage scaledAmount, uint256 interestRate) internal {
|
|
29
|
+
if (scaledAmount.lastUpdate >= uint32(block.timestamp)) return;
|
|
30
|
+
if (scaledAmount.amount == 0) {
|
|
31
|
+
scaledAmount.lastUpdate = uint32(block.timestamp);
|
|
32
|
+
} else {
|
|
33
|
+
scaledAmount.scale = getScale(scaledAmount, interestRate).toUint112();
|
|
34
|
+
scaledAmount.lastUpdate = uint32(block.timestamp);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getScale(ScaledAmount storage scaledAmount, uint256 interestRate)
|
|
39
|
+
internal
|
|
40
|
+
view
|
|
41
|
+
returns (uint256)
|
|
42
|
+
{
|
|
43
|
+
uint32 now_ = uint32(block.timestamp);
|
|
44
|
+
if (scaledAmount.lastUpdate >= now_) {
|
|
45
|
+
return scaledAmount.scale;
|
|
46
|
+
}
|
|
47
|
+
uint256 timeDifference = uint256(now_ - scaledAmount.lastUpdate);
|
|
48
|
+
return
|
|
49
|
+
uint256(scaledAmount.scale).rayMul(
|
|
50
|
+
((interestRate.wadToRay() * timeDifference) / SECONDS_PER_YEAR) + WadRayMath.RAY
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getScaledAmount(ScaledAmount storage scaledAmount, uint256 interestRate)
|
|
55
|
+
internal
|
|
56
|
+
view
|
|
57
|
+
returns (uint256)
|
|
58
|
+
{
|
|
59
|
+
return
|
|
60
|
+
uint256(scaledAmount.amount)
|
|
61
|
+
.wadToRay()
|
|
62
|
+
.rayMul(getScale(scaledAmount, interestRate))
|
|
63
|
+
.rayToWad();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function init(ScaledAmount storage scaledAmount) internal {
|
|
67
|
+
scaledAmount.scale = RAY112;
|
|
68
|
+
scaledAmount.amount = 0;
|
|
69
|
+
scaledAmount.lastUpdate = uint32(block.timestamp);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function scaleAmount(ScaledAmount storage scaledAmount, uint256 toScale)
|
|
73
|
+
internal
|
|
74
|
+
view
|
|
75
|
+
returns (uint256)
|
|
76
|
+
{
|
|
77
|
+
return toScale.wadToRay().rayDiv(uint256(scaledAmount.scale)).rayToWad();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function scaleAmountNow(
|
|
81
|
+
ScaledAmount storage scaledAmount,
|
|
82
|
+
uint256 interestRate,
|
|
83
|
+
uint256 toScale
|
|
84
|
+
) internal view returns (uint256) {
|
|
85
|
+
return toScale.wadToRay().rayDiv(getScale(scaledAmount, interestRate)).rayToWad();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function add(
|
|
89
|
+
ScaledAmount storage scaledAmount,
|
|
90
|
+
uint256 amount,
|
|
91
|
+
uint256 interestRate
|
|
92
|
+
) internal returns (uint256) {
|
|
93
|
+
updateScale(scaledAmount, interestRate);
|
|
94
|
+
uint256 scaledAdd = scaleAmount(scaledAmount, amount);
|
|
95
|
+
scaledAmount.amount += scaledAdd.toUint96();
|
|
96
|
+
return scaledAdd;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function sub(
|
|
100
|
+
ScaledAmount storage scaledAmount,
|
|
101
|
+
uint256 amount,
|
|
102
|
+
uint256 interestRate
|
|
103
|
+
) internal returns (uint256) {
|
|
104
|
+
updateScale(scaledAmount, interestRate);
|
|
105
|
+
uint256 scaledSub = scaleAmount(scaledAmount, amount);
|
|
106
|
+
scaledAmount.amount -= scaledSub.toUint96();
|
|
107
|
+
if (scaledAmount.amount == 0) {
|
|
108
|
+
// Reset scale if amount == 0
|
|
109
|
+
scaledAmount.scale = RAY112;
|
|
110
|
+
}
|
|
111
|
+
return scaledSub;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function discreteChange(
|
|
115
|
+
ScaledAmount storage scaledAmount,
|
|
116
|
+
int256 amount,
|
|
117
|
+
uint256 interestRate
|
|
118
|
+
) internal {
|
|
119
|
+
updateScale(scaledAmount, interestRate);
|
|
120
|
+
uint256 newScaledAmount = uint256(int256(getScaledAmount(scaledAmount, interestRate)) + amount);
|
|
121
|
+
scaledAmount.scale = newScaledAmount
|
|
122
|
+
.wadToRay()
|
|
123
|
+
.rayDiv(uint256(scaledAmount.amount).wadToRay())
|
|
124
|
+
.toUint112();
|
|
125
|
+
require(scaledAmount.scale >= MIN_SCALE, "Scale too small, can lead to rounding errors");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function maxNegativeAdjustment(ScaledAmount storage scaledAmount, uint256 interestRate)
|
|
129
|
+
internal
|
|
130
|
+
view
|
|
131
|
+
returns (uint256)
|
|
132
|
+
{
|
|
133
|
+
uint256 ts = getScaledAmount(scaledAmount, interestRate);
|
|
134
|
+
uint256 minTs = uint256(scaledAmount.amount).wadToRay().rayMul(MIN_SCALE).rayToWad();
|
|
135
|
+
if (ts > minTs) return ts - minTs;
|
|
136
|
+
else return 0;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
-
import {IPolicyPool} from "
|
|
4
|
+
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
5
|
+
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
5
6
|
import {RiskModule} from "./RiskModule.sol";
|
|
6
7
|
import {Policy} from "./Policy.sol";
|
|
7
8
|
|
|
@@ -19,61 +20,122 @@ contract TrustfulRiskModule is RiskModule {
|
|
|
19
20
|
|
|
20
21
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
21
22
|
// solhint-disable-next-line no-empty-blocks
|
|
22
|
-
constructor(IPolicyPool policyPool_
|
|
23
|
+
constructor(IPolicyPool policyPool_, IPremiumsAccount premiumsAccount_)
|
|
24
|
+
RiskModule(policyPool_, premiumsAccount_)
|
|
25
|
+
{} // solhint-disable-line no-empty-blocks
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* @dev Initializes the RiskModule
|
|
26
29
|
* @param name_ Name of the Risk Module
|
|
27
|
-
* @param
|
|
28
|
-
|
|
29
|
-
* @param
|
|
30
|
-
* @param
|
|
31
|
-
* @param
|
|
32
|
-
* @param scrLimit_ Max SCR to be allocated to this module (in wad)
|
|
30
|
+
* @param collRatio_ Collateralization ratio to compute solvency requirement as % of payout (in ray)
|
|
31
|
+
* @param ensuroPpFee_ % of pure premium that will go for Ensuro treasury (in ray)
|
|
32
|
+
* @param srRoc_ return on capital paid to Senior LPs (annualized percentage - in ray)
|
|
33
|
+
* @param maxPayoutPerPolicy_ Maximum payout per policy (in wad)
|
|
34
|
+
* @param exposureLimit_ Max exposure (sum of payouts) to be allocated to this module (in wad)
|
|
33
35
|
* @param wallet_ Address of the RiskModule provider
|
|
34
36
|
*/
|
|
35
37
|
function initialize(
|
|
36
38
|
string memory name_,
|
|
37
|
-
uint256
|
|
38
|
-
uint256
|
|
39
|
-
uint256
|
|
40
|
-
uint256
|
|
41
|
-
uint256
|
|
39
|
+
uint256 collRatio_,
|
|
40
|
+
uint256 ensuroPpFee_,
|
|
41
|
+
uint256 srRoc_,
|
|
42
|
+
uint256 maxPayoutPerPolicy_,
|
|
43
|
+
uint256 exposureLimit_,
|
|
42
44
|
address wallet_
|
|
43
45
|
) public initializer {
|
|
44
46
|
__RiskModule_init(
|
|
45
47
|
name_,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
collRatio_,
|
|
49
|
+
ensuroPpFee_,
|
|
50
|
+
srRoc_,
|
|
51
|
+
maxPayoutPerPolicy_,
|
|
52
|
+
exposureLimit_,
|
|
51
53
|
wallet_
|
|
52
54
|
);
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @dev Creates a new Policy
|
|
59
|
+
*
|
|
60
|
+
* Requirements:
|
|
61
|
+
* - The caller has been granted componentRole(PRICER_ROLE)
|
|
62
|
+
*
|
|
63
|
+
* Emits:
|
|
64
|
+
* - {PolicyPool.NewPolicy}
|
|
65
|
+
*
|
|
66
|
+
* @param payout The exposure (maximum payout) of the policy
|
|
67
|
+
* @param premium The premium that will be paid by the policyHolder
|
|
68
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
69
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
70
|
+
* @param onBehalfOf The policy holder
|
|
71
|
+
* @param internalId An id that's unique within this module and it will be used to identify the policy
|
|
72
|
+
* @return Returns the id of the created policy
|
|
73
|
+
*/
|
|
55
74
|
function newPolicy(
|
|
56
75
|
uint256 payout,
|
|
57
76
|
uint256 premium,
|
|
58
77
|
uint256 lossProb,
|
|
59
78
|
uint40 expiration,
|
|
60
|
-
address
|
|
79
|
+
address onBehalfOf,
|
|
61
80
|
uint96 internalId
|
|
62
|
-
) external
|
|
63
|
-
|
|
81
|
+
) external onlyComponentRole(PRICER_ROLE) returns (uint256) {
|
|
82
|
+
address payer = onBehalfOf;
|
|
83
|
+
if (payer != _msgSender() && _policyPool.currency().allowance(payer, _msgSender()) < premium)
|
|
84
|
+
/**
|
|
85
|
+
* The standard is the payer should be the _msgSender() but usually, in this type of module,
|
|
86
|
+
* the sender is an operative account managed by software, where the onBehalfOf is a more
|
|
87
|
+
* secure account (hardware wallet) that does the cash movements.
|
|
88
|
+
* This non standard behaviour allows for a more secure setup, where the sender never manages
|
|
89
|
+
* cash.
|
|
90
|
+
* We leverage the currency's allowance mechanism to allow the sender access to the payer's
|
|
91
|
+
* funds.
|
|
92
|
+
* Note that this allowance won't be spent, so it can be set as the maximum amount of a single
|
|
93
|
+
* premium even for multiple policies.
|
|
94
|
+
*/
|
|
95
|
+
payer = _msgSender();
|
|
96
|
+
|
|
97
|
+
return _newPolicy(payout, premium, lossProb, expiration, payer, onBehalfOf, internalId).id;
|
|
64
98
|
}
|
|
65
99
|
|
|
100
|
+
/**
|
|
101
|
+
* @dev Resolves a policy, if payout > 0, it pays to the policy holder.
|
|
102
|
+
*
|
|
103
|
+
* Requirements:
|
|
104
|
+
* - The caller has been granted componentRole(RESOLVER_ROLE)
|
|
105
|
+
* - payout <= policy.payout
|
|
106
|
+
* - block.timestamp >= policy.expiration
|
|
107
|
+
*
|
|
108
|
+
* Emits:
|
|
109
|
+
* - {PolicyPool.PolicyResolved}
|
|
110
|
+
*
|
|
111
|
+
* @param policy The policy previously created (from {NewPolicy} event)
|
|
112
|
+
* @param payout The payout to transfer to the policy holder
|
|
113
|
+
*/
|
|
66
114
|
function resolvePolicy(Policy.PolicyData calldata policy, uint256 payout)
|
|
67
115
|
external
|
|
68
|
-
|
|
116
|
+
onlyComponentRole(RESOLVER_ROLE)
|
|
69
117
|
whenNotPaused
|
|
70
118
|
{
|
|
71
119
|
_policyPool.resolvePolicy(policy, payout);
|
|
72
120
|
}
|
|
73
121
|
|
|
122
|
+
/**
|
|
123
|
+
* @dev Resolves a policy with full payout (policy.payout) if customerWon == true
|
|
124
|
+
*
|
|
125
|
+
* Requirements:
|
|
126
|
+
* - The caller has been granted componentRole(RESOLVER_ROLE)
|
|
127
|
+
* - block.timestamp >= policy.expiration
|
|
128
|
+
*
|
|
129
|
+
* Emits:
|
|
130
|
+
* - {PolicyPool.PolicyResolved}
|
|
131
|
+
*
|
|
132
|
+
* @param policy The policy previously created (from {NewPolicy} event)
|
|
133
|
+
* @param customerWon If true, policy.payout is transferred to the policy holder. If false, the policy is resolved
|
|
134
|
+
* without payout and can't be longer claimed.
|
|
135
|
+
*/
|
|
74
136
|
function resolvePolicyFullPayout(Policy.PolicyData calldata policy, bool customerWon)
|
|
75
137
|
external
|
|
76
|
-
|
|
138
|
+
onlyComponentRole(RESOLVER_ROLE)
|
|
77
139
|
whenNotPaused
|
|
78
140
|
{
|
|
79
141
|
_policyPool.resolvePolicyFullPayout(policy, customerWon);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
This is a workaround for:
|
|
6
|
+
|
|
7
|
+
https://github.com/eth-brownie/brownie/issues/1581
|
|
8
|
+
|
|
9
|
+
Which affects ethproto. The contract is just here for ethproto's
|
|
10
|
+
sake and is not actually used by any contract.
|
|
11
|
+
|
|
12
|
+
Once that bug is fixed (either in brownie or in ethproto) this
|
|
13
|
+
file can be safely removed.
|
|
14
|
+
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {ERC1967Proxy as ERC1967ProxyOriginal} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
|
18
|
+
|
|
19
|
+
abstract contract ERC1967Proxy is ERC1967ProxyOriginal {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
This is a workaround for:
|
|
6
|
+
|
|
7
|
+
https://github.com/eth-brownie/brownie/issues/1581
|
|
8
|
+
|
|
9
|
+
Which affects ethproto. The contract is just here for ethproto's
|
|
10
|
+
sake and is not actually used by any contract.
|
|
11
|
+
|
|
12
|
+
Once that bug is fixed (either in brownie or in ethproto) this
|
|
13
|
+
file can be safely removed.
|
|
14
|
+
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {IERC20Metadata as IERC20MetadataOriginal} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
18
|
+
|
|
19
|
+
interface IERC20Metadata is IERC20MetadataOriginal {}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @title WadRayMath library
|
|
6
|
+
* @author Aave
|
|
7
|
+
* @notice Provides functions to perform calculations with Wad and Ray units
|
|
8
|
+
* @dev Provides mul and div function for wads (decimal numbers with 18 digits of precision) and rays (decimal numbers
|
|
9
|
+
* with 27 digits of precision)
|
|
10
|
+
* @dev Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down.
|
|
11
|
+
**/
|
|
12
|
+
library WadRayMath {
|
|
13
|
+
// HALF_WAD and HALF_RAY expressed with extended notation as constant with operations are not supported in Yul assembly
|
|
14
|
+
uint256 internal constant WAD = 1e18;
|
|
15
|
+
uint256 internal constant HALF_WAD = 0.5e18;
|
|
16
|
+
|
|
17
|
+
uint256 internal constant RAY = 1e27;
|
|
18
|
+
uint256 internal constant HALF_RAY = 0.5e27;
|
|
19
|
+
|
|
20
|
+
uint256 internal constant WAD_RAY_RATIO = 1e9;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @dev Multiplies two wad, rounding half up to the nearest wad
|
|
24
|
+
* @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
|
|
25
|
+
* @param a Wad
|
|
26
|
+
* @param b Wad
|
|
27
|
+
* @return c = a*b, in wad
|
|
28
|
+
**/
|
|
29
|
+
function wadMul(uint256 a, uint256 b) internal pure returns (uint256 c) {
|
|
30
|
+
// to avoid overflow, a <= (type(uint256).max - HALF_WAD) / b
|
|
31
|
+
assembly {
|
|
32
|
+
if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_WAD), b))))) {
|
|
33
|
+
revert(0, 0)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
c := div(add(mul(a, b), HALF_WAD), WAD)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @dev Divides two wad, rounding half up to the nearest wad
|
|
42
|
+
* @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
|
|
43
|
+
* @param a Wad
|
|
44
|
+
* @param b Wad
|
|
45
|
+
* @return c = a/b, in wad
|
|
46
|
+
**/
|
|
47
|
+
function wadDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
|
|
48
|
+
// to avoid overflow, a <= (type(uint256).max - halfB) / WAD
|
|
49
|
+
assembly {
|
|
50
|
+
if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), WAD))))) {
|
|
51
|
+
revert(0, 0)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
c := div(add(mul(a, WAD), div(b, 2)), b)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @notice Multiplies two ray, rounding half up to the nearest ray
|
|
60
|
+
* @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
|
|
61
|
+
* @param a Ray
|
|
62
|
+
* @param b Ray
|
|
63
|
+
* @return c = a raymul b
|
|
64
|
+
**/
|
|
65
|
+
function rayMul(uint256 a, uint256 b) internal pure returns (uint256 c) {
|
|
66
|
+
// to avoid overflow, a <= (type(uint256).max - HALF_RAY) / b
|
|
67
|
+
assembly {
|
|
68
|
+
if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_RAY), b))))) {
|
|
69
|
+
revert(0, 0)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
c := div(add(mul(a, b), HALF_RAY), RAY)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @notice Divides two ray, rounding half up to the nearest ray
|
|
78
|
+
* @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
|
|
79
|
+
* @param a Ray
|
|
80
|
+
* @param b Ray
|
|
81
|
+
* @return c = a raydiv b
|
|
82
|
+
**/
|
|
83
|
+
function rayDiv(uint256 a, uint256 b) internal pure returns (uint256 c) {
|
|
84
|
+
// to avoid overflow, a <= (type(uint256).max - halfB) / RAY
|
|
85
|
+
assembly {
|
|
86
|
+
if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), RAY))))) {
|
|
87
|
+
revert(0, 0)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
c := div(add(mul(a, RAY), div(b, 2)), b)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @dev Casts ray down to wad
|
|
96
|
+
* @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
|
|
97
|
+
* @param a Ray
|
|
98
|
+
* @return b = a converted to wad, rounded half up to the nearest wad
|
|
99
|
+
**/
|
|
100
|
+
function rayToWad(uint256 a) internal pure returns (uint256 b) {
|
|
101
|
+
assembly {
|
|
102
|
+
b := div(a, WAD_RAY_RATIO)
|
|
103
|
+
let remainder := mod(a, WAD_RAY_RATIO)
|
|
104
|
+
if iszero(lt(remainder, div(WAD_RAY_RATIO, 2))) {
|
|
105
|
+
b := add(b, 1)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @dev Converts wad up to ray
|
|
112
|
+
* @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328
|
|
113
|
+
* @param a Wad
|
|
114
|
+
* @return b = a converted in ray
|
|
115
|
+
**/
|
|
116
|
+
function wadToRay(uint256 a) internal pure returns (uint256 b) {
|
|
117
|
+
// to avoid overflow, b/WAD_RAY_RATIO == a
|
|
118
|
+
assembly {
|
|
119
|
+
b := mul(a, WAD_RAY_RATIO)
|
|
120
|
+
|
|
121
|
+
if iszero(eq(div(b, WAD_RAY_RATIO), a)) {
|
|
122
|
+
revert(0, 0)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|