@evvm/testnet-contracts 2.2.3 → 3.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.
Files changed (71) hide show
  1. package/LICENSE +145 -118
  2. package/README.md +162 -39
  3. package/contracts/core/Core.sol +1394 -0
  4. package/contracts/core/lib/CoreStorage.sol +171 -0
  5. package/contracts/nameService/NameService.sol +666 -586
  6. package/contracts/nameService/lib/IdentityValidation.sol +18 -3
  7. package/contracts/p2pSwap/P2PSwap.sol +439 -285
  8. package/contracts/staking/Estimator.sol +128 -40
  9. package/contracts/staking/Staking.sol +329 -322
  10. package/contracts/treasury/Treasury.sol +48 -37
  11. package/contracts/treasuryTwoChains/TreasuryExternalChainStation.sol +585 -198
  12. package/contracts/treasuryTwoChains/TreasuryHostChainStation.sol +425 -174
  13. package/contracts/treasuryTwoChains/lib/PayloadUtils.sol +2 -4
  14. package/interfaces/{IEvvm.sol → ICore.sol} +67 -29
  15. package/interfaces/IEstimator.sol +1 -1
  16. package/interfaces/INameService.sol +58 -52
  17. package/interfaces/IP2PSwap.sol +18 -17
  18. package/interfaces/IStaking.sol +22 -17
  19. package/interfaces/ITreasury.sol +2 -1
  20. package/interfaces/ITreasuryExternalChainStation.sol +15 -9
  21. package/interfaces/ITreasuryHostChainStation.sol +14 -11
  22. package/interfaces/IUserValidator.sol +6 -0
  23. package/library/Erc191TestBuilder.sol +350 -297
  24. package/library/EvvmService.sol +38 -27
  25. package/library/errors/CoreError.sol +116 -0
  26. package/library/errors/CrossChainTreasuryError.sol +36 -0
  27. package/library/errors/NameServiceError.sol +79 -0
  28. package/library/errors/StakingError.sol +79 -0
  29. package/library/errors/TreasuryError.sol +33 -0
  30. package/library/primitives/SignatureRecover.sol +33 -0
  31. package/library/structs/CoreStructs.sol +146 -0
  32. package/library/structs/ExternalChainStationStructs.sol +92 -0
  33. package/library/structs/HostChainStationStructs.sol +77 -0
  34. package/library/structs/NameServiceStructs.sol +47 -0
  35. package/library/structs/P2PSwapStructs.sol +127 -0
  36. package/library/structs/StakingStructs.sol +67 -0
  37. package/library/utils/AdvancedStrings.sol +84 -5
  38. package/library/utils/CAUtils.sol +29 -0
  39. package/library/utils/SignatureUtil.sol +34 -0
  40. package/library/utils/governance/Admin.sol +66 -0
  41. package/library/utils/governance/ProposalStructs.sol +49 -0
  42. package/library/utils/service/CoreExecution.sol +177 -0
  43. package/library/utils/service/StakingServiceUtils.sol +30 -3
  44. package/library/utils/signature/CoreHashUtils.sol +73 -0
  45. package/library/utils/signature/NameServiceHashUtils.sol +156 -0
  46. package/library/utils/signature/P2PSwapHashUtils.sol +65 -0
  47. package/library/utils/signature/StakingHashUtils.sol +41 -0
  48. package/library/utils/signature/TreasuryCrossChainHashUtils.sol +40 -0
  49. package/package.json +2 -1
  50. package/contracts/evvm/Evvm.sol +0 -1327
  51. package/contracts/evvm/lib/ErrorsLib.sol +0 -18
  52. package/contracts/evvm/lib/EvvmStorage.sol +0 -62
  53. package/contracts/evvm/lib/EvvmStructs.sol +0 -90
  54. package/contracts/evvm/lib/SignatureUtils.sol +0 -120
  55. package/contracts/nameService/lib/ErrorsLib.sol +0 -21
  56. package/contracts/nameService/lib/NameServiceStructs.sol +0 -69
  57. package/contracts/nameService/lib/SignatureUtils.sol +0 -245
  58. package/contracts/p2pSwap/lib/P2PSwapStructs.sol +0 -59
  59. package/contracts/p2pSwap/lib/SignatureUtils.sol +0 -98
  60. package/contracts/staking/lib/ErrorsLib.sol +0 -22
  61. package/contracts/staking/lib/SignatureUtils.sol +0 -39
  62. package/contracts/staking/lib/StakingStructs.sol +0 -94
  63. package/contracts/treasury/lib/ErrorsLib.sol +0 -11
  64. package/contracts/treasuryTwoChains/lib/ErrorsLib.sol +0 -48
  65. package/contracts/treasuryTwoChains/lib/ExternalChainStationStructs.sol +0 -80
  66. package/contracts/treasuryTwoChains/lib/HostChainStationStructs.sol +0 -87
  67. package/contracts/treasuryTwoChains/lib/SignatureUtils.sol +0 -79
  68. package/library/utils/GovernanceUtils.sol +0 -81
  69. package/library/utils/nonces/AsyncNonce.sol +0 -32
  70. package/library/utils/nonces/SyncNonce.sol +0 -27
  71. package/library/utils/service/EvvmPayments.sol +0 -79
@@ -0,0 +1,1394 @@
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
+ import {
7
+ CoreStorage as Storage
8
+ } from "@evvm/testnet-contracts/contracts/core/lib/CoreStorage.sol";
9
+ import {
10
+ CoreError as Error
11
+ } from "@evvm/testnet-contracts/library/errors/CoreError.sol";
12
+ import {
13
+ CoreHashUtils as Hash
14
+ } from "@evvm/testnet-contracts/library/utils/signature/CoreHashUtils.sol";
15
+ import {
16
+ CoreStructs as Structs
17
+ } from "@evvm/testnet-contracts/library/structs/CoreStructs.sol";
18
+ import {
19
+ IUserValidator as UserValidator
20
+ } from "@evvm/testnet-contracts/interfaces/IUserValidator.sol";
21
+
22
+ import {
23
+ NameService
24
+ } from "@evvm/testnet-contracts/contracts/nameService/NameService.sol";
25
+
26
+ import {
27
+ AdvancedStrings
28
+ } from "@evvm/testnet-contracts/library/utils/AdvancedStrings.sol";
29
+ import {
30
+ SignatureRecover
31
+ } from "@evvm/testnet-contracts/library/primitives/SignatureRecover.sol";
32
+ import {CAUtils} from "@evvm/testnet-contracts/library/utils/CAUtils.sol";
33
+ import {
34
+ ProposalStructs
35
+ } from "@evvm/testnet-contracts/library/utils/governance/ProposalStructs.sol";
36
+
37
+ /**
38
+ ░▒▓██████▓▒░ ░▒▓██████▓▒░░▒▓███████▓▒░░▒▓████████▓▒░
39
+ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░
40
+ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░
41
+ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓██████▓▒░
42
+ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░
43
+ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░
44
+ ░▒▓██████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░
45
+
46
+ ████████╗███████╗███████╗████████╗███╗ ██╗███████╗████████╗
47
+ ╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝████╗ ██║██╔════╝╚══██╔══╝
48
+ ██║ █████╗ ███████╗ ██║ ██╔██╗ ██║█████╗ ██║
49
+ ██║ ██╔══╝ ╚════██║ ██║ ██║╚██╗██║██╔══╝ ██║
50
+ ██║ ███████╗███████║ ██║ ██║ ╚████║███████╗ ██║
51
+ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
52
+ * @title EVVM Core
53
+ * @author Mate labs
54
+ * @notice Central logic for EVVM payments, token management, and nonce tracking.
55
+ * @dev Combines payment operations and nonce management.
56
+ * Features multi-token payments with EIP-191 signatures, dual nonce system (sync/async),
57
+ * and staker rewards. Governed by a time-delayed admin and implementation upgrade system.
58
+ */
59
+
60
+ contract Core is Storage {
61
+ /**
62
+ * @notice Restricts access to the system administrator.
63
+ */
64
+ modifier onlyAdmin() {
65
+ if (msg.sender != admin.current) revert Error.SenderIsNotAdmin();
66
+
67
+ _;
68
+ }
69
+
70
+ /**
71
+ * @notice Initializes the EVVM Core with basic system parameters.
72
+ * @param _initialOwner Address granted administrative control.
73
+ * @param _stakingContractAddress Address of the Staking contract.
74
+ * @param _evvmMetadata Initial configuration (token info, reward amounts, etc.).
75
+ */
76
+ constructor(
77
+ address _initialOwner,
78
+ address _stakingContractAddress,
79
+ Structs.EvvmMetadata memory _evvmMetadata
80
+ ) {
81
+ if (
82
+ _initialOwner == address(0) || _stakingContractAddress == address(0)
83
+ ) revert Error.AddressCantBeZero();
84
+
85
+ evvmMetadata = _evvmMetadata;
86
+
87
+ stakingContractAddress = _stakingContractAddress;
88
+
89
+ admin.current = _initialOwner;
90
+
91
+ balances[_stakingContractAddress][evvmMetadata.principalTokenAddress] =
92
+ getRewardAmount() *
93
+ 2;
94
+
95
+ stakerList[_stakingContractAddress] = FLAG_IS_STAKER;
96
+
97
+ breakerSetupNameServiceAddress = FLAG_IS_STAKER;
98
+ }
99
+
100
+ /**
101
+ * @notice Configures NameService and Treasury addresses once.
102
+ * @dev Uses a breaker flag to prevent re-initialization.
103
+ * @param _nameServiceAddress Address of the NameService contract.
104
+ * @param _treasuryAddress Address of the Treasury contract.
105
+ */
106
+ function initializeSystemContracts(
107
+ address _nameServiceAddress,
108
+ address _treasuryAddress
109
+ ) external {
110
+ if (breakerSetupNameServiceAddress == 0x00)
111
+ revert Error.BreakerExploded();
112
+
113
+ if (_nameServiceAddress == address(0) || _treasuryAddress == address(0))
114
+ revert Error.AddressCantBeZero();
115
+
116
+ nameServiceAddress = _nameServiceAddress;
117
+ balances[nameServiceAddress][evvmMetadata.principalTokenAddress] =
118
+ 10000 *
119
+ 10 ** 18;
120
+ stakerList[nameServiceAddress] = FLAG_IS_STAKER;
121
+
122
+ treasuryAddress = _treasuryAddress;
123
+ }
124
+
125
+ /**
126
+ * @notice Updates the EVVM ID within a 24-hour window after deployment or change.
127
+ * @param newEvvmID New unique identifier for EIP-191 signatures.
128
+ */
129
+ function setEvvmID(uint256 newEvvmID) external onlyAdmin {
130
+ if (evvmMetadata.EvvmID != 0) {
131
+ if (block.timestamp > windowTimeToChangeEvvmID)
132
+ revert Error.WindowExpired();
133
+ }
134
+
135
+ evvmMetadata.EvvmID = newEvvmID;
136
+
137
+ windowTimeToChangeEvvmID = block.timestamp + 24 hours;
138
+ }
139
+
140
+ /**
141
+ * @notice Proxy fallback forwarding calls to the active implementation.
142
+ * @dev Uses delegatecall to execute logic within this contract's storage context.
143
+ * Reverts if currentImplementation is address(0).
144
+ */
145
+ fallback() external {
146
+ if (currentImplementation == address(0))
147
+ revert Error.ImplementationIsNotActive();
148
+
149
+ assembly {
150
+ /**
151
+ * Copy the data of the call
152
+ * copy s bytes of calldata from position
153
+ * f to mem in position t
154
+ * calldatacopy(t, f, s)
155
+ */
156
+ calldatacopy(0, 0, calldatasize())
157
+
158
+ /**
159
+ * 2. We make a delegatecall to the implementation
160
+ * and we copy the result
161
+ */
162
+ let result := delegatecall(
163
+ gas(), // Send all the available gas
164
+ sload(currentImplementation.slot), // Address of the implementation
165
+ 0, // Start of the memory where the data is
166
+ calldatasize(), // Size of the data
167
+ 0, // Where we will store the response
168
+ 0 // Initial size of the response
169
+ )
170
+
171
+ /// Copy the response
172
+ returndatacopy(0, 0, returndatasize())
173
+
174
+ /// Handle the result
175
+ switch result
176
+ case 0 {
177
+ revert(0, returndatasize()) // If it failed, revert
178
+ }
179
+ default {
180
+ return(0, returndatasize()) // If it worked, return
181
+ }
182
+ }
183
+ }
184
+
185
+ /**
186
+ * @notice Faucet: Adds balance to a user for testing (Testnet only).
187
+ * @param user Recipient address.
188
+ * @param token Token contract address.
189
+ * @param quantity Amount to add.
190
+ */
191
+ function addBalance(
192
+ address user,
193
+ address token,
194
+ uint256 quantity
195
+ ) external {
196
+ balances[user][token] += quantity;
197
+ }
198
+
199
+ /**
200
+ * @notice Faucet: Sets staker status for testing (Testnet only).
201
+ * @param user User address.
202
+ * @param answer Status flag (e.g., FLAG_IS_STAKER).
203
+ */
204
+ function setPointStaker(address user, bytes1 answer) external {
205
+ stakerList[user] = answer;
206
+ }
207
+
208
+ //░▒▓█ Payment Functions ██████████████████████████████████████████████████████▓▒░
209
+
210
+ /**
211
+ * @notice Processes a single token payment with signature verification.
212
+ * @dev Validates nonce (sync/async), resolves identity (if provided), and updates balances.
213
+ * Rewarded if the executor is a staker.
214
+ * @param from Sender address.
215
+ * @param to_address Recipient address (overridden if to_identity is set).
216
+ * @param to_identity Recipient username (resolved via NameService).
217
+ * @param token Token address (address(0) for ETH).
218
+ * @param amount Tokens to transfer.
219
+ * @param priorityFee Fee paid to the executor (if staker).
220
+ * @param senderExecutor Optional authorized executor (address(0) for any).
221
+ * @param nonce Transaction nonce.
222
+ * @param isAsyncExec True for parallel nonces, false for sequential.
223
+ * @param signature EIP-191 authorization signature.
224
+ */
225
+ function pay(
226
+ address from,
227
+ address to_address,
228
+ string memory to_identity,
229
+ address token,
230
+ uint256 amount,
231
+ uint256 priorityFee,
232
+ address senderExecutor,
233
+ uint256 nonce,
234
+ bool isAsyncExec,
235
+ bytes memory signature
236
+ ) external {
237
+ if (
238
+ SignatureRecover.recoverSigner(
239
+ AdvancedStrings.buildSignaturePayload(
240
+ evvmMetadata.EvvmID,
241
+ address(this),
242
+ Hash.hashDataForPay(
243
+ to_address,
244
+ to_identity,
245
+ token,
246
+ amount,
247
+ priorityFee
248
+ ),
249
+ senderExecutor,
250
+ nonce,
251
+ isAsyncExec
252
+ ),
253
+ signature
254
+ ) != from
255
+ ) revert Error.InvalidSignature();
256
+
257
+ if (!canExecuteUserTransaction(from))
258
+ revert Error.UserCannotExecuteTransaction();
259
+
260
+ if (isAsyncExec) {
261
+ bytes1 statusNonce = asyncNonceStatus(from, nonce);
262
+ if (asyncNonceStatus(from, nonce) == 0x01)
263
+ revert Error.AsyncNonceAlreadyUsed();
264
+
265
+ if (
266
+ statusNonce == 0x02 &&
267
+ asyncNonceReservedPointers[from][nonce] != address(this)
268
+ ) revert Error.AsyncNonceIsReservedByAnotherService();
269
+
270
+ asyncNonce[from][nonce] = true;
271
+ } else {
272
+ if (nonce != nextSyncNonce[from]) revert Error.SyncNonceMismatch();
273
+
274
+ unchecked {
275
+ ++nextSyncNonce[from];
276
+ }
277
+ }
278
+
279
+ if ((senderExecutor != address(0)) && (msg.sender != senderExecutor))
280
+ revert Error.SenderIsNotTheSenderExecutor();
281
+
282
+ address to = !AdvancedStrings.equal(to_identity, "")
283
+ ? NameService(nameServiceAddress).verifyStrictAndGetOwnerOfIdentity(
284
+ to_identity
285
+ )
286
+ : to_address;
287
+
288
+ _updateBalance(from, to, token, amount);
289
+
290
+ if (isAddressStaker(msg.sender)) {
291
+ if (priorityFee > 0) {
292
+ _updateBalance(from, msg.sender, token, priorityFee);
293
+ }
294
+ _giveReward(msg.sender, 1);
295
+ }
296
+ }
297
+
298
+ /**
299
+ * @notice Processes multiple payments in a single transaction.
300
+ * @dev Each payment is validated and executed independently.
301
+ * @param batchData Array of payment details and signatures.
302
+ * @return successfulTransactions Count of successful payments.
303
+ * @return results Success status for each payment in the batch.
304
+ */
305
+ function batchPay(
306
+ Structs.BatchData[] memory batchData
307
+ ) external returns (uint256 successfulTransactions, bool[] memory results) {
308
+ bool isSenderStaker = isAddressStaker(msg.sender);
309
+ address to_aux;
310
+ Structs.BatchData memory payment;
311
+ results = new bool[](batchData.length);
312
+
313
+ for (uint256 iteration = 0; iteration < batchData.length; iteration++) {
314
+ payment = batchData[iteration];
315
+
316
+ if (
317
+ SignatureRecover.recoverSigner(
318
+ AdvancedStrings.buildSignaturePayload(
319
+ evvmMetadata.EvvmID,
320
+ address(this),
321
+ Hash.hashDataForPay(
322
+ payment.to_address,
323
+ payment.to_identity,
324
+ payment.token,
325
+ payment.amount,
326
+ payment.priorityFee
327
+ ),
328
+ payment.senderExecutor,
329
+ payment.nonce,
330
+ payment.isAsyncExec
331
+ ),
332
+ payment.signature
333
+ ) !=
334
+ payment.from ||
335
+ !canExecuteUserTransaction(payment.from)
336
+ ) {
337
+ results[iteration] = false;
338
+ continue;
339
+ }
340
+
341
+ if (payment.isAsyncExec) {
342
+ bytes1 statusNonce = asyncNonceStatus(
343
+ payment.from,
344
+ payment.nonce
345
+ );
346
+ if (
347
+ statusNonce == 0x01 ||
348
+ (statusNonce == 0x02 &&
349
+ asyncNonceReservedPointers[payment.from][
350
+ payment.nonce
351
+ ] !=
352
+ address(this))
353
+ ) {
354
+ results[iteration] = false;
355
+ continue;
356
+ }
357
+
358
+ asyncNonce[payment.from][payment.nonce] = true;
359
+ } else {
360
+ if (payment.nonce != nextSyncNonce[payment.from]) {
361
+ results[iteration] = false;
362
+ continue;
363
+ }
364
+
365
+ unchecked {
366
+ ++nextSyncNonce[payment.from];
367
+ }
368
+ }
369
+
370
+ if (
371
+ (payment.senderExecutor != address(0) &&
372
+ msg.sender != payment.senderExecutor) ||
373
+ ((isSenderStaker ? payment.priorityFee : 0) + payment.amount >
374
+ balances[payment.from][payment.token])
375
+ ) {
376
+ results[iteration] = false;
377
+ continue;
378
+ }
379
+
380
+ if (!AdvancedStrings.equal(payment.to_identity, "")) {
381
+ to_aux = NameService(nameServiceAddress).getOwnerOfIdentity(
382
+ payment.to_identity
383
+ );
384
+ if (to_aux == address(0)) {
385
+ results[iteration] = false;
386
+ continue;
387
+ }
388
+ } else {
389
+ to_aux = payment.to_address;
390
+ }
391
+
392
+ /// @dev Because of the previous check, _updateBalance can´t fail
393
+
394
+ _updateBalance(payment.from, to_aux, payment.token, payment.amount);
395
+
396
+ if (payment.priorityFee > 0 && isSenderStaker)
397
+ _updateBalance(
398
+ payment.from,
399
+ msg.sender,
400
+ payment.token,
401
+ payment.priorityFee
402
+ );
403
+
404
+ successfulTransactions++;
405
+ results[iteration] = true;
406
+ }
407
+
408
+ if (isSenderStaker) _giveReward(msg.sender, successfulTransactions);
409
+ }
410
+
411
+ /**
412
+ * @notice Distributes tokens from one sender to multiple recipients with a single signature.
413
+ * @param from Sender address.
414
+ * @param toData Array of recipient addresses/identities and their respective amounts.
415
+ * @param token Token address.
416
+ * @param amount Total amount to distribute (sum of toData).
417
+ * @param priorityFee Fee for the executor (if staker).
418
+ * @param nonce Transaction nonce.
419
+ * @param isAsyncExec True for parallel nonces.
420
+ * @param senderExecutor Optional authorized executor.
421
+ * @param signature EIP-191 authorization signature.
422
+ */
423
+ function dispersePay(
424
+ address from,
425
+ Structs.DispersePayMetadata[] memory toData,
426
+ address token,
427
+ uint256 amount,
428
+ uint256 priorityFee,
429
+ address senderExecutor,
430
+ uint256 nonce,
431
+ bool isAsyncExec,
432
+ bytes memory signature
433
+ ) external {
434
+ if (
435
+ SignatureRecover.recoverSigner(
436
+ AdvancedStrings.buildSignaturePayload(
437
+ evvmMetadata.EvvmID,
438
+ address(this),
439
+ Hash.hashDataForDispersePay(
440
+ toData,
441
+ token,
442
+ amount,
443
+ priorityFee
444
+ ),
445
+ senderExecutor,
446
+ nonce,
447
+ isAsyncExec
448
+ ),
449
+ signature
450
+ ) != from
451
+ ) revert Error.InvalidSignature();
452
+
453
+ if (!canExecuteUserTransaction(from))
454
+ revert Error.UserCannotExecuteTransaction();
455
+
456
+ if (isAsyncExec) {
457
+ bytes1 statusNonce = asyncNonceStatus(from, nonce);
458
+ if (asyncNonceStatus(from, nonce) == 0x01)
459
+ revert Error.AsyncNonceAlreadyUsed();
460
+
461
+ if (
462
+ statusNonce == 0x02 &&
463
+ asyncNonceReservedPointers[from][nonce] != address(this)
464
+ ) revert Error.AsyncNonceIsReservedByAnotherService();
465
+
466
+ asyncNonce[from][nonce] = true;
467
+ } else {
468
+ if (nonce != nextSyncNonce[from]) revert Error.SyncNonceMismatch();
469
+
470
+ unchecked {
471
+ ++nextSyncNonce[from];
472
+ }
473
+ }
474
+
475
+ if ((senderExecutor != address(0)) && (msg.sender != senderExecutor))
476
+ revert Error.SenderIsNotTheSenderExecutor();
477
+
478
+ bool isSenderStaker = isAddressStaker(msg.sender);
479
+
480
+ if (balances[from][token] < amount + (isSenderStaker ? priorityFee : 0))
481
+ revert Error.InsufficientBalance();
482
+
483
+ uint256 acomulatedAmount = 0;
484
+ balances[from][token] -= (amount + (isSenderStaker ? priorityFee : 0));
485
+ address to_aux;
486
+ for (uint256 i = 0; i < toData.length; i++) {
487
+ acomulatedAmount += toData[i].amount;
488
+
489
+ if (!AdvancedStrings.equal(toData[i].to_identity, "")) {
490
+ if (
491
+ NameService(nameServiceAddress).strictVerifyIfIdentityExist(
492
+ toData[i].to_identity
493
+ )
494
+ ) {
495
+ to_aux = NameService(nameServiceAddress).getOwnerOfIdentity(
496
+ toData[i].to_identity
497
+ );
498
+ }
499
+ } else {
500
+ to_aux = toData[i].to_address;
501
+ }
502
+
503
+ balances[to_aux][token] += toData[i].amount;
504
+ }
505
+
506
+ if (acomulatedAmount != amount) revert Error.InvalidAmount();
507
+
508
+ if (isSenderStaker) {
509
+ _giveReward(msg.sender, 1);
510
+ balances[msg.sender][token] += priorityFee;
511
+ }
512
+ }
513
+
514
+ /**
515
+ * @notice Contract-to-address payment function for authorized
516
+ * smart contracts
517
+ * @dev Allows registered contracts to distribute tokens without
518
+ * signature verification
519
+ *
520
+ * Authorization Model:
521
+ /**
522
+ * @notice Allows a smart contract (CA) to pay a recipient directly.
523
+ * @dev No signature required as the contract itself is the caller.
524
+ * @param to Recipient address.
525
+ * @param token Token address.
526
+ * @param amount Tokens to transfer.
527
+ */
528
+ function caPay(address to, address token, uint256 amount) external {
529
+ address from = msg.sender;
530
+
531
+ if (!CAUtils.verifyIfCA(from)) revert Error.NotAnCA();
532
+
533
+ _updateBalance(from, to, token, amount);
534
+
535
+ if (isAddressStaker(msg.sender)) _giveReward(msg.sender, 1);
536
+ }
537
+
538
+ /**
539
+ * @notice Allows a smart contract (CA) to distribute tokens to multiple recipients.
540
+ * @param toData Array of recipient addresses/identities and amounts.
541
+ * @param token Token address.
542
+ * @param amount Total amount to distribute.
543
+ */
544
+ function disperseCaPay(
545
+ Structs.DisperseCaPayMetadata[] memory toData,
546
+ address token,
547
+ uint256 amount
548
+ ) external {
549
+ address from = msg.sender;
550
+
551
+ if (!CAUtils.verifyIfCA(from)) revert Error.NotAnCA();
552
+
553
+ if (balances[from][token] < amount) revert Error.InsufficientBalance();
554
+
555
+ uint256 acomulatedAmount = 0;
556
+
557
+ balances[from][token] -= amount;
558
+
559
+ for (uint256 i = 0; i < toData.length; i++) {
560
+ acomulatedAmount += toData[i].amount;
561
+ balances[toData[i].toAddress][token] += toData[i].amount;
562
+ }
563
+
564
+ if (acomulatedAmount != amount) revert Error.InvalidAmount();
565
+
566
+ if (isAddressStaker(from)) _giveReward(from, 1);
567
+ }
568
+
569
+ //░▒▓█ Nonce and Signature Functions ██████████████████████████████████████████▓▒░
570
+
571
+ /**
572
+ * @notice Validates a user signature and consumes a nonce for an EVVM service.
573
+ * @dev Only callable by smart contracts (EVVM services). Atomic verification/consumption.
574
+ * @param user Address of the transaction signer.
575
+ * @param hashPayload Hash of the transaction parameters.
576
+ * @param originExecutor Optional tx.origin restriction (address(0) for none).
577
+ * @param nonce Nonce to validate and consume.
578
+ * @param isAsyncExec True for non-sequential nonces.
579
+ * @param signature User's authorization signature.
580
+ */
581
+ function validateAndConsumeNonce(
582
+ address user,
583
+ bytes32 hashPayload,
584
+ address originExecutor,
585
+ uint256 nonce,
586
+ bool isAsyncExec,
587
+ bytes memory signature
588
+ ) external {
589
+ address servicePointer = msg.sender;
590
+
591
+ if (!CAUtils.verifyIfCA(servicePointer))
592
+ revert Error.MsgSenderIsNotAContract();
593
+
594
+ if (
595
+ SignatureRecover.recoverSigner(
596
+ AdvancedStrings.buildSignaturePayload(
597
+ evvmMetadata.EvvmID,
598
+ servicePointer,
599
+ hashPayload,
600
+ originExecutor,
601
+ nonce,
602
+ isAsyncExec
603
+ ),
604
+ signature
605
+ ) != user
606
+ ) revert Error.InvalidSignature();
607
+
608
+ if (originExecutor != address(0) && tx.origin != originExecutor)
609
+ revert Error.OriginIsNotTheOriginExecutor();
610
+
611
+ if (!canExecuteUserTransaction(user))
612
+ revert Error.UserCannotExecuteTransaction();
613
+
614
+ if (isAsyncExec) {
615
+ bytes1 statusNonce = asyncNonceStatus(user, nonce);
616
+ if (asyncNonceStatus(user, nonce) == 0x01)
617
+ revert Error.AsyncNonceAlreadyUsed();
618
+
619
+ if (
620
+ statusNonce == 0x02 &&
621
+ asyncNonceReservedPointers[user][nonce] != servicePointer
622
+ ) revert Error.AsyncNonceIsReservedByAnotherService();
623
+
624
+ asyncNonce[user][nonce] = true;
625
+ } else {
626
+ if (nonce != nextSyncNonce[user]) revert Error.SyncNonceMismatch();
627
+
628
+ unchecked {
629
+ ++nextSyncNonce[user];
630
+ }
631
+ }
632
+ }
633
+
634
+ //░▒▓█ Nonce Reservation Functions ████████████████████████████████████████████▓▒░
635
+
636
+ /**
637
+ * @notice Reserves an async nonce for exclusive service use
638
+ * @dev Allows users to pre-allocate nonces to specific services
639
+ *
640
+ * Reservation System:
641
+ * - Users reserve nonces for specific service addresses
642
+ * - Prevents other services from using reserved nonces
643
+ * - Useful for multi-step or delayed operations
644
+ * - Reservation persists until revoked or nonce is used
645
+ *
646
+ * Use Cases:
647
+ * - Cross-chain operations requiring coordination
648
+ * - Multi-signature workflows with specific executors
649
+ * - Service-specific transaction queues
650
+ * - Preventing front-running by other services
651
+ *
652
+ * Security Features:
653
+ * - User-controlled reservation (msg.sender)
654
+ * - Validates service address is not zero
655
+ * - Prevents double reservation of same nonce
656
+ * - Cannot reserve already-used nonces
657
+ *
658
+ * @param nonce The async nonce value to reserve
659
+ * @param serviceAddress Service contract that can use nonce
660
+ */
661
+ function reserveAsyncNonce(uint256 nonce, address serviceAddress) external {
662
+ if (serviceAddress == address(0)) revert Error.InvalidServiceAddress();
663
+
664
+ if (asyncNonce[msg.sender][nonce]) revert Error.AsyncNonceAlreadyUsed();
665
+
666
+ if (asyncNonceReservedPointers[msg.sender][nonce] != address(0))
667
+ revert Error.AsyncNonceAlreadyReserved();
668
+
669
+ asyncNonceReservedPointers[msg.sender][nonce] = serviceAddress;
670
+ }
671
+
672
+ /**
673
+ * @notice Revokes a previously reserved async nonce
674
+ * @dev Allows clearing of nonce reservations for reuse
675
+ *
676
+ * Revocation Process:
677
+ * - Validates nonce has not been used yet
678
+ * - Checks that nonce is currently reserved
679
+ * - Clears the service address reservation
680
+ * - Nonce becomes available for any service
681
+ *
682
+ * Authorization:
683
+ * - Currently callable by anyone (potential security issue)
684
+ * - Should validate msg.sender is user or authorized
685
+ * - Allows cancellation of mistaken reservations
686
+ *
687
+ * Use Cases:
688
+ * - Canceling pending service operations
689
+ * - Correcting accidental reservations
690
+ * - Freeing nonces for different services
691
+ *
692
+ * @param user Address that reserved the nonce
693
+ * @param nonce The async nonce to revoke reservation for
694
+ */
695
+ function revokeAsyncNonce(address user, uint256 nonce) external {
696
+ if (asyncNonce[user][nonce]) revert Error.AsyncNonceAlreadyUsed();
697
+
698
+ if (asyncNonceReservedPointers[user][nonce] == address(0))
699
+ revert Error.AsyncNonceNotReserved();
700
+
701
+ asyncNonceReservedPointers[user][nonce] = address(0);
702
+ }
703
+
704
+ //░▒▓█ UserValidator Management Functions █████████████████████████████████████▓▒░
705
+
706
+ /**
707
+ * @notice Proposes new UserValidator contract address
708
+ * @dev Initiates time-delayed governance for validator changes
709
+ *
710
+ * Governance Process:
711
+ * - Admin proposes new validator contract address
712
+ * - 1-day delay enforced before acceptance
713
+ * - Allows community review of validator changes
714
+ * - Can be canceled before acceptance
715
+ *
716
+ * UserValidator Integration:
717
+ * - Optional contract for transaction filtering
718
+ * - Called during validateAndConsumeNonce execution
719
+ * - Can block specific users from executing transactions
720
+ * - Useful for compliance or security requirements
721
+ *
722
+ * Security Features:
723
+ * - Time-delayed governance (DELAY constant)
724
+ * - Admin-only proposal capability
725
+ * - Cancellation mechanism before activation
726
+ *
727
+ * @param newValidator Address of proposed UserValidator
728
+ */
729
+ function proposeUserValidator(address newValidator) external onlyAdmin {
730
+ userValidatorAddress.proposal = newValidator;
731
+ userValidatorAddress.timeToAccept =
732
+ block.timestamp +
733
+ TIME_TO_ACCEPT_PROPOSAL;
734
+ }
735
+
736
+ /**
737
+ * @notice Cancels pending UserValidator proposal
738
+ * @dev Resets proposal state before time-lock expires
739
+ *
740
+ * @custom:access Admin only
741
+ */
742
+ function cancelUserValidatorProposal() external onlyAdmin {
743
+ userValidatorAddress.proposal = address(0);
744
+ userValidatorAddress.timeToAccept = 0;
745
+ }
746
+
747
+ /**
748
+ * @notice Accepts UserValidator proposal after time-lock
749
+ * @dev Activates new validator after delay period expires
750
+ *
751
+ * Activation Process:
752
+ * - Validates time-lock period has passed
753
+ * - Sets new validator as current active validator
754
+ * - Clears proposal state
755
+ * - Validator becomes active immediately
756
+ *
757
+ * Impact:
758
+ * - All future transactions checked by new validator
759
+ * - Affects validateAndConsumeNonce behavior
760
+ * - Can block users from executing transactions
761
+ *
762
+ * @custom:access Admin only
763
+ * @custom:timelock Requires DELAY (1 day) to have passed
764
+ */
765
+ function acceptUserValidatorProposal() external onlyAdmin {
766
+ if (block.timestamp < userValidatorAddress.timeToAccept)
767
+ revert Error.ProposalForUserValidatorNotReady();
768
+
769
+ userValidatorAddress.current = userValidatorAddress.proposal;
770
+ userValidatorAddress.proposal = address(0);
771
+ userValidatorAddress.timeToAccept = 0;
772
+ }
773
+
774
+ //░▒▓█ Treasury Exclusive Functions ███████████████████████████████████████████▓▒░
775
+
776
+ /**
777
+ * @notice Adds tokens to a user's balance in the EVVM system
778
+ * @dev Restricted function that can only be called by the authorized treasury contract
779
+ *
780
+ * Treasury Operations:
781
+ * - Allows treasury to mint or credit tokens to user accounts
782
+ * - Used for reward distributions, airdrops, or token bridging
783
+ * - Direct balance manipulation bypasses normal transfer restrictions
784
+ * - No signature verification required (treasury authorization)
785
+ *
786
+ * Access Control:
787
+ * - Only the registered treasury contract can call this function
788
+ * - Reverts with SenderIsNotTreasury error for unauthorized callers
789
+ * - Provides centralized token distribution mechanism
790
+ *
791
+ * Use Cases:
792
+ * - Cross-chain bridge token minting
793
+ * - Administrative reward distributions
794
+ * - System-level token allocations
795
+ * - Emergency balance corrections
796
+ *
797
+ * @param user Address of the user to receive tokens
798
+ * @param token Address of the token contract to add balance for
799
+ * @param amount Amount of tokens to add to the user's balance
800
+ *
801
+ * @custom:access-control Only treasury contract
802
+ * @custom:security No overflow protection needed due to controlled access
803
+ */
804
+ function addAmountToUser(
805
+ address user,
806
+ address token,
807
+ uint256 amount
808
+ ) external {
809
+ if (msg.sender != treasuryAddress) revert Error.SenderIsNotTreasury();
810
+
811
+ balances[user][token] += amount;
812
+ }
813
+
814
+ /**
815
+ * @notice Deducts tokens from a user's system balance.
816
+ * @dev Restricted to the authorized Treasury contract.
817
+ * @param user Account to debit.
818
+ * @param token Token address.
819
+ * @param amount Amount to remove.
820
+ */
821
+ function removeAmountFromUser(
822
+ address user,
823
+ address token,
824
+ uint256 amount
825
+ ) external {
826
+ if (msg.sender != treasuryAddress) revert Error.SenderIsNotTreasury();
827
+
828
+ balances[user][token] -= amount;
829
+ }
830
+
831
+ //░▒▓█ Administrative Functions ████████████████████████████████████████████████████████▓▒░
832
+
833
+ //██ Proxy Management █████████████████████████████████████████████
834
+
835
+ /**
836
+ * @notice Proposes a new implementation contract for the proxy (30-day delay).
837
+ * @param _newImpl Address of the new logic contract.
838
+ */
839
+ function proposeImplementation(address _newImpl) external onlyAdmin {
840
+ if (_newImpl == address(0)) revert Error.IncorrectAddressInput();
841
+ proposalImplementation = _newImpl;
842
+ timeToAcceptImplementation =
843
+ block.timestamp +
844
+ TIME_TO_ACCEPT_IMPLEMENTATION;
845
+ }
846
+
847
+ /**
848
+ * @notice Cancels a pending implementation upgrade proposal.
849
+ */
850
+ function rejectUpgrade() external onlyAdmin {
851
+ proposalImplementation = address(0);
852
+ timeToAcceptImplementation = 0;
853
+ }
854
+
855
+ /**
856
+ * @notice Finalizes the implementation upgrade after the time delay.
857
+ */
858
+ function acceptImplementation() external onlyAdmin {
859
+ if (block.timestamp < timeToAcceptImplementation)
860
+ revert Error.TimeLockNotExpired();
861
+
862
+ currentImplementation = proposalImplementation;
863
+ proposalImplementation = address(0);
864
+ timeToAcceptImplementation = 0;
865
+ }
866
+
867
+ //██ Admin Management █████████████████████████████████████████████─
868
+
869
+ /**
870
+ * @notice Proposes a new administrator (1-day delay).
871
+ * @param _newOwner Address of the proposed admin.
872
+ */
873
+ function proposeAdmin(address _newOwner) external onlyAdmin {
874
+ if (_newOwner == address(0) || _newOwner == admin.current)
875
+ revert Error.IncorrectAddressInput();
876
+
877
+ admin = ProposalStructs.AddressTypeProposal({
878
+ current: admin.current,
879
+ proposal: _newOwner,
880
+ timeToAccept: block.timestamp + TIME_TO_ACCEPT_PROPOSAL
881
+ });
882
+ }
883
+
884
+ /**
885
+ * @notice Cancels a pending admin change proposal.
886
+ */
887
+ function rejectProposalAdmin() external onlyAdmin {
888
+ admin = ProposalStructs.AddressTypeProposal({
889
+ current: admin.current,
890
+ proposal: address(0),
891
+ timeToAccept: 0
892
+ });
893
+ }
894
+
895
+ /**
896
+ * @notice Finalizes the admin change after the time delay.
897
+ * @dev Must be called by the proposed admin.
898
+ */
899
+ function acceptAdmin() external {
900
+ if (block.timestamp < admin.timeToAccept)
901
+ revert Error.TimeLockNotExpired();
902
+
903
+ if (msg.sender != admin.proposal)
904
+ revert Error.SenderIsNotTheProposedAdmin();
905
+
906
+ admin = ProposalStructs.AddressTypeProposal({
907
+ current: admin.proposal,
908
+ proposal: address(0),
909
+ timeToAccept: 0
910
+ });
911
+ }
912
+
913
+ //░▒▓█ Reward System Functions █████████████████████████████████████████████████████████▓▒░
914
+
915
+ /**
916
+ * @notice Triggers a reward recalculation and era transition in the token economy
917
+ * @dev Implements deflationary tokenomics with halving mechanism and random rewards
918
+ *
919
+ * Era Transition Mechanism:
920
+ * - Activates when total supply exceeds current era token threshold
921
+ * - Moves half of remaining tokens to next era threshold
922
+ * - Halves the base reward amount for future transactions
923
+ * - Provides random Principal Token bonus to caller (1-5083x reward)
924
+ *
925
+ * Economic Impact:
926
+ * - Gradually reduces inflation through reward halving
927
+ * - Creates scarcity as era thresholds become harder to reach
928
+ * - Incentivizes early participation with higher rewards
929
+ * - Provides lottery-style bonus for triggering era transitions
930
+ *
931
+ * Requirements:
932
+ * - Total supply must exceed current era token threshold
933
+ * - Can be called by anyone when conditions are met
934
+ */
935
+ function recalculateReward() public {
936
+ if (evvmMetadata.totalSupply > evvmMetadata.eraTokens) {
937
+ evvmMetadata.eraTokens += ((evvmMetadata.totalSupply -
938
+ evvmMetadata.eraTokens) / 2);
939
+ balances[msg.sender][evvmMetadata.principalTokenAddress] +=
940
+ evvmMetadata.reward *
941
+ getRandom(1, 5083);
942
+ evvmMetadata.reward = evvmMetadata.reward / 2;
943
+ } else {
944
+ revert();
945
+ }
946
+ }
947
+
948
+ /**
949
+ * @notice Generates a pseudo-random number within a specified range
950
+ * @dev Uses block timestamp and prevrandao for randomness (suitable for non-critical randomness)
951
+ *
952
+ * Randomness Source:
953
+ * - Combines block.timestamp and block.prevrandao
954
+ * - Suitable for reward bonuses and non-security-critical randomness
955
+ * - Not suitable for high-stakes randomness requiring true unpredictability
956
+ *
957
+ * @param min Minimum value (inclusive)
958
+ * @param max Maximum value (inclusive)
959
+ * @return Random number between min and max (inclusive)
960
+ */
961
+ function getRandom(
962
+ uint256 min,
963
+ uint256 max
964
+ ) internal view returns (uint256) {
965
+ return
966
+ min +
967
+ (uint256(
968
+ keccak256(abi.encodePacked(block.timestamp, block.prevrandao))
969
+ ) % (max - min + 1));
970
+ }
971
+
972
+ //░▒▓█ Staking Integration Functions █████████████████████████████████████████████████▓▒░
973
+
974
+ /**
975
+ * @notice Updates staker status for a user address
976
+ * @dev Can only be called by the authorized staking contract
977
+ *
978
+ * Staker Status Management:
979
+ * - Controls who can earn staking rewards and process transactions
980
+ * - Integrates with external staking contract for validation
981
+ * - Updates affect payment processing privileges and reward eligibility
982
+ *
983
+ * Access Control:
984
+ * - Only the registered staking contract can call this function
985
+ * - Ensures staker status changes are properly authorized
986
+ *
987
+ * @param user Address to update staker status for
988
+ * @param answer Bytes1 flag indicating staker status/type
989
+ */
990
+ function pointStaker(address user, bytes1 answer) public {
991
+ if (msg.sender != stakingContractAddress) revert();
992
+
993
+ stakerList[user] = answer;
994
+ }
995
+
996
+ //░▒▓█ View Functions █████████████████████████████████████████████████████████████████▓▒░
997
+
998
+ /**
999
+ * @notice Returns the complete EVVM metadata configuration
1000
+ * @dev Provides access to system-wide configuration and economic parameters
1001
+ *
1002
+ * Metadata Contents:
1003
+ * - Principal token address (Principal Token)
1004
+ * - Current reward amount per transaction
1005
+ * - Total supply tracking
1006
+ * - Era tokens threshold for reward transitions
1007
+ * - System configuration parameters
1008
+ *
1009
+ * @return Complete EvvmMetadata struct with all system parameters
1010
+ */
1011
+ function getEvvmMetadata()
1012
+ external
1013
+ view
1014
+ returns (Structs.EvvmMetadata memory)
1015
+ {
1016
+ return evvmMetadata;
1017
+ }
1018
+
1019
+ /**
1020
+ * @notice Gets the address representing the Principal Token in balance mappings
1021
+ * @dev Returns the virtual address used to track Principal Token balances in the balances mapping
1022
+ * This is not an ERC20 contract address but a sentinel value for the EVVM-native token
1023
+ * @return Address used as the key for Principal Token balances
1024
+ */
1025
+ function getPrincipalTokenAddress() external view returns (address) {
1026
+ return evvmMetadata.principalTokenAddress;
1027
+ }
1028
+
1029
+ /**
1030
+ * @notice Gets the address representing native chain currency (ETH/MATIC) in balance mappings
1031
+ * @dev Returns address(0) which is the standard sentinel for native blockchain tokens
1032
+ * Use this address as the token parameter when dealing with ETH or chain-native assets
1033
+ * @return address(0) representing the native chain currency
1034
+ */
1035
+ function getChainHostCoinAddress() external pure returns (address) {
1036
+ return address(0);
1037
+ }
1038
+
1039
+ /**
1040
+ * @notice Gets the unique identifier string for this EVVM instance
1041
+ * @dev Returns the EvvmID used for distinguishing different EVVM deployments
1042
+ * @return Unique EvvmID string
1043
+ */
1044
+ function getEvvmID() external view returns (uint256) {
1045
+ return evvmMetadata.EvvmID;
1046
+ }
1047
+
1048
+ /**
1049
+ * @notice Gets the acceptance deadline for pending token whitelist proposals
1050
+ * @dev Returns timestamp when prepared tokens can be added to whitelist
1051
+ * @return Timestamp when pending token can be whitelisted (0 if no pending proposal)
1052
+ */
1053
+ function getWhitelistTokenToBeAddedDateToSet()
1054
+ external
1055
+ view
1056
+ returns (uint256)
1057
+ {
1058
+ return whitelistTokenToBeAdded_dateToSet;
1059
+ }
1060
+
1061
+ /**
1062
+ * @notice Gets the current NameService contract address
1063
+ * @dev Returns the address used for identity resolution in payments
1064
+ * @return Address of the integrated NameService contract
1065
+ */
1066
+ function getNameServiceAddress() external view returns (address) {
1067
+ return nameServiceAddress;
1068
+ }
1069
+
1070
+ /**
1071
+ * @notice Gets the authorized staking contract address
1072
+ * @dev Returns the address that can modify staker status and receive rewards
1073
+ * @return Address of the integrated staking contract
1074
+ */
1075
+ function getStakingContractAddress() external view returns (address) {
1076
+ return stakingContractAddress;
1077
+ }
1078
+
1079
+ /**
1080
+ * @notice Gets the next Fisher Bridge deposit nonce for a user
1081
+ * @dev Returns the expected nonce for the next cross-chain deposit
1082
+ * @param user Address to check deposit nonce for
1083
+ * @return Next Fisher Bridge deposit nonce
1084
+ */
1085
+ function getNextFisherDepositNonce(
1086
+ address user
1087
+ ) external view returns (uint256) {
1088
+ return nextFisherDepositNonce[user];
1089
+ }
1090
+
1091
+ /**
1092
+ * @notice Gets the balance of a specific token for a user
1093
+ * @dev Returns the current balance stored in the EVVM system
1094
+ * @param user Address to check balance for
1095
+ * @param token Token contract address to check
1096
+ * @return Current token balance for the user
1097
+ */
1098
+ function getBalance(
1099
+ address user,
1100
+ address token
1101
+ ) external view returns (uint) {
1102
+ return balances[user][token];
1103
+ }
1104
+
1105
+ /**
1106
+ * @notice Checks if an address is registered as a staker
1107
+ * @dev Verifies staker status for transaction processing privileges and rewards
1108
+ * @param user Address to check staker status for
1109
+ * @return True if the address is a registered staker
1110
+ */
1111
+ function isAddressStaker(address user) public view returns (bool) {
1112
+ return stakerList[user] == FLAG_IS_STAKER;
1113
+ }
1114
+
1115
+ /**
1116
+ * @notice Gets the current era token threshold for reward transitions
1117
+ * @dev Returns the token supply threshold that triggers the next reward halving
1118
+ * @return Current era tokens threshold
1119
+ */
1120
+ function getEraPrincipalToken() public view returns (uint256) {
1121
+ return evvmMetadata.eraTokens;
1122
+ }
1123
+
1124
+ /**
1125
+ * @notice Gets the current Principal Token reward amount per transaction
1126
+ * @dev Returns the base reward distributed to stakers for transaction processing
1127
+ * @return Current reward amount in Principal Tokens
1128
+ */
1129
+ function getRewardAmount() public view returns (uint256) {
1130
+ return evvmMetadata.reward;
1131
+ }
1132
+
1133
+ /**
1134
+ * @notice Gets the total supply of the Principal Token
1135
+ * @dev Returns the current total supply used for era transition calculations
1136
+ * @return Total supply of Principal Tokens
1137
+ */
1138
+ function getPrincipalTokenTotalSupply() public view returns (uint256) {
1139
+ return evvmMetadata.totalSupply;
1140
+ }
1141
+
1142
+ /**
1143
+ * @notice Gets the current active implementation contract address
1144
+ * @dev Returns the implementation used by the proxy for delegatecalls
1145
+ * @return Address of the current implementation contract
1146
+ */
1147
+ function getCurrentImplementation() public view returns (address) {
1148
+ return currentImplementation;
1149
+ }
1150
+
1151
+ /**
1152
+ * @notice Gets the proposed implementation contract address
1153
+ * @dev Returns the implementation pending approval for proxy upgrade
1154
+ * @return Address of the proposed implementation contract (zero if none)
1155
+ */
1156
+ function getProposalImplementation() public view returns (address) {
1157
+ return proposalImplementation;
1158
+ }
1159
+
1160
+ /**
1161
+ * @notice Gets the acceptance deadline for the pending implementation upgrade
1162
+ * @dev Returns timestamp when the proposed implementation can be accepted
1163
+ * @return Timestamp when implementation upgrade can be executed (0 if no pending proposal)
1164
+ */
1165
+ function getTimeToAcceptImplementation() public view returns (uint256) {
1166
+ return timeToAcceptImplementation;
1167
+ }
1168
+
1169
+ /**
1170
+ * @notice Gets the current admin address
1171
+ * @dev Returns the address with administrative privileges over the contract
1172
+ * @return Address of the current admin
1173
+ */
1174
+ function getCurrentAdmin() public view returns (address) {
1175
+ return admin.current;
1176
+ }
1177
+
1178
+ /**
1179
+ * @notice Gets the proposed admin address
1180
+ * @dev Returns the address pending approval for admin privileges
1181
+ * @return Address of the proposed admin (zero if no pending proposal)
1182
+ */
1183
+ function getProposalAdmin() public view returns (address) {
1184
+ return admin.proposal;
1185
+ }
1186
+
1187
+ /**
1188
+ * @notice Gets the acceptance deadline for the pending admin change
1189
+ * @dev Returns timestamp when the proposed admin can accept the role
1190
+ * @return Timestamp when admin change can be executed (0 if no pending proposal)
1191
+ */
1192
+ function getTimeToAcceptAdmin() public view returns (uint256) {
1193
+ return admin.timeToAccept;
1194
+ }
1195
+
1196
+ /**
1197
+ * @notice Gets the address of the token pending whitelist approval
1198
+ * @dev Returns the token address that can be whitelisted after time delay
1199
+ * @return Address of the token prepared for whitelisting (zero if none)
1200
+ */
1201
+ function getWhitelistTokenToBeAdded() public view returns (address) {
1202
+ return whitelistTokenToBeAdded_address;
1203
+ }
1204
+
1205
+ /**
1206
+ * @notice Gets service address that reserved an async nonce
1207
+ * @dev Returns address(0) if nonce is not reserved
1208
+ *
1209
+ * @param user Address of the user who owns the nonce
1210
+ * @param nonce Async nonce to check reservation for
1211
+ * @return Service address that reserved the nonce, or
1212
+ * address(0) if not reserved
1213
+ */
1214
+ function getAsyncNonceReservation(
1215
+ address user,
1216
+ uint256 nonce
1217
+ ) public view returns (address) {
1218
+ return asyncNonceReservedPointers[user][nonce];
1219
+ }
1220
+
1221
+ /**
1222
+ * @notice Gets comprehensive status of an async nonce
1223
+ * @dev Returns byte code indicating nonce state
1224
+ *
1225
+ * Status Codes:
1226
+ * - 0x00: Available (can be used by any service)
1227
+ * - 0x01: Used (already consumed, cannot be reused)
1228
+ * - 0x02: Reserved (allocated to specific service)
1229
+ *
1230
+ * @param user Address of the user who owns the nonce
1231
+ * @param nonce Async nonce to check status for
1232
+ * @return Status code: 0x00 (available), 0x01 (used),
1233
+ * or 0x02 (reserved)
1234
+ */
1235
+ function asyncNonceStatus(
1236
+ address user,
1237
+ uint256 nonce
1238
+ ) public view returns (bytes1) {
1239
+ if (asyncNonce[user][nonce]) {
1240
+ return 0x01;
1241
+ } else if (asyncNonceReservedPointers[user][nonce] != address(0)) {
1242
+ return 0x02;
1243
+ } else {
1244
+ return 0x00;
1245
+ }
1246
+ }
1247
+
1248
+ /**
1249
+ * @notice Checks if a specific nonce has been used by a user
1250
+ * @dev Public view function for external queries and UI integration
1251
+ * @param user Address of the user to check
1252
+ * @param nonce The nonce value to query
1253
+ * @return True if the nonce has been used, false if available
1254
+ */
1255
+ function getIfUsedAsyncNonce(
1256
+ address user,
1257
+ uint256 nonce
1258
+ ) public view virtual returns (bool) {
1259
+ return asyncNonce[user][nonce];
1260
+ }
1261
+
1262
+ /**
1263
+ * @notice Gets the current (next expected) nonce for a user
1264
+ * @dev Public view function for external queries and transaction preparation
1265
+ * @param user Address of the user to query
1266
+ * @return The next nonce value that must be used by the user
1267
+ */
1268
+ function getNextCurrentSyncNonce(
1269
+ address user
1270
+ ) public view virtual returns (uint256) {
1271
+ return nextSyncNonce[user];
1272
+ }
1273
+
1274
+ /**
1275
+ * @notice Gets current UserValidator contract address
1276
+ * @dev Returns address(0) if no validator is configured
1277
+ *
1278
+ * @return Address of active UserValidator contract
1279
+ */
1280
+ function getUserValidatorAddress() public view returns (address) {
1281
+ return userValidatorAddress.current;
1282
+ }
1283
+
1284
+ /**
1285
+ * @notice Gets full UserValidator proposal details
1286
+ * @dev Returns current, proposed address and time-lock info
1287
+ *
1288
+ * @return Proposal struct with current validator address,
1289
+ * proposed address, and time to accept
1290
+ */
1291
+ function getUserValidatorAddressDetails()
1292
+ public
1293
+ view
1294
+ returns (ProposalStructs.AddressTypeProposal memory)
1295
+ {
1296
+ return userValidatorAddress;
1297
+ }
1298
+
1299
+ //░▒▓█ Internal Functions █████████████████████████████████████████████████████▓▒░
1300
+
1301
+ //██ Balance Management █████████████████████████████████████████████
1302
+
1303
+ /**
1304
+ * @notice Internal function to safely transfer tokens between addresses
1305
+ * @dev Performs balance validation and atomic transfer with overflow protection
1306
+ *
1307
+ * Transfer Process:
1308
+ * - Validates sender has sufficient balance
1309
+ * - Performs atomic balance updates using unchecked arithmetic
1310
+ * - Returns success/failure status for error handling
1311
+ *
1312
+ * Security Features:
1313
+ * - Balance validation prevents overdrafts
1314
+ * - Unchecked arithmetic for gas optimization (overflow impossible)
1315
+ * - Returns boolean for caller error handling
1316
+ *
1317
+ * @param from Address to transfer tokens from
1318
+ * @param to Address to transfer tokens to
1319
+ * @param token Address of the token contract
1320
+ * @param value Amount of tokens to transfer
1321
+ */
1322
+ function _updateBalance(
1323
+ address from,
1324
+ address to,
1325
+ address token,
1326
+ uint256 value
1327
+ ) internal {
1328
+ uint256 fromBalance = balances[from][token];
1329
+ if (fromBalance < value) revert Error.InsufficientBalance();
1330
+
1331
+ unchecked {
1332
+ balances[from][token] = fromBalance - value;
1333
+ balances[to][token] += value;
1334
+ }
1335
+ }
1336
+
1337
+ /**
1338
+ * @notice Internal function to distribute Principal Token rewards to stakers
1339
+ * @dev Provides incentive distribution for transaction processing and staking participation
1340
+ *
1341
+ * Reward System:
1342
+ * - Calculates reward based on system reward rate and transaction count
1343
+ * - Directly increases principal token balance for gas efficiency
1344
+ * - Returns success status for error handling in calling functions
1345
+ *
1346
+ * Reward Calculation:
1347
+ * - Base reward per transaction: evvmMetadata.reward
1348
+ * - Total reward: base_reward × transaction_amount
1349
+ * - Added directly to user's Principal Token balance
1350
+ *
1351
+ * @param user Address of the staker to receive principal token rewards
1352
+ * @param amount Number of transactions or reward multiplier
1353
+ * @return success True if reward distribution completed successfully
1354
+ */
1355
+ function _giveReward(address user, uint256 amount) internal returns (bool) {
1356
+ uint256 principalReward = evvmMetadata.reward * amount;
1357
+ uint256 userBalance = balances[user][
1358
+ evvmMetadata.principalTokenAddress
1359
+ ];
1360
+
1361
+ balances[user][evvmMetadata.principalTokenAddress] =
1362
+ userBalance +
1363
+ principalReward;
1364
+
1365
+ return (userBalance + principalReward ==
1366
+ balances[user][evvmMetadata.principalTokenAddress]);
1367
+ }
1368
+
1369
+ //██ User Validation █████████████████████████████████████████████
1370
+
1371
+ /**
1372
+ * @notice Validates if user can execute transactions
1373
+ * @dev Checks with UserValidator if configured, allows all if not
1374
+ *
1375
+ * Validation Logic:
1376
+ * - If no validator configured: Returns true (all allowed)
1377
+ * - If validator configured: Delegates to validator.canExecute
1378
+ * - Used by validateAndConsumeNonce before nonce consumption
1379
+ *
1380
+ * Integration:
1381
+ * - Called during every transaction validation
1382
+ * - Allows external filtering of user transactions
1383
+ * - Supports compliance and security requirements
1384
+ *
1385
+ * @param user Address to check execution permission for
1386
+ * @return True if user can execute, false if blocked
1387
+ */
1388
+ function canExecuteUserTransaction(
1389
+ address user
1390
+ ) internal view returns (bool) {
1391
+ if (userValidatorAddress.current == address(0)) return true;
1392
+ return UserValidator(userValidatorAddress.current).canExecute(user);
1393
+ }
1394
+ }