@ensuro/core 2.8.3 → 2.9.1
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 +2 -3
- package/build/build-info.json +1 -0
- package/build/contracts/AccessManager.sol/AccessManager.json +2 -15
- package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +2 -2
- package/build/contracts/ERC4626PlusVaultAssetManager.sol/ERC4626PlusVaultAssetManager.json +2 -2
- package/build/contracts/EToken.sol/EToken.json +7 -85
- package/build/contracts/FullSignedBucketRiskModule.sol/FullSignedBucketRiskModule.json +1484 -0
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +7 -85
- package/build/contracts/Policy.sol/Policy.json +2 -2
- package/build/contracts/PolicyPool.sol/PolicyPool.json +2 -15
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +5 -83
- package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +7 -85
- package/build/contracts/Reserve.sol/Reserve.json +5 -83
- package/build/contracts/RiskModule.sol/RiskModule.json +5 -96
- package/build/contracts/SignedBucketRiskModule.sol/SignedBucketRiskModule.json +7 -150
- package/build/contracts/SignedQuoteRiskModule.sol/SignedQuoteRiskModule.json +7 -98
- package/build/contracts/TimeScaled.sol/TimeScaled.json +2 -2
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +7 -98
- package/build/contracts/dependencies/WadRayMath.sol/WadRayMath.json +2 -2
- package/build/contracts/migration/LPManualWhitelistV20.sol/LPManualWhitelistV20.json +5 -83
- package/build/contracts/migration/LPManualWhitelistV20Upgraded.sol/LPManualWhitelistV20Upgraded.json +7 -85
- package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +2 -2
- package/build/contracts/mocks/ForwardProxy.sol/ForwardProxy.json +2 -2
- package/build/contracts/mocks/InterfaceIdCalculator.sol/InterfaceIdCalculator.json +2 -2
- package/build/contracts/mocks/PolicyHolderMock.sol/PolicyHolderMock.json +2 -2
- package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +2 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +2 -2
- package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
- package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +7 -98
- package/build/contracts/mocks/TestCurrency.sol/TestCurrency.json +2 -2
- package/contracts/AccessManager.sol +0 -1
- package/contracts/EToken.sol +2 -20
- package/contracts/FullSignedBucketRiskModule.sol +204 -0
- package/contracts/PolicyPool.sol +0 -1
- package/contracts/PolicyPoolComponent.sol +7 -44
- package/contracts/PremiumsAccount.sol +3 -3
- package/contracts/RiskModule.sol +10 -21
- package/contracts/SignedBucketRiskModule.sol +15 -9
- package/contracts/SignedQuoteRiskModule.sol +7 -4
- package/js/deploy.js +1 -1
- package/js/test-utils.js +2 -92
- package/js/utils.js +67 -208
- package/package.json +1 -1
- package/scripts/deploySmokeTest-fork.sh +1 -1
- package/scripts/deploySmokeTest.sh +1 -1
- package/build/contracts/mocks/TestNFT.sol/TestNFT.json +0 -388
- package/contracts/mocks/TestNFT.sol +0 -23
- package/js/constants.js +0 -13
package/contracts/EToken.sol
CHANGED
|
@@ -697,31 +697,14 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
697
697
|
return _4toWad(_params.internalLoanInterestRate);
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
-
function setParam(Parameter param, uint256 newValue) external
|
|
701
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE);
|
|
700
|
+
function setParam(Parameter param, uint256 newValue) external onlyGlobalOrComponentRole(LEVEL2_ROLE) {
|
|
702
701
|
if (param == Parameter.liquidityRequirement) {
|
|
703
|
-
require(
|
|
704
|
-
!tweak || _isTweakWad(liquidityRequirement(), newValue, 1e17),
|
|
705
|
-
"Tweak exceeded: liquidityRequirement tweaks only up to 10%"
|
|
706
|
-
);
|
|
707
702
|
_params.liquidityRequirement = _wadTo4(newValue);
|
|
708
703
|
} else if (param == Parameter.minUtilizationRate) {
|
|
709
|
-
require(
|
|
710
|
-
!tweak || _isTweakWad(minUtilizationRate(), newValue, 3e17),
|
|
711
|
-
"Tweak exceeded: minUtilizationRate tweaks only up to 30%"
|
|
712
|
-
);
|
|
713
704
|
_params.minUtilizationRate = _wadTo4(newValue);
|
|
714
705
|
} else if (param == Parameter.maxUtilizationRate) {
|
|
715
|
-
require(
|
|
716
|
-
!tweak || _isTweakWad(maxUtilizationRate(), newValue, 3e17),
|
|
717
|
-
"Tweak exceeded: maxUtilizationRate tweaks only up to 30%"
|
|
718
|
-
);
|
|
719
706
|
_params.maxUtilizationRate = _wadTo4(newValue);
|
|
720
707
|
} else if (param == Parameter.internalLoanInterestRate) {
|
|
721
|
-
require(
|
|
722
|
-
!tweak || _isTweakWad(internalLoanInterestRate(), newValue, 3e17),
|
|
723
|
-
"Tweak exceeded: internalLoanInterestRate tweaks only up to 30%"
|
|
724
|
-
);
|
|
725
708
|
// This call changes the interest rate without updating the current loans up to this point
|
|
726
709
|
// So, if interest rate goes from 5% to 6%, this change will be retroactive to the lastUpdate of each
|
|
727
710
|
// loan. Since it's a permissioned call, I'm ok with this. If a caller wants to reduce the impact, it can
|
|
@@ -732,8 +715,7 @@ contract EToken is Reserve, IERC20Metadata, IEToken {
|
|
|
732
715
|
IAccessManager.GovernanceActions(
|
|
733
716
|
uint256(IAccessManager.GovernanceActions.setLiquidityRequirement) + uint256(param)
|
|
734
717
|
),
|
|
735
|
-
newValue
|
|
736
|
-
tweak
|
|
718
|
+
newValue
|
|
737
719
|
);
|
|
738
720
|
}
|
|
739
721
|
|
|
@@ -0,0 +1,204 @@
|
|
|
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
|
+
|
|
6
|
+
import {IPolicyPool} from "./interfaces/IPolicyPool.sol";
|
|
7
|
+
import {IPremiumsAccount} from "./interfaces/IPremiumsAccount.sol";
|
|
8
|
+
import {Policy} from "./Policy.sol";
|
|
9
|
+
import {SignedBucketRiskModule} from "./SignedBucketRiskModule.sol";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @title FullSignedBucket Risk Module
|
|
13
|
+
* @dev Variation of SignedBucketRiskModule that also supports the creation of policies receiving all the
|
|
14
|
+
parameters that affect the price (not just the lossProb). And validates the signature.
|
|
15
|
+
It requires a new permission, the FULL_PRICER_ROLE.
|
|
16
|
+
* @custom:security-contact security@ensuro.co
|
|
17
|
+
* @author Ensuro
|
|
18
|
+
*/
|
|
19
|
+
contract FullSignedBucketRiskModule is SignedBucketRiskModule {
|
|
20
|
+
bytes32 internal constant FULL_PRICER_ROLE = keccak256("FULL_PRICER_ROLE");
|
|
21
|
+
|
|
22
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
23
|
+
constructor(
|
|
24
|
+
IPolicyPool policyPool_,
|
|
25
|
+
IPremiumsAccount premiumsAccount_
|
|
26
|
+
) SignedBucketRiskModule(policyPool_, premiumsAccount_) {}
|
|
27
|
+
|
|
28
|
+
function _paramsAsUint256(PackedParams memory overrideParams) internal pure returns (uint256) {
|
|
29
|
+
return
|
|
30
|
+
(uint256(overrideParams.moc) << 240) |
|
|
31
|
+
(uint256(overrideParams.jrCollRatio) << 224) |
|
|
32
|
+
(uint256(overrideParams.collRatio) << 208) |
|
|
33
|
+
(uint256(overrideParams.ensuroPpFee) << 192) |
|
|
34
|
+
(uint256(overrideParams.ensuroCocFee) << 176) |
|
|
35
|
+
(uint256(overrideParams.jrRoc) << 160) |
|
|
36
|
+
(uint256(overrideParams.srRoc) << 144);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function _checkFullSignature(
|
|
40
|
+
uint256 payout,
|
|
41
|
+
uint256 premium,
|
|
42
|
+
uint256 lossProb,
|
|
43
|
+
uint40 expiration,
|
|
44
|
+
bytes32 policyData,
|
|
45
|
+
PackedParams memory params,
|
|
46
|
+
bytes32 quoteSignatureR,
|
|
47
|
+
bytes32 quoteSignatureVS,
|
|
48
|
+
uint40 quoteValidUntil
|
|
49
|
+
) internal view {
|
|
50
|
+
if (quoteValidUntil < block.timestamp) revert QuoteExpired();
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Checks the quote has been signed by an authorized user
|
|
54
|
+
* The "quote" is computed as hash of the following fields (encodePacked):
|
|
55
|
+
* - address(this): the address of this RiskModule
|
|
56
|
+
* - payout, premium, lossProb, expiration: the base parameters of the policy
|
|
57
|
+
* - policyData: a hash of the private details of the policy. The calculation should include some
|
|
58
|
+
* unique id (quoteId), so each policyData identifies a policy.
|
|
59
|
+
* - params: packed as a uint256
|
|
60
|
+
* - quoteValidUntil: the maximum validity of the quote
|
|
61
|
+
*/
|
|
62
|
+
bytes32 quoteHash = ECDSA.toEthSignedMessageHash(
|
|
63
|
+
abi.encodePacked(
|
|
64
|
+
address(this),
|
|
65
|
+
payout,
|
|
66
|
+
premium,
|
|
67
|
+
lossProb,
|
|
68
|
+
expiration,
|
|
69
|
+
policyData,
|
|
70
|
+
_paramsAsUint256(params),
|
|
71
|
+
quoteValidUntil
|
|
72
|
+
)
|
|
73
|
+
);
|
|
74
|
+
address signer = ECDSA.recover(quoteHash, quoteSignatureR, quoteSignatureVS);
|
|
75
|
+
_policyPool.access().checkComponentRole(address(this), FULL_PRICER_ROLE, signer, false);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @dev Creates a new Policy using a full signed quote that overrides params.
|
|
80
|
+
* The caller is the payer of the policy.
|
|
81
|
+
*
|
|
82
|
+
* Requirements:
|
|
83
|
+
* - The caller approved the spending of the premium to the PolicyPool
|
|
84
|
+
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
85
|
+
*
|
|
86
|
+
* Emits:
|
|
87
|
+
* - {PolicyPool.NewPolicy}
|
|
88
|
+
* - {NewSignedPolicy}
|
|
89
|
+
*
|
|
90
|
+
* @param payout The exposure (maximum payout) of the policy
|
|
91
|
+
* @param premium The premium that will be paid by the payer
|
|
92
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
93
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
94
|
+
* @param onBehalfOf The policy holder
|
|
95
|
+
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
96
|
+
* @param params The parameters for the policy creation (coll ratios, RoCs, fees, etc.)
|
|
97
|
+
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
98
|
+
* @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
99
|
+
* @param quoteValidUntil The expiration of the quote
|
|
100
|
+
* @return createdPolicy Returns the created policy
|
|
101
|
+
*/
|
|
102
|
+
function newPolicyFullParams(
|
|
103
|
+
uint256 payout,
|
|
104
|
+
uint256 premium,
|
|
105
|
+
uint256 lossProb,
|
|
106
|
+
uint40 expiration,
|
|
107
|
+
address onBehalfOf,
|
|
108
|
+
bytes32 policyData,
|
|
109
|
+
PackedParams memory params,
|
|
110
|
+
bytes32 quoteSignatureR,
|
|
111
|
+
bytes32 quoteSignatureVS,
|
|
112
|
+
uint40 quoteValidUntil
|
|
113
|
+
) external whenNotPaused onlyComponentRole(POLICY_CREATOR_ROLE) returns (Policy.PolicyData memory createdPolicy) {
|
|
114
|
+
_checkFullSignature(
|
|
115
|
+
payout,
|
|
116
|
+
premium,
|
|
117
|
+
lossProb,
|
|
118
|
+
expiration,
|
|
119
|
+
policyData,
|
|
120
|
+
params,
|
|
121
|
+
quoteSignatureR,
|
|
122
|
+
quoteSignatureVS,
|
|
123
|
+
quoteValidUntil
|
|
124
|
+
);
|
|
125
|
+
createdPolicy = _newPolicyWithParams(
|
|
126
|
+
payout,
|
|
127
|
+
premium,
|
|
128
|
+
lossProb,
|
|
129
|
+
expiration,
|
|
130
|
+
_msgSender(),
|
|
131
|
+
onBehalfOf,
|
|
132
|
+
_makeInternalId(policyData),
|
|
133
|
+
_unpackParams(params)
|
|
134
|
+
);
|
|
135
|
+
emit NewSignedPolicy(createdPolicy.id, policyData);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @dev Replace a policy with a new one, reusing the premium and the capital locked
|
|
140
|
+
*
|
|
141
|
+
* Requirements:
|
|
142
|
+
* - The caller approved the spending of the premium to the PolicyPool
|
|
143
|
+
* - The quote has been signed by an address with the component role PRICER_ROLE
|
|
144
|
+
* - The caller has been granted component role REPLACER_ROLE or creation is open
|
|
145
|
+
*
|
|
146
|
+
* Emits:
|
|
147
|
+
* - {PolicyPool.PolicyReplaced}
|
|
148
|
+
* - {PolicyPool.NewPolicy}
|
|
149
|
+
*
|
|
150
|
+
* @param oldPolicy The policy to be replaced
|
|
151
|
+
* @param payout The exposure (maximum payout) of the new policy
|
|
152
|
+
* @param premium The premium that will be paid by the caller
|
|
153
|
+
* @param lossProb The probability of having to pay the maximum payout (wad)
|
|
154
|
+
* @param expiration The expiration of the policy (timestamp)
|
|
155
|
+
* @param policyData A hash of the private details of the policy. The last 96 bits will be used as internalId
|
|
156
|
+
* @param params The parameters for the policy creation (coll ratios, RoCs, fees, etc.)
|
|
157
|
+
* @param quoteSignatureR The signature of the quote. R component (EIP-2098 signature)
|
|
158
|
+
* @param quoteSignatureVS The signature of the quote. VS component (EIP-2098 signature)
|
|
159
|
+
* @param quoteValidUntil The expiration of the quote
|
|
160
|
+
* @return Returns the id of the created policy
|
|
161
|
+
*/
|
|
162
|
+
function replacePolicyFullParams(
|
|
163
|
+
Policy.PolicyData calldata oldPolicy,
|
|
164
|
+
uint256 payout,
|
|
165
|
+
uint256 premium,
|
|
166
|
+
uint256 lossProb,
|
|
167
|
+
uint40 expiration,
|
|
168
|
+
bytes32 policyData,
|
|
169
|
+
PackedParams memory params,
|
|
170
|
+
bytes32 quoteSignatureR,
|
|
171
|
+
bytes32 quoteSignatureVS,
|
|
172
|
+
uint40 quoteValidUntil
|
|
173
|
+
) external whenNotPaused onlyComponentRole(REPLACER_ROLE) returns (uint256) {
|
|
174
|
+
_checkFullSignature(
|
|
175
|
+
payout,
|
|
176
|
+
premium,
|
|
177
|
+
lossProb,
|
|
178
|
+
expiration,
|
|
179
|
+
policyData,
|
|
180
|
+
params,
|
|
181
|
+
quoteSignatureR,
|
|
182
|
+
quoteSignatureVS,
|
|
183
|
+
quoteValidUntil
|
|
184
|
+
);
|
|
185
|
+
return
|
|
186
|
+
_replacePolicy(
|
|
187
|
+
oldPolicy,
|
|
188
|
+
payout,
|
|
189
|
+
premium,
|
|
190
|
+
lossProb,
|
|
191
|
+
expiration,
|
|
192
|
+
_msgSender(),
|
|
193
|
+
_makeInternalId(policyData),
|
|
194
|
+
_unpackParams(params)
|
|
195
|
+
).id;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
200
|
+
* variables without shifting down storage in the inheritance chain.
|
|
201
|
+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
202
|
+
*/
|
|
203
|
+
uint256[50] private __gap;
|
|
204
|
+
}
|
package/contracts/PolicyPool.sol
CHANGED
|
@@ -42,7 +42,6 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable, ERC721
|
|
|
42
42
|
bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
|
|
43
43
|
bytes32 public constant LEVEL1_ROLE = keccak256("LEVEL1_ROLE");
|
|
44
44
|
bytes32 public constant LEVEL2_ROLE = keccak256("LEVEL2_ROLE");
|
|
45
|
-
bytes32 public constant LEVEL3_ROLE = keccak256("LEVEL3_ROLE");
|
|
46
45
|
|
|
47
46
|
uint256 internal constant HOLDER_GAS_LIMIT = 150000;
|
|
48
47
|
|
|
@@ -17,7 +17,6 @@ import {WadRayMath} from "./dependencies/WadRayMath.sol";
|
|
|
17
17
|
* Holds the reference to _policyPool as immutable, also provides access to common admin roles:
|
|
18
18
|
* - LEVEL1_ROLE: High impact changes like upgrades, adding or removing components or other critical operations
|
|
19
19
|
* - LEVEL2_ROLE: Mid-impact changes like changing some parameters
|
|
20
|
-
* - LEVEL3_ROLE: Low-impact changes like changing some parameters up to given percentage (tweaks)
|
|
21
20
|
* - GUARDIAN_ROLE: For emergency operations oriented to protect the protocol in case of attacks or hacking.
|
|
22
21
|
*
|
|
23
22
|
* This contract also keeps track of the tweaks to avoid two tweaks of the same type are done in a short period.
|
|
@@ -27,26 +26,22 @@ import {WadRayMath} from "./dependencies/WadRayMath.sol";
|
|
|
27
26
|
abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, IPolicyPoolComponent {
|
|
28
27
|
using WadRayMath for uint256;
|
|
29
28
|
|
|
30
|
-
bytes32
|
|
31
|
-
bytes32
|
|
32
|
-
bytes32
|
|
33
|
-
bytes32 public constant LEVEL3_ROLE = keccak256("LEVEL3_ROLE");
|
|
34
|
-
|
|
35
|
-
uint40 public constant TWEAK_EXPIRATION = 1 days;
|
|
29
|
+
bytes32 internal constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
|
|
30
|
+
bytes32 internal constant LEVEL1_ROLE = keccak256("LEVEL1_ROLE");
|
|
31
|
+
bytes32 internal constant LEVEL2_ROLE = keccak256("LEVEL2_ROLE");
|
|
36
32
|
|
|
37
33
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
38
34
|
IPolicyPool internal immutable _policyPool;
|
|
39
|
-
uint40 internal _lastTweakTimestamp;
|
|
40
|
-
uint56 internal _lastTweakActions; // bitwise map of applied actions
|
|
41
35
|
|
|
42
36
|
event GovernanceAction(IAccessManager.GovernanceActions indexed action, uint256 value);
|
|
43
37
|
event ComponentChanged(IAccessManager.GovernanceActions indexed action, address value);
|
|
44
38
|
|
|
45
39
|
error NoZeroPolicyPool();
|
|
46
40
|
error UpgradeCannotChangePolicyPool();
|
|
41
|
+
error OnlyPolicyPool();
|
|
47
42
|
|
|
48
43
|
modifier onlyPolicyPool() {
|
|
49
|
-
require(_msgSender() == address(_policyPool),
|
|
44
|
+
require(_msgSender() == address(_policyPool), OnlyPolicyPool());
|
|
50
45
|
_;
|
|
51
46
|
}
|
|
52
47
|
|
|
@@ -65,18 +60,6 @@ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, I
|
|
|
65
60
|
_;
|
|
66
61
|
}
|
|
67
62
|
|
|
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
|
-
}
|
|
77
|
-
_;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
63
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
81
64
|
constructor(IPolicyPool policyPool_) {
|
|
82
65
|
if (address(policyPool_) == address(0)) revert NoZeroPolicyPool();
|
|
@@ -141,9 +124,8 @@ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, I
|
|
|
141
124
|
// solhint-disable-next-line no-empty-blocks
|
|
142
125
|
function _validateParameters() internal view virtual {} // Must be reimplemented with specific validations
|
|
143
126
|
|
|
144
|
-
function _parameterChanged(IAccessManager.GovernanceActions action, uint256 value
|
|
127
|
+
function _parameterChanged(IAccessManager.GovernanceActions action, uint256 value) internal {
|
|
145
128
|
_validateParameters();
|
|
146
|
-
if (tweak) _registerTweak(action);
|
|
147
129
|
emit GovernanceAction(action, value);
|
|
148
130
|
}
|
|
149
131
|
|
|
@@ -152,29 +134,10 @@ abstract contract PolicyPoolComponent is UUPSUpgradeable, PausableUpgradeable, I
|
|
|
152
134
|
emit ComponentChanged(action, value);
|
|
153
135
|
}
|
|
154
136
|
|
|
155
|
-
function lastTweak() external view returns (uint40, uint56) {
|
|
156
|
-
return (_lastTweakTimestamp, _lastTweakActions);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function _registerTweak(IAccessManager.GovernanceActions action) internal {
|
|
160
|
-
uint56 actionBitMap = uint56(1 << (uint8(action) - 1));
|
|
161
|
-
if ((uint40(block.timestamp) - _lastTweakTimestamp) > TWEAK_EXPIRATION) {
|
|
162
|
-
_lastTweakTimestamp = uint40(block.timestamp);
|
|
163
|
-
_lastTweakActions = actionBitMap;
|
|
164
|
-
} else {
|
|
165
|
-
if ((actionBitMap & _lastTweakActions) == 0) {
|
|
166
|
-
_lastTweakActions |= actionBitMap;
|
|
167
|
-
_lastTweakTimestamp = uint40(block.timestamp); // Updates the expiration
|
|
168
|
-
} else {
|
|
169
|
-
revert("You already tweaked this parameter recently. Wait before tweaking again");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
137
|
/**
|
|
175
138
|
* @dev This empty reserved space is put in place to allow future versions to add new
|
|
176
139
|
* variables without shifting down storage in the inheritance chain.
|
|
177
140
|
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
|
|
178
141
|
*/
|
|
179
|
-
uint256[
|
|
142
|
+
uint256[50] private __gap;
|
|
180
143
|
}
|
|
@@ -329,7 +329,7 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
329
329
|
_borrowFromEtk(borrow, address(this), address(_juniorEtk) != address(0));
|
|
330
330
|
action = IAccessManager.GovernanceActions.setDeficitRatioWithAdjustment;
|
|
331
331
|
}
|
|
332
|
-
_parameterChanged(action, newRatio
|
|
332
|
+
_parameterChanged(action, newRatio);
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
/**
|
|
@@ -350,12 +350,12 @@ contract PremiumsAccount is IPremiumsAccount, Reserve {
|
|
|
350
350
|
if (newLimitJr != type(uint256).max) {
|
|
351
351
|
_params.jrLoanLimit = _toZeroDecimals(newLimitJr);
|
|
352
352
|
require(_toAmount(_params.jrLoanLimit) == newLimitJr, "Validation: no decimals allowed");
|
|
353
|
-
_parameterChanged(IAccessManager.GovernanceActions.setJrLoanLimit, newLimitJr
|
|
353
|
+
_parameterChanged(IAccessManager.GovernanceActions.setJrLoanLimit, newLimitJr);
|
|
354
354
|
}
|
|
355
355
|
if (newLimitSr != type(uint256).max) {
|
|
356
356
|
_params.srLoanLimit = _toZeroDecimals(newLimitSr);
|
|
357
357
|
require(_toAmount(_params.srLoanLimit) == newLimitSr, "Validation: no decimals allowed");
|
|
358
|
-
_parameterChanged(IAccessManager.GovernanceActions.setSrLoanLimit, newLimitSr
|
|
358
|
+
_parameterChanged(IAccessManager.GovernanceActions.setSrLoanLimit, newLimitSr);
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
|
package/contracts/RiskModule.sol
CHANGED
|
@@ -30,7 +30,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
30
30
|
uint16 internal constant MAX_MOC = 4e4; // 400%
|
|
31
31
|
|
|
32
32
|
// For parameters that can be changed by the risk module provider
|
|
33
|
-
bytes32
|
|
33
|
+
bytes32 internal constant RM_PROVIDER_ROLE = keccak256("RM_PROVIDER_ROLE");
|
|
34
34
|
|
|
35
35
|
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
|
|
36
36
|
IPremiumsAccount internal immutable _premiumsAccount;
|
|
@@ -206,48 +206,33 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
206
206
|
return _wallet;
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
function setParam(
|
|
210
|
-
Parameter param,
|
|
211
|
-
uint256 newValue
|
|
212
|
-
) external onlyGlobalOrComponentRole3(LEVEL1_ROLE, LEVEL2_ROLE, LEVEL3_ROLE) {
|
|
213
|
-
bool tweak = !hasPoolRole(LEVEL2_ROLE) && !hasPoolRole(LEVEL1_ROLE);
|
|
209
|
+
function setParam(Parameter param, uint256 newValue) external onlyGlobalOrComponentRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
|
|
214
210
|
if (param == Parameter.moc) {
|
|
215
|
-
require(!tweak || _isTweakWad(_4toWad(_params.moc), newValue, 1e17), "Tweak exceeded");
|
|
216
211
|
_params.moc = _wadTo4(newValue);
|
|
217
212
|
} else if (param == Parameter.jrCollRatio) {
|
|
218
|
-
require(!tweak || _isTweakWad(_4toWad(_params.jrCollRatio), newValue, 1e17), "Tweak exceeded");
|
|
219
213
|
_params.jrCollRatio = _wadTo4(newValue);
|
|
220
214
|
} else if (param == Parameter.collRatio) {
|
|
221
|
-
require(!tweak || _isTweakWad(_4toWad(_params.collRatio), newValue, 1e17), "Tweak exceeded");
|
|
222
215
|
_params.collRatio = _wadTo4(newValue);
|
|
223
216
|
} else if (param == Parameter.ensuroPpFee) {
|
|
224
|
-
require(!tweak || _isTweakWad(_4toWad(_params.ensuroPpFee), newValue, 1e17), "Tweak exceeded");
|
|
225
217
|
_params.ensuroPpFee = _wadTo4(newValue);
|
|
226
218
|
} else if (param == Parameter.ensuroCocFee) {
|
|
227
|
-
require(!tweak || _isTweakWad(_4toWad(_params.ensuroCocFee), newValue, 1e17), "Tweak exceeded");
|
|
228
219
|
_params.ensuroCocFee = _wadTo4(newValue);
|
|
229
220
|
} else if (param == Parameter.jrRoc) {
|
|
230
|
-
require(!tweak || _isTweakWad(_4toWad(_params.jrRoc), newValue, 1e17), "Tweak exceeded");
|
|
231
221
|
_params.jrRoc = _wadTo4(newValue);
|
|
232
222
|
} else if (param == Parameter.srRoc) {
|
|
233
|
-
require(!tweak || _isTweakWad(_4toWad(_params.srRoc), newValue, 1e17), "Tweak exceeded");
|
|
234
223
|
_params.srRoc = _wadTo4(newValue);
|
|
235
224
|
} else if (param == Parameter.maxPayoutPerPolicy) {
|
|
236
|
-
require(!tweak || _isTweakWad(maxPayoutPerPolicy(), newValue, 1e17), "Tweak exceeded");
|
|
237
225
|
_params.maxPayoutPerPolicy = _amountToX(2, newValue);
|
|
238
226
|
} else if (param == Parameter.exposureLimit) {
|
|
239
227
|
require(newValue >= _activeExposure, "Can't set exposureLimit less than active exposure");
|
|
240
|
-
require(
|
|
241
|
-
require(newValue <= exposureLimit() || hasPoolRole(LEVEL1_ROLE), "Tweak exceeded: Increase requires LEVEL1_ROLE");
|
|
228
|
+
require(newValue <= exposureLimit() || hasPoolRole(LEVEL1_ROLE), "Increase requires LEVEL1_ROLE");
|
|
242
229
|
_params.exposureLimit = _amountToX(0, newValue);
|
|
243
230
|
} else if (param == Parameter.maxDuration) {
|
|
244
|
-
require(!tweak, "Tweak exceeded");
|
|
245
231
|
_params.maxDuration = newValue.toUint16();
|
|
246
232
|
}
|
|
247
233
|
_parameterChanged(
|
|
248
234
|
IAccessManager.GovernanceActions(uint256(IAccessManager.GovernanceActions.setMoc) + uint256(param)),
|
|
249
|
-
newValue
|
|
250
|
-
tweak
|
|
235
|
+
newValue
|
|
251
236
|
);
|
|
252
237
|
}
|
|
253
238
|
|
|
@@ -255,7 +240,7 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
255
240
|
return _unpackParams(_params);
|
|
256
241
|
}
|
|
257
242
|
|
|
258
|
-
function _unpackParams(PackedParams
|
|
243
|
+
function _unpackParams(PackedParams memory params_) internal pure returns (Params memory ret) {
|
|
259
244
|
return
|
|
260
245
|
Params({
|
|
261
246
|
moc: _4toWad(params_.moc),
|
|
@@ -268,12 +253,16 @@ abstract contract RiskModule is IRiskModule, PolicyPoolComponent {
|
|
|
268
253
|
});
|
|
269
254
|
}
|
|
270
255
|
|
|
256
|
+
function _makeInternalId(bytes32 policyData) internal pure returns (uint96) {
|
|
257
|
+
return uint96(uint256(policyData) % 2 ** 96);
|
|
258
|
+
}
|
|
259
|
+
|
|
271
260
|
function setWallet(address wallet_) external onlyComponentRole(RM_PROVIDER_ROLE) {
|
|
272
261
|
if (wallet_ == address(0)) {
|
|
273
262
|
revert NoZeroWallet();
|
|
274
263
|
}
|
|
275
264
|
_wallet = wallet_;
|
|
276
|
-
_parameterChanged(IAccessManager.GovernanceActions.setWallet, uint256(uint160(wallet_))
|
|
265
|
+
_parameterChanged(IAccessManager.GovernanceActions.setWallet, uint256(uint160(wallet_)));
|
|
277
266
|
}
|
|
278
267
|
|
|
279
268
|
function getMinimumPremium(
|
|
@@ -18,10 +18,10 @@ import {RiskModule} from "./RiskModule.sol";
|
|
|
18
18
|
* @author Ensuro
|
|
19
19
|
*/
|
|
20
20
|
contract SignedBucketRiskModule is RiskModule {
|
|
21
|
-
bytes32
|
|
22
|
-
bytes32
|
|
23
|
-
bytes32
|
|
24
|
-
bytes32
|
|
21
|
+
bytes32 internal constant POLICY_CREATOR_ROLE = keccak256("POLICY_CREATOR_ROLE");
|
|
22
|
+
bytes32 internal constant REPLACER_ROLE = keccak256("REPLACER_ROLE");
|
|
23
|
+
bytes32 internal constant PRICER_ROLE = keccak256("PRICER_ROLE");
|
|
24
|
+
bytes32 internal constant RESOLVER_ROLE = keccak256("RESOLVER_ROLE");
|
|
25
25
|
|
|
26
26
|
mapping(uint256 => PackedParams) internal _buckets;
|
|
27
27
|
|
|
@@ -114,7 +114,6 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
114
114
|
address payer,
|
|
115
115
|
address onBehalfOf
|
|
116
116
|
) internal returns (Policy.PolicyData memory createdPolicy) {
|
|
117
|
-
uint96 internalId = uint96(uint256(policyData) % 2 ** 96);
|
|
118
117
|
createdPolicy = _newPolicyWithParams(
|
|
119
118
|
payout,
|
|
120
119
|
premium,
|
|
@@ -122,7 +121,7 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
122
121
|
expiration,
|
|
123
122
|
payer,
|
|
124
123
|
onBehalfOf,
|
|
125
|
-
|
|
124
|
+
_makeInternalId(policyData),
|
|
126
125
|
bucketParams(bucketId)
|
|
127
126
|
);
|
|
128
127
|
emit NewSignedPolicy(createdPolicy.id, policyData);
|
|
@@ -225,10 +224,17 @@ contract SignedBucketRiskModule is RiskModule {
|
|
|
225
224
|
quoteSignatureVS,
|
|
226
225
|
quoteValidUntil
|
|
227
226
|
);
|
|
228
|
-
uint96 internalId = uint96(uint256(policyData) % 2 ** 96);
|
|
229
227
|
return
|
|
230
|
-
_replacePolicy(
|
|
231
|
-
|
|
228
|
+
_replacePolicy(
|
|
229
|
+
oldPolicy,
|
|
230
|
+
payout,
|
|
231
|
+
premium,
|
|
232
|
+
lossProb,
|
|
233
|
+
expiration,
|
|
234
|
+
_msgSender(),
|
|
235
|
+
_makeInternalId(policyData),
|
|
236
|
+
bucketParams(bucketId)
|
|
237
|
+
).id;
|
|
232
238
|
}
|
|
233
239
|
|
|
234
240
|
function resolvePolicy(
|
|
@@ -91,11 +91,14 @@ contract SignedQuoteRiskModule is RiskModule {
|
|
|
91
91
|
bytes32 quoteHash = ECDSA.toEthSignedMessageHash(
|
|
92
92
|
abi.encodePacked(address(this), payout, premium, lossProb, expiration, policyData, quoteValidUntil)
|
|
93
93
|
);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
_policyPool.access().checkComponentRole(
|
|
95
|
+
address(this),
|
|
96
|
+
PRICER_ROLE,
|
|
97
|
+
ECDSA.recover(quoteHash, quoteSignatureR, quoteSignatureVS),
|
|
98
|
+
false
|
|
99
|
+
);
|
|
97
100
|
|
|
98
|
-
createdPolicy = _newPolicy(payout, premium, lossProb, expiration, payer, onBehalfOf,
|
|
101
|
+
createdPolicy = _newPolicy(payout, premium, lossProb, expiration, payer, onBehalfOf, _makeInternalId(policyData));
|
|
99
102
|
emit NewSignedPolicy(createdPolicy.id, policyData);
|
|
100
103
|
return createdPolicy;
|
|
101
104
|
}
|
package/js/deploy.js
CHANGED
|
@@ -3,7 +3,7 @@ const fs = require("fs");
|
|
|
3
3
|
const ethers = require("ethers");
|
|
4
4
|
const { task, types } = require("hardhat/config");
|
|
5
5
|
const { WhitelistStatus } = require("../js/enums");
|
|
6
|
-
const { amountFunction, _W, grantRole, grantComponentRole, getDefaultSigner } = require("
|
|
6
|
+
const { amountFunction, _W, grantRole, grantComponentRole, getDefaultSigner } = require("@ensuro/utils/js/utils");
|
|
7
7
|
|
|
8
8
|
const reservesOpts = {
|
|
9
9
|
unsafeAllow: ["delegatecall"],
|
package/js/test-utils.js
CHANGED
|
@@ -1,48 +1,10 @@
|
|
|
1
1
|
const hre = require("hardhat");
|
|
2
|
-
const { _W, grantRole, getTransactionEvent } = require("
|
|
3
|
-
const { RiskModuleParameter } = require("
|
|
4
|
-
const helpers = require("@nomicfoundation/hardhat-network-helpers");
|
|
2
|
+
const { _W, grantRole, getTransactionEvent } = require("@ensuro/utils/js/utils");
|
|
3
|
+
const { RiskModuleParameter } = require("./enums");
|
|
5
4
|
|
|
6
5
|
const { ethers } = hre;
|
|
7
6
|
const { ZeroAddress } = ethers;
|
|
8
7
|
|
|
9
|
-
async function initCurrency(options, initial_targets, initial_balances) {
|
|
10
|
-
const Currency = await ethers.getContractFactory(options.contractClass || "TestCurrency");
|
|
11
|
-
let currency = await Currency.deploy(
|
|
12
|
-
options.name || "Test Currency",
|
|
13
|
-
options.symbol || "TEST",
|
|
14
|
-
options.initial_supply,
|
|
15
|
-
options.decimals || 18
|
|
16
|
-
);
|
|
17
|
-
initial_targets = initial_targets || [];
|
|
18
|
-
await Promise.all(
|
|
19
|
-
initial_targets.map(async function (user, index) {
|
|
20
|
-
await currency.transfer(user, initial_balances[index]);
|
|
21
|
-
})
|
|
22
|
-
);
|
|
23
|
-
return currency;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
28
|
-
* @param currencyAddress The currency contract address, for example the USDC address
|
|
29
|
-
* @param currencyOrigin An account that holds at least sum(initialBalances) of currency tokens
|
|
30
|
-
* @param initialTargets Array of addresses that will receive the initial balances
|
|
31
|
-
* @param initialBalances Initial balances for each address
|
|
32
|
-
*/
|
|
33
|
-
async function initForkCurrency(currencyAddress, currencyOrigin, initialTargets, initialBalances) {
|
|
34
|
-
const currency = await ethers.getContractAt("IERC20", currencyAddress);
|
|
35
|
-
await helpers.impersonateAccount(currencyOrigin);
|
|
36
|
-
await helpers.setBalance(currencyOrigin, ethers.parseEther("100"));
|
|
37
|
-
const whale = await ethers.getSigner(currencyOrigin);
|
|
38
|
-
await Promise.all(
|
|
39
|
-
initialTargets.map(async function (user, index) {
|
|
40
|
-
await currency.connect(whale).transfer(user, initialBalances[index]);
|
|
41
|
-
})
|
|
42
|
-
);
|
|
43
|
-
return currency;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
8
|
async function createRiskModule(
|
|
47
9
|
pool,
|
|
48
10
|
premiumsAccount,
|
|
@@ -227,7 +189,6 @@ async function deployPool(options) {
|
|
|
227
189
|
if (options.dontGrantL123Roles === undefined) {
|
|
228
190
|
await grantRole(hre, accessManager, "LEVEL1_ROLE");
|
|
229
191
|
await grantRole(hre, accessManager, "LEVEL2_ROLE");
|
|
230
|
-
await grantRole(hre, accessManager, "LEVEL3_ROLE");
|
|
231
192
|
}
|
|
232
193
|
|
|
233
194
|
return policyPool;
|
|
@@ -259,52 +220,6 @@ async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration,
|
|
|
259
220
|
return newPolicyEvt;
|
|
260
221
|
}
|
|
261
222
|
|
|
262
|
-
/**
|
|
263
|
-
* Resets hardhat network to fork on the specified block and url
|
|
264
|
-
*/
|
|
265
|
-
async function setupChain(block, alchemyUrlEnv = "ALCHEMY_URL") {
|
|
266
|
-
const alchemyUrl = process.env[alchemyUrlEnv];
|
|
267
|
-
if (alchemyUrl === undefined) throw new Error(`Define envvar ${alchemyUrlEnv} for this test`);
|
|
268
|
-
|
|
269
|
-
if (block === undefined) throw new Error("Block can't be undefined use null for the current block");
|
|
270
|
-
if (block === null) block = undefined;
|
|
271
|
-
return hre.network.provider.request({
|
|
272
|
-
method: "hardhat_reset",
|
|
273
|
-
params: [
|
|
274
|
-
{
|
|
275
|
-
forking: {
|
|
276
|
-
jsonRpcUrl: alchemyUrl,
|
|
277
|
-
blockNumber: block,
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
|
-
],
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const skipForkTests = process.env.SKIP_FORK_TESTS === "true";
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Chai test case wrapper for tests that require forking a live chain.
|
|
288
|
-
*
|
|
289
|
-
* It validates that the chain node URL is set, forks the chain at the specified block and adds the
|
|
290
|
-
* block number to the test name.
|
|
291
|
-
*/
|
|
292
|
-
const fork = {
|
|
293
|
-
it: (name, blockNumber, test, alchemyUrlEnv = "ALCHEMY_URL") => {
|
|
294
|
-
const fullName = `[FORK ${blockNumber}] ${name}`;
|
|
295
|
-
|
|
296
|
-
// eslint-disable-next-line func-style
|
|
297
|
-
const wrapped = async (...args) => {
|
|
298
|
-
await setupChain(blockNumber, alchemyUrlEnv);
|
|
299
|
-
|
|
300
|
-
return test(...args);
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
return (skipForkTests ? it.skip : it)(fullName, wrapped);
|
|
304
|
-
},
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
if (process.env.ENABLE_HH_WARNINGS !== "yes") hre.upgrades.silenceWarnings();
|
|
308
223
|
|
|
309
224
|
module.exports = {
|
|
310
225
|
addEToken,
|
|
@@ -313,10 +228,5 @@ module.exports = {
|
|
|
313
228
|
createRiskModule,
|
|
314
229
|
deployPool,
|
|
315
230
|
deployPremiumsAccount,
|
|
316
|
-
fork,
|
|
317
|
-
initCurrency,
|
|
318
|
-
initForkCurrency,
|
|
319
231
|
makePolicy,
|
|
320
|
-
setupChain,
|
|
321
|
-
skipForkTests,
|
|
322
232
|
};
|