@ensuro/core 1.2.0

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.
Files changed (55) hide show
  1. package/README.md +93 -0
  2. package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +772 -0
  3. package/build/contracts/BaseAssetManager.sol/BaseAssetManager.json +494 -0
  4. package/build/contracts/DataTypes.sol/DataTypes.json +10 -0
  5. package/build/contracts/EToken.sol/EToken.json +1148 -0
  6. package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +1093 -0
  7. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +412 -0
  8. package/build/contracts/Policy.sol/Policy.json +10 -0
  9. package/build/contracts/PolicyNFT.sol/PolicyNFT.json +570 -0
  10. package/build/contracts/PolicyPool.sol/PolicyPool.json +1257 -0
  11. package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +281 -0
  12. package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +660 -0
  13. package/build/contracts/RiskModule.sol/RiskModule.json +748 -0
  14. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +1032 -0
  15. package/build/contracts/WadRayMath.sol/WadRayMath.json +10 -0
  16. package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +50 -0
  17. package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +322 -0
  18. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +571 -0
  19. package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +602 -0
  20. package/build/interfaces/IAssetManager.sol/IAssetManager.json +31 -0
  21. package/build/interfaces/IEToken.sol/IEToken.json +491 -0
  22. package/build/interfaces/IInsolvencyHook.sol/IInsolvencyHook.json +42 -0
  23. package/build/interfaces/ILPWhitelist.sol/ILPWhitelist.json +74 -0
  24. package/build/interfaces/IPolicyNFT.sol/IPolicyNFT.json +321 -0
  25. package/build/interfaces/IPolicyPool.sol/IPolicyPool.json +445 -0
  26. package/build/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +24 -0
  27. package/build/interfaces/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +328 -0
  28. package/build/interfaces/IRiskModule.sol/IRiskModule.json +141 -0
  29. package/contracts/AaveAssetManager.sol +326 -0
  30. package/contracts/BaseAssetManager.sol +283 -0
  31. package/contracts/DataTypes.sol +287 -0
  32. package/contracts/EToken.sol +773 -0
  33. package/contracts/FlightDelayRiskModule.sol +208 -0
  34. package/contracts/LPManualWhitelist.sol +57 -0
  35. package/contracts/Policy.sol +104 -0
  36. package/contracts/PolicyNFT.sol +96 -0
  37. package/contracts/PolicyPool.sol +716 -0
  38. package/contracts/PolicyPoolComponent.sol +164 -0
  39. package/contracts/PolicyPoolConfig.sol +231 -0
  40. package/contracts/RiskModule.sol +323 -0
  41. package/contracts/TrustfulRiskModule.sol +81 -0
  42. package/contracts/WadRayMath.sol +135 -0
  43. package/contracts/dependencies/ChainlinkClientUpgradeable.sol +371 -0
  44. package/contracts/upgraded/IPolicyNFTv1.sol +15 -0
  45. package/contracts/upgraded/PolicyNFTv1.sol +126 -0
  46. package/interfaces/IAssetManager.sol +23 -0
  47. package/interfaces/IEToken.sol +44 -0
  48. package/interfaces/IInsolvencyHook.sol +27 -0
  49. package/interfaces/ILPWhitelist.sol +23 -0
  50. package/interfaces/IPolicyNFT.sol +15 -0
  51. package/interfaces/IPolicyPool.sol +44 -0
  52. package/interfaces/IPolicyPoolComponent.sol +13 -0
  53. package/interfaces/IPolicyPoolConfig.sol +81 -0
  54. package/interfaces/IRiskModule.sol +29 -0
  55. package/package.json +30 -0
@@ -0,0 +1,164 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
5
+ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
+ import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
7
+ import {IPolicyPoolComponent} from "../interfaces/IPolicyPoolComponent.sol";
8
+ import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
9
+ import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
10
+ import {WadRayMath} from "./WadRayMath.sol";
11
+
12
+ /**
13
+ * @title Base class for PolicyPool components
14
+ * @dev This is the base class of all the components of the protocol that are linked to the PolicyPool and created
15
+ * after it.
16
+ * Holds the reference to _policyPool as immutable, also provides access to common admin roles:
17
+ * - LEVEL1_ROLE: High impact changes like upgrades or other critical operations
18
+ * - LEVEL2_ROLE: Mid-impact changes like adding new risk modules or changing some parameters
19
+ * - LEVEL3_ROLE: Low-impact changes like changing some parameters up to given percentage (tweaks)
20
+ * - GUARDIAN_ROLE: For emergency operations oriented to protect the protocol in case of attacks or hacking.
21
+ *
22
+ * This contract also keeps track of the tweaks to avoid two tweaks of the same type are done in a short period.
23
+ * @custom:security-contact security@ensuro.co
24
+ * @author Ensuro
25
+ */
26
+ abstract contract PolicyPoolComponent is
27
+ UUPSUpgradeable,
28
+ PausableUpgradeable,
29
+ IPolicyPoolComponent
30
+ {
31
+ using WadRayMath for uint256;
32
+
33
+ bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
34
+ bytes32 public constant LEVEL1_ROLE = keccak256("LEVEL1_ROLE");
35
+ bytes32 public constant LEVEL2_ROLE = keccak256("LEVEL2_ROLE");
36
+ bytes32 public constant LEVEL3_ROLE = keccak256("LEVEL3_ROLE");
37
+
38
+ uint40 public constant TWEAK_EXPIRATION = 1 days;
39
+
40
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
41
+ IPolicyPool internal immutable _policyPool;
42
+ uint40 internal _lastTweakTimestamp;
43
+ uint56 internal _lastTweakActions; // bitwise map of applied actions
44
+
45
+ event GovernanceAction(IPolicyPoolConfig.GovernanceActions indexed action, uint256 value);
46
+
47
+ modifier onlyPolicyPool() {
48
+ require(_msgSender() == address(_policyPool), "The caller must be the PolicyPool");
49
+ _;
50
+ }
51
+
52
+ modifier onlyPoolRole3(
53
+ bytes32 role1,
54
+ bytes32 role2,
55
+ bytes32 role3
56
+ ) {
57
+ if (!hasPoolRole(role1)) {
58
+ _policyPool.config().checkRole2(role2, role3, msg.sender);
59
+ }
60
+ _;
61
+ }
62
+
63
+ modifier onlyPoolRole2(bytes32 role1, bytes32 role2) {
64
+ _policyPool.config().checkRole2(role1, role2, msg.sender);
65
+ _;
66
+ }
67
+
68
+ modifier onlyPoolRole(bytes32 role) {
69
+ _policyPool.config().checkRole(role, msg.sender);
70
+ _;
71
+ }
72
+
73
+ /// @custom:oz-upgrades-unsafe-allow constructor
74
+ constructor(IPolicyPool policyPool_) {
75
+ _policyPool = policyPool_;
76
+ }
77
+
78
+ // solhint-disable-next-line func-name-mixedcase
79
+ function __PolicyPoolComponent_init() internal initializer {
80
+ __UUPSUpgradeable_init();
81
+ __Pausable_init();
82
+ }
83
+
84
+ // solhint-disable-next-line no-empty-blocks
85
+ function _authorizeUpgrade(address) internal override onlyPoolRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
86
+
87
+ function pause() public onlyPoolRole(GUARDIAN_ROLE) {
88
+ _pause();
89
+ }
90
+
91
+ function unpause() public onlyPoolRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
92
+ _unpause();
93
+ }
94
+
95
+ function policyPool() public view override returns (IPolicyPool) {
96
+ return _policyPool;
97
+ }
98
+
99
+ function currency() public view returns (IERC20Metadata) {
100
+ return _policyPool.currency();
101
+ }
102
+
103
+ function hasPoolRole(bytes32 role) internal view returns (bool) {
104
+ return _policyPool.config().hasRole(role, msg.sender);
105
+ }
106
+
107
+ function _isTweakRay(
108
+ uint256 oldValue,
109
+ uint256 newValue,
110
+ uint256 maxTweak
111
+ ) internal pure returns (bool) {
112
+ if (oldValue == newValue) return true;
113
+ if (oldValue == 0) return maxTweak >= WadRayMath.RAY;
114
+ if (newValue == 0) return false;
115
+ if (oldValue < newValue) {
116
+ return (newValue.rayDiv(oldValue) - WadRayMath.RAY) <= maxTweak;
117
+ } else {
118
+ return (WadRayMath.RAY - newValue.rayDiv(oldValue)) <= maxTweak;
119
+ }
120
+ }
121
+
122
+ function _isTweakWad(
123
+ uint256 oldValue,
124
+ uint256 newValue,
125
+ uint256 maxTweak
126
+ ) internal pure returns (bool) {
127
+ if (oldValue == newValue) return true;
128
+ if (oldValue == 0) return maxTweak >= WadRayMath.WAD;
129
+ if (newValue == 0) return false;
130
+ if (oldValue < newValue) {
131
+ return (newValue.wadDiv(oldValue) - WadRayMath.WAD) <= maxTweak;
132
+ } else {
133
+ return (WadRayMath.WAD - newValue.wadDiv(oldValue)) <= maxTweak;
134
+ }
135
+ }
136
+
137
+ function _parameterChanged(
138
+ IPolicyPoolConfig.GovernanceActions action,
139
+ uint256 value,
140
+ bool tweak
141
+ ) internal {
142
+ if (tweak) _registerTweak(action);
143
+ emit GovernanceAction(action, value);
144
+ }
145
+
146
+ function lastTweak() external view returns (uint40, uint56) {
147
+ return (_lastTweakTimestamp, _lastTweakActions);
148
+ }
149
+
150
+ function _registerTweak(IPolicyPoolConfig.GovernanceActions action) internal {
151
+ uint56 actionBitMap = uint56(1 << (uint8(action) - 1));
152
+ if ((uint40(block.timestamp) - _lastTweakTimestamp) > TWEAK_EXPIRATION) {
153
+ _lastTweakTimestamp = uint40(block.timestamp);
154
+ _lastTweakActions = actionBitMap;
155
+ } else {
156
+ if ((actionBitMap & _lastTweakActions) == 0) {
157
+ _lastTweakActions |= actionBitMap;
158
+ _lastTweakTimestamp = uint40(block.timestamp); // Updates the expiration
159
+ } else {
160
+ revert("You already tweaked this parameter recently. Wait before tweaking again");
161
+ }
162
+ }
163
+ }
164
+ }
@@ -0,0 +1,231 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
5
+ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
6
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
7
+ import {IAssetManager} from "../interfaces/IAssetManager.sol";
8
+ import {IInsolvencyHook} from "../interfaces/IInsolvencyHook.sol";
9
+ import {IPolicyPoolConfig} from "../interfaces/IPolicyPoolConfig.sol";
10
+ import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
11
+ import {IRiskModule} from "../interfaces/IRiskModule.sol";
12
+ import {ILPWhitelist} from "../interfaces/ILPWhitelist.sol";
13
+ import {IPolicyPoolComponent} from "../interfaces/IPolicyPoolComponent.sol";
14
+ import {WadRayMath} from "./WadRayMath.sol";
15
+
16
+ /**
17
+ * @title PolicyPoolConfig - Protocol access roles and other settings/components
18
+ * @dev Contract that holds the access roles for PolicyPool and other components of the protocol.
19
+ * @custom:security-contact security@ensuro.co
20
+ * @author Ensuro
21
+ */
22
+ contract PolicyPoolConfig is
23
+ Initializable,
24
+ AccessControlUpgradeable,
25
+ UUPSUpgradeable,
26
+ IPolicyPoolConfig
27
+ {
28
+ using WadRayMath for uint256;
29
+
30
+ // Core governance roles
31
+ bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
32
+ bytes32 public constant LEVEL1_ROLE = keccak256("LEVEL1_ROLE");
33
+ bytes32 public constant LEVEL2_ROLE = keccak256("LEVEL2_ROLE");
34
+ bytes32 public constant LEVEL3_ROLE = keccak256("LEVEL3_ROLE");
35
+
36
+ uint256 public constant L2_RM_LIMIT = 5e16; // 5% in WAD
37
+
38
+ address internal _treasury; // address of Ensuro treasury
39
+ IAssetManager internal _assetManager; // asset manager
40
+ IInsolvencyHook internal _insolvencyHook; // Contract that handles insolvency situations
41
+ IPolicyPool internal _policyPool;
42
+ ILPWhitelist internal _lpWhitelist; // Contract that handles whitelisting of Liquidity Providers
43
+
44
+ mapping(IRiskModule => RiskModuleStatus) private _riskModules;
45
+
46
+ event ComponentChanged(IPolicyPoolConfig.GovernanceActions indexed action, address value);
47
+
48
+ modifier onlyRole2(bytes32 role1, bytes32 role2) {
49
+ if (!hasRole(role1, _msgSender())) _checkRole(role2, _msgSender());
50
+ _;
51
+ }
52
+
53
+ modifier onlyRole3(
54
+ bytes32 role1,
55
+ bytes32 role2,
56
+ bytes32 role3
57
+ ) {
58
+ if (!hasRole(role1, _msgSender()) && !hasRole(role2, _msgSender())) {
59
+ _checkRole(role3, _msgSender());
60
+ }
61
+ _;
62
+ }
63
+
64
+ function initialize(IPolicyPool policyPool_, address treasury_) public initializer {
65
+ __AccessControl_init();
66
+ __UUPSUpgradeable_init();
67
+ __PolicyPoolConfig_init_unchained(policyPool_, treasury_);
68
+ }
69
+
70
+ // solhint-disable-next-line func-name-mixedcase
71
+ function __PolicyPoolConfig_init_unchained(IPolicyPool policyPool_, address treasury_)
72
+ internal
73
+ initializer
74
+ {
75
+ _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
76
+ _policyPool = policyPool_;
77
+ _treasury = treasury_;
78
+ }
79
+
80
+ /**
81
+ * @dev This function can be called only once in contract's lifetime. It links the PolicyPoolConfig with the
82
+ * PolicyPool contract. It's called in PolicyPool initialization.
83
+ */
84
+ function connect() external override {
85
+ require(
86
+ address(_policyPool) == address(0) || address(_policyPool) == _msgSender(),
87
+ "PolicyPool already connected"
88
+ );
89
+ _policyPool = IPolicyPool(_msgSender());
90
+ // Not possible to do this validation because connect is called in _policyPool initialize :'(
91
+ // require(_policyPool.config() == this, "PolicyPool not connected to this config");
92
+ }
93
+
94
+ function policyPool() external view returns (IPolicyPool) {
95
+ return _policyPool;
96
+ }
97
+
98
+ // solhint-disable-next-line no-empty-blocks
99
+ function _authorizeUpgrade(address) internal override onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
100
+
101
+ function checkRole(bytes32 role, address account) external view override {
102
+ _checkRole(role, account);
103
+ }
104
+
105
+ function checkRole2(
106
+ bytes32 role1,
107
+ bytes32 role2,
108
+ address account
109
+ ) external view override {
110
+ if (!hasRole(role1, account)) _checkRole(role2, account);
111
+ }
112
+
113
+ function setAssetManager(IAssetManager assetManager_) external onlyRole(LEVEL1_ROLE) {
114
+ require(
115
+ address(assetManager_) == address(0) ||
116
+ IPolicyPoolComponent(address(assetManager_)).policyPool() == _policyPool,
117
+ "Component not linked to this PolicyPool"
118
+ );
119
+ _policyPool.setAssetManager(assetManager_);
120
+ _assetManager = assetManager_;
121
+ emit ComponentChanged(GovernanceActions.setAssetManager, address(_assetManager));
122
+ }
123
+
124
+ function assetManager() external view virtual override returns (IAssetManager) {
125
+ return _assetManager;
126
+ }
127
+
128
+ function setTreasury(address treasury_) external onlyRole(LEVEL1_ROLE) {
129
+ _treasury = treasury_;
130
+ emit ComponentChanged(GovernanceActions.setTreasury, _treasury);
131
+ }
132
+
133
+ function treasury() external view override returns (address) {
134
+ return _treasury;
135
+ }
136
+
137
+ function setInsolvencyHook(IInsolvencyHook insolvencyHook_)
138
+ external
139
+ onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
140
+ {
141
+ require(
142
+ address(insolvencyHook_) == address(0) ||
143
+ IPolicyPoolComponent(address(insolvencyHook_)).policyPool() == _policyPool,
144
+ "Component not linked to this PolicyPool"
145
+ );
146
+ _insolvencyHook = insolvencyHook_;
147
+ emit ComponentChanged(GovernanceActions.setInsolvencyHook, address(_insolvencyHook));
148
+ }
149
+
150
+ function insolvencyHook() external view override returns (IInsolvencyHook) {
151
+ return _insolvencyHook;
152
+ }
153
+
154
+ function setLPWhitelist(ILPWhitelist lpWhitelist_)
155
+ external
156
+ onlyRole2(GUARDIAN_ROLE, LEVEL1_ROLE)
157
+ {
158
+ require(
159
+ address(lpWhitelist_) == address(0) ||
160
+ IPolicyPoolComponent(address(lpWhitelist_)).policyPool() == _policyPool,
161
+ "Component not linked to this PolicyPool"
162
+ );
163
+ _lpWhitelist = lpWhitelist_;
164
+ emit ComponentChanged(GovernanceActions.setLPWhitelist, address(_lpWhitelist));
165
+ }
166
+
167
+ function lpWhitelist() external view override returns (ILPWhitelist) {
168
+ return _lpWhitelist;
169
+ }
170
+
171
+ function addRiskModule(IRiskModule riskModule) external onlyRole2(LEVEL1_ROLE, LEVEL2_ROLE) {
172
+ require(
173
+ _riskModules[riskModule] == RiskModuleStatus.inactive,
174
+ "Risk Module already in the pool"
175
+ );
176
+ require(address(riskModule) != address(0), "riskModule can't be zero");
177
+ require(
178
+ IPolicyPoolComponent(address(riskModule)).policyPool() == _policyPool,
179
+ "RiskModule not linked to this pool"
180
+ );
181
+ require(
182
+ hasRole(LEVEL1_ROLE, msg.sender) ||
183
+ _policyPool.totalETokenSupply() > (riskModule.scrLimit().wadMul(L2_RM_LIMIT)),
184
+ "RiskModule SCR Limit exceeds the limit for LEVEL2 user"
185
+ );
186
+ _riskModules[riskModule] = RiskModuleStatus.active;
187
+ emit RiskModuleStatusChanged(riskModule, RiskModuleStatus.active);
188
+ }
189
+
190
+ function removeRiskModule(IRiskModule riskModule) external onlyRole(LEVEL2_ROLE) {
191
+ require(_riskModules[riskModule] != RiskModuleStatus.inactive, "Risk Module not found");
192
+ require(riskModule.totalScr() == 0, "Can't remove a module with active policies");
193
+ delete _riskModules[riskModule];
194
+ emit RiskModuleStatusChanged(riskModule, RiskModuleStatus.inactive);
195
+ }
196
+
197
+ // #if_succeeds_disabled _riskModules.get(riskModule) == newStatus;
198
+ function changeRiskModuleStatus(IRiskModule riskModule, RiskModuleStatus newStatus)
199
+ external
200
+ onlyRole3(GUARDIAN_ROLE, LEVEL1_ROLE, LEVEL2_ROLE)
201
+ {
202
+ require(_riskModules[riskModule] != RiskModuleStatus.inactive, "Risk Module not found");
203
+ require(
204
+ newStatus != RiskModuleStatus.suspended || hasRole(GUARDIAN_ROLE, msg.sender),
205
+ "Only GUARDIAN can suspend modules"
206
+ );
207
+ // To activate LEVEL1 required or LEVEL2 if <5% of total liquidity
208
+ require(
209
+ newStatus != RiskModuleStatus.active ||
210
+ hasRole(LEVEL1_ROLE, msg.sender) ||
211
+ _policyPool.totalETokenSupply() > (riskModule.scrLimit().wadMul(L2_RM_LIMIT)),
212
+ "RiskModule SCR Limit exceeds the limit for LEVEL2 user"
213
+ );
214
+ // Anyone (LEVEL1, LEVEL2, GUARDIAN) can deprecate
215
+ _riskModules[riskModule] = newStatus;
216
+ emit RiskModuleStatusChanged(riskModule, newStatus);
217
+ }
218
+
219
+ function checkAcceptsNewPolicy(IRiskModule riskModule) external view override {
220
+ RiskModuleStatus rmStatus = _riskModules[riskModule];
221
+ require(rmStatus == RiskModuleStatus.active, "RM module not found or not active");
222
+ }
223
+
224
+ function checkAcceptsResolvePolicy(IRiskModule riskModule) external view override {
225
+ RiskModuleStatus rmStatus = _riskModules[riskModule];
226
+ require(
227
+ rmStatus == RiskModuleStatus.active || rmStatus == RiskModuleStatus.deprecated,
228
+ "Module must be active or deprecated to process resolutions"
229
+ );
230
+ }
231
+ }