diff --git a/src/Rewards.sol b/src/Rewards.sol index 8d7795f..5ce73b5 100644 --- a/src/Rewards.sol +++ b/src/Rewards.sol @@ -94,6 +94,10 @@ contract Rewards is AccessControl, EIP712 { * @dev The sequence number of the batch reward. */ uint256 public batchSequence; + /** + * @dev Represents the latest batch reward digest. + */ + bytes32 public latestBatchRewardDigest; /** * @dev Determines the amount of rewards to be minted for the submitter of batch as a percentage of total rewards in that batch. * This value indicates the cost overhead of minting rewards that the network is happy to take. Though it is set to 2% by default, @@ -148,7 +152,7 @@ contract Rewards is AccessControl, EIP712 { * @param batchSum The sum of rewards in the batch. * @param totalRewardsClaimed The total number of rewards claimed so far. */ - event BatchMinted(uint256 batchSum, uint256 totalRewardsClaimed); + event BatchMinted(uint256 batchSum, uint256 totalRewardsClaimed, bytes32 digest); /** * @dev Initializes the contract with the specified parameters. @@ -218,7 +222,10 @@ contract Rewards is AccessControl, EIP712 { function mintBatchReward(BatchReward memory batch, bytes memory signature) external { _mustBeValidBatchStructure(batch); _mustBeExpectedBatchSequence(batch.sequence); - _mustBeFromAuthorizedOracle(digestBatchReward(batch), signature); + + bytes32 digest = digestBatchReward(batch); + + _mustBeFromAuthorizedOracle(digest, signature); _checkedUpdateQuota(); @@ -230,12 +237,14 @@ contract Rewards is AccessControl, EIP712 { // Safe to increment the sequence after checking this is the expected number (no overflow for the age of universe even with 1000 reward claims per second) batchSequence = batch.sequence + 1; + latestBatchRewardDigest = digest; + for (uint256 i = 0; i < batch.recipients.length; i++) { nodl.mint(batch.recipients[i], batch.amounts[i]); } nodl.mint(msg.sender, submitterRewardAmount); - emit BatchMinted(batchSum, claimed); + emit BatchMinted(batchSum, claimed, digest); } /** @@ -369,4 +378,12 @@ contract Rewards is AccessControl, EIP712 { return _hashTypedDataV4(keccak256(abi.encode(BATCH_REWARD_TYPE_HASH, receipentsHash, amountsHash, batch.sequence))); } + + /** + * @dev Returns the latest batch details. + * @return The next batch sequence and the latest digest of a successfully submitted batch which must have been for batchSequence - 1. + */ + function latestBatchDetails() external view returns (uint256, bytes32) { + return (batchSequence, latestBatchRewardDigest); + } } diff --git a/test/Rewards.t.sol b/test/Rewards.t.sol index 6878863..75cfdc6 100644 --- a/test/Rewards.t.sol +++ b/test/Rewards.t.sol @@ -122,6 +122,10 @@ contract RewardsTest is Test { assertEq(rewards.sequences(recipients[0]), 0); assertEq(rewards.sequences(recipients[1]), 0); assertEq(rewards.batchSequence(), 1); + + (uint256 currentSeq, bytes32 batchHash) = rewards.latestBatchDetails(); + assertEq(currentSeq, 1); + assertEq(batchHash, rewards.digestBatchReward(rewardsBatch)); } function test_gasUsed() public { @@ -284,6 +288,10 @@ contract RewardsTest is Test { vm.expectRevert(); rewards.mintBatchReward(Rewards.BatchReward(recipients, amounts, 0), signature); + + (uint256 currentSeq, bytes32 batchHash) = rewards.latestBatchDetails(); + assertEq(currentSeq, 0); + assertEq(batchHash, bytes32(0)); } function test_rewardsClaimedResetsOnNewPeriod() public {