Sparkn

CodeFox Inc.
DeFiFoundryProxy
15,000 USDC
View results
Submission Details
Severity: low
Valid

Out of gas error/High fees if transaction is called with a lot of winners

Summary

A transaction's cost increases with the size of the winners' array. If it grows significantly large (e.g., > 500), the transaction might become prohibitively expensive or even fail due to an "out of gas" error.

Vulnerability Details

  • Transferring tokens is gas-intensive, with each transfer costing approximately 21000 gas.

  • As the winners' array grows, the cost multiplies, making the transaction expensive and potentially causing failures.

POC : Gas estimation after calling the function deployProxyAndDistribute

function createLargeData() public view returns (bytes memory data) {
address[] memory tokens_ = new address[](1);
tokens_[0] = jpycv2Address;
address[] memory winners = new address[](2000);
uint256[] memory percentages_ = new uint256[](2000);
for (uint256 i = 0; i < 2000; ++i) {
winners[i] = user1;
percentages_[i] = 4;
}
percentages_[0] = 1504;
data = abi.encodeWithSelector(Distributor.distribute.selector, jpycv2Address, winners, percentages_, "");
}
function testGasCost() public setUpContestForJasonAndSentJpycv2Token(organizer) {
// before
assertEq(MockERC20(jpycv2Address).balanceOf(user1), 0 ether);
assertEq(MockERC20(jpycv2Address).balanceOf(stadiumAddress), 0 ether);
bytes32 randomId_ = keccak256(abi.encode("Jason", "001"));
bytes memory data = createLargeData();
uint256 checkpointGasLeft1 = gasleft();
vm.warp(9 days); // 9 days later
vm.startPrank(organizer);
proxyFactory.deployProxyAndDistribute(randomId_, address(distributor), data);
vm.stopPrank();
uint256 checkpointGasLeft2 = gasleft();
console.log("Gas left: ", checkpointGasLeft1 - checkpointGasLeft2);
}

Current gas prices around 60 Gwei, for context:

Winners[] length Gas Price (USD)
500 3,520,745 $348,553.755
2000 14,592,880 $1,444.70
3000 22,715,339 $2,248.82
  • At around 500, the gas cost becomes too expensive. Also, for Ethereum for example, the target block size is 15M. So more than 2000 in size will almost always lead to an out of gas error.

  • There is also the risk that the caller will not be able to provide enough gas for the transaction to run properly.

Impact

  • Organizers/Owners might need to pay high gas fees.

  • "Out of gas" errors can halt the reward distribution process.

  • Prizes might not be distributed if winners are removed to reduce array length.

  • Failed transactions still charge organizers despite not completing.

Tools Used

Manual review and Foundry testing

Recommendations

  • Implement a pull-based mechanism where winners claim their rewards.

  • Limit the array of winners which might hinder the number of participants.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.