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: 76/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
Some addresses that are on the HolderAllowlist but do not hold any LiquidInfrastructureERC20 tokens might be repeatedly added to the holders array, potentially causing issues in the system, such as failure in distribution processes. If a malicious actor possesses two Holder Allowlist addresses, it becomes easier to infinitely increase the holders array.
In the _beforeTokenTransfer function, the to address will be checked to determine whether it should be added to the holders array.
Github:[143]
bool exists = (this.balanceOf(to) != 0); if (!exists) { holders.push(to); }
The logic implemented is that if the balance of the to address is zero, then they are definitely not in the holders array. However, after a transfer, if their balance becomes greater than zero, indicating that the to address now holds some LiquidInfrastructureERC20 tokens, they need to be added to the holders array.
However, as LiquidInfrastructureERC20 does not restrict transfers with an amount of 0, this implies that if an address is on the HolderAllowlist but does not hold any LiquidInfrastructureERC20 tokens, any other address can transfer tokens with an amount of 0 to this address an arbitrary number of times. Consequently, each time such a transfer occurs, the address will be added to the holders array because the balance of to address remains 0 after each transfer.
If the caller of the transfer function with amount 0 holds any amount of LiquidInfrastructureERC20, then they don't need to iterate through the holders array in the _afterTokenTransfer function, making it very easy to infinitely increase the holders array.
I have implemented a simple function called getHoldersLength() to retrieve the length of the holders array.
async function testTransferZero( infraERC20: LiquidInfrastructureERC20, holder1: HardhatEthersSigner, holder2: HardhatEthersSigner, badSigner: HardhatEthersSigner) { const infraERC20NotOwner = infraERC20.connect(badSigner); const initialSupply = await infraERC20.totalSupply(); expect(await infraERC20.isApprovedHolder(holder1.address)).to.be.false; expect(await infraERC20.isApprovedHolder(holder2.address)).to.be.false; expect(await infraERC20.isApprovedHolder(badSigner.address)).to.be.false; await expect(infraERC20.approveHolder(holder1.address)).to.not.be.reverted; expect(await infraERC20.isApprovedHolder(holder1.address)).to.be.true; expect(await infraERC20.getholderslength()).to.equal(0); const infraERC20Holder2 = infraERC20.connect(holder2); for (let i = 0; i < 100; i++) { await expect(infraERC20Holder2.transfer(holder1.address, 0)).to.not.be.reverted; } expect(await infraERC20.getholderslength()).to.equal(100); }
result
> althea-contracts@1.0.0 test > npx hardhat test test/liquidERC20.ts LiquidInfrastructureERC20 tests ✔ testTransferZero (4085ms) 1 passing (4s)
hardhat,Manual review.
bool nonZeroAmount = (amount > 0); bool zeroBalance = (this.balanceOf(to) == 0); if (nonZeroAmount && zeroBalance) { holders.push(to); }
Other
#0 - c4-pre-sort
2024-02-22T06:44:24Z
0xRobocop marked the issue as duplicate of #77
#1 - c4-judge
2024-03-04T13:23:30Z
0xA5DF marked the issue as satisfactory