@ensuro/core 1.2.1 → 1.2.4

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.
@@ -14,6 +14,7 @@ import {IInsolvencyHook} from "../interfaces/IInsolvencyHook.sol";
14
14
  import {IPolicyPoolComponent} from "../interfaces/IPolicyPoolComponent.sol";
15
15
  import {IEToken} from "../interfaces/IEToken.sol";
16
16
  import {IPolicyNFT} from "../interfaces/IPolicyNFT.sol";
17
+ import {IPolicyHolder} from "../interfaces/IPolicyHolder.sol";
17
18
  import {IAssetManager} from "../interfaces/IAssetManager.sol";
18
19
  import {Policy} from "./Policy.sol";
19
20
  import {WadRayMath} from "./WadRayMath.sol";
@@ -45,7 +46,6 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
45
46
  // solhint-disable-next-line var-name-mixedcase
46
47
  uint256 public immutable NEGLIGIBLE_AMOUNT; // init as 10**(decimals-3) == 0.001 USD
47
48
 
48
- bytes32 public constant REBALANCE_ROLE = keccak256("REBALANCE_ROLE");
49
49
  bytes32 public constant WITHDRAW_WON_PREMIUMS_ROLE = keccak256("WITHDRAW_WON_PREMIUMS_ROLE");
50
50
 
51
51
  bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
@@ -466,19 +466,46 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
466
466
  delete _policies[policy.id];
467
467
  delete _policiesFunds[policy.id];
468
468
  if (payout > 0) {
469
- address customer = _policyNFT.ownerOf(policy.id);
470
- if (AddressUpgradeable.isContract(customer)) {
471
- // If it's a contract, call callback function to allow on-chain reaction
472
- // TODO: Should we use gasLimit?
473
- // TODO: Should have a reentrancy guard?
474
- // solhint-disable-next-line avoid-low-level-calls
475
- customer.call(
476
- abi.encodeWithSignature("ensuroPayoutCallback(uint256,uint256)", policy.id, payout)
477
- );
469
+ _notifyPayout(policy.id, payout);
470
+ } else {
471
+ _notifyExpiration(policy.id);
472
+ }
473
+ }
474
+
475
+ function _notifyPayout(uint256 policyId, uint256 payout) internal {
476
+ address customer = _policyNFT.ownerOf(policyId);
477
+ if (!AddressUpgradeable.isContract(customer)) return;
478
+ try
479
+ IPolicyHolder(customer).onPayoutReceived(_msgSender(), address(this), policyId, payout)
480
+ returns (bytes4 retval) {
481
+ require(
482
+ retval == IPolicyHolder.onPayoutReceived.selector,
483
+ "Invalid return value from Policy Holder"
484
+ );
485
+ } catch (bytes memory reason) {
486
+ if (reason.length == 0) {
487
+ return; // Not implemented, it's fine
488
+ } else {
489
+ // solhint-disable-next-line no-inline-assembly
490
+ assembly {
491
+ revert(add(32, reason), mload(reason))
492
+ }
478
493
  }
479
494
  }
480
495
  }
481
496
 
497
+ function _notifyExpiration(uint256 policyId) internal {
498
+ address customer = _policyNFT.ownerOf(policyId);
499
+ if (!AddressUpgradeable.isContract(customer)) return;
500
+ try IPolicyHolder(customer).onPolicyExpired(_msgSender(), address(this), policyId) returns (
501
+ bytes4
502
+ ) {
503
+ return;
504
+ } catch {
505
+ return;
506
+ }
507
+ }
508
+
482
509
  function _interestAdjustment(Policy.PolicyData memory policy)
483
510
  internal
484
511
  view
@@ -622,40 +649,6 @@ contract PolicyPool is IPolicyPool, PausableUpgradeable, UUPSUpgradeable {
622
649
  return amount;
623
650
  }
624
651
 
625
- function rebalancePolicy(Policy.PolicyData calldata policy)
626
- external
627
- onlyRole(REBALANCE_ROLE)
628
- whenNotPaused
629
- {
630
- _validatePolicy(policy);
631
- DataTypes.ETokenToWadMap storage policyFunds = _policiesFunds[policy.id];
632
- uint256 ocean = 0;
633
-
634
- // Iterates all the tokens
635
- // If locked - unlocks - finally stores the available ocean in policyFunds
636
- for (uint256 i = 0; i < _eTokens.length(); i++) {
637
- (IEToken etk, DataTypes.ETokenStatus etkStatus) = _eTokens.at(i);
638
- uint256 etkOcean = 0;
639
- (bool locked, uint256 etkScr) = policyFunds.tryGet(etk);
640
- if (locked) {
641
- etk.unlockScr(policy.interestRate(), etkScr);
642
- }
643
- if (
644
- etkStatus == DataTypes.ETokenStatus.active &&
645
- etk.accepts(address(policy.riskModule), policy.expiration)
646
- ) etkOcean = etk.oceanForNewScr();
647
- if (etkOcean == 0) {
648
- if (locked) policyFunds.remove(etk);
649
- } else {
650
- policyFunds.set(etk, etkOcean);
651
- ocean += etkOcean;
652
- }
653
- }
654
-
655
- _distributeScr(policy.scr, policy.interestRate(), ocean, policyFunds);
656
- emit PolicyRebalanced(policy.riskModule, policy.id);
657
- }
658
-
659
652
  function getInvestable() external view override returns (uint256) {
660
653
  uint256 borrowedFromEtk = 0;
661
654
  for (uint256 i = 0; i < _eTokens.length(); i++) {
@@ -41,4 +41,8 @@ interface IEToken is IERC20 {
41
41
  function getPoolLoan() external view returns (uint256);
42
42
 
43
43
  function getInvestable() external view returns (uint256);
44
+
45
+ function tokenInterestRate() external view returns (uint256);
46
+
47
+ function scrInterestRate() external view returns (uint256);
44
48
  }
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.0;
3
+
4
+ import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
5
+
6
+ /**
7
+ * @title Policy holder interface
8
+ * @dev Interface for any contract that wants to be a holder of Ensuro Policies and receive the payouts
9
+ */
10
+ interface IPolicyHolder is IERC721Receiver {
11
+ /**
12
+ * @dev Whenever an Policy is expired or resolved with payout = 0, this function is called
13
+ *
14
+ * It should return its Solidity selector to confirm the payout.
15
+ * If interface is not implemented by the recipient, it will be ignored and the payout will be successful.
16
+ * No mather what's the return value or even if this function reverts, this function will not revert the policy
17
+ * expiration.
18
+ *
19
+ * The selector can be obtained in Solidity with `IPolicyPool.onPolicyExpired.selector`.
20
+ */
21
+ function onPolicyExpired(
22
+ address operator,
23
+ address from,
24
+ uint256 policyId
25
+ ) external returns (bytes4);
26
+
27
+ /**
28
+ * @dev Whenever an Policy is resolved with payout > 0, this function is called
29
+ *
30
+ * It must return its Solidity selector to confirm the payout.
31
+ * If interface is not implemented by the recipient, it will be ignored and the payout will be successful.
32
+ * If any other value is returned or it reverts, the policy resolution / payout will be reverted.
33
+ *
34
+ * The selector can be obtained in Solidity with `IPolicyPool.onPayoutReceived.selector`.
35
+ */
36
+ function onPayoutReceived(
37
+ address operator,
38
+ address from,
39
+ uint256 policyId,
40
+ uint256 amount
41
+ ) external returns (bytes4);
42
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ensuro/core",
3
3
  "description": "Ensuro - Decentralized insurance protocol",
4
- "version": "1.2.1",
4
+ "version": "1.2.4",
5
5
  "files": [
6
6
  "**/*.sol",
7
7
  "/build/contracts/*.json",