@evvm/testnet-contracts 1.0.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/LICENSE +166 -0
- package/README.md +216 -0
- package/package.json +51 -0
- package/src/contracts/evvm/Evvm.sol +1327 -0
- package/src/contracts/evvm/EvvmLegacy.sol +1553 -0
- package/src/contracts/evvm/lib/ErrorsLib.sol +17 -0
- package/src/contracts/evvm/lib/EvvmStorage.sol +60 -0
- package/src/contracts/evvm/lib/EvvmStructs.sol +64 -0
- package/src/contracts/evvm/lib/SignatureUtils.sol +124 -0
- package/src/contracts/nameService/NameService.sol +1751 -0
- package/src/contracts/nameService/lib/ErrorsLib.sol +27 -0
- package/src/contracts/nameService/lib/SignatureUtils.sol +239 -0
- package/src/contracts/staking/Estimator.sol +358 -0
- package/src/contracts/staking/Staking.sol +1148 -0
- package/src/contracts/staking/lib/ErrorsLib.sol +19 -0
- package/src/contracts/staking/lib/SignatureUtils.sol +68 -0
- package/src/contracts/treasury/Treasury.sol +104 -0
- package/src/contracts/treasury/lib/ErrorsLib.sol +11 -0
- package/src/contracts/treasuryTwoChains/TreasuryExternalChainStation.sol +551 -0
- package/src/contracts/treasuryTwoChains/TreasuryHostChainStation.sol +512 -0
- package/src/contracts/treasuryTwoChains/lib/ErrorsLib.sol +15 -0
- package/src/contracts/treasuryTwoChains/lib/ExternalChainStationStructs.sol +41 -0
- package/src/contracts/treasuryTwoChains/lib/HostChainStationStructs.sol +52 -0
- package/src/contracts/treasuryTwoChains/lib/SignatureUtils.sol +47 -0
- package/src/interfaces/IEstimator.sol +102 -0
- package/src/interfaces/IEvvm.sol +195 -0
- package/src/interfaces/INameService.sol +283 -0
- package/src/interfaces/IStaking.sol +202 -0
- package/src/interfaces/ITreasury.sol +17 -0
- package/src/interfaces/ITreasuryExternalChainStation.sol +262 -0
- package/src/interfaces/ITreasuryHostChainStation.sol +251 -0
- package/src/lib/AdvancedStrings.sol +77 -0
- package/src/lib/Erc191TestBuilder.sol +402 -0
- package/src/lib/SignatureRecover.sol +56 -0
|
@@ -0,0 +1,1148 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EVVM-NONCOMMERCIAL-1.0
|
|
2
|
+
// Full license terms available at: https://www.evvm.info/docs/EVVMNoncommercialLicense
|
|
3
|
+
|
|
4
|
+
pragma solidity ^0.8.0;
|
|
5
|
+
/**
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/$$$$$$ /$$ /$$ /$$
|
|
9
|
+
/$$__ $$| $$ | $$ |__/
|
|
10
|
+
| $$ \__/$$$$$$ /$$$$$$| $$ /$$/$$/$$$$$$$ /$$$$$$
|
|
11
|
+
| $$$$$|_ $$_/ |____ $| $$ /$$| $| $$__ $$/$$__ $$
|
|
12
|
+
\____ $$| $$ /$$$$$$| $$$$$$/| $| $$ \ $| $$ \ $$
|
|
13
|
+
/$$ \ $$| $$ /$$/$$__ $| $$_ $$| $| $$ | $| $$ | $$
|
|
14
|
+
| $$$$$$/| $$$$| $$$$$$| $$ \ $| $| $$ | $| $$$$$$$
|
|
15
|
+
\______/ \___/ \_______|__/ \__|__|__/ |__/\____ $$
|
|
16
|
+
/$$ \ $$
|
|
17
|
+
| $$$$$$/
|
|
18
|
+
\______/
|
|
19
|
+
|
|
20
|
+
████████╗███████╗███████╗████████╗███╗ ██╗███████╗████████╗
|
|
21
|
+
╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝████╗ ██║██╔════╝╚══██╔══╝
|
|
22
|
+
██║ █████╗ ███████╗ ██║ ██╔██╗ ██║█████╗ ██║
|
|
23
|
+
██║ ██╔══╝ ╚════██║ ██║ ██║╚██╗██║██╔══╝ ██║
|
|
24
|
+
██║ ███████╗███████║ ██║ ██║ ╚████║███████╗ ██║
|
|
25
|
+
╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
|
|
26
|
+
* @title Staking Mate contract
|
|
27
|
+
* @author jistro.eth ariutokintumi.eth
|
|
28
|
+
* @notice This contract manages the staking mechanism for the EVVM ecosystem
|
|
29
|
+
* @dev Handles presale staking, public staking, and service staking with time locks and signature verification
|
|
30
|
+
*
|
|
31
|
+
* The contract supports three types of staking:
|
|
32
|
+
* 1. Golden Staking: Exclusive to the goldenFisher address
|
|
33
|
+
* 2. Presale Staking: Limited to 800 presale users with 2 staking token limit
|
|
34
|
+
* 3. Public Staking: Open to all users when enabled
|
|
35
|
+
* 4. Service Staking: Allows smart contracts to stake on behalf of users
|
|
36
|
+
*
|
|
37
|
+
* Key features:
|
|
38
|
+
* - Time-locked unstaking mechanisms
|
|
39
|
+
* - Signature-based authorization
|
|
40
|
+
* - Integration with EVVM core contract for payments and rewards
|
|
41
|
+
* - Estimator integration for yield calculations
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import {Evvm} from "@evvm/testnet-contracts/contracts/evvm/Evvm.sol";
|
|
45
|
+
import {NameService} from "@evvm/testnet-contracts/contracts/nameService/NameService.sol";
|
|
46
|
+
import {Estimator} from "@evvm/testnet-contracts/contracts/staking/Estimator.sol";
|
|
47
|
+
import {ErrorsLib} from "@evvm/testnet-contracts/contracts/staking/lib/ErrorsLib.sol";
|
|
48
|
+
import {SignatureUtils} from "@evvm/testnet-contracts/contracts/staking/lib/SignatureUtils.sol";
|
|
49
|
+
|
|
50
|
+
contract Staking {
|
|
51
|
+
/**
|
|
52
|
+
* @dev Metadata for presale stakers
|
|
53
|
+
* @param isAllow Whether the address is allowed to participate in presale staking
|
|
54
|
+
* @param stakingAmount Current number of staking tokens staked (max 2 for presale)
|
|
55
|
+
*/
|
|
56
|
+
struct presaleStakerMetadata {
|
|
57
|
+
bool isAllow;
|
|
58
|
+
uint256 stakingAmount;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @dev Struct to store the history of the user
|
|
63
|
+
* @param transactionType Type of transaction:
|
|
64
|
+
* - 0x01 for staking
|
|
65
|
+
* - 0x02 for unstaking
|
|
66
|
+
* - Other values for yield/reward transactions
|
|
67
|
+
* @param amount Amount of staking staked/unstaked or reward received
|
|
68
|
+
* @param timestamp Timestamp when the transaction occurred
|
|
69
|
+
* @param totalStaked Total amount of staking currently staked after this transaction
|
|
70
|
+
*/
|
|
71
|
+
struct HistoryMetadata {
|
|
72
|
+
bytes32 transactionType;
|
|
73
|
+
uint256 amount;
|
|
74
|
+
uint256 timestamp;
|
|
75
|
+
uint256 totalStaked;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @dev Struct for managing address change proposals with time delay
|
|
80
|
+
* @param actual Current active address
|
|
81
|
+
* @param proposal Proposed new address
|
|
82
|
+
* @param timeToAccept Timestamp when the proposal can be accepted
|
|
83
|
+
*/
|
|
84
|
+
struct AddressTypeProposal {
|
|
85
|
+
address actual;
|
|
86
|
+
address proposal;
|
|
87
|
+
uint256 timeToAccept;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @dev Struct for managing uint256 change proposals with time delay
|
|
92
|
+
* @param actual Current active value
|
|
93
|
+
* @param proposal Proposed new value
|
|
94
|
+
* @param timeToAccept Timestamp when the proposal can be accepted
|
|
95
|
+
*/
|
|
96
|
+
struct UintTypeProposal {
|
|
97
|
+
uint256 actual;
|
|
98
|
+
uint256 proposal;
|
|
99
|
+
uint256 timeToAccept;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @dev Struct for managing boolean flag changes with time delay
|
|
104
|
+
* @param flag Current boolean state
|
|
105
|
+
* @param timeToAccept Timestamp when the flag change can be executed
|
|
106
|
+
*/
|
|
107
|
+
struct BoolTypeProposal {
|
|
108
|
+
bool flag;
|
|
109
|
+
uint256 timeToAccept;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// @dev Address of the EVVM core contract
|
|
113
|
+
address private EVVM_ADDRESS;
|
|
114
|
+
|
|
115
|
+
/// @dev Maximum number of presale stakers allowed
|
|
116
|
+
uint256 private constant LIMIT_PRESALE_STAKER = 800;
|
|
117
|
+
/// @dev Current count of registered presale stakers
|
|
118
|
+
uint256 private presaleStakerCount;
|
|
119
|
+
/// @dev Price of one staking main token (5083 main token = 1 staking)
|
|
120
|
+
uint256 private constant PRICE_OF_STAKING = 5083 * (10 ** 18);
|
|
121
|
+
|
|
122
|
+
/// @dev Admin address management with proposal system
|
|
123
|
+
AddressTypeProposal private admin;
|
|
124
|
+
/// @dev Golden Fisher address management with proposal system
|
|
125
|
+
AddressTypeProposal private goldenFisher;
|
|
126
|
+
/// @dev Estimator contract address management with proposal system
|
|
127
|
+
AddressTypeProposal private estimator;
|
|
128
|
+
/// @dev Time delay for regular staking after unstaking
|
|
129
|
+
UintTypeProposal private secondsToUnlockStaking;
|
|
130
|
+
/// @dev Time delay for full unstaking (21 days default)
|
|
131
|
+
UintTypeProposal private secondsToUnllockFullUnstaking;
|
|
132
|
+
/// @dev Flag to enable/disable presale staking
|
|
133
|
+
BoolTypeProposal private allowPresaleStaking;
|
|
134
|
+
/// @dev Flag to enable/disable public staking
|
|
135
|
+
BoolTypeProposal private allowPublicStaking;
|
|
136
|
+
|
|
137
|
+
/// @dev Address representing the principal Principal Token
|
|
138
|
+
address private constant PRINCIPAL_TOKEN_ADDRESS =
|
|
139
|
+
0x0000000000000000000000000000000000000001;
|
|
140
|
+
|
|
141
|
+
/// @dev One-time setup breaker for estimator and EVVM addresses
|
|
142
|
+
bytes1 private breakerSetupEstimatorAndEvvm;
|
|
143
|
+
|
|
144
|
+
/// @dev Mapping to track used nonces for staking operations per user
|
|
145
|
+
mapping(address => mapping(uint256 => bool)) private stakingNonce;
|
|
146
|
+
|
|
147
|
+
/// @dev Mapping to store presale staker metadata
|
|
148
|
+
mapping(address => presaleStakerMetadata) private userPresaleStaker;
|
|
149
|
+
|
|
150
|
+
/// @dev Mapping to store complete staking history for each user
|
|
151
|
+
mapping(address => HistoryMetadata[]) private userHistory;
|
|
152
|
+
|
|
153
|
+
/// @dev Modifier to restrict access to admin functions
|
|
154
|
+
modifier onlyOwner() {
|
|
155
|
+
if (msg.sender != admin.actual) revert ErrorsLib.SenderIsNotAdmin();
|
|
156
|
+
|
|
157
|
+
_;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @notice Contract constructor
|
|
162
|
+
* @dev Initializes the staking contract with admin and golden fisher addresses
|
|
163
|
+
* @param initialAdmin Address that will have admin privileges
|
|
164
|
+
* @param initialGoldenFisher Address that will have golden fisher privileges
|
|
165
|
+
*/
|
|
166
|
+
constructor(address initialAdmin, address initialGoldenFisher) {
|
|
167
|
+
admin.actual = initialAdmin;
|
|
168
|
+
|
|
169
|
+
goldenFisher.actual = initialGoldenFisher;
|
|
170
|
+
|
|
171
|
+
allowPublicStaking.flag = true;
|
|
172
|
+
allowPresaleStaking.flag = false;
|
|
173
|
+
|
|
174
|
+
secondsToUnlockStaking.actual = 0;
|
|
175
|
+
|
|
176
|
+
secondsToUnllockFullUnstaking.actual = 21 days;
|
|
177
|
+
|
|
178
|
+
breakerSetupEstimatorAndEvvm = 0x01;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @notice One-time setup function for estimator and EVVM addresses
|
|
183
|
+
* @dev Can only be called once during contract initialization
|
|
184
|
+
* @param _estimator Address of the Estimator contract
|
|
185
|
+
* @param _evvm Address of the EVVM core contract
|
|
186
|
+
*/
|
|
187
|
+
function _setupEstimatorAndEvvm(
|
|
188
|
+
address _estimator,
|
|
189
|
+
address _evvm
|
|
190
|
+
) external {
|
|
191
|
+
if (breakerSetupEstimatorAndEvvm == 0x00) revert();
|
|
192
|
+
|
|
193
|
+
estimator.actual = _estimator;
|
|
194
|
+
EVVM_ADDRESS = _evvm;
|
|
195
|
+
breakerSetupEstimatorAndEvvm = 0x00;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @notice Allows the golden fisher to stake/unstake with synchronized EVVM nonces
|
|
200
|
+
* @dev Only the golden fisher address can call this function
|
|
201
|
+
* @param isStaking True for staking, false for unstaking
|
|
202
|
+
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
203
|
+
* @param signature_EVVM Signature for the EVVM contract transaction
|
|
204
|
+
*/
|
|
205
|
+
function goldenStaking(
|
|
206
|
+
bool isStaking,
|
|
207
|
+
uint256 amountOfStaking,
|
|
208
|
+
bytes memory signature_EVVM
|
|
209
|
+
) external {
|
|
210
|
+
if (msg.sender != goldenFisher.actual)
|
|
211
|
+
revert ErrorsLib.SenderIsNotGoldenFisher();
|
|
212
|
+
|
|
213
|
+
stakingUserProcess(
|
|
214
|
+
goldenFisher.actual,
|
|
215
|
+
amountOfStaking,
|
|
216
|
+
isStaking,
|
|
217
|
+
0,
|
|
218
|
+
Evvm(EVVM_ADDRESS).getNextCurrentSyncNonce(msg.sender),
|
|
219
|
+
false,
|
|
220
|
+
signature_EVVM
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @notice Allows presale users to stake/unstake with a limit of 2 staking tokens
|
|
226
|
+
* @dev Only registered presale users can call this function when presale staking is enabled
|
|
227
|
+
* @param user Address of the user performing the staking operation
|
|
228
|
+
* @param isStaking True for staking, false for unstaking
|
|
229
|
+
* @param nonce Unique nonce for this staking operation
|
|
230
|
+
* @param signature Signature proving authorization for this staking operation
|
|
231
|
+
* @param priorityFee_EVVM Priority fee for the EVVM transaction
|
|
232
|
+
* @param nonce_EVVM Nonce for the EVVM contract transaction
|
|
233
|
+
* @param priorityFlag_EVVM True for async EVVM transaction, false for sync
|
|
234
|
+
* @param signature_EVVM Signature for the EVVM contract transaction
|
|
235
|
+
*/
|
|
236
|
+
function presaleStaking(
|
|
237
|
+
address user,
|
|
238
|
+
bool isStaking,
|
|
239
|
+
uint256 nonce,
|
|
240
|
+
bytes memory signature,
|
|
241
|
+
uint256 priorityFee_EVVM,
|
|
242
|
+
uint256 nonce_EVVM,
|
|
243
|
+
bool priorityFlag_EVVM,
|
|
244
|
+
bytes memory signature_EVVM
|
|
245
|
+
) external {
|
|
246
|
+
if (
|
|
247
|
+
!SignatureUtils.verifyMessageSignedForStake(
|
|
248
|
+
Evvm(EVVM_ADDRESS).getEvvmID(),
|
|
249
|
+
user,
|
|
250
|
+
false,
|
|
251
|
+
isStaking,
|
|
252
|
+
1,
|
|
253
|
+
nonce,
|
|
254
|
+
signature
|
|
255
|
+
)
|
|
256
|
+
) revert ErrorsLib.InvalidSignatureOnStaking();
|
|
257
|
+
|
|
258
|
+
if (checkIfStakeNonceUsed(user, nonce))
|
|
259
|
+
revert ErrorsLib.StakingNonceAlreadyUsed();
|
|
260
|
+
|
|
261
|
+
presaleClaims(isStaking, user);
|
|
262
|
+
|
|
263
|
+
if (!allowPresaleStaking.flag)
|
|
264
|
+
revert ErrorsLib.PresaleStakingDisabled();
|
|
265
|
+
|
|
266
|
+
stakingUserProcess(
|
|
267
|
+
user,
|
|
268
|
+
1,
|
|
269
|
+
isStaking,
|
|
270
|
+
priorityFee_EVVM,
|
|
271
|
+
nonce_EVVM,
|
|
272
|
+
priorityFlag_EVVM,
|
|
273
|
+
signature_EVVM
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
stakingNonce[user][nonce] = true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* @notice Internal function to manage presale staking limits and permissions
|
|
281
|
+
* @dev Enforces the 2 staking token limit for presale users and tracks staking amounts
|
|
282
|
+
* @param _isStaking True for staking (increments count), false for unstaking (decrements count)
|
|
283
|
+
* @param _user Address of the presale user
|
|
284
|
+
*/
|
|
285
|
+
function presaleClaims(bool _isStaking, address _user) internal {
|
|
286
|
+
if (allowPublicStaking.flag) {
|
|
287
|
+
revert ErrorsLib.PresaleStakingDisabled();
|
|
288
|
+
} else {
|
|
289
|
+
if (userPresaleStaker[_user].isAllow) {
|
|
290
|
+
if (_isStaking) {
|
|
291
|
+
// staking
|
|
292
|
+
|
|
293
|
+
if (userPresaleStaker[_user].stakingAmount >= 2)
|
|
294
|
+
revert ErrorsLib.UserPresaleStakerLimitExceeded();
|
|
295
|
+
|
|
296
|
+
userPresaleStaker[_user].stakingAmount++;
|
|
297
|
+
} else {
|
|
298
|
+
// unstaking
|
|
299
|
+
|
|
300
|
+
if (userPresaleStaker[_user].stakingAmount == 0)
|
|
301
|
+
revert ErrorsLib.UserPresaleStakerLimitExceeded();
|
|
302
|
+
|
|
303
|
+
userPresaleStaker[_user].stakingAmount--;
|
|
304
|
+
}
|
|
305
|
+
} else {
|
|
306
|
+
revert ErrorsLib.UserIsNotPresaleStaker();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @notice Allows any user to stake/unstake when public staking is enabled
|
|
313
|
+
* @dev Requires signature verification and handles nonce management
|
|
314
|
+
* @param user Address of the user performing the staking operation
|
|
315
|
+
* @param isStaking True for staking, false for unstaking
|
|
316
|
+
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
317
|
+
* @param nonce Unique nonce for this staking operation
|
|
318
|
+
* @param signature Signature proving authorization for this staking operation
|
|
319
|
+
* @param priorityFee_EVVM Priority fee for the EVVM transaction
|
|
320
|
+
* @param nonce_EVVM Nonce for the EVVM contract transaction
|
|
321
|
+
* @param priorityFlag_EVVM True for async EVVM transaction, false for sync
|
|
322
|
+
* @param signature_EVVM Signature for the EVVM contract transaction
|
|
323
|
+
*/
|
|
324
|
+
function publicStaking(
|
|
325
|
+
address user,
|
|
326
|
+
bool isStaking,
|
|
327
|
+
uint256 amountOfStaking,
|
|
328
|
+
uint256 nonce,
|
|
329
|
+
bytes memory signature,
|
|
330
|
+
uint256 priorityFee_EVVM,
|
|
331
|
+
uint256 nonce_EVVM,
|
|
332
|
+
bool priorityFlag_EVVM,
|
|
333
|
+
bytes memory signature_EVVM
|
|
334
|
+
) external {
|
|
335
|
+
if (!allowPublicStaking.flag) {
|
|
336
|
+
revert();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (
|
|
340
|
+
!SignatureUtils.verifyMessageSignedForStake(
|
|
341
|
+
Evvm(EVVM_ADDRESS).getEvvmID(),
|
|
342
|
+
user,
|
|
343
|
+
true,
|
|
344
|
+
isStaking,
|
|
345
|
+
amountOfStaking,
|
|
346
|
+
nonce,
|
|
347
|
+
signature
|
|
348
|
+
)
|
|
349
|
+
) revert ErrorsLib.InvalidSignatureOnStaking();
|
|
350
|
+
|
|
351
|
+
if (checkIfStakeNonceUsed(user, nonce))
|
|
352
|
+
revert ErrorsLib.StakingNonceAlreadyUsed();
|
|
353
|
+
|
|
354
|
+
stakingUserProcess(
|
|
355
|
+
user,
|
|
356
|
+
amountOfStaking,
|
|
357
|
+
isStaking,
|
|
358
|
+
priorityFee_EVVM,
|
|
359
|
+
nonce_EVVM,
|
|
360
|
+
priorityFlag_EVVM,
|
|
361
|
+
signature_EVVM
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
stakingNonce[user][nonce] = true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* @notice Allows smart contracts (services) to stake on behalf of users
|
|
369
|
+
* @dev Verifies that the service address has contract code and handles service-specific logic
|
|
370
|
+
* @param user Address of the user who owns the stake
|
|
371
|
+
* @param service Address of the smart contract performing the staking
|
|
372
|
+
* @param isStaking True for staking, false for unstaking
|
|
373
|
+
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
374
|
+
* @param nonce Unique nonce for this staking operation
|
|
375
|
+
* @param signature Signature proving authorization for service staking
|
|
376
|
+
* @param priorityFee_EVVM Priority fee for the EVVM transaction (only for staking)
|
|
377
|
+
* @param nonce_EVVM Nonce for the EVVM contract transaction (only for staking)
|
|
378
|
+
* @param priorityFlag_EVVM Priority flag for EVVM transaction (only for staking)
|
|
379
|
+
* @param signature_EVVM Signature for the EVVM contract transaction (only for staking)
|
|
380
|
+
*/
|
|
381
|
+
function publicServiceStaking(
|
|
382
|
+
address user,
|
|
383
|
+
address service,
|
|
384
|
+
bool isStaking,
|
|
385
|
+
uint256 amountOfStaking,
|
|
386
|
+
uint256 nonce,
|
|
387
|
+
bytes memory signature,
|
|
388
|
+
uint256 priorityFee_EVVM,
|
|
389
|
+
uint256 nonce_EVVM,
|
|
390
|
+
bool priorityFlag_EVVM,
|
|
391
|
+
bytes memory signature_EVVM
|
|
392
|
+
) external {
|
|
393
|
+
if (!allowPublicStaking.flag) revert ErrorsLib.PublicStakingDisabled();
|
|
394
|
+
|
|
395
|
+
uint256 size;
|
|
396
|
+
|
|
397
|
+
assembly {
|
|
398
|
+
/// @dev check the size of the opcode of the address
|
|
399
|
+
size := extcodesize(service)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (size == 0) revert ErrorsLib.AddressIsNotAService();
|
|
403
|
+
|
|
404
|
+
if (isStaking) {
|
|
405
|
+
if (
|
|
406
|
+
!SignatureUtils.verifyMessageSignedForPublicServiceStake(
|
|
407
|
+
Evvm(EVVM_ADDRESS).getEvvmID(),
|
|
408
|
+
user,
|
|
409
|
+
service,
|
|
410
|
+
isStaking,
|
|
411
|
+
amountOfStaking,
|
|
412
|
+
nonce,
|
|
413
|
+
signature
|
|
414
|
+
)
|
|
415
|
+
) revert ErrorsLib.InvalidSignatureOnStaking();
|
|
416
|
+
} else {
|
|
417
|
+
if (service != user) revert ErrorsLib.UserAndServiceMismatch();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (checkIfStakeNonceUsed(user, nonce))
|
|
421
|
+
revert ErrorsLib.StakingNonceAlreadyUsed();
|
|
422
|
+
|
|
423
|
+
stakingServiceProcess(
|
|
424
|
+
user,
|
|
425
|
+
service,
|
|
426
|
+
isStaking,
|
|
427
|
+
amountOfStaking,
|
|
428
|
+
isStaking ? priorityFee_EVVM : 0,
|
|
429
|
+
isStaking ? nonce_EVVM : 0,
|
|
430
|
+
isStaking ? priorityFlag_EVVM : false,
|
|
431
|
+
isStaking ? signature_EVVM : bytes("")
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
stakingNonce[user][nonce] = true;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* @notice Internal function to process service staking operations
|
|
439
|
+
* @dev Wrapper function that calls the base staking process for service operations
|
|
440
|
+
* @param user Address of the user who owns the stake
|
|
441
|
+
* @param service Address of the smart contract performing the staking
|
|
442
|
+
* @param isStaking True for staking, false for unstaking
|
|
443
|
+
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
444
|
+
* @param priorityFee_EVVM Priority fee for the EVVM transaction
|
|
445
|
+
* @param nonce_EVVM Nonce for the EVVM contract transaction
|
|
446
|
+
* @param priorityFlag_EVVM Priority flag for EVVM transaction
|
|
447
|
+
* @param signature_EVVM Signature for the EVVM contract transaction
|
|
448
|
+
*/
|
|
449
|
+
function stakingServiceProcess(
|
|
450
|
+
address user,
|
|
451
|
+
address service,
|
|
452
|
+
bool isStaking,
|
|
453
|
+
uint256 amountOfStaking,
|
|
454
|
+
uint256 priorityFee_EVVM,
|
|
455
|
+
uint256 nonce_EVVM,
|
|
456
|
+
bool priorityFlag_EVVM,
|
|
457
|
+
bytes memory signature_EVVM
|
|
458
|
+
) internal {
|
|
459
|
+
stakingBaseProcess(
|
|
460
|
+
user,
|
|
461
|
+
service,
|
|
462
|
+
isStaking,
|
|
463
|
+
amountOfStaking,
|
|
464
|
+
priorityFee_EVVM,
|
|
465
|
+
nonce_EVVM,
|
|
466
|
+
priorityFlag_EVVM,
|
|
467
|
+
signature_EVVM
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* @notice Internal function to process user staking operations
|
|
473
|
+
* @dev Wrapper function that calls the base staking process for user operations
|
|
474
|
+
* @param user Address of the user performing the staking operation
|
|
475
|
+
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
476
|
+
* @param isStaking True for staking, false for unstaking
|
|
477
|
+
* @param priorityFee_EVVM Priority fee for the EVVM transaction
|
|
478
|
+
* @param nonce_EVVM Nonce for the EVVM contract transaction
|
|
479
|
+
* @param priorityFlag_EVVM Priority flag for EVVM transaction
|
|
480
|
+
* @param signature_EVVM Signature for the EVVM contract transaction
|
|
481
|
+
*/
|
|
482
|
+
function stakingUserProcess(
|
|
483
|
+
address user,
|
|
484
|
+
uint256 amountOfStaking,
|
|
485
|
+
bool isStaking,
|
|
486
|
+
uint256 priorityFee_EVVM,
|
|
487
|
+
uint256 nonce_EVVM,
|
|
488
|
+
bool priorityFlag_EVVM,
|
|
489
|
+
bytes memory signature_EVVM
|
|
490
|
+
) internal {
|
|
491
|
+
stakingBaseProcess(
|
|
492
|
+
user,
|
|
493
|
+
user,
|
|
494
|
+
isStaking,
|
|
495
|
+
amountOfStaking,
|
|
496
|
+
priorityFee_EVVM,
|
|
497
|
+
nonce_EVVM,
|
|
498
|
+
priorityFlag_EVVM,
|
|
499
|
+
signature_EVVM
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* @notice Core staking logic that handles both service and user staking operations
|
|
505
|
+
* @dev Processes payments, updates history, handles time locks, and manages EVVM integration
|
|
506
|
+
* @param userAccount Address of the user paying for the transaction
|
|
507
|
+
* @param stakingAccount Address that will receive the stake/unstake (can be same as userAccount)
|
|
508
|
+
* @param isStaking True for staking (requires payment), false for unstaking (provides refund)
|
|
509
|
+
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
510
|
+
* @param priorityFee_EVVM Priority fee for EVVM transaction
|
|
511
|
+
* @param nonce_EVVM Nonce for EVVM contract transaction
|
|
512
|
+
* @param priorityFlag_EVVM True for async EVVM transaction, false for sync
|
|
513
|
+
* @param signature_EVVM Signature for EVVM contract transaction
|
|
514
|
+
*/
|
|
515
|
+
function stakingBaseProcess(
|
|
516
|
+
address userAccount,
|
|
517
|
+
address stakingAccount,
|
|
518
|
+
bool isStaking,
|
|
519
|
+
uint256 amountOfStaking,
|
|
520
|
+
uint256 priorityFee_EVVM,
|
|
521
|
+
uint256 nonce_EVVM,
|
|
522
|
+
bool priorityFlag_EVVM,
|
|
523
|
+
bytes memory signature_EVVM
|
|
524
|
+
) internal {
|
|
525
|
+
uint256 auxSMsteBalance;
|
|
526
|
+
|
|
527
|
+
if (isStaking) {
|
|
528
|
+
if (
|
|
529
|
+
getTimeToUserUnlockStakingTime(stakingAccount) > block.timestamp
|
|
530
|
+
) revert ErrorsLib.UserMustWaitToStakeAgain();
|
|
531
|
+
|
|
532
|
+
makePay(
|
|
533
|
+
userAccount,
|
|
534
|
+
(PRICE_OF_STAKING * amountOfStaking),
|
|
535
|
+
priorityFee_EVVM,
|
|
536
|
+
priorityFlag_EVVM,
|
|
537
|
+
nonce_EVVM,
|
|
538
|
+
signature_EVVM
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
Evvm(EVVM_ADDRESS).pointStaker(stakingAccount, 0x01);
|
|
542
|
+
|
|
543
|
+
auxSMsteBalance = userHistory[stakingAccount].length == 0
|
|
544
|
+
? amountOfStaking
|
|
545
|
+
: userHistory[stakingAccount][
|
|
546
|
+
userHistory[stakingAccount].length - 1
|
|
547
|
+
].totalStaked + amountOfStaking;
|
|
548
|
+
} else {
|
|
549
|
+
if (amountOfStaking == getUserAmountStaked(stakingAccount)) {
|
|
550
|
+
if (
|
|
551
|
+
getTimeToUserUnlockFullUnstakingTime(stakingAccount) >
|
|
552
|
+
block.timestamp
|
|
553
|
+
) revert ErrorsLib.UserMustWaitToFullUnstake();
|
|
554
|
+
|
|
555
|
+
Evvm(EVVM_ADDRESS).pointStaker(stakingAccount, 0x00);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Only for user unstaking, not service
|
|
559
|
+
if (userAccount == stakingAccount && priorityFee_EVVM != 0) {
|
|
560
|
+
makePay(
|
|
561
|
+
userAccount,
|
|
562
|
+
priorityFee_EVVM,
|
|
563
|
+
0,
|
|
564
|
+
priorityFlag_EVVM,
|
|
565
|
+
nonce_EVVM,
|
|
566
|
+
signature_EVVM
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
auxSMsteBalance =
|
|
571
|
+
userHistory[stakingAccount][
|
|
572
|
+
userHistory[stakingAccount].length - 1
|
|
573
|
+
].totalStaked -
|
|
574
|
+
amountOfStaking;
|
|
575
|
+
|
|
576
|
+
makeCaPay(
|
|
577
|
+
PRINCIPAL_TOKEN_ADDRESS,
|
|
578
|
+
stakingAccount,
|
|
579
|
+
(PRICE_OF_STAKING * amountOfStaking)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
userHistory[stakingAccount].push(
|
|
584
|
+
HistoryMetadata({
|
|
585
|
+
transactionType: isStaking
|
|
586
|
+
? bytes32(uint256(1))
|
|
587
|
+
: bytes32(uint256(2)),
|
|
588
|
+
amount: amountOfStaking,
|
|
589
|
+
timestamp: block.timestamp,
|
|
590
|
+
totalStaked: auxSMsteBalance
|
|
591
|
+
})
|
|
592
|
+
);
|
|
593
|
+
|
|
594
|
+
if (Evvm(EVVM_ADDRESS).isAddressStaker(msg.sender)) {
|
|
595
|
+
makeCaPay(
|
|
596
|
+
PRINCIPAL_TOKEN_ADDRESS,
|
|
597
|
+
msg.sender,
|
|
598
|
+
(Evvm(EVVM_ADDRESS).getRewardAmount() * 2) + priorityFee_EVVM
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* @notice Allows users to claim their staking rewards (yield)
|
|
605
|
+
* @dev Interacts with the Estimator contract to calculate and distribute rewards
|
|
606
|
+
* @param user Address of the user claiming rewards
|
|
607
|
+
* @return epochAnswer Epoch identifier for the reward calculation
|
|
608
|
+
* @return tokenToBeRewarded Address of the token being rewarded
|
|
609
|
+
* @return amountTotalToBeRewarded Total amount of rewards to be distributed
|
|
610
|
+
* @return idToOverwriteUserHistory Index in user history to update with reward info
|
|
611
|
+
* @return timestampToBeOverwritten Timestamp to record for the reward transaction
|
|
612
|
+
*/
|
|
613
|
+
function gimmeYiel(
|
|
614
|
+
address user
|
|
615
|
+
)
|
|
616
|
+
external
|
|
617
|
+
returns (
|
|
618
|
+
bytes32 epochAnswer,
|
|
619
|
+
address tokenToBeRewarded,
|
|
620
|
+
uint256 amountTotalToBeRewarded,
|
|
621
|
+
uint256 idToOverwriteUserHistory,
|
|
622
|
+
uint256 timestampToBeOverwritten
|
|
623
|
+
)
|
|
624
|
+
{
|
|
625
|
+
if (userHistory[user].length > 0) {
|
|
626
|
+
(
|
|
627
|
+
epochAnswer,
|
|
628
|
+
tokenToBeRewarded,
|
|
629
|
+
amountTotalToBeRewarded,
|
|
630
|
+
idToOverwriteUserHistory,
|
|
631
|
+
timestampToBeOverwritten
|
|
632
|
+
) = Estimator(estimator.actual).makeEstimation(user);
|
|
633
|
+
|
|
634
|
+
if (amountTotalToBeRewarded > 0) {
|
|
635
|
+
makeCaPay(tokenToBeRewarded, user, amountTotalToBeRewarded);
|
|
636
|
+
|
|
637
|
+
userHistory[user][idToOverwriteUserHistory]
|
|
638
|
+
.transactionType = epochAnswer;
|
|
639
|
+
userHistory[user][idToOverwriteUserHistory]
|
|
640
|
+
.amount = amountTotalToBeRewarded;
|
|
641
|
+
userHistory[user][idToOverwriteUserHistory]
|
|
642
|
+
.timestamp = timestampToBeOverwritten;
|
|
643
|
+
|
|
644
|
+
if (Evvm(EVVM_ADDRESS).isAddressStaker(msg.sender)) {
|
|
645
|
+
makeCaPay(
|
|
646
|
+
PRINCIPAL_TOKEN_ADDRESS,
|
|
647
|
+
msg.sender,
|
|
648
|
+
(Evvm(EVVM_ADDRESS).getRewardAmount() * 1)
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
//▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀
|
|
656
|
+
// Tools for Evvm Integration
|
|
657
|
+
//▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* @notice Internal function to handle payments through the EVVM contract
|
|
661
|
+
* @dev Supports both synchronous and asynchronous payment modes
|
|
662
|
+
* @param user Address of the user making the payment
|
|
663
|
+
* @param amount Amount to be paid in Principal Tokens
|
|
664
|
+
* @param priorityFee Additional priority fee for the transaction
|
|
665
|
+
* @param priorityFlag True for async payment, false for sync payment
|
|
666
|
+
* @param nonce Nonce for the EVVM transaction
|
|
667
|
+
* @param signature Signature authorizing the payment
|
|
668
|
+
*/
|
|
669
|
+
function makePay(
|
|
670
|
+
address user,
|
|
671
|
+
uint256 amount,
|
|
672
|
+
uint256 priorityFee,
|
|
673
|
+
bool priorityFlag,
|
|
674
|
+
uint256 nonce,
|
|
675
|
+
bytes memory signature
|
|
676
|
+
) internal {
|
|
677
|
+
Evvm(EVVM_ADDRESS).pay(
|
|
678
|
+
user,
|
|
679
|
+
address(this),
|
|
680
|
+
"",
|
|
681
|
+
PRINCIPAL_TOKEN_ADDRESS,
|
|
682
|
+
amount,
|
|
683
|
+
priorityFee,
|
|
684
|
+
nonce,
|
|
685
|
+
priorityFlag,
|
|
686
|
+
address(this),
|
|
687
|
+
signature
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* @notice Internal function to handle token distributions through EVVM contract
|
|
693
|
+
* @dev Used for unstaking refunds and reward distributions
|
|
694
|
+
* @param tokenAddress Address of the token to be distributed
|
|
695
|
+
* @param user Address of the recipient
|
|
696
|
+
* @param amount Amount of tokens to distribute
|
|
697
|
+
*/
|
|
698
|
+
function makeCaPay(
|
|
699
|
+
address tokenAddress,
|
|
700
|
+
address user,
|
|
701
|
+
uint256 amount
|
|
702
|
+
) internal {
|
|
703
|
+
Evvm(EVVM_ADDRESS).caPay(user, tokenAddress, amount);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
//▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀
|
|
707
|
+
// Administrative Functions with Time-Delayed Governance
|
|
708
|
+
//▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* @notice Adds a single address to the presale staker list
|
|
712
|
+
* @dev Only admin can call this function, limited to 800 presale stakers total
|
|
713
|
+
* @param _staker Address to be added to the presale staker list
|
|
714
|
+
*/
|
|
715
|
+
function addPresaleStaker(address _staker) external onlyOwner {
|
|
716
|
+
if (presaleStakerCount > LIMIT_PRESALE_STAKER) {
|
|
717
|
+
revert();
|
|
718
|
+
}
|
|
719
|
+
userPresaleStaker[_staker].isAllow = true;
|
|
720
|
+
presaleStakerCount++;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* @notice Adds multiple addresses to the presale staker list in batch
|
|
725
|
+
* @dev Only admin can call this function, limited to 800 presale stakers total
|
|
726
|
+
* @param _stakers Array of addresses to be added to the presale staker list
|
|
727
|
+
*/
|
|
728
|
+
function addPresaleStakers(address[] calldata _stakers) external onlyOwner {
|
|
729
|
+
for (uint256 i = 0; i < _stakers.length; i++) {
|
|
730
|
+
if (presaleStakerCount > LIMIT_PRESALE_STAKER) {
|
|
731
|
+
revert();
|
|
732
|
+
}
|
|
733
|
+
userPresaleStaker[_stakers[i]].isAllow = true;
|
|
734
|
+
presaleStakerCount++;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* @notice Proposes a new admin address with 1-day time delay
|
|
740
|
+
* @dev Part of the time-delayed governance system for admin changes
|
|
741
|
+
* @param _newAdmin Address of the proposed new admin
|
|
742
|
+
*/
|
|
743
|
+
function proposeAdmin(address _newAdmin) external onlyOwner {
|
|
744
|
+
admin.proposal = _newAdmin;
|
|
745
|
+
admin.timeToAccept = block.timestamp + 1 days;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @notice Rejects the current admin proposal
|
|
750
|
+
* @dev Only current admin can reject the pending proposal
|
|
751
|
+
*/
|
|
752
|
+
function rejectProposalAdmin() external onlyOwner {
|
|
753
|
+
admin.proposal = address(0);
|
|
754
|
+
admin.timeToAccept = 0;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* @notice Accepts the admin proposal and becomes the new admin
|
|
759
|
+
* @dev Can only be called by the proposed admin after the time delay has passed
|
|
760
|
+
*/
|
|
761
|
+
function acceptNewAdmin() external {
|
|
762
|
+
if (
|
|
763
|
+
msg.sender != admin.proposal || admin.timeToAccept > block.timestamp
|
|
764
|
+
) {
|
|
765
|
+
revert();
|
|
766
|
+
}
|
|
767
|
+
admin.actual = admin.proposal;
|
|
768
|
+
admin.proposal = address(0);
|
|
769
|
+
admin.timeToAccept = 0;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function proposeGoldenFisher(address _goldenFisher) external onlyOwner {
|
|
773
|
+
goldenFisher.proposal = _goldenFisher;
|
|
774
|
+
goldenFisher.timeToAccept = block.timestamp + 1 days;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function rejectProposalGoldenFisher() external onlyOwner {
|
|
778
|
+
goldenFisher.proposal = address(0);
|
|
779
|
+
goldenFisher.timeToAccept = 0;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function acceptNewGoldenFisher() external onlyOwner {
|
|
783
|
+
if (goldenFisher.timeToAccept > block.timestamp) {
|
|
784
|
+
revert();
|
|
785
|
+
}
|
|
786
|
+
goldenFisher.actual = goldenFisher.proposal;
|
|
787
|
+
goldenFisher.proposal = address(0);
|
|
788
|
+
goldenFisher.timeToAccept = 0;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
function proposeSetSecondsToUnlockStaking(
|
|
792
|
+
uint256 _secondsToUnlockStaking
|
|
793
|
+
) external onlyOwner {
|
|
794
|
+
secondsToUnlockStaking.proposal = _secondsToUnlockStaking;
|
|
795
|
+
secondsToUnlockStaking.timeToAccept = block.timestamp + 1 days;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function rejectProposalSetSecondsToUnlockStaking() external onlyOwner {
|
|
799
|
+
secondsToUnlockStaking.proposal = 0;
|
|
800
|
+
secondsToUnlockStaking.timeToAccept = 0;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
function acceptSetSecondsToUnlockStaking() external onlyOwner {
|
|
804
|
+
if (secondsToUnlockStaking.timeToAccept > block.timestamp) {
|
|
805
|
+
revert();
|
|
806
|
+
}
|
|
807
|
+
secondsToUnlockStaking.actual = secondsToUnlockStaking.proposal;
|
|
808
|
+
secondsToUnlockStaking.proposal = 0;
|
|
809
|
+
secondsToUnlockStaking.timeToAccept = 0;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function prepareSetSecondsToUnllockFullUnstaking(
|
|
813
|
+
uint256 _secondsToUnllockFullUnstaking
|
|
814
|
+
) external onlyOwner {
|
|
815
|
+
secondsToUnllockFullUnstaking.proposal = _secondsToUnllockFullUnstaking;
|
|
816
|
+
secondsToUnllockFullUnstaking.timeToAccept = block.timestamp + 1 days;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function cancelSetSecondsToUnllockFullUnstaking() external onlyOwner {
|
|
820
|
+
secondsToUnllockFullUnstaking.proposal = 0;
|
|
821
|
+
secondsToUnllockFullUnstaking.timeToAccept = 0;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function confirmSetSecondsToUnllockFullUnstaking() external onlyOwner {
|
|
825
|
+
if (secondsToUnllockFullUnstaking.timeToAccept > block.timestamp) {
|
|
826
|
+
revert();
|
|
827
|
+
}
|
|
828
|
+
secondsToUnllockFullUnstaking.actual = secondsToUnllockFullUnstaking
|
|
829
|
+
.proposal;
|
|
830
|
+
secondsToUnllockFullUnstaking.proposal = 0;
|
|
831
|
+
secondsToUnllockFullUnstaking.timeToAccept = 0;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
function prepareChangeAllowPublicStaking() external onlyOwner {
|
|
835
|
+
allowPublicStaking.timeToAccept = block.timestamp + 1 days;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function cancelChangeAllowPublicStaking() external onlyOwner {
|
|
839
|
+
allowPublicStaking.timeToAccept = 0;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function confirmChangeAllowPublicStaking() external onlyOwner {
|
|
843
|
+
if (allowPublicStaking.timeToAccept > block.timestamp) {
|
|
844
|
+
revert();
|
|
845
|
+
}
|
|
846
|
+
allowPublicStaking = BoolTypeProposal({
|
|
847
|
+
flag: !allowPublicStaking.flag,
|
|
848
|
+
timeToAccept: 0
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function prepareChangeAllowPresaleStaking() external onlyOwner {
|
|
853
|
+
allowPresaleStaking.timeToAccept = block.timestamp + 1 days;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function cancelChangeAllowPresaleStaking() external onlyOwner {
|
|
857
|
+
allowPresaleStaking.timeToAccept = 0;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function confirmChangeAllowPresaleStaking() external onlyOwner {
|
|
861
|
+
if (allowPresaleStaking.timeToAccept > block.timestamp) {
|
|
862
|
+
revert();
|
|
863
|
+
}
|
|
864
|
+
allowPresaleStaking = BoolTypeProposal({
|
|
865
|
+
flag: !allowPresaleStaking.flag,
|
|
866
|
+
timeToAccept: 0
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
function proposeEstimator(address _estimator) external onlyOwner {
|
|
871
|
+
estimator.proposal = _estimator;
|
|
872
|
+
estimator.timeToAccept = block.timestamp + 1 days;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
function rejectProposalEstimator() external onlyOwner {
|
|
876
|
+
estimator.proposal = address(0);
|
|
877
|
+
estimator.timeToAccept = 0;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
function acceptNewEstimator() external onlyOwner {
|
|
881
|
+
if (estimator.timeToAccept > block.timestamp) {
|
|
882
|
+
revert();
|
|
883
|
+
}
|
|
884
|
+
estimator.actual = estimator.proposal;
|
|
885
|
+
estimator.proposal = address(0);
|
|
886
|
+
estimator.timeToAccept = 0;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
//▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀
|
|
890
|
+
// View Functions - Public Data Access
|
|
891
|
+
//▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀▄▀
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* @notice Returns the complete staking history for an address
|
|
895
|
+
* @dev Returns an array of all staking transactions and rewards for the user
|
|
896
|
+
* @param _account Address to query the history for
|
|
897
|
+
* @return Array of HistoryMetadata containing all transactions
|
|
898
|
+
*/
|
|
899
|
+
function getAddressHistory(
|
|
900
|
+
address _account
|
|
901
|
+
) public view returns (HistoryMetadata[] memory) {
|
|
902
|
+
return userHistory[_account];
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* @notice Returns the number of transactions in an address's staking history
|
|
907
|
+
* @dev Useful for pagination or checking if an address has any staking history
|
|
908
|
+
* @param _account Address to query the history size for
|
|
909
|
+
* @return Number of transactions in the history
|
|
910
|
+
*/
|
|
911
|
+
function getSizeOfAddressHistory(
|
|
912
|
+
address _account
|
|
913
|
+
) public view returns (uint256) {
|
|
914
|
+
return userHistory[_account].length;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* @notice Returns a specific transaction from an address's staking history
|
|
919
|
+
* @dev Allows accessing individual transactions by index
|
|
920
|
+
* @param _account Address to query the history for
|
|
921
|
+
* @param _index Index of the transaction to retrieve (0-based)
|
|
922
|
+
* @return HistoryMetadata of the transaction at the specified index
|
|
923
|
+
*/
|
|
924
|
+
function getAddressHistoryByIndex(
|
|
925
|
+
address _account,
|
|
926
|
+
uint256 _index
|
|
927
|
+
) public view returns (HistoryMetadata memory) {
|
|
928
|
+
return userHistory[_account][_index];
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* @notice Returns the fixed price of one staking token in Principal Tokens
|
|
933
|
+
* @dev Returns the constant price of 5083 Principal Tokens per staking
|
|
934
|
+
* @return Price of one staking token in Principal Tokens (with 18 decimals)
|
|
935
|
+
*/
|
|
936
|
+
function priceOfStaking() external pure returns (uint256) {
|
|
937
|
+
return PRICE_OF_STAKING;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* @notice Calculates when a user can perform full unstaking (withdraw all tokens)
|
|
942
|
+
* @dev Full unstaking requires waiting 21 days after the last time their balance reached 0
|
|
943
|
+
* @param _account Address to check the unlock time for
|
|
944
|
+
* @return Timestamp when full unstaking will be allowed
|
|
945
|
+
*/
|
|
946
|
+
function getTimeToUserUnlockFullUnstakingTime(
|
|
947
|
+
address _account
|
|
948
|
+
) public view returns (uint256) {
|
|
949
|
+
for (uint256 i = userHistory[_account].length; i > 0; i--) {
|
|
950
|
+
if (userHistory[_account][i - 1].totalStaked == 0) {
|
|
951
|
+
return
|
|
952
|
+
userHistory[_account][i - 1].timestamp +
|
|
953
|
+
secondsToUnllockFullUnstaking.actual;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return
|
|
958
|
+
userHistory[_account][0].timestamp +
|
|
959
|
+
secondsToUnllockFullUnstaking.actual;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* @notice Calculates when a user can stake again after unstaking
|
|
964
|
+
* @dev Users must wait a configurable period after unstaking before they can stake again
|
|
965
|
+
* @param _account Address to check the unlock time for
|
|
966
|
+
* @return Timestamp when staking will be allowed again (0 if already allowed)
|
|
967
|
+
*/
|
|
968
|
+
function getTimeToUserUnlockStakingTime(
|
|
969
|
+
address _account
|
|
970
|
+
) public view returns (uint256) {
|
|
971
|
+
uint256 lengthOfHistory = userHistory[_account].length;
|
|
972
|
+
|
|
973
|
+
if (lengthOfHistory == 0) {
|
|
974
|
+
return 0;
|
|
975
|
+
}
|
|
976
|
+
if (userHistory[_account][lengthOfHistory - 1].totalStaked == 0) {
|
|
977
|
+
return
|
|
978
|
+
userHistory[_account][lengthOfHistory - 1].timestamp +
|
|
979
|
+
secondsToUnlockStaking.actual;
|
|
980
|
+
} else {
|
|
981
|
+
return 0;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* @notice Returns the current time delay for full unstaking operations
|
|
987
|
+
* @dev Full unstaking requires waiting this many seconds (default: 21 days)
|
|
988
|
+
* @return Number of seconds required to wait for full unstaking
|
|
989
|
+
*/
|
|
990
|
+
function getSecondsToUnlockFullUnstaking() external view returns (uint256) {
|
|
991
|
+
return secondsToUnllockFullUnstaking.actual;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* @notice Returns the current time delay for regular staking operations
|
|
996
|
+
* @dev Users must wait this many seconds after unstaking before they can stake again
|
|
997
|
+
* @return Number of seconds required to wait between unstaking and staking
|
|
998
|
+
*/
|
|
999
|
+
function getSecondsToUnlockStaking() external view returns (uint256) {
|
|
1000
|
+
return secondsToUnlockStaking.actual;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* @notice Returns the current amount of staking tokens staked by a user
|
|
1005
|
+
* @dev Returns the total staked amount from the user's most recent transaction
|
|
1006
|
+
* @param _account Address to check the staked amount for
|
|
1007
|
+
* @return Amount of staking tokens currently staked by the user
|
|
1008
|
+
*/
|
|
1009
|
+
function getUserAmountStaked(
|
|
1010
|
+
address _account
|
|
1011
|
+
) public view returns (uint256) {
|
|
1012
|
+
uint256 lengthOfHistory = userHistory[_account].length;
|
|
1013
|
+
|
|
1014
|
+
if (lengthOfHistory == 0) {
|
|
1015
|
+
return 0;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
return userHistory[_account][lengthOfHistory - 1].totalStaked;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* @notice Checks if a specific nonce has been used for staking by a user
|
|
1023
|
+
* @dev Prevents replay attacks by tracking used nonces
|
|
1024
|
+
* @param _account Address to check the nonce for
|
|
1025
|
+
* @param _nonce Nonce value to check
|
|
1026
|
+
* @return True if the nonce has been used, false otherwise
|
|
1027
|
+
*/
|
|
1028
|
+
function checkIfStakeNonceUsed(
|
|
1029
|
+
address _account,
|
|
1030
|
+
uint256 _nonce
|
|
1031
|
+
) public view returns (bool) {
|
|
1032
|
+
return stakingNonce[_account][_nonce];
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* @notice Returns the current golden fisher address
|
|
1037
|
+
* @dev The golden fisher has special staking privileges
|
|
1038
|
+
* @return Address of the current golden fisher
|
|
1039
|
+
*/
|
|
1040
|
+
function getGoldenFisher() external view returns (address) {
|
|
1041
|
+
return goldenFisher.actual;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* @notice Returns the proposed new golden fisher address (if any)
|
|
1046
|
+
* @dev Shows pending golden fisher changes in the governance system
|
|
1047
|
+
* @return Address of the proposed golden fisher (zero address if none)
|
|
1048
|
+
*/
|
|
1049
|
+
function getGoldenFisherProposal() external view returns (address) {
|
|
1050
|
+
return goldenFisher.proposal;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* @notice Returns presale staker information for a given address
|
|
1055
|
+
* @dev Shows if an address is allowed for presale and how many tokens they've staked
|
|
1056
|
+
* @param _account Address to check presale status for
|
|
1057
|
+
* @return isAllow True if the address is allowed for presale staking
|
|
1058
|
+
* @return stakingAmount Number of staking tokens currently staked in presale (max 2)
|
|
1059
|
+
*/
|
|
1060
|
+
function getPresaleStaker(
|
|
1061
|
+
address _account
|
|
1062
|
+
) external view returns (bool, uint256) {
|
|
1063
|
+
return (
|
|
1064
|
+
userPresaleStaker[_account].isAllow,
|
|
1065
|
+
userPresaleStaker[_account].stakingAmount
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* @notice Returns the current estimator contract address
|
|
1071
|
+
* @dev The estimator calculates staking rewards and yields
|
|
1072
|
+
* @return Address of the current estimator contract
|
|
1073
|
+
*/
|
|
1074
|
+
function getEstimatorAddress() external view returns (address) {
|
|
1075
|
+
return estimator.actual;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* @notice Returns the proposed new estimator contract address (if any)
|
|
1080
|
+
* @dev Shows pending estimator changes in the governance system
|
|
1081
|
+
* @return Address of the proposed estimator contract (zero address if none)
|
|
1082
|
+
*/
|
|
1083
|
+
function getEstimatorProposal() external view returns (address) {
|
|
1084
|
+
return estimator.proposal;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* @notice Returns the current number of registered presale stakers
|
|
1089
|
+
* @dev Maximum allowed is 800 presale stakers
|
|
1090
|
+
* @return Current count of presale stakers
|
|
1091
|
+
*/
|
|
1092
|
+
function getPresaleStakerCount() external view returns (uint256) {
|
|
1093
|
+
return presaleStakerCount;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* @notice Returns the complete public staking configuration and status
|
|
1098
|
+
* @dev Includes current flag state and any pending changes with timestamps
|
|
1099
|
+
* @return BoolTypeProposal struct containing flag and timeToAccept
|
|
1100
|
+
*/
|
|
1101
|
+
function getAllDataOfAllowPublicStaking()
|
|
1102
|
+
external
|
|
1103
|
+
view
|
|
1104
|
+
returns (BoolTypeProposal memory)
|
|
1105
|
+
{
|
|
1106
|
+
return allowPublicStaking;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* @notice Returns the complete presale staking configuration and status
|
|
1111
|
+
* @dev Includes current flag state and any pending changes with timestamps
|
|
1112
|
+
* @return BoolTypeProposal struct containing flag and timeToAccept
|
|
1113
|
+
*/
|
|
1114
|
+
function getAllowPresaleStaking()
|
|
1115
|
+
external
|
|
1116
|
+
view
|
|
1117
|
+
returns (BoolTypeProposal memory)
|
|
1118
|
+
{
|
|
1119
|
+
return allowPresaleStaking;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
/**
|
|
1123
|
+
* @notice Returns the address of the EVVM core contract
|
|
1124
|
+
* @dev The EVVM contract handles payments and staker registration
|
|
1125
|
+
* @return Address of the EVVM core contract
|
|
1126
|
+
*/
|
|
1127
|
+
function getEvvmAddress() external view returns (address) {
|
|
1128
|
+
return EVVM_ADDRESS;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* @notice Returns the address representing the Principal Token
|
|
1133
|
+
* @dev This is a constant address used to represent the principal token
|
|
1134
|
+
* @return Address representing the Principal Token (0x...0001)
|
|
1135
|
+
*/
|
|
1136
|
+
function getMateAddress() external pure returns (address) {
|
|
1137
|
+
return PRINCIPAL_TOKEN_ADDRESS;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* @notice Returns the current admin/owner address
|
|
1142
|
+
* @dev The admin has full control over contract parameters and governance
|
|
1143
|
+
* @return Address of the current contract admin
|
|
1144
|
+
*/
|
|
1145
|
+
function getOwner() external view returns (address) {
|
|
1146
|
+
return admin.actual;
|
|
1147
|
+
}
|
|
1148
|
+
}
|