forked from neptune-mutual-blue/protocol
-
Notifications
You must be signed in to change notification settings - Fork 1
/
cxToken.sol
209 lines (191 loc) · 6.92 KB
/
cxToken.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Neptune Mutual Protocol (https://neptunemutual.com)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "../../interfaces/IStore.sol";
import "../../interfaces/ICxToken.sol";
import "../../libraries/GovernanceUtilV1.sol";
import "../../libraries/PolicyHelperV1.sol";
import "../Recoverable.sol";
/**
* @title cxToken
*
* @dev cxTokens are minted when someone purchases a cover.
*
* <br /> <br />
*
* The cxTokens can be exchanged for a USD stablecoin at a 1:1 exchange rate
* after a cover incident is successfully resolved (minus platform fees).
* <br /> <br />
*
* **Restrictions:**
*
* - cxTokens cannot be transferred from one person to another.
* - Only claims can be submitted with cxTokens
* - There is a lag period before your cxTokens starts its coverage.
* cxTokens start coverage the next day (or longer) at the UTC EOD timestamp and remain valid until the expiration date.
* - The lag configuration can be found in [ProtoUtilV1.NS_COVERAGE_LAG](ProtoUtilV1.md)
* and [PolicyAdmin.getCoverageLag](PolicyAdmin.md#getcoveragelag) function.
*
*/
// slither-disable-next-line naming-convention
contract cxToken is ICxToken, Recoverable, ERC20 {
// solhint-disable-previous-line
using CoverUtilV1 for IStore;
using GovernanceUtilV1 for IStore;
using ProtoUtilV1 for IStore;
using PolicyHelperV1 for IStore;
using ValidationLibV1 for IStore;
// slither-disable-next-line naming-convention
bytes32 public immutable override COVER_KEY; // solhint-disable-line
// slither-disable-next-line naming-convention
bytes32 public immutable override PRODUCT_KEY; // solhint-disable-line
uint256 public immutable override createdOn = block.timestamp; // solhint-disable-line
uint256 public immutable override expiresOn;
/**
* @dev Constructs this contract.
*
* @param store Provide the store contract instance
* @param coverKey Enter the cover key
* @param productKey Enter the product key
* @param tokenName Enter token name for this ERC-20 contract. The token symbol will be `cxUSD`.
* @param expiry Provide the cover expiry timestamp
*
*/
constructor(
IStore store,
bytes32 coverKey,
bytes32 productKey,
string memory tokenName,
uint256 expiry
) ERC20(tokenName, "cxUSD") Recoverable(store) {
COVER_KEY = coverKey;
PRODUCT_KEY = productKey;
expiresOn = expiry;
}
/** @dev Account to coverage start date to amount mapping */
mapping(address => mapping(uint256 => uint256)) public coverageStartsFrom;
/**
* @dev Returns the value of the `coverageStartsFrom` mapping.
*
* Warning: this function does not validate the input arguments.
*
* @param account Enter an account to get the `coverageStartsFrom` value.
* @param date Enter a date. Ensure that you supply a UTC EOD value.
*
*/
function getCoverageStartsFrom(address account, uint256 date) external view override returns (uint256) {
return coverageStartsFrom[account][date];
}
/**
* @dev Gets sum of the lagged and, therefore, excluded policy of a given account.
*
* <br /><br />
*
* Only policies purchased within 24-48 hours (or longer depending on this cover's configuration) are valid.
* Given the present codebase, the loop that follows may appear pointless and invalid.
*
* <br /><br />
*
* Since the protocol is upgradable but not cxTokens,
* erroneous code could be introduced in the future,
* which is why we go all the way until the resolution deadline.
*
* @param account Enter an account.
*
*/
function _getExcludedCoverageOf(address account) private view returns (uint256 exclusion) {
uint256 incidentDate = s.getActiveIncidentDateInternal(COVER_KEY, PRODUCT_KEY);
uint256 resolutionEOD = PolicyHelperV1.getEODInternal(s.getResolutionTimestampInternal(COVER_KEY, PRODUCT_KEY));
uint256 totalDays = (resolutionEOD - incidentDate) / 1 days;
for (uint256 i = 0; i < totalDays; i++) {
uint256 date = PolicyHelperV1.getEODInternal(incidentDate + (i * 1 days));
exclusion += coverageStartsFrom[account][date];
}
}
/**
* @dev Gets the claimable policy of an account.
*
* Warning: this function does not validate the input arguments.
*
* @param account Enter an account.
*
*/
function getClaimablePolicyOf(address account) external view override returns (uint256) {
uint256 exclusion = _getExcludedCoverageOf(account);
uint256 balance = super.balanceOf(account);
if (exclusion > balance) {
return 0;
}
return balance - exclusion;
}
/**
* @dev Mints cxTokens when a policy is purchased.
* This feature can only be accessed by the latest policy smart contract.
*
* @custom:suppress-acl Can only be called by the latest policy contract
*
* @param coverKey Enter the cover key for which the cxTokens are being minted
* @param to Enter the address where the minted token will be sent
* @param amount Specify the amount of cxTokens to mint
*
*/
function mint(
bytes32 coverKey,
bytes32 productKey,
address to,
uint256 amount
) external override nonReentrant {
require(amount > 0, "Please specify amount");
require(coverKey == COVER_KEY, "Invalid cover");
require(productKey == PRODUCT_KEY, "Invalid product");
s.mustNotBePaused();
s.senderMustBePolicyContract();
s.mustBeSupportedProductOrEmpty(coverKey, productKey);
uint256 effectiveFrom = PolicyHelperV1.getEODInternal(block.timestamp) + s.getCoverageLagInternal(coverKey); // solhint-disable-line
coverageStartsFrom[to][effectiveFrom] += amount;
super._mint(to, amount);
}
/**
* @dev Burns the tokens held by the sender.
*
* @custom:suppress-acl This is a publicly accessible feature
*
* @param amount Specify the amount of tokens to burn
*
*/
function burn(uint256 amount) external override nonReentrant {
require(amount > 0, "Please specify amount");
s.mustNotBePaused();
super._burn(msg.sender, amount);
}
/**
* @dev Overrides Openzeppelin ERC-20 contract's `_beforeTokenTransfer` hook.
* This is called during `transfer`, `transferFrom`, `mint`, and `burn` function invocation.
*
* <br /><br/>
*
* **cxToken Restrictions:**
*
* - An expired cxToken can't be transferred.
* - cxTokens can only be transferred to the claims processor contract.
*
* @param from The account sending the cxTokens
* @param to The account receiving the cxTokens
*
*/
function _beforeTokenTransfer(
address from,
address to,
uint256
) internal view override {
// solhint-disable-next-line
if (block.timestamp > expiresOn) {
require(to == address(0), "Expired cxToken");
}
// cxTokens can only be transferred to the claims processor contract
if (from != address(0) && to != address(0)) {
s.mustBeExactContract(ProtoUtilV1.CNS_CLAIM_PROCESSOR, ProtoUtilV1.KEY_INTENTIONALLY_EMPTY, to);
}
}
}