@evvm/testnet-contracts 1.0.7 → 2.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/contracts/evvm/Evvm.sol +1 -1
- package/contracts/evvm/EvvmLegacy.sol +1 -1
- package/contracts/evvm/lib/EvvmStorage.sol +1 -1
- package/contracts/nameService/NameService.sol +1 -1
- package/contracts/staking/Estimator.sol +1 -1
- package/contracts/staking/Staking.sol +258 -163
- package/contracts/staking/lib/ErrorsLib.sol +6 -2
- package/contracts/treasury/Treasury.sol +1 -1
- package/library/Erc191TestBuilder.sol +1 -1
- package/library/SignatureRecover.sol +85 -1
- package/library/StakingServiceHooks.sol +116 -0
- package/package.json +1 -1
package/contracts/evvm/Evvm.sol
CHANGED
|
@@ -20,7 +20,7 @@ pragma solidity ^0.8.0;
|
|
|
20
20
|
╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
|
|
21
21
|
|
|
22
22
|
* @title EVVM (Ethereum Virtual Machine Virtualization) Core Contract
|
|
23
|
-
* @author
|
|
23
|
+
* @author Mate labs
|
|
24
24
|
* @notice Core payment processing and token management system for the EVVM ecosystem
|
|
25
25
|
* @dev This contract serves as the central hub for:
|
|
26
26
|
* - Multi-token payment processing with signature verification
|
|
@@ -61,7 +61,7 @@ pragma solidity ^0.8.0;
|
|
|
61
61
|
╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
|
|
62
62
|
|
|
63
63
|
* @title EVVM (Ethereum Virtual Machine Virtualization) Core Contract
|
|
64
|
-
* @author
|
|
64
|
+
* @author Mate labs
|
|
65
65
|
* @notice Core payment processing and token management system for the EVVM ecosystem
|
|
66
66
|
* @dev This contract serves as the central hub for:
|
|
67
67
|
* - Multi-token payment processing with signature verification
|
|
@@ -7,7 +7,7 @@ import {EvvmStructs} from "./EvvmStructs.sol";
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @title EvvmStorage
|
|
10
|
-
* @author
|
|
10
|
+
* @author Mate labs
|
|
11
11
|
* @dev Storage layout contract for EVVM proxy pattern implementation.
|
|
12
12
|
* This contract inherits all structures from EvvmStructs and
|
|
13
13
|
* defines the storage layout that will be used by the proxy pattern.
|
|
@@ -27,7 +27,7 @@ pragma solidity ^0.8.0;
|
|
|
27
27
|
╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
|
|
28
28
|
*
|
|
29
29
|
* @title EVVM Name Service Contract
|
|
30
|
-
* @author
|
|
30
|
+
* @author Mate labs
|
|
31
31
|
* @notice This contract manages username registration and domain name services for the EVVM ecosystem
|
|
32
32
|
* @dev Provides a comprehensive domain name system with features including:
|
|
33
33
|
*
|
|
@@ -12,7 +12,7 @@ MM .M `88888P' dP dP dP dP dP `88888P8 dP `88888P' dP
|
|
|
12
12
|
MMMMMMMMMMMM
|
|
13
13
|
|
|
14
14
|
* @title Staking Mate contract for Roll A Mate Protocol
|
|
15
|
-
* @author
|
|
15
|
+
* @author Mate labs
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import {Staking} from "@evvm/testnet-contracts/contracts/staking/Staking.sol";
|
|
@@ -24,7 +24,7 @@ pragma solidity ^0.8.0;
|
|
|
24
24
|
██║ ███████╗███████║ ██║ ██║ ╚████║███████╗ ██║
|
|
25
25
|
╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
|
|
26
26
|
* @title Staking Mate contract
|
|
27
|
-
* @author
|
|
27
|
+
* @author Mate labs
|
|
28
28
|
* @notice This contract manages the staking mechanism for the EVVM ecosystem
|
|
29
29
|
* @dev Handles presale staking, public staking, and service staking with time locks and signature verification
|
|
30
30
|
*
|
|
@@ -109,6 +109,32 @@ contract Staking {
|
|
|
109
109
|
uint256 timeToAccept;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* @dev Struct to store service staking metadata during the staking process
|
|
114
|
+
* @param service Address of the service or contract account
|
|
115
|
+
* @param timestamp Timestamp when the prepareServiceStaking was called
|
|
116
|
+
* @param amountOfStaking Amount of staking tokens to be staked
|
|
117
|
+
* @param amountServiceBeforeStaking Service's Principal Token balance before staking
|
|
118
|
+
* @param amountStakingBeforeStaking Staking contract's Principal Token balance before staking
|
|
119
|
+
*/
|
|
120
|
+
struct ServiceStakingMetadata {
|
|
121
|
+
address service;
|
|
122
|
+
uint256 timestamp;
|
|
123
|
+
uint256 amountOfStaking;
|
|
124
|
+
uint256 amountServiceBeforeStaking;
|
|
125
|
+
uint256 amountStakingBeforeStaking;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @dev Struct to encapsulate account metadata for staking operations
|
|
130
|
+
* @param Address Address of the account
|
|
131
|
+
* @param IsAService Boolean indicating if the account is a smart contract (service) account
|
|
132
|
+
*/
|
|
133
|
+
struct AccountMetadata {
|
|
134
|
+
address Address;
|
|
135
|
+
bool IsAService;
|
|
136
|
+
}
|
|
137
|
+
|
|
112
138
|
/// @dev Address of the EVVM core contract
|
|
113
139
|
address private EVVM_ADDRESS;
|
|
114
140
|
|
|
@@ -119,6 +145,10 @@ contract Staking {
|
|
|
119
145
|
/// @dev Price of one staking main token (5083 main token = 1 staking)
|
|
120
146
|
uint256 private constant PRICE_OF_STAKING = 5083 * (10 ** 18);
|
|
121
147
|
|
|
148
|
+
/// @dev Address representing the principal Principal Token
|
|
149
|
+
address private constant PRINCIPAL_TOKEN_ADDRESS =
|
|
150
|
+
0x0000000000000000000000000000000000000001;
|
|
151
|
+
|
|
122
152
|
/// @dev Admin address management with proposal system
|
|
123
153
|
AddressTypeProposal private admin;
|
|
124
154
|
/// @dev Golden Fisher address management with proposal system
|
|
@@ -133,10 +163,8 @@ contract Staking {
|
|
|
133
163
|
BoolTypeProposal private allowPresaleStaking;
|
|
134
164
|
/// @dev Flag to enable/disable public staking
|
|
135
165
|
BoolTypeProposal private allowPublicStaking;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
address private constant PRINCIPAL_TOKEN_ADDRESS =
|
|
139
|
-
0x0000000000000000000000000000000000000001;
|
|
166
|
+
/// @dev Variable to store service staking metadata
|
|
167
|
+
ServiceStakingMetadata private serviceStakingData;
|
|
140
168
|
|
|
141
169
|
/// @dev One-time setup breaker for estimator and EVVM addresses
|
|
142
170
|
bytes1 private breakerSetupEstimatorAndEvvm;
|
|
@@ -150,13 +178,28 @@ contract Staking {
|
|
|
150
178
|
/// @dev Mapping to store complete staking history for each user
|
|
151
179
|
mapping(address => HistoryMetadata[]) private userHistory;
|
|
152
180
|
|
|
153
|
-
/// @dev Modifier to
|
|
181
|
+
/// @dev Modifier to verify access to admin functions
|
|
154
182
|
modifier onlyOwner() {
|
|
155
183
|
if (msg.sender != admin.actual) revert ErrorsLib.SenderIsNotAdmin();
|
|
156
184
|
|
|
157
185
|
_;
|
|
158
186
|
}
|
|
159
187
|
|
|
188
|
+
/// @dev Modifier to verify access to a contract or service account
|
|
189
|
+
modifier onlyCA() {
|
|
190
|
+
uint256 size;
|
|
191
|
+
address callerAddress = msg.sender;
|
|
192
|
+
|
|
193
|
+
assembly {
|
|
194
|
+
/// @dev check the size of the opcode of the address
|
|
195
|
+
size := extcodesize(callerAddress)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (size == 0) revert ErrorsLib.AddressIsNotAService();
|
|
199
|
+
|
|
200
|
+
_;
|
|
201
|
+
}
|
|
202
|
+
|
|
160
203
|
/**
|
|
161
204
|
* @notice Contract constructor
|
|
162
205
|
* @dev Initializes the staking contract with admin and golden fisher addresses
|
|
@@ -210,10 +253,10 @@ contract Staking {
|
|
|
210
253
|
if (msg.sender != goldenFisher.actual)
|
|
211
254
|
revert ErrorsLib.SenderIsNotGoldenFisher();
|
|
212
255
|
|
|
213
|
-
|
|
214
|
-
goldenFisher.actual,
|
|
215
|
-
amountOfStaking,
|
|
256
|
+
stakingBaseProcess(
|
|
257
|
+
AccountMetadata({Address: goldenFisher.actual, IsAService: false}),
|
|
216
258
|
isStaking,
|
|
259
|
+
amountOfStaking,
|
|
217
260
|
0,
|
|
218
261
|
Evvm(EVVM_ADDRESS).getNextCurrentSyncNonce(msg.sender),
|
|
219
262
|
false,
|
|
@@ -263,10 +306,10 @@ contract Staking {
|
|
|
263
306
|
if (!allowPresaleStaking.flag)
|
|
264
307
|
revert ErrorsLib.PresaleStakingDisabled();
|
|
265
308
|
|
|
266
|
-
|
|
267
|
-
user,
|
|
268
|
-
1,
|
|
309
|
+
stakingBaseProcess(
|
|
310
|
+
AccountMetadata({Address: user, IsAService: false}),
|
|
269
311
|
isStaking,
|
|
312
|
+
1,
|
|
270
313
|
priorityFee_EVVM,
|
|
271
314
|
nonce_EVVM,
|
|
272
315
|
priorityFlag_EVVM,
|
|
@@ -351,10 +394,10 @@ contract Staking {
|
|
|
351
394
|
if (checkIfStakeNonceUsed(user, nonce))
|
|
352
395
|
revert ErrorsLib.StakingNonceAlreadyUsed();
|
|
353
396
|
|
|
354
|
-
|
|
355
|
-
user,
|
|
356
|
-
amountOfStaking,
|
|
397
|
+
stakingBaseProcess(
|
|
398
|
+
AccountMetadata({Address: user, IsAService: false}),
|
|
357
399
|
isStaking,
|
|
400
|
+
amountOfStaking,
|
|
358
401
|
priorityFee_EVVM,
|
|
359
402
|
nonce_EVVM,
|
|
360
403
|
priorityFlag_EVVM,
|
|
@@ -365,146 +408,120 @@ contract Staking {
|
|
|
365
408
|
}
|
|
366
409
|
|
|
367
410
|
/**
|
|
368
|
-
* @notice
|
|
369
|
-
* @dev
|
|
370
|
-
* @param
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
* @
|
|
378
|
-
* @
|
|
379
|
-
*
|
|
411
|
+
* @notice Prepares a service/contract account for staking by recording pre-staking state
|
|
412
|
+
* @dev First step in the service staking process. Must be followed by payment via caPay and confirmServiceStaking in the same transaction
|
|
413
|
+
* @param amountOfStaking Amount of staking tokens the service intends to stake
|
|
414
|
+
*
|
|
415
|
+
* Service Staking Process:
|
|
416
|
+
* 1. Call prepareServiceStaking(amount) - Records balances and metadata
|
|
417
|
+
* 2. Use EVVM.caPay() to transfer the required Principal Tokens to this contract
|
|
418
|
+
* 3. Call confirmServiceStaking() - Validates payment and completes staking
|
|
419
|
+
*
|
|
420
|
+
* @dev All three steps MUST occur in the same transaction or the staking will fail
|
|
421
|
+
* @dev CRITICAL WARNING: If the process is not completed properly (especially if caPay is called
|
|
422
|
+
* but confirmServiceStaking is not), the Principal Tokens will remain locked in the staking
|
|
423
|
+
* contract with no way to recover them. The service will lose the tokens permanently.
|
|
424
|
+
* @dev Only callable by contract accounts (services), not EOAs
|
|
380
425
|
*/
|
|
381
|
-
function
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
426
|
+
function prepareServiceStaking(uint256 amountOfStaking) external onlyCA {
|
|
427
|
+
serviceStakingData = ServiceStakingMetadata({
|
|
428
|
+
service: msg.sender,
|
|
429
|
+
timestamp: block.timestamp,
|
|
430
|
+
amountOfStaking: amountOfStaking,
|
|
431
|
+
amountServiceBeforeStaking: Evvm(EVVM_ADDRESS).getBalance(
|
|
432
|
+
msg.sender,
|
|
433
|
+
PRINCIPAL_TOKEN_ADDRESS
|
|
434
|
+
),
|
|
435
|
+
amountStakingBeforeStaking: Evvm(EVVM_ADDRESS).getBalance(
|
|
436
|
+
address(this),
|
|
437
|
+
PRINCIPAL_TOKEN_ADDRESS
|
|
438
|
+
)
|
|
439
|
+
});
|
|
440
|
+
}
|
|
396
441
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
442
|
+
/**
|
|
443
|
+
* @notice Confirms and completes the service staking operation after payment verification
|
|
444
|
+
* @dev Final step in service staking. Validates that payment was made correctly and completes the staking process
|
|
445
|
+
*
|
|
446
|
+
* Validation checks:
|
|
447
|
+
* - Service balance decreased by the exact staking cost
|
|
448
|
+
* - Staking contract balance increased by the exact staking cost
|
|
449
|
+
* - Operation occurs in the same transaction as prepareServiceStaking
|
|
450
|
+
* - Caller matches the service that initiated the preparation
|
|
451
|
+
*
|
|
452
|
+
* @dev Only callable by the same contract that called prepareServiceStaking
|
|
453
|
+
* @dev Must be called in the same transaction as prepareServiceStaking
|
|
454
|
+
*/
|
|
455
|
+
function confirmServiceStaking() external onlyCA {
|
|
456
|
+
uint256 totalStakingRequired = PRICE_OF_STAKING *
|
|
457
|
+
serviceStakingData.amountOfStaking;
|
|
401
458
|
|
|
402
|
-
|
|
459
|
+
uint256 actualServiceBalance = Evvm(EVVM_ADDRESS).getBalance(
|
|
460
|
+
msg.sender,
|
|
461
|
+
PRINCIPAL_TOKEN_ADDRESS
|
|
462
|
+
);
|
|
403
463
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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
|
-
}
|
|
464
|
+
uint256 actualStakingBalance = Evvm(EVVM_ADDRESS).getBalance(
|
|
465
|
+
address(this),
|
|
466
|
+
PRINCIPAL_TOKEN_ADDRESS
|
|
467
|
+
);
|
|
419
468
|
|
|
420
|
-
if (
|
|
421
|
-
|
|
469
|
+
if (
|
|
470
|
+
serviceStakingData.amountServiceBeforeStaking -
|
|
471
|
+
totalStakingRequired !=
|
|
472
|
+
actualServiceBalance &&
|
|
473
|
+
serviceStakingData.amountStakingBeforeStaking +
|
|
474
|
+
totalStakingRequired !=
|
|
475
|
+
actualStakingBalance
|
|
476
|
+
)
|
|
477
|
+
revert ErrorsLib.ServiceDoesNotFulfillCorrectStakingAmount(
|
|
478
|
+
totalStakingRequired
|
|
479
|
+
);
|
|
422
480
|
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
);
|
|
481
|
+
if (serviceStakingData.timestamp != block.timestamp)
|
|
482
|
+
revert ErrorsLib.ServiceDoesNotStakeInSameTx();
|
|
433
483
|
|
|
434
|
-
|
|
435
|
-
|
|
484
|
+
if (serviceStakingData.service != msg.sender)
|
|
485
|
+
revert ErrorsLib.AddressMismatch();
|
|
436
486
|
|
|
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
487
|
stakingBaseProcess(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
signature_EVVM
|
|
488
|
+
AccountMetadata({Address: msg.sender, IsAService: true}),
|
|
489
|
+
true,
|
|
490
|
+
serviceStakingData.amountOfStaking,
|
|
491
|
+
0,
|
|
492
|
+
0,
|
|
493
|
+
false,
|
|
494
|
+
""
|
|
468
495
|
);
|
|
469
496
|
}
|
|
470
497
|
|
|
471
498
|
/**
|
|
472
|
-
* @notice
|
|
473
|
-
* @dev
|
|
474
|
-
* @param
|
|
475
|
-
*
|
|
476
|
-
* @
|
|
477
|
-
* @
|
|
478
|
-
* @
|
|
479
|
-
* @param priorityFlag_EVVM Priority flag for EVVM transaction
|
|
480
|
-
* @param signature_EVVM Signature for the EVVM contract transaction
|
|
499
|
+
* @notice Allows a service/contract account to unstake their staking tokens
|
|
500
|
+
* @dev Simplified unstaking process for services - no signature or payment required, just direct unstaking
|
|
501
|
+
* @param amountOfStaking Amount of staking tokens to unstake
|
|
502
|
+
*
|
|
503
|
+
* @dev The service will receive Principal Tokens equal to: amountOfStaking * PRICE_OF_STAKING
|
|
504
|
+
* @dev Subject to the same time locks as regular unstaking (21 days for full unstake)
|
|
505
|
+
* @dev Only callable by contract accounts (services), not EOAs
|
|
481
506
|
*/
|
|
482
|
-
function
|
|
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 {
|
|
507
|
+
function serviceUnstaking(uint256 amountOfStaking) external onlyCA {
|
|
491
508
|
stakingBaseProcess(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
isStaking,
|
|
509
|
+
AccountMetadata({Address: msg.sender, IsAService: true}),
|
|
510
|
+
false,
|
|
495
511
|
amountOfStaking,
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
512
|
+
0,
|
|
513
|
+
0,
|
|
514
|
+
false,
|
|
515
|
+
""
|
|
500
516
|
);
|
|
501
517
|
}
|
|
502
518
|
|
|
503
519
|
/**
|
|
504
520
|
* @notice Core staking logic that handles both service and user staking operations
|
|
505
521
|
* @dev Processes payments, updates history, handles time locks, and manages EVVM integration
|
|
506
|
-
* @param
|
|
507
|
-
*
|
|
522
|
+
* @param account Metadata of the account performing the staking operation
|
|
523
|
+
* - Address: Address of the account
|
|
524
|
+
* - IsAService: Boolean indicating if the account is a smart contract (service) account
|
|
508
525
|
* @param isStaking True for staking (requires payment), false for unstaking (provides refund)
|
|
509
526
|
* @param amountOfStaking Amount of staking tokens to stake/unstake
|
|
510
527
|
* @param priorityFee_EVVM Priority fee for EVVM transaction
|
|
@@ -513,8 +530,7 @@ contract Staking {
|
|
|
513
530
|
* @param signature_EVVM Signature for EVVM contract transaction
|
|
514
531
|
*/
|
|
515
532
|
function stakingBaseProcess(
|
|
516
|
-
|
|
517
|
-
address stakingAccount,
|
|
533
|
+
AccountMetadata memory account,
|
|
518
534
|
bool isStaking,
|
|
519
535
|
uint256 amountOfStaking,
|
|
520
536
|
uint256 priorityFee_EVVM,
|
|
@@ -526,61 +542,61 @@ contract Staking {
|
|
|
526
542
|
|
|
527
543
|
if (isStaking) {
|
|
528
544
|
if (
|
|
529
|
-
getTimeToUserUnlockStakingTime(
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
makePay(
|
|
533
|
-
userAccount,
|
|
534
|
-
(PRICE_OF_STAKING * amountOfStaking),
|
|
535
|
-
priorityFee_EVVM,
|
|
536
|
-
priorityFlag_EVVM,
|
|
537
|
-
nonce_EVVM,
|
|
538
|
-
signature_EVVM
|
|
539
|
-
);
|
|
545
|
+
getTimeToUserUnlockStakingTime(account.Address) >
|
|
546
|
+
block.timestamp
|
|
547
|
+
) revert ErrorsLib.AddressMustWaitToStakeAgain();
|
|
540
548
|
|
|
541
|
-
|
|
549
|
+
if (!account.IsAService)
|
|
550
|
+
makePay(
|
|
551
|
+
account.Address,
|
|
552
|
+
(PRICE_OF_STAKING * amountOfStaking),
|
|
553
|
+
priorityFee_EVVM,
|
|
554
|
+
priorityFlag_EVVM,
|
|
555
|
+
nonce_EVVM,
|
|
556
|
+
signature_EVVM
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
Evvm(EVVM_ADDRESS).pointStaker(account.Address, 0x01);
|
|
542
560
|
|
|
543
|
-
auxSMsteBalance = userHistory[
|
|
561
|
+
auxSMsteBalance = userHistory[account.Address].length == 0
|
|
544
562
|
? amountOfStaking
|
|
545
|
-
: userHistory[
|
|
546
|
-
userHistory[
|
|
563
|
+
: userHistory[account.Address][
|
|
564
|
+
userHistory[account.Address].length - 1
|
|
547
565
|
].totalStaked + amountOfStaking;
|
|
548
566
|
} else {
|
|
549
|
-
if (amountOfStaking == getUserAmountStaked(
|
|
567
|
+
if (amountOfStaking == getUserAmountStaked(account.Address)) {
|
|
550
568
|
if (
|
|
551
|
-
getTimeToUserUnlockFullUnstakingTime(
|
|
569
|
+
getTimeToUserUnlockFullUnstakingTime(account.Address) >
|
|
552
570
|
block.timestamp
|
|
553
|
-
) revert ErrorsLib.
|
|
571
|
+
) revert ErrorsLib.AddressMustWaitToFullUnstake();
|
|
554
572
|
|
|
555
|
-
Evvm(EVVM_ADDRESS).pointStaker(
|
|
573
|
+
Evvm(EVVM_ADDRESS).pointStaker(account.Address, 0x00);
|
|
556
574
|
}
|
|
557
575
|
|
|
558
|
-
|
|
559
|
-
if (userAccount == stakingAccount && priorityFee_EVVM != 0) {
|
|
576
|
+
if (priorityFee_EVVM != 0 && !account.IsAService)
|
|
560
577
|
makePay(
|
|
561
|
-
|
|
578
|
+
account.Address,
|
|
562
579
|
priorityFee_EVVM,
|
|
563
580
|
0,
|
|
564
581
|
priorityFlag_EVVM,
|
|
565
582
|
nonce_EVVM,
|
|
566
583
|
signature_EVVM
|
|
567
584
|
);
|
|
568
|
-
}
|
|
569
585
|
|
|
570
586
|
auxSMsteBalance =
|
|
571
|
-
userHistory[
|
|
572
|
-
userHistory[
|
|
587
|
+
userHistory[account.Address][
|
|
588
|
+
userHistory[account.Address].length - 1
|
|
573
589
|
].totalStaked -
|
|
574
590
|
amountOfStaking;
|
|
575
591
|
|
|
576
592
|
makeCaPay(
|
|
577
593
|
PRINCIPAL_TOKEN_ADDRESS,
|
|
578
|
-
|
|
594
|
+
account.Address,
|
|
579
595
|
(PRICE_OF_STAKING * amountOfStaking)
|
|
580
596
|
);
|
|
581
597
|
}
|
|
582
598
|
|
|
583
|
-
userHistory[
|
|
599
|
+
userHistory[account.Address].push(
|
|
584
600
|
HistoryMetadata({
|
|
585
601
|
transactionType: isStaking
|
|
586
602
|
? bytes32(uint256(1))
|
|
@@ -591,7 +607,10 @@ contract Staking {
|
|
|
591
607
|
})
|
|
592
608
|
);
|
|
593
609
|
|
|
594
|
-
if (
|
|
610
|
+
if (
|
|
611
|
+
Evvm(EVVM_ADDRESS).isAddressStaker(msg.sender) &&
|
|
612
|
+
!account.IsAService
|
|
613
|
+
) {
|
|
595
614
|
makeCaPay(
|
|
596
615
|
PRINCIPAL_TOKEN_ADDRESS,
|
|
597
616
|
msg.sender,
|
|
@@ -769,16 +788,29 @@ contract Staking {
|
|
|
769
788
|
admin.timeToAccept = 0;
|
|
770
789
|
}
|
|
771
790
|
|
|
791
|
+
/**
|
|
792
|
+
* @notice Proposes a new golden fisher address with 1-day time delay
|
|
793
|
+
* @dev Part of the time-delayed governance system for golden fisher changes
|
|
794
|
+
* @param _goldenFisher Address of the proposed new golden fisher
|
|
795
|
+
*/
|
|
772
796
|
function proposeGoldenFisher(address _goldenFisher) external onlyOwner {
|
|
773
797
|
goldenFisher.proposal = _goldenFisher;
|
|
774
798
|
goldenFisher.timeToAccept = block.timestamp + 1 days;
|
|
775
799
|
}
|
|
776
800
|
|
|
801
|
+
/**
|
|
802
|
+
* @notice Rejects the current golden fisher proposal
|
|
803
|
+
* @dev Only current admin can reject the pending golden fisher proposal
|
|
804
|
+
*/
|
|
777
805
|
function rejectProposalGoldenFisher() external onlyOwner {
|
|
778
806
|
goldenFisher.proposal = address(0);
|
|
779
807
|
goldenFisher.timeToAccept = 0;
|
|
780
808
|
}
|
|
781
809
|
|
|
810
|
+
/**
|
|
811
|
+
* @notice Accepts the golden fisher proposal after the time delay has passed
|
|
812
|
+
* @dev Can only be called by the current admin after the 1-day time delay
|
|
813
|
+
*/
|
|
782
814
|
function acceptNewGoldenFisher() external onlyOwner {
|
|
783
815
|
if (goldenFisher.timeToAccept > block.timestamp) {
|
|
784
816
|
revert();
|
|
@@ -788,6 +820,11 @@ contract Staking {
|
|
|
788
820
|
goldenFisher.timeToAccept = 0;
|
|
789
821
|
}
|
|
790
822
|
|
|
823
|
+
/**
|
|
824
|
+
* @notice Proposes a new time delay for staking after unstaking with 1-day time delay
|
|
825
|
+
* @dev Part of the time-delayed governance system for staking unlock time changes
|
|
826
|
+
* @param _secondsToUnlockStaking New number of seconds users must wait after unstaking before staking again
|
|
827
|
+
*/
|
|
791
828
|
function proposeSetSecondsToUnlockStaking(
|
|
792
829
|
uint256 _secondsToUnlockStaking
|
|
793
830
|
) external onlyOwner {
|
|
@@ -795,11 +832,19 @@ contract Staking {
|
|
|
795
832
|
secondsToUnlockStaking.timeToAccept = block.timestamp + 1 days;
|
|
796
833
|
}
|
|
797
834
|
|
|
835
|
+
/**
|
|
836
|
+
* @notice Rejects the current staking unlock time proposal
|
|
837
|
+
* @dev Only current admin can reject the pending staking unlock time proposal
|
|
838
|
+
*/
|
|
798
839
|
function rejectProposalSetSecondsToUnlockStaking() external onlyOwner {
|
|
799
840
|
secondsToUnlockStaking.proposal = 0;
|
|
800
841
|
secondsToUnlockStaking.timeToAccept = 0;
|
|
801
842
|
}
|
|
802
843
|
|
|
844
|
+
/**
|
|
845
|
+
* @notice Accepts the staking unlock time proposal after the time delay has passed
|
|
846
|
+
* @dev Can only be called by the current admin after the 1-day time delay
|
|
847
|
+
*/
|
|
803
848
|
function acceptSetSecondsToUnlockStaking() external onlyOwner {
|
|
804
849
|
if (secondsToUnlockStaking.timeToAccept > block.timestamp) {
|
|
805
850
|
revert();
|
|
@@ -809,6 +854,11 @@ contract Staking {
|
|
|
809
854
|
secondsToUnlockStaking.timeToAccept = 0;
|
|
810
855
|
}
|
|
811
856
|
|
|
857
|
+
/**
|
|
858
|
+
* @notice Proposes a new time delay for full unstaking operations with 1-day time delay
|
|
859
|
+
* @dev Part of the time-delayed governance system for full unstaking time changes
|
|
860
|
+
* @param _secondsToUnllockFullUnstaking New number of seconds users must wait for full unstaking (default: 21 days)
|
|
861
|
+
*/
|
|
812
862
|
function prepareSetSecondsToUnllockFullUnstaking(
|
|
813
863
|
uint256 _secondsToUnllockFullUnstaking
|
|
814
864
|
) external onlyOwner {
|
|
@@ -816,11 +866,19 @@ contract Staking {
|
|
|
816
866
|
secondsToUnllockFullUnstaking.timeToAccept = block.timestamp + 1 days;
|
|
817
867
|
}
|
|
818
868
|
|
|
869
|
+
/**
|
|
870
|
+
* @notice Cancels the current full unstaking time proposal
|
|
871
|
+
* @dev Only current admin can cancel the pending full unstaking time proposal
|
|
872
|
+
*/
|
|
819
873
|
function cancelSetSecondsToUnllockFullUnstaking() external onlyOwner {
|
|
820
874
|
secondsToUnllockFullUnstaking.proposal = 0;
|
|
821
875
|
secondsToUnllockFullUnstaking.timeToAccept = 0;
|
|
822
876
|
}
|
|
823
877
|
|
|
878
|
+
/**
|
|
879
|
+
* @notice Confirms the full unstaking time proposal after the time delay has passed
|
|
880
|
+
* @dev Can only be called by the current admin after the 1-day time delay
|
|
881
|
+
*/
|
|
824
882
|
function confirmSetSecondsToUnllockFullUnstaking() external onlyOwner {
|
|
825
883
|
if (secondsToUnllockFullUnstaking.timeToAccept > block.timestamp) {
|
|
826
884
|
revert();
|
|
@@ -831,14 +889,26 @@ contract Staking {
|
|
|
831
889
|
secondsToUnllockFullUnstaking.timeToAccept = 0;
|
|
832
890
|
}
|
|
833
891
|
|
|
892
|
+
/**
|
|
893
|
+
* @notice Prepares to toggle the public staking flag with 1-day time delay
|
|
894
|
+
* @dev Initiates the time-delayed process to enable/disable public staking
|
|
895
|
+
*/
|
|
834
896
|
function prepareChangeAllowPublicStaking() external onlyOwner {
|
|
835
897
|
allowPublicStaking.timeToAccept = block.timestamp + 1 days;
|
|
836
898
|
}
|
|
837
899
|
|
|
900
|
+
/**
|
|
901
|
+
* @notice Cancels the pending public staking flag change
|
|
902
|
+
* @dev Only current admin can cancel the pending public staking toggle
|
|
903
|
+
*/
|
|
838
904
|
function cancelChangeAllowPublicStaking() external onlyOwner {
|
|
839
905
|
allowPublicStaking.timeToAccept = 0;
|
|
840
906
|
}
|
|
841
907
|
|
|
908
|
+
/**
|
|
909
|
+
* @notice Confirms and executes the public staking flag toggle after the time delay has passed
|
|
910
|
+
* @dev Toggles between enabled/disabled state for public staking after 1-day delay
|
|
911
|
+
*/
|
|
842
912
|
function confirmChangeAllowPublicStaking() external onlyOwner {
|
|
843
913
|
if (allowPublicStaking.timeToAccept > block.timestamp) {
|
|
844
914
|
revert();
|
|
@@ -849,14 +919,26 @@ contract Staking {
|
|
|
849
919
|
});
|
|
850
920
|
}
|
|
851
921
|
|
|
922
|
+
/**
|
|
923
|
+
* @notice Prepares to toggle the presale staking flag with 1-day time delay
|
|
924
|
+
* @dev Initiates the time-delayed process to enable/disable presale staking
|
|
925
|
+
*/
|
|
852
926
|
function prepareChangeAllowPresaleStaking() external onlyOwner {
|
|
853
927
|
allowPresaleStaking.timeToAccept = block.timestamp + 1 days;
|
|
854
928
|
}
|
|
855
929
|
|
|
930
|
+
/**
|
|
931
|
+
* @notice Cancels the pending presale staking flag change
|
|
932
|
+
* @dev Only current admin can cancel the pending presale staking toggle
|
|
933
|
+
*/
|
|
856
934
|
function cancelChangeAllowPresaleStaking() external onlyOwner {
|
|
857
935
|
allowPresaleStaking.timeToAccept = 0;
|
|
858
936
|
}
|
|
859
937
|
|
|
938
|
+
/**
|
|
939
|
+
* @notice Confirms and executes the presale staking flag toggle after the time delay has passed
|
|
940
|
+
* @dev Toggles between enabled/disabled state for presale staking after 1-day delay
|
|
941
|
+
*/
|
|
860
942
|
function confirmChangeAllowPresaleStaking() external onlyOwner {
|
|
861
943
|
if (allowPresaleStaking.timeToAccept > block.timestamp) {
|
|
862
944
|
revert();
|
|
@@ -867,16 +949,29 @@ contract Staking {
|
|
|
867
949
|
});
|
|
868
950
|
}
|
|
869
951
|
|
|
952
|
+
/**
|
|
953
|
+
* @notice Proposes a new estimator contract address with 1-day time delay
|
|
954
|
+
* @dev Part of the time-delayed governance system for estimator contract changes
|
|
955
|
+
* @param _estimator Address of the proposed new estimator contract
|
|
956
|
+
*/
|
|
870
957
|
function proposeEstimator(address _estimator) external onlyOwner {
|
|
871
958
|
estimator.proposal = _estimator;
|
|
872
959
|
estimator.timeToAccept = block.timestamp + 1 days;
|
|
873
960
|
}
|
|
874
961
|
|
|
962
|
+
/**
|
|
963
|
+
* @notice Rejects the current estimator contract proposal
|
|
964
|
+
* @dev Only current admin can reject the pending estimator contract proposal
|
|
965
|
+
*/
|
|
875
966
|
function rejectProposalEstimator() external onlyOwner {
|
|
876
967
|
estimator.proposal = address(0);
|
|
877
968
|
estimator.timeToAccept = 0;
|
|
878
969
|
}
|
|
879
970
|
|
|
971
|
+
/**
|
|
972
|
+
* @notice Accepts the estimator contract proposal after the time delay has passed
|
|
973
|
+
* @dev Can only be called by the current admin after the 1-day time delay
|
|
974
|
+
*/
|
|
880
975
|
function acceptNewEstimator() external onlyOwner {
|
|
881
976
|
if (estimator.timeToAccept > block.timestamp) {
|
|
882
977
|
revert();
|
|
@@ -14,6 +14,10 @@ library ErrorsLib {
|
|
|
14
14
|
error PublicStakingDisabled();
|
|
15
15
|
error AddressIsNotAService();
|
|
16
16
|
error UserAndServiceMismatch();
|
|
17
|
-
error
|
|
18
|
-
error
|
|
17
|
+
error AddressMustWaitToStakeAgain();
|
|
18
|
+
error AddressMustWaitToFullUnstake();
|
|
19
|
+
error ServiceDoesNotFulfillCorrectStakingAmount(uint256 requiredAmount);
|
|
20
|
+
error ServiceDoesNotStakeInSameTx();
|
|
21
|
+
error AddressMismatch();
|
|
19
22
|
}
|
|
23
|
+
|
|
@@ -22,7 +22,7 @@ pragma solidity ^0.8.0;
|
|
|
22
22
|
╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
|
|
23
23
|
|
|
24
24
|
* @title Treasury Contract
|
|
25
|
-
* @author
|
|
25
|
+
* @author Mate labs
|
|
26
26
|
* @notice Treasury for managing deposits and withdrawals in the EVVM ecosystem
|
|
27
27
|
* @dev Secure vault for ETH and ERC20 tokens with EVVM integration and input validation
|
|
28
28
|
*/
|
|
@@ -3,9 +3,59 @@
|
|
|
3
3
|
|
|
4
4
|
pragma solidity ^0.8.0;
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @title SignatureRecover
|
|
8
|
+
* @author Mate labs
|
|
9
|
+
* @notice Library for ECDSA signature verification and signer recovery in the EVVM ecosystem
|
|
10
|
+
* @dev Provides utilities for verifying signatures against expected signers and recovering addresses from signatures.
|
|
11
|
+
* Uses ERC-191 standard message signing format with proper message hashing and signature validation.
|
|
12
|
+
*
|
|
13
|
+
* Key Features:
|
|
14
|
+
* - EVVM-specific signature verification with structured message format
|
|
15
|
+
* - ERC-191 compliant signature format (\x19Ethereum Signed Message)
|
|
16
|
+
* - Safe signature splitting and validation
|
|
17
|
+
* - Address recovery from message signatures
|
|
18
|
+
*
|
|
19
|
+
* Security Features:
|
|
20
|
+
* - Validates signature length (must be 65 bytes)
|
|
21
|
+
* - Ensures proper v value (27 or 28)
|
|
22
|
+
* - Uses keccak256 hashing with ERC-191 message prefix
|
|
23
|
+
* - Prevents signature malleability attacks
|
|
24
|
+
*
|
|
25
|
+
* Usage Pattern:
|
|
26
|
+
* ```solidity
|
|
27
|
+
* bool isValid = SignatureRecover.signatureVerification(
|
|
28
|
+
* evvmID,
|
|
29
|
+
* "functionName",
|
|
30
|
+
* string.concat(param1, ",", param2, ",", param3),
|
|
31
|
+
* signature,
|
|
32
|
+
* expectedAddress
|
|
33
|
+
* );
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
|
|
6
37
|
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
7
38
|
|
|
8
39
|
library SignatureRecover {
|
|
40
|
+
/**
|
|
41
|
+
* @notice Verifies that a signature matches the expected signer for EVVM operations
|
|
42
|
+
* @dev Constructs a standardized message format and verifies the signature against the expected signer
|
|
43
|
+
*
|
|
44
|
+
* Message Format: "{evvmID},{functionName},{inputs}"
|
|
45
|
+
* This creates a unique signature for each EVVM operation preventing replay attacks across:
|
|
46
|
+
* - Different EVVM instances (via evvmID)
|
|
47
|
+
* - Different functions (via functionName)
|
|
48
|
+
* - Different parameters (via inputs)
|
|
49
|
+
*
|
|
50
|
+
* @param evvmID Unique identifier for the EVVM instance (prevents cross-chain replay)
|
|
51
|
+
* @param functionName Name of the function being called (prevents cross-function replay)
|
|
52
|
+
* @param inputs Comma-separated string of function inputs. Must be constructed using
|
|
53
|
+
* string.concat(param1, ",", param2, ",", param3)
|
|
54
|
+
* where all parameters are converted to strings
|
|
55
|
+
* @param signature The ECDSA signature to verify (65 bytes: r(32) + s(32) + v(1))
|
|
56
|
+
* @param expectedSigner Address that should have signed the message
|
|
57
|
+
* @return bool True if the signature is valid and matches the expected signer, false otherwise
|
|
58
|
+
*/
|
|
9
59
|
function signatureVerification(
|
|
10
60
|
string memory evvmID,
|
|
11
61
|
string memory functionName,
|
|
@@ -20,7 +70,22 @@ library SignatureRecover {
|
|
|
20
70
|
) == expectedSigner;
|
|
21
71
|
}
|
|
22
72
|
|
|
23
|
-
|
|
73
|
+
/**
|
|
74
|
+
* @notice Recovers the signer address from a message and its signature
|
|
75
|
+
* @dev Uses ERC-191 standard message signing format with proper prefix and length encoding
|
|
76
|
+
*
|
|
77
|
+
* The message is hashed using the ERC-191 standard format:
|
|
78
|
+
* keccak256("\x19Ethereum Signed Message:\n" + messageLength + message)
|
|
79
|
+
*
|
|
80
|
+
* This ensures compatibility with standard Ethereum wallets and signing tools like:
|
|
81
|
+
* - MetaMask personal_sign
|
|
82
|
+
* - web3.eth.personal.sign
|
|
83
|
+
* - ethers.js signMessage
|
|
84
|
+
*
|
|
85
|
+
* @param message The original message that was signed (plain text)
|
|
86
|
+
* @param signature The ECDSA signature (65 bytes: r + s + v)
|
|
87
|
+
* @return address The recovered signer address, or zero address if signature is invalid
|
|
88
|
+
*/
|
|
24
89
|
function recoverSigner(
|
|
25
90
|
string memory message,
|
|
26
91
|
bytes memory signature
|
|
@@ -36,6 +101,25 @@ library SignatureRecover {
|
|
|
36
101
|
return ecrecover(messageHash, v, r, s);
|
|
37
102
|
}
|
|
38
103
|
|
|
104
|
+
/**
|
|
105
|
+
* @notice Splits a signature into its component parts (r, s, v)
|
|
106
|
+
* @dev Extracts r, s, and v values from a 65-byte signature and validates the format
|
|
107
|
+
*
|
|
108
|
+
* Signature Format (65 bytes total):
|
|
109
|
+
* - r: bytes 0-31 (32 bytes) - First part of ECDSA signature
|
|
110
|
+
* - s: bytes 32-63 (32 bytes) - Second part of ECDSA signature
|
|
111
|
+
* - v: byte 64 (1 byte) - Recovery identifier (27 or 28)
|
|
112
|
+
*
|
|
113
|
+
* Security validations:
|
|
114
|
+
* - Ensures signature is exactly 65 bytes
|
|
115
|
+
* - Normalizes v value to 27/28 if needed
|
|
116
|
+
* - Validates v is either 27 or 28 (standard Ethereum values)
|
|
117
|
+
*
|
|
118
|
+
* @param signature The complete signature bytes to split (must be 65 bytes)
|
|
119
|
+
* @return r The r component of the signature (bytes32)
|
|
120
|
+
* @return s The s component of the signature (bytes32)
|
|
121
|
+
* @return v The recovery identifier (uint8, either 27 or 28)
|
|
122
|
+
*/
|
|
39
123
|
function splitSignature(
|
|
40
124
|
bytes memory signature
|
|
41
125
|
) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EVVM-NONCOMMERCIAL-1.0
|
|
2
|
+
// Full license terms available at: https://www.evvm.info/docs/EVVMNoncommercialLicense
|
|
3
|
+
pragma solidity ^0.8.0;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @title StakingServiceHooks
|
|
7
|
+
* @author Mate labs
|
|
8
|
+
* @notice Abstract contract providing simplified staking functionality for service contracts
|
|
9
|
+
* @dev This contract provides pre-built hooks for service contracts to easily interact with the EVVM staking system.
|
|
10
|
+
* It handles the complex 3-step staking process atomically to prevent token loss.
|
|
11
|
+
*
|
|
12
|
+
* Key Features:
|
|
13
|
+
* - Atomic service staking: Combines prepareServiceStaking, caPay, and confirmServiceStaking in one call
|
|
14
|
+
* - Simplified unstaking for services
|
|
15
|
+
* - Automatic address management for Staking and EVVM contracts
|
|
16
|
+
* - Safe state management to prevent token loss
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
* - Inherit from this contract in your service contract
|
|
20
|
+
* - Call makeStakeService(amount) to stake tokens safely
|
|
21
|
+
* - Call makeUnstakeService(amount) to unstake tokens
|
|
22
|
+
*
|
|
23
|
+
* IMPORTANT: The service contract must have sufficient Principal Token balance before calling makeStakeService
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import {Staking} from "@evvm/testnet-contracts/contracts/staking/Staking.sol";
|
|
27
|
+
import {Evvm} from "@evvm/testnet-contracts/contracts/evvm/Evvm.sol";
|
|
28
|
+
|
|
29
|
+
abstract contract StakingServiceHooks {
|
|
30
|
+
/// @dev Address of the Staking contract that handles staking operations
|
|
31
|
+
address stakingHookAddress;
|
|
32
|
+
/// @dev Address of the EVVM core contract that handles token operations
|
|
33
|
+
address evvmHookAddress;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @notice Initializes the service hooks with the staking contract address
|
|
37
|
+
* @dev Automatically retrieves and stores the EVVM contract address from the staking contract
|
|
38
|
+
* @param _stakingAddress Address of the deployed Staking contract
|
|
39
|
+
*/
|
|
40
|
+
constructor(address _stakingAddress) {
|
|
41
|
+
stakingHookAddress = _stakingAddress;
|
|
42
|
+
evvmHookAddress = Staking(stakingHookAddress).getEvvmAddress();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @notice Performs atomic staking operation for the service contract
|
|
47
|
+
* @dev Executes the complete 3-step staking process in a single transaction to prevent token loss:
|
|
48
|
+
* 1. Prepares service staking (records pre-staking state)
|
|
49
|
+
* 2. Transfers Principal Tokens to staking contract via caPay
|
|
50
|
+
* 3. Confirms staking completion
|
|
51
|
+
*
|
|
52
|
+
* @param amountToStake Number of staking tokens to stake (not Principal Tokens)
|
|
53
|
+
*
|
|
54
|
+
* Requirements:
|
|
55
|
+
* - Service must have sufficient Principal Token balance (amountToStake * PRICE_OF_STAKING)
|
|
56
|
+
* - Service must not be in cooldown period from previous unstaking
|
|
57
|
+
* - All operations must succeed in the same transaction
|
|
58
|
+
*
|
|
59
|
+
* @dev CRITICAL: This function ensures atomicity - if any step fails, the entire transaction reverts
|
|
60
|
+
* preventing the loss of Principal Tokens that could occur with manual step-by-step execution
|
|
61
|
+
*/
|
|
62
|
+
function makeStakeService(uint256 amountToStake) public {
|
|
63
|
+
Staking(stakingHookAddress).prepareServiceStaking(amountToStake);
|
|
64
|
+
Evvm(evvmHookAddress).caPay(
|
|
65
|
+
address(stakingHookAddress),
|
|
66
|
+
0x0000000000000000000000000000000000000001,
|
|
67
|
+
Staking(stakingHookAddress).priceOfStaking() * amountToStake
|
|
68
|
+
);
|
|
69
|
+
Staking(stakingHookAddress).confirmServiceStaking();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @notice Performs unstaking operation for the service contract
|
|
74
|
+
* @dev Allows the service to withdraw staked tokens and receive Principal Tokens back
|
|
75
|
+
*
|
|
76
|
+
* @param amountToUnstake Number of staking tokens to unstake
|
|
77
|
+
*
|
|
78
|
+
* The service will receive: amountToUnstake * PRICE_OF_STAKING Principal Tokens
|
|
79
|
+
*
|
|
80
|
+
* Requirements:
|
|
81
|
+
* - Service must have at least amountToUnstake staking tokens staked
|
|
82
|
+
* - If unstaking all tokens, must wait 21 days since last zero balance
|
|
83
|
+
* - Cannot unstake more than currently staked amount
|
|
84
|
+
*
|
|
85
|
+
* @dev Unstaking is subject to the same time locks as regular user unstaking
|
|
86
|
+
*/
|
|
87
|
+
function makeUnstakeService(uint256 amountToUnstake) public {
|
|
88
|
+
Staking(stakingHookAddress).serviceUnstaking(amountToUnstake);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @notice Internal function to update the staking contract address
|
|
93
|
+
* @dev Updates both staking and EVVM addresses. Should be used when staking contract is upgraded
|
|
94
|
+
* @param newStakingAddress Address of the new Staking contract
|
|
95
|
+
*
|
|
96
|
+
* @dev This function should be called by inheriting contracts when they need to migrate
|
|
97
|
+
* to a new version of the staking contract. It automatically updates the EVVM address too.
|
|
98
|
+
*/
|
|
99
|
+
function _changeStakingHookAddress(address newStakingAddress) internal {
|
|
100
|
+
stakingHookAddress = newStakingAddress;
|
|
101
|
+
evvmHookAddress = Staking(stakingHookAddress).getEvvmAddress();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @notice Internal function to manually update the EVVM contract address
|
|
106
|
+
* @dev Updates only the EVVM address. Use when EVVM contract is upgraded independently
|
|
107
|
+
* @param newEvvmAddress Address of the new EVVM contract
|
|
108
|
+
*
|
|
109
|
+
* @dev This function should be used sparingly, typically only when the EVVM contract
|
|
110
|
+
* is upgraded but the staking contract remains the same. In most cases, prefer
|
|
111
|
+
* using _changeStakingHookAddress which updates both addresses automatically.
|
|
112
|
+
*/
|
|
113
|
+
function changeEvvmHookAddress(address newEvvmAddress) internal {
|
|
114
|
+
evvmHookAddress = newEvvmAddress;
|
|
115
|
+
}
|
|
116
|
+
}
|
package/package.json
CHANGED