@@ -100,24 +100,28 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
100100 // --- Authorized minters (for BME bridge, disbursers, etc.) ---
101101 mapping (address => bool ) public authorizedMinters;
102102
103- // --- Training rewards ---
104- uint256 public trainingRewardPool;
105- uint256 public totalTrainingTokens;
103+ // --- Training rewards (funded by share purchases, caps ATN minting) ---
104+ uint256 public trainingRewardPool; // normalized value: total budget ceiling for minting
105+ uint256 public totalTrainingTokens; // total contribution units across all agents
106+ uint256 public totalTrainingMinted; // total ATN minted as training rewards
106107 uint256 public currentEpoch;
107108 mapping (uint256 => TrainingRecord[]) public epochRecords;
108109 mapping (address => uint256 ) public agentTrainingTokens;
109110 mapping (address => uint256 ) public claimedRewards;
110111
111- // --- Per-token pool tracking (token address -> amount held in raw token units) ---
112+ // --- Per-token pool tracking for training pool (token address -> raw units held ) ---
112113 mapping (address => uint256 ) public tokenPoolBalances;
113114
114115 // --- RPB shares (claims on inference dividends) ---
115116 uint256 public totalShares;
116117 mapping (address => uint256 ) public shares;
117- uint256 public totalInferenceRevenue;
118+ uint256 public totalInferenceRevenue; // cumulative normalized inference revenue
118119 uint256 public totalDividendsPaid;
119120 mapping (address => uint256 ) public lastDividendClaim;
120121
122+ // --- Dividend pool (separate from training pool, funded by inference revenue) ---
123+ mapping (address => uint256 ) public dividendPoolBalances; // token -> raw units held for dividends
124+
121125 // --- Inference accounting ---
122126 uint256 public totalInferenceUnits;
123127 uint256 public inferenceProviderShare; // Basis points
@@ -205,7 +209,6 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
205209 error NoShares ();
206210 error NoSharesOutstanding ();
207211 error NoDividendsToClaim ();
208- error OnlyDAO ();
209212 error RevenueSplitInvalid ();
210213 error TransferFailed ();
211214 error ProviderPaymentFailed ();
@@ -499,36 +502,30 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
499502 }
500503
501504 /**
502- * @notice Claim training rewards, withdrawn in a specific value-index token.
503- * @param token ERC20 token to receive (must be in value index; use address(this) for ATN)
505+ * @notice Claim training rewards as freshly minted ATN.
506+ * @dev ATN is minted proportional to the agent's training contribution,
507+ * capped by the training reward pool (funded by share purchases).
504508 */
505- function claimTrainingReward (address token ) external nonReentrant {
509+ function claimTrainingReward () external nonReentrant {
506510 uint256 tokens = agentTrainingTokens[msg .sender ];
507511 uint256 alreadyClaimed = claimedRewards[msg .sender ];
508512 if (tokens <= alreadyClaimed) revert NoRewardsToClaim ();
509513 if (trainingRewardPool == 0 || totalTrainingTokens == 0 ) revert RewardPoolEmpty ();
510514
511515 uint256 unclaimed = tokens - alreadyClaimed;
512- uint256 normalizedReward = (unclaimed * trainingRewardPool) / totalTrainingTokens;
516+ uint256 reward = (unclaimed * trainingRewardPool) / totalTrainingTokens;
513517
514- if (normalizedReward > trainingRewardPool) {
515- normalizedReward = trainingRewardPool;
518+ if (reward > trainingRewardPool) {
519+ reward = trainingRewardPool;
516520 }
517-
518- uint256 rawAmount = _denormalize (token, normalizedReward);
519- if (rawAmount == 0 ) revert NoRewardsToClaim ();
520- if (tokenPoolBalances[token] < rawAmount) revert InsufficientPoolBalance ();
521+ if (reward == 0 ) revert NoRewardsToClaim ();
521522
522523 claimedRewards[msg .sender ] = tokens;
523- trainingRewardPool -= normalizedReward ;
524- tokenPoolBalances[token] -= rawAmount ;
524+ totalTrainingMinted += reward ;
525+ agents[ msg . sender ].totalRewardsEarned += reward ;
525526
526- if (token == address (this )) {
527- _transfer (address (this ), msg .sender , rawAmount);
528- } else {
529- if (! IERC20 (token).transfer (msg .sender , rawAmount)) revert TransferFailed ();
530- }
531- emit RewardClaimed (msg .sender , token, rawAmount);
527+ _mint (msg .sender , reward);
528+ emit RewardClaimed (msg .sender , address (this ), reward);
532529 }
533530
534531 /**
@@ -583,11 +580,11 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
583580
584581 uint256 rawAmount = _denormalize (token, normalizedToClaim);
585582 if (rawAmount == 0 ) revert NoDividendsToClaim ();
586- if (tokenPoolBalances [token] < rawAmount) revert InsufficientPoolBalance ();
583+ if (dividendPoolBalances [token] < rawAmount) revert InsufficientPoolBalance ();
587584
588585 lastDividendClaim[msg .sender ] = myShare;
589586 totalDividendsPaid += normalizedToClaim;
590- tokenPoolBalances [token] -= rawAmount;
587+ dividendPoolBalances [token] -= rawAmount;
591588
592589 if (token == address (this )) {
593590 _transfer (address (this ), msg .sender , rawAmount);
@@ -610,6 +607,13 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
610607 ) external onlyOperator nonReentrant {
611608 if (! agents[provider].active) revert AgentNotActive ();
612609
610+ // Pull payment from the requester
611+ if (token == address (this )) {
612+ _transfer (requester, address (this ), cost);
613+ } else {
614+ if (! IERC20 (token).transferFrom (requester, address (this ), cost)) revert TransferFailed ();
615+ }
616+
613617 uint256 normalizedCost = _normalize (token, cost);
614618
615619 totalInferenceUnits += units;
@@ -627,6 +631,7 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
627631 uint256 treasuryPayment = (cost * treasuryShare) / 10000 ;
628632 uint256 shareholderPoolPayment = cost - providerPayment - treasuryPayment;
629633
634+ // Distribute provider and treasury shares
630635 if (token == address (this )) {
631636 if (providerPayment > 0 ) _transfer (address (this ), provider, providerPayment);
632637 if (treasuryPayment > 0 ) _transfer (address (this ), dao, treasuryPayment);
@@ -639,8 +644,9 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
639644 }
640645 }
641646
647+ // Shareholder portion goes to dividend pool (separate from training pool)
642648 if (shareholderPoolPayment > 0 ) {
643- tokenPoolBalances [token] += shareholderPoolPayment;
649+ dividendPoolBalances [token] += shareholderPoolPayment;
644650 }
645651
646652 emit InferenceServed (provider, requester, units, normalizedCost);
@@ -671,9 +677,9 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
671677 }
672678 }
673679
674- // Track shareholder pool (bridge already minted ATN to this contract)
680+ // Track dividend pool (bridge already minted ATN to this contract)
675681 if (shareholderAmount > 0 ) {
676- tokenPoolBalances [address (this )] += shareholderAmount;
682+ dividendPoolBalances [address (this )] += shareholderAmount;
677683 }
678684
679685 emit InferenceServed (provider, requester, units, totalRevenue);
@@ -782,7 +788,7 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
782788 uint256 _shareholderShare ,
783789 uint256 _treasuryShare
784790 ) external {
785- if (msg .sender != dao) revert OnlyDAO ();
791+ if (msg .sender != dao) revert NotDAO ();
786792 if (_providerShare + _shareholderShare + _treasuryShare != 10000 ) revert RevenueSplitInvalid ();
787793 inferenceProviderShare = _providerShare;
788794 shareholderShare = _shareholderShare;
@@ -856,6 +862,10 @@ contract RPB is ReentrancyGuard, ERC20, ERC20Permit, ERC20Votes, ERC20Burnable {
856862 return tokenPoolBalances[token];
857863 }
858864
865+ function getDividendPoolBalance (address token ) external view returns (uint256 ) {
866+ return dividendPoolBalances[token];
867+ }
868+
859869 function getRegisteredAgents () external view returns (address [] memory ) {
860870 return registeredAgentList;
861871 }
0 commit comments