@@ -72,39 +72,6 @@ contract KnowledgeCollection is INamed, IVersioned, ContractStatus, IInitializab
7272 return _VERSION;
7373 }
7474
75- function _distributeTokens (EpochStorage es , uint96 tokenAmount , uint256 epochs , uint40 currentEpoch ) internal {
76- require (epochs > 0 , "epochs must be > 0 " );
77-
78- uint256 epochLen = chronos.epochLength ();
79- uint256 timeLeft = chronos.timeUntilNextEpoch (); // seconds remaining in current epoch
80- uint256 basePer = tokenAmount / epochs; // nominal amount for a full epoch
81- uint256 curPart = (basePer * timeLeft) / epochLen;
82- uint256 tailPart = basePer - curPart; // goes to the final fractional epoch
83- uint256 fullEpCnt = epochs - 1 ; // number of full middle epochs
84- uint256 allocFull = basePer * fullEpCnt;
85-
86- // Add any rounding remainder to the tail so total == tokenAmount
87- uint256 allocated = curPart + allocFull + tailPart;
88- if (allocated < tokenAmount) {
89- tailPart += tokenAmount - allocated;
90- }
91-
92- // 1) Current (fractional) epoch
93- if (curPart > 0 ) {
94- es.addTokensToEpochRange (1 , currentEpoch, currentEpoch, uint96 (curPart));
95- }
96-
97- // 2) Full epochs between current and final
98- if (fullEpCnt > 0 && allocFull > 0 ) {
99- es.addTokensToEpochRange (1 , currentEpoch + 1 , currentEpoch + uint40 (fullEpCnt), uint96 (allocFull));
100- }
101-
102- // 3) Final (fractional) epoch
103- if (tailPart > 0 ) {
104- es.addTokensToEpochRange (1 , currentEpoch + uint40 (epochs), currentEpoch + uint40 (epochs), uint96 (tailPart));
105- }
106- }
107-
10875 function createKnowledgeCollection (
10976 string calldata publishOperationId ,
11077 bytes32 merkleRoot ,
@@ -146,9 +113,9 @@ contract KnowledgeCollection is INamed, IVersioned, ContractStatus, IInitializab
146113 isImmutable
147114 );
148115
149- _validateTokenAmount (byteSize, epochs, tokenAmount, /* includeCurrentEpoch = */ false );
150- _distributeTokens (es, tokenAmount, epochs, currentEpoch);
151- es .addEpochProducedKnowledgeValue (publisherNodeIdentityId, currentEpoch, tokenAmount);
116+ _validateTokenAmount (byteSize, epochs, tokenAmount, true );
117+ _distributeTokens (tokenAmount, epochs, currentEpoch);
118+ epochStorage .addEpochProducedKnowledgeValue (publisherNodeIdentityId, currentEpoch, tokenAmount);
152119
153120 _addTokens (tokenAmount, paymaster);
154121
@@ -355,4 +322,47 @@ contract KnowledgeCollection is INamed, IVersioned, ContractStatus, IInitializab
355322 }
356323 }
357324 }
325+
326+ function _distributeTokens (uint96 tokenAmount , uint256 epochs , uint40 currentEpoch ) internal {
327+ require (epochs > 0 , "epochs must be > 0 " );
328+
329+ uint256 epochLengthInSeconds = chronos.epochLength ();
330+ uint256 timeRemainingInCurrentEpoch = chronos.timeUntilNextEpoch (); // seconds remaining in current epoch
331+ uint256 baseTokensPerFullEpoch = tokenAmount / epochs; // nominal amount for a full epoch
332+ uint256 currentEpochAllocation = (baseTokensPerFullEpoch * timeRemainingInCurrentEpoch) / epochLengthInSeconds;
333+ uint256 finalEpochAllocation = baseTokensPerFullEpoch - currentEpochAllocation; // goes to the final fractional epoch
334+ uint256 numberOfFullEpochs = epochs - 1 ; // number of full middle epochs
335+ uint256 totalTokensForFullEpochs = baseTokensPerFullEpoch * numberOfFullEpochs;
336+
337+ // Add any rounding remainder to the final epoch so total == tokenAmount
338+ uint256 totalAllocated = currentEpochAllocation + totalTokensForFullEpochs + finalEpochAllocation;
339+ if (totalAllocated < tokenAmount) {
340+ finalEpochAllocation += tokenAmount - totalAllocated;
341+ }
342+
343+ // 1) Current (fractional) epoch
344+ if (currentEpochAllocation > 0 ) {
345+ epochStorage.addTokensToEpochRange (1 , currentEpoch, currentEpoch, uint96 (currentEpochAllocation));
346+ }
347+
348+ // 2) Full epochs between current and final
349+ if (numberOfFullEpochs > 0 && totalTokensForFullEpochs > 0 ) {
350+ epochStorage.addTokensToEpochRange (
351+ 1 ,
352+ currentEpoch + 1 ,
353+ currentEpoch + uint40 (numberOfFullEpochs),
354+ uint96 (totalTokensForFullEpochs)
355+ );
356+ }
357+
358+ // 3) Final (fractional) epoch
359+ if (finalEpochAllocation > 0 ) {
360+ epochStorage.addTokensToEpochRange (
361+ 1 ,
362+ currentEpoch + uint40 (epochs),
363+ currentEpoch + uint40 (epochs),
364+ uint96 (finalEpochAllocation)
365+ );
366+ }
367+ }
358368}
0 commit comments