Skip to content

Commit

Permalink
release 1.2.14
Browse files Browse the repository at this point in the history
  • Loading branch information
RCantu92 committed Jul 31, 2024
1 parent 7d5489a commit 60f69ea
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 1 deletion.
11 changes: 11 additions & 0 deletions contracts/components/staking/rewards/RewardsDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ contract RewardsDistributor is BaseComponentUpgradeable, SubjectTypeValidator, I
uint256 public delegationParamsEpochDelay;
uint256 public defaultFeeBps;

// subject => epoch => claimedByPoolOwner
mapping(uint256 => mapping(uint256 => bool)) public poolRewardsAtEpochClaimedByOwner;

event DidAccumulateRate(uint8 indexed subjectType, uint256 indexed subject, address indexed staker, uint256 stakeAmount, uint256 sharesAmount);
event DidReduceRate(uint8 indexed subjectType, uint256 indexed subject, address indexed staker, uint256 stakeAmount, uint256 sharesAmount);
event Rewarded(uint8 indexed subjectType, uint256 indexed subject, uint256 amount, uint256 epochNumber);
Expand All @@ -63,6 +66,7 @@ contract RewardsDistributor is BaseComponentUpgradeable, SubjectTypeValidator, I
event TokensSwept(address indexed token, address to, uint256 amount);

error RewardingNonRegisteredSubject(uint8 subjectType, uint256 subject);
error AlreadyClaimedByOwner();
error AlreadyClaimed();
error AlreadyRewarded(uint256 epochNumber);
error SetDelegationFeeNotReady();
Expand Down Expand Up @@ -153,6 +157,9 @@ contract RewardsDistributor is BaseComponentUpgradeable, SubjectTypeValidator, I

function availableReward(uint8 subjectType, uint256 subjectId, uint256 epochNumber, address staker) public view returns (uint256) {
(uint256 shareId, bool isDelegator) = _getShareId(subjectType, subjectId);
if (!isDelegator && (_subjectGateway.ownerOf(subjectType, subjectId) != staker || poolRewardsAtEpochClaimedByOwner[subjectId][epochNumber])) {
return 0;
}
if (claimedRewardsPerEpoch[shareId][epochNumber][staker]) {
return 0;
}
Expand Down Expand Up @@ -221,7 +228,11 @@ contract RewardsDistributor is BaseComponentUpgradeable, SubjectTypeValidator, I
if (_subjectGateway.ownerOf(subjectType, subjectId) != _msgSender()) revert SenderNotOwner(_msgSender(), subjectId);
}
for (uint256 i = 0; i < epochNumbers.length; i++) {
if (!isDelegator && poolRewardsAtEpochClaimedByOwner[subjectId][epochNumbers[i]]) {
revert AlreadyClaimedByOwner();
}
if (claimedRewardsPerEpoch[shareId][epochNumbers[i]][_msgSender()]) revert AlreadyClaimed();
if (!isDelegator) poolRewardsAtEpochClaimedByOwner[subjectId][epochNumbers[i]] = true;
claimedRewardsPerEpoch[shareId][epochNumbers[i]][_msgSender()] = true;
uint256 epochRewards = _availableReward(shareId, isDelegator, epochNumbers[i], _msgSender());
if (epochRewards == 0) revert ZeroAmount("epochRewards");
Expand Down
72 changes: 71 additions & 1 deletion test/components/staking.rewards.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,83 @@ describe('Staking Rewards', function () {
expect(await this.rewardsDistributor.availableReward(DELEGATOR_SUBJECT_TYPE, SCANNER_POOL_ID, epoch, this.accounts.user2.address)).to.be.equal('0');

await expect(this.rewardsDistributor.connect(this.accounts.user1).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epoch])).to.be.revertedWith(
'AlreadyClaimed()'
'AlreadyClaimedByOwner()'
);
await expect(this.rewardsDistributor.connect(this.accounts.user2).claimRewards(DELEGATOR_SUBJECT_TYPE, SCANNER_POOL_ID, [epoch])).to.be.revertedWith(
'AlreadyClaimed()'
);
});

it('should fail to reclaim for same pool and epoch even if pool ownership is transferred', async function () {
// disable automine so deposits are instantaneous to simplify math
await network.provider.send('evm_setAutomine', [false]);
await this.staking.connect(this.accounts.user1).deposit(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, '100');
await this.scannerPools.connect(this.accounts.user1).registerScannerNode(registration, signature);
await network.provider.send('evm_setAutomine', [true]);
await network.provider.send('evm_mine');

expect(await this.stakeAllocator.allocatedManagedStake(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID)).to.be.equal('100');

const latestTimestamp = await helpers.time.latest();
const timeToNextEpoch = EPOCH_LENGTH - ((latestTimestamp - OFFSET) % EPOCH_LENGTH);
await helpers.time.increase(Math.floor(timeToNextEpoch / 2));

const epoch = await this.rewardsDistributor.getCurrentEpochNumber();

await helpers.time.increase(1 + EPOCH_LENGTH /* 1 week */);

expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epoch, this.accounts.user1.address)).to.be.equal('0');

await this.rewardsDistributor.connect(this.accounts.manager).reward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, '2000', epoch);

expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epoch, this.accounts.user1.address)).to.be.equal('2000');

const balanceBefore1 = await this.token.balanceOf(this.accounts.user1.address);

await this.rewardsDistributor.connect(this.accounts.user1).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epoch]);

expect(await this.token.balanceOf(this.accounts.user1.address)).to.eq(balanceBefore1.add('2000'));
expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epoch, this.accounts.user1.address)).to.be.equal('0');

await expect(this.rewardsDistributor.connect(this.accounts.user1).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epoch])).to.be.revertedWith(
'AlreadyClaimedByOwner()'
);

expect(await this.scannerPools.ownerOf(SCANNER_POOL_ID)).to.eq(this.accounts.user1.address);
await this.scannerPools.connect(this.accounts.user1).transferFrom(this.accounts.user1.address, this.accounts.user2.address, SCANNER_POOL_ID);
expect(await this.scannerPools.ownerOf(SCANNER_POOL_ID)).to.eq(this.accounts.user2.address);

expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epoch, this.accounts.user2.address)).to.be.equal('0');

await expect(this.rewardsDistributor.connect(this.accounts.user2).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epoch])).to.be.revertedWith(
'AlreadyClaimedByOwner()'
);

const epochTwo = await this.rewardsDistributor.getCurrentEpochNumber();

await helpers.time.increase(1 + EPOCH_LENGTH /* 1 week */);

expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epochTwo, this.accounts.user1.address)).to.be.equal('0');
expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epochTwo, this.accounts.user2.address)).to.be.equal('0');

await this.rewardsDistributor.connect(this.accounts.manager).reward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, '2000', epochTwo);

expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epochTwo, this.accounts.user1.address)).to.be.equal('0');
expect(await this.rewardsDistributor.availableReward(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, epochTwo, this.accounts.user2.address)).to.be.equal('2000');
await expect(this.rewardsDistributor.connect(this.accounts.user1).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epochTwo])).to.be.revertedWith(
`SenderNotOwner("${this.accounts.user1.address}", ${SCANNER_POOL_ID})`
);

const balanceBefore2 = await this.token.balanceOf(this.accounts.user2.address);

await this.rewardsDistributor.connect(this.accounts.user2).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epochTwo]);

expect(await this.token.balanceOf(this.accounts.user2.address)).to.eq(balanceBefore2.add('2000'));
await expect(this.rewardsDistributor.connect(this.accounts.user2).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [epochTwo])).to.be.revertedWith(
'AlreadyClaimedByOwner()'
);
});

it('should fail to reclaim if no rewards available', async function () {
await expect(this.rewardsDistributor.connect(this.accounts.user1).claimRewards(SCANNER_POOL_SUBJECT_TYPE, SCANNER_POOL_ID, [1])).to.be.revertedWith(
'ZeroAmount("epochRewards")'
Expand Down

0 comments on commit 60f69ea

Please sign in to comment.