@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.
- package/README.md +93 -0
- package/build/contracts/AaveAssetManager.sol/AaveAssetManager.json +772 -0
- package/build/contracts/BaseAssetManager.sol/BaseAssetManager.json +494 -0
- package/build/contracts/DataTypes.sol/DataTypes.json +10 -0
- package/build/contracts/EToken.sol/EToken.json +1148 -0
- package/build/contracts/FlightDelayRiskModule.sol/FlightDelayRiskModule.json +1093 -0
- package/build/contracts/LPManualWhitelist.sol/LPManualWhitelist.json +412 -0
- package/build/contracts/Policy.sol/Policy.json +10 -0
- package/build/contracts/PolicyNFT.sol/PolicyNFT.json +570 -0
- package/build/contracts/PolicyPool.sol/PolicyPool.json +1257 -0
- package/build/contracts/PolicyPoolComponent.sol/PolicyPoolComponent.json +281 -0
- package/build/contracts/PolicyPoolConfig.sol/PolicyPoolConfig.json +660 -0
- package/build/contracts/RiskModule.sol/RiskModule.json +748 -0
- package/build/contracts/TrustfulRiskModule.sol/TrustfulRiskModule.json +1032 -0
- package/build/contracts/WadRayMath.sol/WadRayMath.json +10 -0
- package/build/contracts/dependencies/ChainlinkClientUpgradeable.sol/ChainlinkClientUpgradeable.json +50 -0
- package/build/contracts/upgraded/IPolicyNFTv1.sol/IPolicyNFTv1.json +322 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1.json +571 -0
- package/build/contracts/upgraded/PolicyNFTv1.sol/PolicyNFTv1_Upgrade.json +602 -0
- package/build/interfaces/IAssetManager.sol/IAssetManager.json +31 -0
- package/build/interfaces/IEToken.sol/IEToken.json +491 -0
- package/build/interfaces/IInsolvencyHook.sol/IInsolvencyHook.json +42 -0
- package/build/interfaces/ILPWhitelist.sol/ILPWhitelist.json +74 -0
- package/build/interfaces/IPolicyNFT.sol/IPolicyNFT.json +321 -0
- package/build/interfaces/IPolicyPool.sol/IPolicyPool.json +445 -0
- package/build/interfaces/IPolicyPoolComponent.sol/IPolicyPoolComponent.json +24 -0
- package/build/interfaces/IPolicyPoolConfig.sol/IPolicyPoolConfig.json +328 -0
- package/build/interfaces/IRiskModule.sol/IRiskModule.json +141 -0
- package/contracts/AaveAssetManager.sol +326 -0
- package/contracts/BaseAssetManager.sol +283 -0
- package/contracts/DataTypes.sol +287 -0
- package/contracts/EToken.sol +773 -0
- package/contracts/FlightDelayRiskModule.sol +208 -0
- package/contracts/LPManualWhitelist.sol +57 -0
- package/contracts/Policy.sol +104 -0
- package/contracts/PolicyNFT.sol +96 -0
- package/contracts/PolicyPool.sol +716 -0
- package/contracts/PolicyPoolComponent.sol +164 -0
- package/contracts/PolicyPoolConfig.sol +231 -0
- package/contracts/RiskModule.sol +323 -0
- package/contracts/TrustfulRiskModule.sol +81 -0
- package/contracts/WadRayMath.sol +135 -0
- package/contracts/dependencies/ChainlinkClientUpgradeable.sol +371 -0
- package/contracts/upgraded/IPolicyNFTv1.sol +15 -0
- package/contracts/upgraded/PolicyNFTv1.sol +126 -0
- package/interfaces/IAssetManager.sol +23 -0
- package/interfaces/IEToken.sol +44 -0
- package/interfaces/IInsolvencyHook.sol +27 -0
- package/interfaces/ILPWhitelist.sol +23 -0
- package/interfaces/IPolicyNFT.sol +15 -0
- package/interfaces/IPolicyPool.sol +44 -0
- package/interfaces/IPolicyPoolComponent.sol +13 -0
- package/interfaces/IPolicyPoolConfig.sol +81 -0
- package/interfaces/IRiskModule.sol +29 -0
- package/package.json +30 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
5
|
+
import {Policy} from "./Policy.sol";
|
|
6
|
+
import {RiskModule} from "./RiskModule.sol";
|
|
7
|
+
import {Chainlink} from "@chainlink/contracts/src/v0.8/Chainlink.sol";
|
|
8
|
+
import {ChainlinkClientUpgradeable} from "./dependencies/ChainlinkClientUpgradeable.sol";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @title Flight Delay Risk Module
|
|
12
|
+
* @dev Risk Module that resolves policy based in actualarrivaldate of flight
|
|
13
|
+
* @custom:security-contact security@ensuro.co
|
|
14
|
+
* @author Ensuro
|
|
15
|
+
*/
|
|
16
|
+
contract FlightDelayRiskModule is RiskModule, ChainlinkClientUpgradeable {
|
|
17
|
+
using Chainlink for Chainlink.Request;
|
|
18
|
+
|
|
19
|
+
bytes32 public constant PRICER_ROLE = keccak256("PRICER_ROLE");
|
|
20
|
+
bytes32 public constant ORACLE_ADMIN_ROLE = keccak256("ORACLE_ADMIN_ROLE");
|
|
21
|
+
// Multiplier to calculate expiration = expectedArrival + tolerance + delayTime * DELAY_EXPIRATION_TIMES
|
|
22
|
+
uint40 public constant DELAY_EXPIRATION_TIMES = 5;
|
|
23
|
+
|
|
24
|
+
struct PolicyData {
|
|
25
|
+
Policy.PolicyData ensuroPolicy;
|
|
26
|
+
string flight;
|
|
27
|
+
uint40 departure;
|
|
28
|
+
uint40 expectedArrival;
|
|
29
|
+
uint40 tolerance;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
struct OracleParams {
|
|
33
|
+
address oracle;
|
|
34
|
+
uint96 delayTime;
|
|
35
|
+
uint256 fee;
|
|
36
|
+
bytes16 dataJobId;
|
|
37
|
+
bytes16 sleepJobId;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
OracleParams internal _oracleParams;
|
|
41
|
+
|
|
42
|
+
mapping(bytes32 => uint256) internal _pendingQueries;
|
|
43
|
+
mapping(uint256 => PolicyData) internal _policies;
|
|
44
|
+
|
|
45
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
46
|
+
// solhint-disable-next-line no-empty-blocks
|
|
47
|
+
constructor(IPolicyPool policyPool_) RiskModule(policyPool_) {}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @dev Initializes the RiskModule
|
|
51
|
+
* @param name_ Name of the Risk Module
|
|
52
|
+
* @param scrPercentage_ Solvency Capital Requirement percentage, to calculate
|
|
53
|
+
capital requirement as % of (payout - premium) (in ray)
|
|
54
|
+
* @param ensuroFee_ % of premium that will go for Ensuro treasury (in ray)
|
|
55
|
+
* @param scrInterestRate_ cost of capital (in ray)
|
|
56
|
+
* @param maxScrPerPolicy_ Max SCR to be allocated to this module (in wad)
|
|
57
|
+
* @param scrLimit_ Max SCR to be allocated to this module (in wad)
|
|
58
|
+
* @param wallet_ Address of the RiskModule provider
|
|
59
|
+
* @param linkToken_ Address of ChainLink LINK token
|
|
60
|
+
* @param oracleParams_ Parameters of the Oracle
|
|
61
|
+
*/
|
|
62
|
+
function initialize(
|
|
63
|
+
string memory name_,
|
|
64
|
+
uint256 scrPercentage_,
|
|
65
|
+
uint256 ensuroFee_,
|
|
66
|
+
uint256 scrInterestRate_,
|
|
67
|
+
uint256 maxScrPerPolicy_,
|
|
68
|
+
uint256 scrLimit_,
|
|
69
|
+
address wallet_,
|
|
70
|
+
address linkToken_,
|
|
71
|
+
OracleParams memory oracleParams_
|
|
72
|
+
) public initializer {
|
|
73
|
+
__RiskModule_init(
|
|
74
|
+
name_,
|
|
75
|
+
scrPercentage_,
|
|
76
|
+
ensuroFee_,
|
|
77
|
+
scrInterestRate_,
|
|
78
|
+
maxScrPerPolicy_,
|
|
79
|
+
scrLimit_,
|
|
80
|
+
wallet_
|
|
81
|
+
);
|
|
82
|
+
__ChainlinkClient_init();
|
|
83
|
+
__FlightDelayRiskModule_init_unchained(linkToken_, oracleParams_);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
87
|
+
function __FlightDelayRiskModule_init_unchained(
|
|
88
|
+
address linkToken_,
|
|
89
|
+
OracleParams memory oracleParams_
|
|
90
|
+
) internal initializer {
|
|
91
|
+
setChainlinkToken(linkToken_);
|
|
92
|
+
_oracleParams = oracleParams_;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function setOracleParams(OracleParams memory newParams) external onlyRole(ORACLE_ADMIN_ROLE) {
|
|
96
|
+
_oracleParams = newParams;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function oracleParams() external view returns (OracleParams memory) {
|
|
100
|
+
return _oracleParams;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @dev Creates a new policy
|
|
105
|
+
* @param flight Flight Number as String (ex: NAX105)
|
|
106
|
+
* @param departure Departure in epoch seconds (ex: 1631817600)
|
|
107
|
+
* @param expectedArrival Expected arrival in epoch seconds (ex: 1631824800)
|
|
108
|
+
* @param tolerance In seconds, the tolerance margin after expectedArrival before trigger the policy
|
|
109
|
+
* @param payout Payout for customer in case policy is triggered
|
|
110
|
+
* @param premium Premium the customer pays
|
|
111
|
+
* @param lossProb Probability of policy being triggered
|
|
112
|
+
* @param customer Customer address (to take premium from and send payout)
|
|
113
|
+
*/
|
|
114
|
+
function newPolicy(
|
|
115
|
+
string memory flight,
|
|
116
|
+
uint40 departure,
|
|
117
|
+
uint40 expectedArrival,
|
|
118
|
+
uint40 tolerance,
|
|
119
|
+
uint256 payout,
|
|
120
|
+
uint256 premium,
|
|
121
|
+
uint256 lossProb,
|
|
122
|
+
address customer,
|
|
123
|
+
uint96 internalId
|
|
124
|
+
) external onlyRole(PRICER_ROLE) returns (uint256) {
|
|
125
|
+
require(expectedArrival > block.timestamp, "expectedArrival can't be in the past");
|
|
126
|
+
require(departure != 0 && expectedArrival > departure, "expectedArrival <= departure!");
|
|
127
|
+
uint40 expiration = expectedArrival +
|
|
128
|
+
tolerance +
|
|
129
|
+
uint40(_oracleParams.delayTime) *
|
|
130
|
+
DELAY_EXPIRATION_TIMES;
|
|
131
|
+
Policy.PolicyData memory ensuroPolicy = _newPolicy(
|
|
132
|
+
payout,
|
|
133
|
+
premium,
|
|
134
|
+
lossProb,
|
|
135
|
+
expiration,
|
|
136
|
+
customer,
|
|
137
|
+
internalId
|
|
138
|
+
);
|
|
139
|
+
PolicyData storage policy = _policies[ensuroPolicy.id];
|
|
140
|
+
policy.ensuroPolicy = ensuroPolicy;
|
|
141
|
+
policy.flight = flight;
|
|
142
|
+
policy.departure = departure;
|
|
143
|
+
policy.expectedArrival = expectedArrival;
|
|
144
|
+
policy.tolerance = tolerance;
|
|
145
|
+
|
|
146
|
+
uint256 until = expectedArrival + tolerance + uint256(_oracleParams.delayTime);
|
|
147
|
+
_chainlinkRequest(ensuroPolicy.id, policy, until);
|
|
148
|
+
return ensuroPolicy.id;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function _chainlinkRequest(
|
|
152
|
+
uint256 policyId,
|
|
153
|
+
PolicyData storage policy,
|
|
154
|
+
uint256 until
|
|
155
|
+
) internal {
|
|
156
|
+
// request takes a JobID, a callback address, and callback function as input
|
|
157
|
+
Chainlink.Request memory req = buildChainlinkRequest(
|
|
158
|
+
until == 0 ? _oracleParams.dataJobId : _oracleParams.sleepJobId,
|
|
159
|
+
address(this),
|
|
160
|
+
this.fulfill.selector
|
|
161
|
+
);
|
|
162
|
+
req.add("flight", policy.flight);
|
|
163
|
+
req.add("endpoint", "actualarrivaldate");
|
|
164
|
+
req.addUint("departure", policy.departure);
|
|
165
|
+
if (until > 0) {
|
|
166
|
+
req.addUint("until", until);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Sends the request with the amount of payment specified to the oracle
|
|
170
|
+
// (results will arrive with the callback = later)
|
|
171
|
+
bytes32 queryId = sendChainlinkRequestTo(_oracleParams.oracle, req, _oracleParams.fee);
|
|
172
|
+
_pendingQueries[queryId] = policyId;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @dev Forces the resolution of the policy (without waiting Chainlink scheduled on creation)
|
|
177
|
+
* @param policyId The id of the policy previously created (in newPolicy)
|
|
178
|
+
*/
|
|
179
|
+
function resolvePolicy(uint256 policyId) external onlyRole(PRICER_ROLE) returns (uint256) {
|
|
180
|
+
PolicyData storage policy = _policies[policyId];
|
|
181
|
+
require(policy.expectedArrival != 0, "Policy not found!");
|
|
182
|
+
_chainlinkRequest(policyId, policy, 0);
|
|
183
|
+
return policyId;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function fulfill(bytes32 queryId, int256 actualArrivalDate)
|
|
187
|
+
public
|
|
188
|
+
recordChainlinkFulfillment(queryId)
|
|
189
|
+
{
|
|
190
|
+
uint256 policyId = _pendingQueries[queryId];
|
|
191
|
+
require(policyId != 0, "queryId not found!");
|
|
192
|
+
PolicyData storage policy = _policies[policyId];
|
|
193
|
+
|
|
194
|
+
if (actualArrivalDate == 0) {
|
|
195
|
+
if (block.timestamp > (policy.expectedArrival + policy.tolerance)) {
|
|
196
|
+
// Treat as arrived after tolerance
|
|
197
|
+
actualArrivalDate = int256(uint256((policy.expectedArrival + policy.tolerance) + 1));
|
|
198
|
+
} else {
|
|
199
|
+
// Not arrived yet
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
bool customerWon = (actualArrivalDate <= 0 || // cancelled
|
|
204
|
+
uint256(actualArrivalDate) > uint256(policy.expectedArrival + policy.tolerance)); // arrived after tolerance
|
|
205
|
+
|
|
206
|
+
_policyPool.resolvePolicyFullPayout(policy.ensuroPolicy, customerWon);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
5
|
+
import {PolicyPoolComponent} from "./PolicyPoolComponent.sol";
|
|
6
|
+
import {ILPWhitelist} from "../interfaces/ILPWhitelist.sol";
|
|
7
|
+
import {IEToken} from "../interfaces/IEToken.sol";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @title Manual Whitelisting contract
|
|
11
|
+
* @dev LP addresses are whitelisted (and un-whitelisted) manually with transactions by user with given role
|
|
12
|
+
* @custom:security-contact security@ensuro.co
|
|
13
|
+
* @author Ensuro
|
|
14
|
+
*/
|
|
15
|
+
contract LPManualWhitelist is ILPWhitelist, PolicyPoolComponent {
|
|
16
|
+
bytes32 public constant LP_WHITELIST_ROLE = keccak256("LP_WHITELIST_ROLE");
|
|
17
|
+
|
|
18
|
+
mapping(address => bool) private _whitelisted;
|
|
19
|
+
|
|
20
|
+
event LPWhitelisted(address provider, bool whitelisted);
|
|
21
|
+
|
|
22
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
23
|
+
// solhint-disable-next-line no-empty-blocks
|
|
24
|
+
constructor(IPolicyPool policyPool_) PolicyPoolComponent(policyPool_) {}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @dev Initializes the Whitelist contract
|
|
28
|
+
*/
|
|
29
|
+
function initialize() public initializer {
|
|
30
|
+
__PolicyPoolComponent_init();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function whitelistAddress(address provider, bool whitelisted)
|
|
34
|
+
external
|
|
35
|
+
onlyPoolRole(LP_WHITELIST_ROLE)
|
|
36
|
+
{
|
|
37
|
+
_whitelisted[provider] = whitelisted;
|
|
38
|
+
emit LPWhitelisted(provider, whitelisted);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function acceptsDeposit(
|
|
42
|
+
IEToken,
|
|
43
|
+
address provider,
|
|
44
|
+
uint256
|
|
45
|
+
) external view override returns (bool) {
|
|
46
|
+
return _whitelisted[provider];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function acceptsTransfer(
|
|
50
|
+
IEToken,
|
|
51
|
+
address,
|
|
52
|
+
address providerTo,
|
|
53
|
+
uint256
|
|
54
|
+
) external view override returns (bool) {
|
|
55
|
+
return _whitelisted[providerTo];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
import {WadRayMath} from "./WadRayMath.sol";
|
|
4
|
+
import {IRiskModule} from "../interfaces/IRiskModule.sol";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @title Policy library
|
|
8
|
+
* @dev Library for PolicyData struct. This struct represents an active policy, how the premium is
|
|
9
|
+
* distributed, the probability of payout, duration and how the capital is locked.
|
|
10
|
+
* @custom:security-contact security@ensuro.co
|
|
11
|
+
* @author Ensuro
|
|
12
|
+
*/
|
|
13
|
+
library Policy {
|
|
14
|
+
using WadRayMath for uint256;
|
|
15
|
+
|
|
16
|
+
uint256 internal constant SECONDS_IN_YEAR = 31536000e18; /* 365 * 24 * 3600 * 10e18 */
|
|
17
|
+
uint256 internal constant SECONDS_IN_YEAR_RAY = 31536000e27; /* 365 * 24 * 3600 * 10e27 */
|
|
18
|
+
|
|
19
|
+
// Active Policies
|
|
20
|
+
struct PolicyData {
|
|
21
|
+
uint256 id;
|
|
22
|
+
uint256 payout;
|
|
23
|
+
uint256 premium;
|
|
24
|
+
uint256 scr;
|
|
25
|
+
uint256 lossProb; // original loss probability (in ray)
|
|
26
|
+
uint256 purePremium; // share of the premium that covers expected losses
|
|
27
|
+
// equal to payout * lossProb * riskModule.moc
|
|
28
|
+
uint256 premiumForEnsuro; // share of the premium that goes for Ensuro (if policy won)
|
|
29
|
+
uint256 premiumForRm; // share of the premium that goes for the RM (if policy won)
|
|
30
|
+
uint256 premiumForLps; // share of the premium that goes to the liquidity providers (won or not)
|
|
31
|
+
IRiskModule riskModule;
|
|
32
|
+
uint40 start;
|
|
33
|
+
uint40 expiration;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// #if_succeeds {:msg "premium preserved"} premium == (newPolicy.premium);
|
|
37
|
+
/// #if_succeeds
|
|
38
|
+
/// {:msg "premium distributed"}
|
|
39
|
+
/// premium == (newPolicy.purePremium + newPolicy.premiumForLps +
|
|
40
|
+
/// newPolicy.premiumForRm + newPolicy.premiumForEnsuro);
|
|
41
|
+
function initialize(
|
|
42
|
+
IRiskModule riskModule,
|
|
43
|
+
uint256 premium,
|
|
44
|
+
uint256 payout,
|
|
45
|
+
uint256 lossProb,
|
|
46
|
+
uint40 expiration
|
|
47
|
+
) internal view returns (PolicyData memory newPolicy) {
|
|
48
|
+
require(premium <= payout, "Premium cannot be more than payout");
|
|
49
|
+
PolicyData memory policy;
|
|
50
|
+
policy.riskModule = riskModule;
|
|
51
|
+
policy.premium = premium;
|
|
52
|
+
policy.payout = payout;
|
|
53
|
+
policy.lossProb = lossProb;
|
|
54
|
+
policy.purePremium = payout.wadToRay().rayMul(lossProb.rayMul(riskModule.moc())).rayToWad();
|
|
55
|
+
policy.scr = payout.wadMul(riskModule.scrPercentage().rayToWad()) - policy.purePremium;
|
|
56
|
+
require(policy.scr != 0, "SCR can't be zero");
|
|
57
|
+
policy.start = uint40(block.timestamp);
|
|
58
|
+
policy.expiration = expiration;
|
|
59
|
+
policy.premiumForLps = policy.scr.wadMul(
|
|
60
|
+
(
|
|
61
|
+
(riskModule.scrInterestRate() * (policy.expiration - policy.start)).rayDiv(
|
|
62
|
+
SECONDS_IN_YEAR_RAY
|
|
63
|
+
)
|
|
64
|
+
).rayToWad()
|
|
65
|
+
);
|
|
66
|
+
policy.premiumForEnsuro = (policy.purePremium + policy.premiumForLps).wadMul(
|
|
67
|
+
riskModule.ensuroFee().rayToWad()
|
|
68
|
+
);
|
|
69
|
+
require(
|
|
70
|
+
policy.purePremium + policy.premiumForEnsuro + policy.premiumForLps <= premium,
|
|
71
|
+
"Premium less than minimum"
|
|
72
|
+
);
|
|
73
|
+
policy.premiumForRm =
|
|
74
|
+
premium -
|
|
75
|
+
policy.purePremium -
|
|
76
|
+
policy.premiumForLps -
|
|
77
|
+
policy.premiumForEnsuro;
|
|
78
|
+
return policy;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function interestRate(PolicyData memory policy) internal pure returns (uint256) {
|
|
82
|
+
return
|
|
83
|
+
policy
|
|
84
|
+
.premiumForLps
|
|
85
|
+
.wadMul(SECONDS_IN_YEAR)
|
|
86
|
+
.wadDiv((policy.expiration - policy.start) * policy.scr)
|
|
87
|
+
.wadToRay();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function accruedInterest(PolicyData memory policy) internal view returns (uint256) {
|
|
91
|
+
uint256 secs = block.timestamp - policy.start;
|
|
92
|
+
return
|
|
93
|
+
policy
|
|
94
|
+
.scr
|
|
95
|
+
.wadToRay()
|
|
96
|
+
.rayMul(secs * interestRate(policy))
|
|
97
|
+
.rayDiv(SECONDS_IN_YEAR_RAY)
|
|
98
|
+
.rayToWad();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function hash(PolicyData memory policy) internal pure returns (bytes32) {
|
|
102
|
+
return keccak256(abi.encode(policy));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.2;
|
|
3
|
+
|
|
4
|
+
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
5
|
+
import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
|
|
6
|
+
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
|
|
7
|
+
import {IPolicyPool} from "../interfaces/IPolicyPool.sol";
|
|
8
|
+
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
|
9
|
+
import {IPolicyNFT} from "../interfaces/IPolicyNFT.sol";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @title PolicyNFT - NFT that keeps track of issued policies and its owners
|
|
13
|
+
* @dev Every time a new policy is accepted by the PolicyPool, a new NFT is minted generating a new
|
|
14
|
+
* policyId owned by the customer. Only the PolicyPool can mint NFTs.
|
|
15
|
+
* After creation, NFTs can be transferred in the ERC721 standard way and that changes the policy holder.
|
|
16
|
+
* @custom:security-contact security@ensuro.co
|
|
17
|
+
* @author Ensuro
|
|
18
|
+
*/
|
|
19
|
+
contract PolicyNFT is UUPSUpgradeable, ERC721Upgradeable, PausableUpgradeable, IPolicyNFT {
|
|
20
|
+
bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");
|
|
21
|
+
bytes32 public constant LEVEL1_ROLE = keccak256("LEVEL1_ROLE");
|
|
22
|
+
|
|
23
|
+
IPolicyPool internal _policyPool;
|
|
24
|
+
|
|
25
|
+
modifier onlyPolicyPool() {
|
|
26
|
+
require(_msgSender() == address(_policyPool), "The caller must be the PolicyPool");
|
|
27
|
+
_;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
modifier onlyPoolRole2(bytes32 role1, bytes32 role2) {
|
|
31
|
+
_policyPool.config().checkRole2(role1, role2, msg.sender);
|
|
32
|
+
_;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
modifier onlyPoolRole(bytes32 role) {
|
|
36
|
+
_policyPool.config().checkRole(role, msg.sender);
|
|
37
|
+
_;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function initialize(
|
|
41
|
+
string memory name_,
|
|
42
|
+
string memory symbol_,
|
|
43
|
+
IPolicyPool policyPool_
|
|
44
|
+
) public initializer {
|
|
45
|
+
__UUPSUpgradeable_init();
|
|
46
|
+
__Pausable_init();
|
|
47
|
+
__ERC721_init(name_, symbol_);
|
|
48
|
+
__PolicyNFT_init_unchained(policyPool_);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// solhint-disable-next-line func-name-mixedcase
|
|
52
|
+
function __PolicyNFT_init_unchained(IPolicyPool policyPool_) internal initializer {
|
|
53
|
+
_policyPool = policyPool_;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// solhint-disable-next-line no-empty-blocks
|
|
57
|
+
function _authorizeUpgrade(address) internal override onlyPoolRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {}
|
|
58
|
+
|
|
59
|
+
function pause() public onlyPoolRole(GUARDIAN_ROLE) {
|
|
60
|
+
_pause();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function unpause() public onlyPoolRole2(GUARDIAN_ROLE, LEVEL1_ROLE) {
|
|
64
|
+
_unpause();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @dev This function can be called only once in contract's lifetime. It links the NFT with the
|
|
69
|
+
* PolicyPool contract. It's called in PolicyPool initialization.
|
|
70
|
+
*/
|
|
71
|
+
function connect() external override {
|
|
72
|
+
require(
|
|
73
|
+
address(_policyPool) == address(0) || address(_policyPool) == _msgSender(),
|
|
74
|
+
"PolicyPool already connected"
|
|
75
|
+
);
|
|
76
|
+
_policyPool = IPolicyPool(_msgSender());
|
|
77
|
+
// Not possible to do this validation because connect is called in _policyPool initialize :'(
|
|
78
|
+
// require(_policyPool.policyNFT() == address(this), "PolicyPool not connected to this config");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function policyPool() external view returns (IPolicyPool) {
|
|
82
|
+
return _policyPool;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function safeMint(address to, uint256 policyId) external override onlyPolicyPool whenNotPaused {
|
|
86
|
+
_safeMint(to, policyId, "");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function _beforeTokenTransfer(
|
|
90
|
+
address from,
|
|
91
|
+
address to,
|
|
92
|
+
uint256 tokenId
|
|
93
|
+
) internal override whenNotPaused {
|
|
94
|
+
super._beforeTokenTransfer(from, to, tokenId);
|
|
95
|
+
}
|
|
96
|
+
}
|