@@ -71,6 +71,7 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
7171
7272 /** Constants */
7373 uint8 private constant VALIDATOR_REWARD_PERCENTAGE = 10 ;
74+ uint8 private constant DAO_REWARD_PERCENTAGE = 3 ;
7475 uint256 private constant BASE_EMISSION_RATE = 5832e18 ; // Base hourly emission rate
7576 uint256 private constant TAIL_EMISSION = 420e18 ; // Base hourly tail emission
7677 uint256 private constant REWARD_PERIOD = 365 days ;
@@ -91,18 +92,17 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
9192 uint256 public s_validatorLockAmount;
9293 uint256 public s_userLockAmount;
9394
94- uint256 public s_currentDistributionId;
95+ // Payment and rewards tracking (SNO + ETH)
9596 PaymentAmounts public s_totalUnclaimed;
9697 PaymentAmounts public s_totalEscrowed;
97- uint256 public s_totalLocked;
98+ uint256 public s_totalLocked; // SNO
99+ uint256 public s_totalETHDeposited;
100+ uint256 public s_totalETHWithdrawn;
98101
102+ uint256 public s_currentDistributionId;
99103 uint256 public s_distributionInterval;
100104 uint256 public s_lastDistributionTime;
101105
102- // ETH balance tracking
103- uint256 public s_totalETHDeposited;
104- uint256 public s_totalETHWithdrawn;
105-
106106 mapping (uint256 => MerkleDistribution) public s_distributions;
107107 mapping (uint256 => mapping (address => bool )) public s_claimed;
108108 mapping (address => LockedTokens) private s_lockedTokens;
@@ -120,8 +120,9 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
120120 }
121121
122122 modifier onlyDAO () {
123- if (s_dao != address (0 )) {
124- if (msg .sender != s_dao) {
123+ address dao = s_dao;
124+ if (dao != address (0 )) {
125+ if (msg .sender != dao) {
125126 revert Token__OnlyDAO ();
126127 }
127128 }
@@ -162,6 +163,11 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
162163 uint256 totalSno ,
163164 uint256 totalEth
164165 );
166+ event DAORewardsDistributed (
167+ uint256 indexed distributionId ,
168+ uint256 snoAmount ,
169+ uint256 ethAmount
170+ );
165171 event ETHDeposited (address indexed from , uint256 amount );
166172 event ETHWithdrawn (address indexed to , uint256 amount );
167173 event DistributionIntervalUpdated (uint256 oldInterval , uint256 newInterval );
@@ -315,7 +321,7 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
315321 ethShare += ethRemainder;
316322 }
317323
318- _payValidator (validator, snoShare, ethShare);
324+ _payAccount (validator, snoShare, ethShare);
319325 }
320326
321327 emit ValidatorRewardsDistributed (
@@ -332,7 +338,7 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
332338 * @param snoAmount Amount of SNO tokens to mint/send
333339 * @param ethAmount Amount of ETH to transfer
334340 */
335- function _payValidator (
341+ function _payAccount (
336342 address validator ,
337343 uint256 snoAmount ,
338344 uint256 ethAmount
@@ -362,9 +368,9 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
362368 * @param _payments Additional payments to be added to the current emission rate
363369 * @param _approvedValidators List of validators that voted
364370 * @param _dustValidator Address of validator to receive dust rewards (usually the proposal executor)
365- * @dev Workers receive 90 % of the total reward, validators receive 10%
366- * @dev Rewards are distributed with bias towards specified validator, then proportionally to workers based on their capacities
367- * @dev This function is called by SmartnodesCore during state updates to distribute rewards.
371+ * @dev Workers receive 85 % of the total reward, validators receive 10%, dao receives 5 %
372+ * @dev Rewards are distributed proportionally to workers based on their capacities.
373+ * @dev This function is called periodically by SmartnodesCore during state updates to distribute rewards.
368374 */
369375 function createMerkleDistribution (
370376 bytes32 _merkleRoot ,
@@ -389,54 +395,71 @@ contract SmartnodesToken is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard {
389395
390396 uint256 distributionId = ++ s_currentDistributionId;
391397
392- if (_totalCapacity == 0 ) {
393- // All rewards go to validators
394- _distributeValidatorRewards (
395- _approvedValidators,
396- totalReward,
397- distributionId,
398- _dustValidator
399- );
400- return ; // exit early
401- }
402-
403- // Split validator/worker share from the remaining pool
404- PaymentAmounts memory validatorReward = PaymentAmounts ({
398+ // Calculate reward distributions
399+ PaymentAmounts memory daoReward = PaymentAmounts ({
405400 sno: uint128 (
406- (uint256 (totalReward.sno) * VALIDATOR_REWARD_PERCENTAGE ) / 100
401+ (uint256 (totalReward.sno) * DAO_REWARD_PERCENTAGE ) / 100
407402 ),
408403 eth: uint128 (
409- (uint256 (totalReward.eth) * VALIDATOR_REWARD_PERCENTAGE ) / 100
404+ (uint256 (totalReward.eth) * DAO_REWARD_PERCENTAGE ) / 100
410405 )
411406 });
407+ PaymentAmounts memory validatorReward;
412408
413- PaymentAmounts memory workerReward = PaymentAmounts ({
414- sno: totalReward.sno - validatorReward.sno,
415- eth: totalReward.eth - validatorReward.eth
416- });
409+ if (_totalCapacity == 0 ) {
410+ // If no workers, just give to validators
411+ validatorReward = PaymentAmounts ({
412+ sno: totalReward.sno - daoReward.sno,
413+ eth: totalReward.eth - daoReward.eth
414+ });
415+ } else {
416+ // Split validator/worker share from the remaining pool
417+ validatorReward = PaymentAmounts ({
418+ sno: uint128 (
419+ (uint256 (totalReward.sno) * VALIDATOR_REWARD_PERCENTAGE) /
420+ 100
421+ ),
422+ eth: uint128 (
423+ (uint256 (totalReward.eth) * VALIDATOR_REWARD_PERCENTAGE) /
424+ 100
425+ )
426+ });
417427
418- // Store merkle distribution (only worker rewards are stored for claiming)
419- s_distributions[distributionId] = MerkleDistribution ({
420- merkleRoot: _merkleRoot,
421- workerReward: workerReward,
422- totalCapacity: _totalCapacity,
423- active: true ,
424- timestamp: block .timestamp
425- });
428+ PaymentAmounts memory workerReward = PaymentAmounts ({
429+ sno: totalReward.sno - validatorReward.sno - daoReward.sno,
430+ eth: totalReward.eth - validatorReward.eth - daoReward.eth
431+ });
432+
433+ // Store merkle distribution (only worker rewards are stored for claiming)
434+ s_distributions[distributionId] = MerkleDistribution ({
435+ merkleRoot: _merkleRoot,
436+ workerReward: workerReward,
437+ totalCapacity: _totalCapacity,
438+ active: true ,
439+ timestamp: block .timestamp
440+ });
426441
427- // Update total unclaimed (only worker rewards)
428- s_totalUnclaimed.sno += workerReward.sno;
429- s_totalUnclaimed.eth += workerReward.eth;
442+ // Update total unclaimed (only worker rewards)
443+ s_totalUnclaimed.sno += workerReward.sno;
444+ s_totalUnclaimed.eth += workerReward.eth;
430445
431- emit MerkleDistributionCreated (
446+ emit MerkleDistributionCreated (
447+ distributionId,
448+ _merkleRoot,
449+ totalReward.sno,
450+ totalReward.eth,
451+ block .timestamp
452+ );
453+ }
454+ // Distribute DAO rewards
455+ _payAccount (s_dao, daoReward.sno, daoReward.eth);
456+ emit DAORewardsDistributed (
432457 distributionId,
433- _merkleRoot,
434- totalReward.sno,
435- totalReward.eth,
436- block .timestamp
458+ daoReward.sno,
459+ daoReward.eth
437460 );
438461
439- // Distribute validator rewards immediately with bias
462+ // Distribute validator rewards
440463 _distributeValidatorRewards (
441464 _approvedValidators,
442465 validatorReward,
0 commit comments