@evvm/testnet-contracts 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -170,9 +170,11 @@ Quick Start (CLI): https://www.evvm.info/docs/QuickStart
170
170
  - **RPC timeouts**: CLI automatically tries fallback RPCs; set `RPC_URL` in `.env` to a reliable endpoint.
171
171
  - **Wallet not found**: import with `cast wallet import <name> --interactive`.
172
172
  - **Bun missing**: install Bun (`curl -fsSL https://bun.sh/install | bash`).
173
+ - **Native binary fails (exit 126)**: if you see "cannot execute binary file" the wrapper will now try running the CLI via `bun run cli/index.ts` automatically when Bun is available. This works as a fallback until correct platform-specific binaries are built.
173
174
  - **Tests**: run `./evvm developer --runTest` (Linux/Mac) or `evvm.bat developer --runTest` (Windows), or `forge test`.
174
175
  - **Script not executable (Linux/Mac)**: run `chmod +x ./evvm` and ensure `.executables/` binaries have execute permissions.
175
176
  - **Wrong architecture detected**: The wrapper scripts auto-detect OS/architecture. If issues occur, manually run the correct binary from `.executables/`.
177
+ - **Binaries built on the wrong host**: macOS and Windows executables must be compiled on their respective platforms. Building on Linux will produce a Linux ELF file regardless of the filename, which leads to "cannot execute binary file" errors on macOS. Use `npm run build-macos` on a Mac and `npm run build-windows` on Windows, or rely on the Bun fallback described below.
176
178
 
177
179
  Files & structure (short)
178
180
 
@@ -88,9 +88,9 @@ contract Core is Storage {
88
88
 
89
89
  admin.current = _initialOwner;
90
90
 
91
- balances[_stakingContractAddress][evvmMetadata.principalTokenAddress] =
92
- getRewardAmount() *
93
- 2;
91
+ rewardFlowDistribution.flag = true;
92
+
93
+ _giveReward(_stakingContractAddress, 2);
94
94
 
95
95
  stakerList[_stakingContractAddress] = FLAG_IS_STAKER;
96
96
 
@@ -114,9 +114,9 @@ contract Core is Storage {
114
114
  revert Error.AddressCantBeZero();
115
115
 
116
116
  nameServiceAddress = _nameServiceAddress;
117
- balances[nameServiceAddress][evvmMetadata.principalTokenAddress] =
118
- 10000 *
119
- 10 ** 18;
117
+
118
+ _giveReward(_nameServiceAddress, 20);
119
+
120
120
  stakerList[nameServiceAddress] = FLAG_IS_STAKER;
121
121
 
122
122
  treasuryAddress = _treasuryAddress;
@@ -182,6 +182,8 @@ contract Core is Storage {
182
182
  }
183
183
  }
184
184
 
185
+ //░▒▓█ Testnet Functions ██████████████████████████████████████████████████████▓▒░
186
+
185
187
  /**
186
188
  * @notice Faucet: Adds balance to a user for testing (Testnet only).
187
189
  * @param user Recipient address.
@@ -194,6 +196,9 @@ contract Core is Storage {
194
196
  uint256 quantity
195
197
  ) external {
196
198
  balances[user][token] += quantity;
199
+
200
+ if (token == evvmMetadata.principalTokenAddress)
201
+ currentSupply += quantity;
197
202
  }
198
203
 
199
204
  /**
@@ -254,7 +259,7 @@ contract Core is Storage {
254
259
  ) != from
255
260
  ) revert Error.InvalidSignature();
256
261
 
257
- if (!canExecuteUserTransaction(from))
262
+ if (!_canExecuteUserTransaction(from))
258
263
  revert Error.UserCannotExecuteTransaction();
259
264
 
260
265
  if (isAsyncExec) {
@@ -288,9 +293,9 @@ contract Core is Storage {
288
293
  _updateBalance(from, to, token, amount);
289
294
 
290
295
  if (isAddressStaker(msg.sender)) {
291
- if (priorityFee > 0) {
296
+ if (priorityFee > 0)
292
297
  _updateBalance(from, msg.sender, token, priorityFee);
293
- }
298
+
294
299
  _giveReward(msg.sender, 1);
295
300
  }
296
301
  }
@@ -332,7 +337,7 @@ contract Core is Storage {
332
337
  payment.signature
333
338
  ) !=
334
339
  payment.from ||
335
- !canExecuteUserTransaction(payment.from)
340
+ !_canExecuteUserTransaction(payment.from)
336
341
  ) {
337
342
  results[iteration] = false;
338
343
  continue;
@@ -367,6 +372,14 @@ contract Core is Storage {
367
372
  }
368
373
  }
369
374
 
375
+ if (
376
+ (listStatus.current == 0x01 && !allowList[payment.token]) ||
377
+ (listStatus.current == 0x02 && denyList[payment.token])
378
+ ) {
379
+ results[iteration] = false;
380
+ continue;
381
+ }
382
+
370
383
  if (
371
384
  (payment.senderExecutor != address(0) &&
372
385
  msg.sender != payment.senderExecutor) ||
@@ -450,7 +463,7 @@ contract Core is Storage {
450
463
  ) != from
451
464
  ) revert Error.InvalidSignature();
452
465
 
453
- if (!canExecuteUserTransaction(from))
466
+ if (!_canExecuteUserTransaction(from))
454
467
  revert Error.UserCannotExecuteTransaction();
455
468
 
456
469
  if (isAsyncExec) {
@@ -480,6 +493,8 @@ contract Core is Storage {
480
493
  if (balances[from][token] < amount + (isSenderStaker ? priorityFee : 0))
481
494
  revert Error.InsufficientBalance();
482
495
 
496
+ if (listStatus.current != 0x00) _verifyTokenInteractionAllowance(token);
497
+
483
498
  uint256 acomulatedAmount = 0;
484
499
  balances[from][token] -= (amount + (isSenderStaker ? priorityFee : 0));
485
500
  address to_aux;
@@ -546,6 +561,8 @@ contract Core is Storage {
546
561
  address token,
547
562
  uint256 amount
548
563
  ) external {
564
+ if (listStatus.current != 0x00) _verifyTokenInteractionAllowance(token);
565
+
549
566
  address from = msg.sender;
550
567
 
551
568
  if (!CAUtils.verifyIfCA(from)) revert Error.NotAnCA();
@@ -608,7 +625,7 @@ contract Core is Storage {
608
625
  if (originExecutor != address(0) && tx.origin != originExecutor)
609
626
  revert Error.OriginIsNotTheOriginExecutor();
610
627
 
611
- if (!canExecuteUserTransaction(user))
628
+ if (!_canExecuteUserTransaction(user))
612
629
  revert Error.UserCannotExecuteTransaction();
613
630
 
614
631
  if (isAsyncExec) {
@@ -762,7 +779,7 @@ contract Core is Storage {
762
779
  */
763
780
  function acceptUserValidatorProposal() external onlyAdmin {
764
781
  if (block.timestamp < userValidatorAddress.timeToAccept)
765
- revert Error.ProposalForUserValidatorNotReady();
782
+ revert Error.ProposalNotReadyToAccept();
766
783
 
767
784
  userValidatorAddress.current = userValidatorAddress.proposal;
768
785
  userValidatorAddress.proposal = address(0);
@@ -804,6 +821,8 @@ contract Core is Storage {
804
821
  address token,
805
822
  uint256 amount
806
823
  ) external {
824
+ if (listStatus.current != 0x00) _verifyTokenInteractionAllowance(token);
825
+
807
826
  if (msg.sender != treasuryAddress) revert Error.SenderIsNotTreasury();
808
827
 
809
828
  balances[user][token] += amount;
@@ -828,6 +847,113 @@ contract Core is Storage {
828
847
 
829
848
  //░▒▓█ Administrative Functions ████████████████████████████████████████████████████████▓▒░
830
849
 
850
+ //██ Total Supply Management ████████████████████████████████████████
851
+
852
+ function proposeDeleteTotalSupply() external onlyAdmin {
853
+ if (
854
+ currentSupply < (evvmMetadata.totalSupply * 9999) / 10000 ||
855
+ evvmMetadata.totalSupply == type(uint256).max
856
+ ) revert Error.MaxSupplyDeletionNotAllowed();
857
+
858
+ timeToDeleteMaxSupply = block.timestamp + TIME_TO_ACCEPT_PROPOSAL;
859
+ }
860
+
861
+ function rejectDeleteTotalSupply() external onlyAdmin {
862
+ timeToDeleteMaxSupply = 0;
863
+ }
864
+
865
+ function acceptDeleteTotalSupply() external onlyAdmin {
866
+ if (block.timestamp < timeToDeleteMaxSupply)
867
+ revert Error.ProposalNotReadyToAccept();
868
+
869
+ evvmMetadata.totalSupply = type(uint256).max;
870
+ }
871
+
872
+ //██ Reward distribution ████████████████████████████████████████
873
+
874
+ function proposeChangeBaseRewardAmount(
875
+ uint256 newBaseReward
876
+ ) external onlyAdmin {
877
+ if (
878
+ evvmMetadata.totalSupply != type(uint256).max ||
879
+ newBaseReward >= evvmMetadata.reward
880
+ ) revert Error.BaseRewardIncreaseNotAllowed();
881
+ proposalChangeReward = newBaseReward;
882
+ timeToAcceptChangeReward = block.timestamp + TIME_TO_ACCEPT_PROPOSAL;
883
+ }
884
+
885
+ function rejectChangeBaseRewardAmount() external onlyAdmin {
886
+ proposalChangeReward = 0;
887
+ timeToAcceptChangeReward = 0;
888
+ }
889
+
890
+ function acceptChangeBaseRewardAmount() external onlyAdmin {
891
+ if (block.timestamp < timeToAcceptChangeReward)
892
+ revert Error.ProposalNotReadyToAccept();
893
+
894
+ evvmMetadata.reward = proposalChangeReward;
895
+ proposalChangeReward = 0;
896
+ timeToAcceptChangeReward = 0;
897
+ }
898
+
899
+ function proposeChangeRewardFlowDistribution() external onlyAdmin {
900
+ if (currentSupply < (evvmMetadata.totalSupply * 9999) / 10000)
901
+ revert Error.RewardFlowDistributionChangeNotAllowed();
902
+
903
+ rewardFlowDistribution.timeToAccept =
904
+ block.timestamp +
905
+ TIME_TO_ACCEPT_PROPOSAL;
906
+ }
907
+
908
+ function rejectChangeRewardFlowDistribution() external onlyAdmin {
909
+ rewardFlowDistribution.timeToAccept = 0;
910
+ }
911
+
912
+ function acceptChangeRewardFlowDistribution() external onlyAdmin {
913
+ if (block.timestamp < rewardFlowDistribution.timeToAccept)
914
+ revert Error.ProposalNotReadyToAccept();
915
+
916
+ rewardFlowDistribution.flag = !rewardFlowDistribution.flag;
917
+ rewardFlowDistribution.timeToAccept = 0;
918
+ }
919
+
920
+ //██ List state Management ████████████████████████████████████████
921
+
922
+ function proposeListStatus(bytes1 newStatus) external onlyAdmin {
923
+ if (uint8(newStatus) >= uint8(0x03)) revert Error.InvalidListStatus();
924
+
925
+ listStatus.proposal = newStatus;
926
+ listStatus.timeToAccept = block.timestamp + TIME_TO_ACCEPT_PROPOSAL;
927
+ }
928
+
929
+ function rejectListStatusProposal() external onlyAdmin {
930
+ listStatus.proposal = 0x00;
931
+ listStatus.timeToAccept = 0;
932
+ }
933
+
934
+ function acceptListStatusProposal() external onlyAdmin {
935
+ if (block.timestamp < listStatus.timeToAccept)
936
+ revert Error.ProposalNotReadyToAccept();
937
+
938
+ listStatus.current = listStatus.proposal;
939
+ listStatus.proposal = 0x00;
940
+ listStatus.timeToAccept = 0;
941
+ }
942
+
943
+ function setTokenStatusOnAllowList(
944
+ address token,
945
+ bool status
946
+ ) external onlyAdmin {
947
+ allowList[token] = status;
948
+ }
949
+
950
+ function setTokenStatusOnDenyList(
951
+ address token,
952
+ bool status
953
+ ) external onlyAdmin {
954
+ denyList[token] = status;
955
+ }
956
+
831
957
  //██ Proxy Management █████████████████████████████████████████████
832
958
 
833
959
  /**
@@ -855,7 +981,7 @@ contract Core is Storage {
855
981
  */
856
982
  function acceptImplementation() external onlyAdmin {
857
983
  if (block.timestamp < timeToAcceptImplementation)
858
- revert Error.TimeLockNotExpired();
984
+ revert Error.ProposalNotReadyToAccept();
859
985
 
860
986
  currentImplementation = proposalImplementation;
861
987
  proposalImplementation = address(0);
@@ -896,7 +1022,7 @@ contract Core is Storage {
896
1022
  */
897
1023
  function acceptAdmin() external {
898
1024
  if (block.timestamp < admin.timeToAccept)
899
- revert Error.TimeLockNotExpired();
1025
+ revert Error.ProposalNotReadyToAccept();
900
1026
 
901
1027
  if (msg.sender != admin.proposal)
902
1028
  revert Error.SenderIsNotTheProposedAdmin();
@@ -931,42 +1057,21 @@ contract Core is Storage {
931
1057
  * - Can be called by anyone when conditions are met
932
1058
  */
933
1059
  function recalculateReward() public {
934
- if (evvmMetadata.totalSupply > evvmMetadata.eraTokens) {
1060
+ if (
1061
+ evvmMetadata.totalSupply > evvmMetadata.eraTokens &&
1062
+ evvmMetadata.totalSupply != type(uint256).max
1063
+ ) {
935
1064
  evvmMetadata.eraTokens += ((evvmMetadata.totalSupply -
936
1065
  evvmMetadata.eraTokens) / 2);
937
1066
  balances[msg.sender][evvmMetadata.principalTokenAddress] +=
938
1067
  evvmMetadata.reward *
939
- getRandom(1, 5083);
1068
+ _getRandom(1, 5083);
940
1069
  evvmMetadata.reward = evvmMetadata.reward / 2;
941
1070
  } else {
942
1071
  revert();
943
1072
  }
944
1073
  }
945
1074
 
946
- /**
947
- * @notice Generates a pseudo-random number within a specified range
948
- * @dev Uses block timestamp and prevrandao for randomness (suitable for non-critical randomness)
949
- *
950
- * Randomness Source:
951
- * - Combines block.timestamp and block.prevrandao
952
- * - Suitable for reward bonuses and non-security-critical randomness
953
- * - Not suitable for high-stakes randomness requiring true unpredictability
954
- *
955
- * @param min Minimum value (inclusive)
956
- * @param max Maximum value (inclusive)
957
- * @return Random number between min and max (inclusive)
958
- */
959
- function getRandom(
960
- uint256 min,
961
- uint256 max
962
- ) internal view returns (uint256) {
963
- return
964
- min +
965
- (uint256(
966
- keccak256(abi.encodePacked(block.timestamp, block.prevrandao))
967
- ) % (max - min + 1));
968
- }
969
-
970
1075
  //░▒▓█ Staking Integration Functions █████████████████████████████████████████████████▓▒░
971
1076
 
972
1077
  /**
@@ -1043,19 +1148,6 @@ contract Core is Storage {
1043
1148
  return evvmMetadata.EvvmID;
1044
1149
  }
1045
1150
 
1046
- /**
1047
- * @notice Gets the acceptance deadline for pending token whitelist proposals
1048
- * @dev Returns timestamp when prepared tokens can be added to whitelist
1049
- * @return Timestamp when pending token can be whitelisted (0 if no pending proposal)
1050
- */
1051
- function getWhitelistTokenToBeAddedDateToSet()
1052
- external
1053
- view
1054
- returns (uint256)
1055
- {
1056
- return whitelistTokenToBeAdded_dateToSet;
1057
- }
1058
-
1059
1151
  /**
1060
1152
  * @notice Gets the current NameService contract address
1061
1153
  * @dev Returns the address used for identity resolution in payments
@@ -1074,18 +1166,6 @@ contract Core is Storage {
1074
1166
  return stakingContractAddress;
1075
1167
  }
1076
1168
 
1077
- /**
1078
- * @notice Gets the next Fisher Bridge deposit nonce for a user
1079
- * @dev Returns the expected nonce for the next cross-chain deposit
1080
- * @param user Address to check deposit nonce for
1081
- * @return Next Fisher Bridge deposit nonce
1082
- */
1083
- function getNextFisherDepositNonce(
1084
- address user
1085
- ) external view returns (uint256) {
1086
- return nextFisherDepositNonce[user];
1087
- }
1088
-
1089
1169
  /**
1090
1170
  * @notice Gets the balance of a specific token for a user
1091
1171
  * @dev Returns the current balance stored in the EVVM system
@@ -1110,15 +1190,6 @@ contract Core is Storage {
1110
1190
  return stakerList[user] == FLAG_IS_STAKER;
1111
1191
  }
1112
1192
 
1113
- /**
1114
- * @notice Gets the current era token threshold for reward transitions
1115
- * @dev Returns the token supply threshold that triggers the next reward halving
1116
- * @return Current era tokens threshold
1117
- */
1118
- function getEraPrincipalToken() public view returns (uint256) {
1119
- return evvmMetadata.eraTokens;
1120
- }
1121
-
1122
1193
  /**
1123
1194
  * @notice Gets the current Principal Token reward amount per transaction
1124
1195
  * @dev Returns the base reward distributed to stakers for transaction processing
@@ -1128,6 +1199,25 @@ contract Core is Storage {
1128
1199
  return evvmMetadata.reward;
1129
1200
  }
1130
1201
 
1202
+ /**
1203
+ * @notice Gets comprehensive details of the reward change proposal
1204
+ * @dev Returns current reward, proposed reward and time-lock info
1205
+ *
1206
+ * @return Proposal struct with current reward, proposed reward,
1207
+ * and time to accept the proposal
1208
+ */
1209
+ function getFullDetailReward()
1210
+ public
1211
+ view
1212
+ returns (ProposalStructs.UintTypeProposal memory)
1213
+ {
1214
+ return ProposalStructs.UintTypeProposal({
1215
+ current: evvmMetadata.reward,
1216
+ proposal: proposalChangeReward,
1217
+ timeToAccept: timeToAcceptChangeReward
1218
+ });
1219
+ }
1220
+
1131
1221
  /**
1132
1222
  * @notice Gets the total supply of the Principal Token
1133
1223
  * @dev Returns the current total supply used for era transition calculations
@@ -1137,6 +1227,14 @@ contract Core is Storage {
1137
1227
  return evvmMetadata.totalSupply;
1138
1228
  }
1139
1229
 
1230
+ /**
1231
+ * @notice Gets the current supply of the Principal Token in circulation
1232
+ * @dev Returns the current circulating supply used for reward recalculations
1233
+ */
1234
+ function getCurrentSupply() public view returns (uint256) {
1235
+ return currentSupply;
1236
+ }
1237
+
1140
1238
  /**
1141
1239
  * @notice Gets the current active implementation contract address
1142
1240
  * @dev Returns the implementation used by the proxy for delegatecalls
@@ -1147,21 +1245,23 @@ contract Core is Storage {
1147
1245
  }
1148
1246
 
1149
1247
  /**
1150
- * @notice Gets the proposed implementation contract address
1151
- * @dev Returns the implementation pending approval for proxy upgrade
1152
- * @return Address of the proposed implementation contract (zero if none)
1153
- */
1154
- function getProposalImplementation() public view returns (address) {
1155
- return proposalImplementation;
1156
- }
1157
-
1158
- /**
1159
- * @notice Gets the acceptance deadline for the pending implementation upgrade
1160
- * @dev Returns timestamp when the proposed implementation can be accepted
1161
- * @return Timestamp when implementation upgrade can be executed (0 if no pending proposal)
1248
+ * @notice Gets comprehensive details of the implementation upgrade proposal
1249
+ * @dev Returns current, proposed implementation addresses and time-lock info
1250
+ *
1251
+ * @return Proposal struct with current implementation, proposed implementation,
1252
+ * and time to accept the proposal
1162
1253
  */
1163
- function getTimeToAcceptImplementation() public view returns (uint256) {
1164
- return timeToAcceptImplementation;
1254
+ function getFullDetailImplementation()
1255
+ public
1256
+ view
1257
+ returns (ProposalStructs.AddressTypeProposal memory)
1258
+ {
1259
+ return
1260
+ ProposalStructs.AddressTypeProposal({
1261
+ current: currentImplementation,
1262
+ proposal: proposalImplementation,
1263
+ timeToAccept: timeToAcceptImplementation
1264
+ });
1165
1265
  }
1166
1266
 
1167
1267
  /**
@@ -1173,31 +1273,12 @@ contract Core is Storage {
1173
1273
  return admin.current;
1174
1274
  }
1175
1275
 
1176
- /**
1177
- * @notice Gets the proposed admin address
1178
- * @dev Returns the address pending approval for admin privileges
1179
- * @return Address of the proposed admin (zero if no pending proposal)
1180
- */
1181
- function getProposalAdmin() public view returns (address) {
1182
- return admin.proposal;
1183
- }
1184
-
1185
- /**
1186
- * @notice Gets the acceptance deadline for the pending admin change
1187
- * @dev Returns timestamp when the proposed admin can accept the role
1188
- * @return Timestamp when admin change can be executed (0 if no pending proposal)
1189
- */
1190
- function getTimeToAcceptAdmin() public view returns (uint256) {
1191
- return admin.timeToAccept;
1192
- }
1193
-
1194
- /**
1195
- * @notice Gets the address of the token pending whitelist approval
1196
- * @dev Returns the token address that can be whitelisted after time delay
1197
- * @return Address of the token prepared for whitelisting (zero if none)
1198
- */
1199
- function getWhitelistTokenToBeAdded() public view returns (address) {
1200
- return whitelistTokenToBeAdded_address;
1276
+ function getFullDetailAdmin()
1277
+ public
1278
+ view
1279
+ returns (ProposalStructs.AddressTypeProposal memory)
1280
+ {
1281
+ return admin;
1201
1282
  }
1202
1283
 
1203
1284
  /**
@@ -1286,7 +1367,7 @@ contract Core is Storage {
1286
1367
  * @return Proposal struct with current validator address,
1287
1368
  * proposed address, and time to accept
1288
1369
  */
1289
- function getUserValidatorAddressDetails()
1370
+ function getFullDetailUserValidator()
1290
1371
  public
1291
1372
  view
1292
1373
  returns (ProposalStructs.AddressTypeProposal memory)
@@ -1294,8 +1375,113 @@ contract Core is Storage {
1294
1375
  return userValidatorAddress;
1295
1376
  }
1296
1377
 
1378
+ /**
1379
+ * @notice Gets the current token list status (none, denylist, allowlist)
1380
+ * @dev Returns byte code indicating current token restriction mode
1381
+ * - 0x00: No restrictions
1382
+ * - 0x01: Denylist active
1383
+ * - 0x02: Allowlist active
1384
+ */
1385
+ function getCurrentListStatus() public view returns (bytes1) {
1386
+ return listStatus.current;
1387
+ }
1388
+
1389
+ /**
1390
+ * @notice Gets comprehensive token list status details
1391
+ * @dev Returns current list status along with pending proposal info
1392
+ */
1393
+ function getFullDetailListStatus()
1394
+ public
1395
+ view
1396
+ returns (ProposalStructs.Bytes1TypeProposal memory)
1397
+ {
1398
+ return listStatus;
1399
+ }
1400
+
1401
+ /**
1402
+ * @notice Checks if a token is on the allowList or denyList based on current list status
1403
+ * @dev Returns boolean indicating if token is allowed for execution
1404
+ * - true if allowed
1405
+ * - false if denied
1406
+ */
1407
+ function getAllowListStatus(address token) public view returns (bool) {
1408
+ return allowList[token];
1409
+ }
1410
+
1411
+ /**
1412
+ * @notice Checks if a token is on the denylist or allowlist based on current list status
1413
+ * @dev Returns boolean indicating if token is restricted for execution
1414
+ * - true if denied
1415
+ * - false if allowed
1416
+ */
1417
+ function getDenyListStatus(address token) public view returns (bool) {
1418
+ return denyList[token];
1419
+ }
1420
+
1421
+ /**
1422
+ * @notice Gets the current status of the reward flow distribution flag
1423
+ * @dev Returns boolean indicating if reward distribution is active
1424
+ * - true if rewards are distributed to stakers
1425
+ * - false if rewards are disabled
1426
+ */
1427
+ function getRewardFlowDistributionFlag() public view returns (bool) {
1428
+ return rewardFlowDistribution.flag;
1429
+ }
1430
+
1431
+ /**
1432
+ * @notice Gets full details of the reward flow distribution proposal
1433
+ * @dev Returns current flag, proposed flag, and time-lock info
1434
+ *
1435
+ * @return Proposal struct with current flag, proposed flag, and time to accept
1436
+ */
1437
+ function getFullDetailRewardFlowDistribution()
1438
+ public
1439
+ view
1440
+ returns (ProposalStructs.BoolTypeProposal memory)
1441
+ {
1442
+ return rewardFlowDistribution;
1443
+ }
1444
+
1445
+ /**
1446
+ * @notice Gets the time remaining to delete the maximum supply
1447
+ * @dev Returns the timestamp when the max supply can be deleted
1448
+ *
1449
+ * @return Timestamp for max supply deletion
1450
+ */
1451
+ function getTimeToDeleteMaxSupply() public view returns (uint256) {
1452
+ return timeToDeleteMaxSupply;
1453
+ }
1454
+
1297
1455
  //░▒▓█ Internal Functions █████████████████████████████████████████████████████▓▒░
1298
1456
 
1457
+ /**
1458
+ * @notice Generates a pseudo-random number within a specified range
1459
+ * @dev Uses block timestamp and prevrandao for randomness (suitable for non-critical randomness)
1460
+ *
1461
+ * @param min Minimum value (inclusive)
1462
+ * @param max Maximum value (inclusive)
1463
+ * @return Random number between min and max (inclusive)
1464
+ */
1465
+ function _getRandom(
1466
+ uint256 min,
1467
+ uint256 max
1468
+ ) internal view returns (uint256) {
1469
+ uint256 randomHash = uint256(
1470
+ keccak256(
1471
+ abi.encodePacked(
1472
+ blockhash(block.number - 1),
1473
+ block.timestamp,
1474
+ block.prevrandao,
1475
+ msg.sender,
1476
+ tx.origin,
1477
+ gasleft()
1478
+ )
1479
+ )
1480
+ );
1481
+
1482
+ return min + (randomHash % (max - min + 1));
1483
+ }
1484
+
1299
1485
  //██ Balance Management █████████████████████████████████████████████
1300
1486
 
1301
1487
  /**
@@ -1323,6 +1509,8 @@ contract Core is Storage {
1323
1509
  address token,
1324
1510
  uint256 value
1325
1511
  ) internal {
1512
+ if (listStatus.current != 0x00) _verifyTokenInteractionAllowance(token);
1513
+
1326
1514
  uint256 fromBalance = balances[from][token];
1327
1515
  if (fromBalance < value) revert Error.InsufficientBalance();
1328
1516
 
@@ -1348,20 +1536,28 @@ contract Core is Storage {
1348
1536
  *
1349
1537
  * @param user Address of the staker to receive principal token rewards
1350
1538
  * @param amount Number of transactions or reward multiplier
1351
- * @return success True if reward distribution completed successfully
1352
1539
  */
1353
- function _giveReward(address user, uint256 amount) internal returns (bool) {
1354
- uint256 principalReward = evvmMetadata.reward * amount;
1355
- uint256 userBalance = balances[user][
1356
- evvmMetadata.principalTokenAddress
1357
- ];
1540
+ function _giveReward(address user, uint256 amount) internal {
1541
+ if (
1542
+ !rewardFlowDistribution.flag ||
1543
+ currentSupply >= evvmMetadata.totalSupply
1544
+ ) return;
1358
1545
 
1359
- balances[user][evvmMetadata.principalTokenAddress] =
1360
- userBalance +
1361
- principalReward;
1546
+ uint256 principalReward = evvmMetadata.reward * amount;
1547
+ balances[user][evvmMetadata.principalTokenAddress] += principalReward;
1548
+ currentSupply += principalReward;
1549
+ }
1362
1550
 
1363
- return (userBalance + principalReward ==
1364
- balances[user][evvmMetadata.principalTokenAddress]);
1551
+ /**
1552
+ * @notice Internal function to check from the token allowlist/denylist
1553
+ * based on current list status and revert if the token is not allowed for execution
1554
+ * @dev Used by functions that execute transactions to enforce token restrictions
1555
+ */
1556
+ function _verifyTokenInteractionAllowance(address token) internal view {
1557
+ if (
1558
+ (listStatus.current == 0x01 && !allowList[token]) ||
1559
+ (listStatus.current == 0x02 && denyList[token])
1560
+ ) revert Error.TokenIsDeniedForExecution();
1365
1561
  }
1366
1562
 
1367
1563
  //██ User Validation █████████████████████████████████████████████
@@ -1383,7 +1579,7 @@ contract Core is Storage {
1383
1579
  * @param user Address to check execution permission for
1384
1580
  * @return True if user can execute, false if blocked
1385
1581
  */
1386
- function canExecuteUserTransaction(
1582
+ function _canExecuteUserTransaction(
1387
1583
  address user
1388
1584
  ) internal view returns (bool) {
1389
1585
  if (userValidatorAddress.current == address(0)) return true;