@ensuro/core 2.0.0-beta5 → 2.0.0-beta7

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 (44) hide show
  1. package/build/contracts/AccessManager.sol/AccessManager.json +74 -2
  2. package/build/contracts/ERC4626AssetManager.sol/ERC4626AssetManager.json +219 -0
  3. package/build/contracts/EToken.sol/EToken.json +114 -45
  4. package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +2 -2
  5. package/build/contracts/LiquidityThresholdAssetManager.sol/LiquidityThresholdAssetManager.json +203 -0
  6. package/build/contracts/Policy.sol/Policy.json +2 -2
  7. package/build/contracts/PolicyPool.sol/PolicyPool.json +324 -100
  8. package/build/contracts/PremiumsAccount.sol/PremiumsAccount.json +122 -2
  9. package/build/contracts/Reserve.sol/Reserve.json +71 -0
  10. package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +3 -3
  11. package/build/contracts/interfaces/IAccessManager.sol/IAccessManager.json +96 -0
  12. package/build/contracts/interfaces/IAssetManager.sol/IAssetManager.json +109 -0
  13. package/build/contracts/interfaces/IEToken.sol/IEToken.json +13 -0
  14. package/build/contracts/interfaces/IPolicyPool.sol/IPolicyPool.json +6 -14
  15. package/build/contracts/interfaces/IPremiumsAccount.sol/IPremiumsAccount.json +13 -0
  16. package/build/contracts/mocks/FixedRateVault.sol/FixedRateVault.json +736 -0
  17. package/build/contracts/mocks/PolicyPoolComponentMock.sol/PolicyPoolComponentMock.json +2 -2
  18. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMock.json +7 -15
  19. package/build/contracts/mocks/PolicyPoolMock.sol/PolicyPoolMockForward.json +2 -2
  20. package/build/contracts/mocks/RiskModuleMock.sol/RiskModuleMock.json +674 -0
  21. package/contracts/AccessManager.sol +39 -8
  22. package/contracts/ERC4626AssetManager.sol +50 -0
  23. package/contracts/EToken.sol +72 -52
  24. package/contracts/LiquidityThresholdAssetManager.sol +158 -0
  25. package/contracts/PolicyPool.sol +155 -135
  26. package/contracts/PolicyPoolComponent.sol +29 -19
  27. package/contracts/PremiumsAccount.sol +125 -62
  28. package/contracts/Reserve.sol +86 -2
  29. package/contracts/RiskModule.sol +17 -6
  30. package/contracts/TrustfulRiskModule.sol +17 -2
  31. package/contracts/interfaces/IAccessManager.sol +23 -5
  32. package/contracts/interfaces/IAssetManager.sol +22 -0
  33. package/contracts/interfaces/IEToken.sol +21 -1
  34. package/contracts/interfaces/IPolicyPool.sol +6 -11
  35. package/contracts/interfaces/IPremiumsAccount.sol +5 -0
  36. package/contracts/mocks/FixedRateVault.sol +85 -0
  37. package/contracts/mocks/PolicyPoolMock.sol +2 -5
  38. package/contracts/mocks/RiskModuleMock.sol +69 -0
  39. package/js/test-utils.js +38 -31
  40. package/package.json +1 -1
  41. package/build/contracts/PolicyNFT.sol/PolicyNFT.json +0 -583
  42. package/build/contracts/interfaces/IPolicyNFT.sol/IPolicyNFT.json +0 -321
  43. package/contracts/PolicyNFT.sol +0 -96
  44. package/contracts/interfaces/IPolicyNFT.sol +0 -15
@@ -0,0 +1,85 @@
1
+ //SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+ import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
6
+ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
7
+ import {IMintableERC20} from "./IMintableERC20.sol";
8
+ import {TimeScaled} from "../TimeScaled.sol";
9
+
10
+ contract FixedRateVault is ERC4626 {
11
+ using TimeScaled for TimeScaled.ScaledAmount;
12
+
13
+ uint256 internal _interestRate;
14
+ TimeScaled.ScaledAmount internal _totalAssets;
15
+ bool internal _broken;
16
+
17
+ constructor(
18
+ string memory name_,
19
+ string memory symbol_,
20
+ IERC20Metadata asset_,
21
+ uint256 interestRate_
22
+ ) ERC20(name_, symbol_) ERC4626(asset_) {
23
+ _interestRate = interestRate_;
24
+ _totalAssets.init();
25
+ }
26
+
27
+ /** @dev See {IERC4262-totalAssets}. */
28
+ function totalAssets() public view virtual override returns (uint256) {
29
+ require(!_broken, "Vault is broken");
30
+ return _totalAssets.getScaledAmount(_interestRate);
31
+ }
32
+
33
+ /**
34
+ * @dev Deposit/mint common workflow.
35
+ */
36
+ function _deposit(
37
+ address caller,
38
+ address receiver,
39
+ uint256 assets,
40
+ uint256 shares
41
+ ) internal virtual override {
42
+ require(!_broken, "Vault is broken");
43
+ _totalAssets.add(assets, _interestRate);
44
+ super._deposit(caller, receiver, assets, shares);
45
+ }
46
+
47
+ /**
48
+ * @dev Withdraw/redeem common workflow.
49
+ */
50
+ function _withdraw(
51
+ address caller,
52
+ address receiver,
53
+ address owner,
54
+ uint256 assets,
55
+ uint256 shares
56
+ ) internal virtual override {
57
+ require(!_broken, "Vault is broken");
58
+ _totalAssets.sub(assets, _interestRate);
59
+ uint256 balance = IERC20Metadata(asset()).balanceOf(address(this));
60
+ if (balance < assets) {
61
+ // Here comes the magic! Free money!
62
+ IMintableERC20(asset()).mint(address(this), assets - balance);
63
+ }
64
+ super._withdraw(caller, receiver, owner, assets, shares);
65
+ }
66
+
67
+ /*
68
+ * @dev Adds or remove assets not generated by deposits/withdraw - For testing discrete earnings/losses
69
+ */
70
+ function discreteEarning(int256 assets) external {
71
+ if (assets > 0) {
72
+ _totalAssets.add(uint256(assets), _interestRate);
73
+ } else {
74
+ _totalAssets.sub(uint256(-assets), _interestRate);
75
+ }
76
+ }
77
+
78
+ function setBroken(bool broken_) external {
79
+ _broken = broken_;
80
+ }
81
+
82
+ function broken() external view returns (bool) {
83
+ return _broken;
84
+ }
85
+ }
@@ -38,17 +38,14 @@ contract PolicyPoolMock is IPolicyPool {
38
38
  return _access;
39
39
  }
40
40
 
41
- function policyNFT() external pure override returns (address) {
42
- return address(0);
43
- }
44
-
45
41
  function treasury() external pure override returns (address) {
46
42
  return address(0);
47
43
  }
48
44
 
49
45
  function newPolicy(
50
46
  Policy.PolicyData memory policy,
51
- address, /* customer */
47
+ address, /* caller */
48
+ address, /* policyHolder */
52
49
  uint96 internalId
53
50
  ) external override returns (uint256) {
54
51
  policy.id = (uint256(uint160(address(policy.riskModule))) << 96) + internalId;
@@ -0,0 +1,69 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ pragma solidity ^0.8.0;
4
+
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 Trustful Risk Module
12
+ * @dev Risk Module without any validation, just the newPolicy and resolvePolicy need to be called by
13
+ authorized users
14
+ * @custom:security-contact security@ensuro.co
15
+ * @author Ensuro
16
+ */
17
+
18
+ contract RiskModuleMock is RiskModule {
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 constructor
23
+ // solhint-disable-next-line no-empty-blocks
24
+ constructor(IPolicyPool policyPool_, IPremiumsAccount premiumsAccount_)
25
+ RiskModule(policyPool_, premiumsAccount_)
26
+ {} // solhint-disable-line no-empty-blocks
27
+
28
+ /**
29
+ * @dev Initializes the RiskModule
30
+ * @param name_ Name of the Risk Module
31
+ * @param collRatio_ Collateralization ratio to compute solvency requirement as % of payout (in ray)
32
+ * @param ensuroPpFee_ % of pure premium that will go for Ensuro treasury (in ray)
33
+ * @param srRoc_ return on capital paid to Senior LPs (annualized percentage - in ray)
34
+ * @param maxPayoutPerPolicy_ Maximum payout per policy (in wad)
35
+ * @param exposureLimit_ Max exposure (sum of payouts) to be allocated to this module (in wad)
36
+ * @param wallet_ Address of the RiskModule provider
37
+ */
38
+ function initialize(
39
+ string memory name_,
40
+ uint256 collRatio_,
41
+ uint256 ensuroPpFee_,
42
+ uint256 srRoc_,
43
+ uint256 maxPayoutPerPolicy_,
44
+ uint256 exposureLimit_,
45
+ address wallet_
46
+ ) public initializer {
47
+ __RiskModule_init(
48
+ name_,
49
+ collRatio_,
50
+ ensuroPpFee_,
51
+ srRoc_,
52
+ maxPayoutPerPolicy_,
53
+ exposureLimit_,
54
+ wallet_
55
+ );
56
+ }
57
+
58
+ function newPolicy(
59
+ uint256 payout,
60
+ uint256 premium,
61
+ uint256 lossProb,
62
+ uint40 expiration,
63
+ address payer,
64
+ address onBehalfOf,
65
+ uint96 internalId
66
+ ) external onlyComponentRole(PRICER_ROLE) returns (uint256) {
67
+ return _newPolicy(payout, premium, lossProb, expiration, payer, onBehalfOf, internalId).id;
68
+ }
69
+ }
package/js/test-utils.js CHANGED
@@ -70,7 +70,7 @@ exports.addRiskModule = async function (
70
70
  _W(scrInterestRate) || _W(0.1),
71
71
  _A(maxScrPerPolicy) || _A(1000),
72
72
  _A(scrLimit) || _A(1000000),
73
- wallet || "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", // Random address
73
+ wallet || "0xdD2FD4581271e230360230F9337D5c0430Bf44C0", // Random address
74
74
  ...extraArgs,
75
75
  ],
76
76
  {
@@ -86,7 +86,7 @@ exports.addRiskModule = async function (
86
86
  moc = _W(moc);
87
87
  await rm.setParam(0, moc);
88
88
  }
89
- await pool.addRiskModule(rm.address);
89
+ await pool.addComponent(rm.address, 2);
90
90
  return rm;
91
91
  };
92
92
 
@@ -114,7 +114,7 @@ exports.addEToken = async function (
114
114
  );
115
115
 
116
116
  await etk.deployed();
117
- await pool.addEToken(etk.address);
117
+ await pool.addComponent(etk.address, 1);
118
118
  return etk;
119
119
  };
120
120
 
@@ -142,7 +142,7 @@ exports.impersonate = async function (address, setBalanceTo) {
142
142
  * @param {String} eventName The name of the event we are interested in
143
143
  * @returns {LogDescription}
144
144
  */
145
- exports.getTransactionEvent = function (interface, receipt, eventName) {
145
+ const getTransactionEvent = function (interface, receipt, eventName) {
146
146
  // for each log in the transaction receipt
147
147
  for (const log of receipt.events) {
148
148
  let parsedLog;
@@ -158,43 +158,34 @@ exports.getTransactionEvent = function (interface, receipt, eventName) {
158
158
  return null; // not found
159
159
  };
160
160
 
161
+ exports.getTransactionEvent = getTransactionEvent;
162
+
161
163
  exports.deployPool = async function (hre, options) {
162
164
  const PolicyPool = await ethers.getContractFactory("PolicyPool");
163
165
  const AccessManager = await ethers.getContractFactory("AccessManager");
164
- const PolicyNFT = await ethers.getContractFactory("PolicyNFT");
165
-
166
- // Deploy PolicyNFT
167
- const policyNFT = await hre.upgrades.deployProxy(
168
- PolicyNFT,
169
- [
170
- options.nftName || "Policy NFT",
171
- options.nftSymbol || "EPOL",
172
- options.policyPoolDetAddress || ethers.constants.AddressZero,
173
- ],
174
- { kind: "uups" }
175
- );
176
- await policyNFT.deployed();
177
166
 
178
167
  // Deploy AccessManager
179
- const accessManager = await hre.upgrades.deployProxy(AccessManager, [
180
- options.policyPoolDetAddress || ethers.constants.AddressZero,
181
- ], {kind: 'uups'});
168
+ const accessManager = await hre.upgrades.deployProxy(AccessManager, [], { kind: "uups" });
182
169
 
183
170
  await accessManager.deployed();
184
171
 
185
172
  const policyPool = await hre.upgrades.deployProxy(
186
173
  PolicyPool,
187
- [options.treasuryAddress || ethers.constants.AddressZero],
174
+ [
175
+ options.nftName || "Policy NFT",
176
+ options.nftSymbol || "EPOL",
177
+ options.treasuryAddress || ethers.constants.AddressZero,
178
+ ],
188
179
  {
189
- constructorArgs: [accessManager.address, policyNFT.address, options.currency],
190
- kind: 'uups',
180
+ constructorArgs: [accessManager.address, options.currency],
181
+ kind: "uups",
191
182
  unsafeAllow: ["delegatecall"],
192
183
  }
193
184
  );
194
185
 
195
186
  await policyPool.deployed();
196
187
 
197
- for (const role of (options.grantRoles || [])) {
188
+ for (const role of options.grantRoles || []) {
198
189
  await grantRole(hre, accessManager, role);
199
190
  }
200
191
 
@@ -217,7 +208,7 @@ exports.deployPremiumsAccount = async function (hre, pool, options) {
217
208
  });
218
209
 
219
210
  await premiumsAccount.deployed();
220
- await pool.addPremiumsAccount(premiumsAccount.address);
211
+ await pool.addComponent(premiumsAccount.address, 3);
221
212
  return premiumsAccount;
222
213
  };
223
214
 
@@ -242,18 +233,18 @@ async function grantRole(hre, contract, role, user) {
242
233
 
243
234
  exports.grantRole = grantRole;
244
235
 
245
- async function grantComponentRole(hre, contract, component, role, user) {
236
+ async function grantComponentRole(hre, accessManager, component, role, user) {
246
237
  let userAddress;
247
238
  if (user === undefined) {
248
239
  user = await _getDefaultSigner(hre);
249
240
  userAddress = user.address;
250
241
  } else {
251
- userAddress = user;
242
+ userAddress = user.address === undefined ? user : user.address;
252
243
  }
253
244
  const roleHex = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(role));
254
- const componentRole = await contract.getComponentRole(component.address, roleHex);
255
- if (!(await contract.hasRole(componentRole, userAddress))) {
256
- await contract.grantComponentRole(component.address, roleHex, userAddress);
245
+ const componentRole = await accessManager.getComponentRole(component.address, roleHex);
246
+ if (!(await accessManager.hasRole(componentRole, userAddress))) {
247
+ await accessManager.grantComponentRole(component.address, roleHex, userAddress);
257
248
  }
258
249
  }
259
250
 
@@ -303,7 +294,7 @@ Mimics the behaviour of the PolicyPoolConfig.getComponentRole method
303
294
  Component roles are roles created doing XOR between the component
304
295
  address and the original role.
305
296
 
306
- Example:
297
+ Example:
307
298
  getComponentRole("0xc6e7DF5E7b4f2A278906862b61205850344D4e7d", "ORACLE_ADMIN_ROLE")
308
299
  // "0x05e01b185238b49f750d03d945e38a7f6c3be8b54de0ee42d481eb7814f0d3a8"
309
300
  */
@@ -334,3 +325,19 @@ function makePolicyId(rm, internalId) {
334
325
  }
335
326
 
336
327
  exports.makePolicyId = makePolicyId;
328
+
329
+ async function makePolicy(pool, rm, cust, payout, premium, lossProb, expiration, internalId) {
330
+ let tx = await rm.connect(cust).newPolicy(payout, premium, lossProb, expiration, cust.address, internalId);
331
+ let receipt = await tx.wait();
332
+ const newPolicyEvt = getTransactionEvent(pool.interface, receipt, "NewPolicy");
333
+
334
+ return newPolicyEvt;
335
+ }
336
+
337
+ exports.makePolicy = makePolicy;
338
+
339
+ async function blockchainNow(owner) {
340
+ return (await owner.provider.getBlock("latest")).timestamp;
341
+ }
342
+
343
+ exports.blockchainNow = blockchainNow;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ensuro/core",
3
3
  "description": "Ensuro - Decentralized insurance protocol",
4
- "version": "2.0.0-beta5",
4
+ "version": "v2.0.0-beta7",
5
5
  "files": [
6
6
  "**/*.sol",
7
7
  "/build/contracts/*.json",