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: 41/84
Findings: 1
Award: $60.42
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xloscar01
Also found by: 0xAadi, 0xpiken, BowTiedOriole, Breeje, Fassi_Security, JohnSmith, Limbooo, SpicyMeatball, Tendency, Topmark, ZanyBonzy, aslanbek, atoko, jesjupyter, matejdb, max10afternoon, n0kto, peanuts, pkqs90, rouhsamad, thank_you, zhaojohnson
60.4187 USDC - $60.42
Entitlement Distribution meant for Unapproved Holders Would be Lost in the LiquidInfrastructureERC20 contract as value recovery is not implemented in this regards.
function distribute(uint256 numDistributions) public nonReentrant { require(numDistributions > 0, "must process at least 1 distribution"); if (!LockedForDistribution) { require( _isPastMinDistributionPeriod(), "MinDistributionPeriod not met" ); _beginDistribution(); } uint256 limit = Math.min( nextDistributionRecipient + numDistributions, holders.length ); 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); } } >>> nextDistributionRecipient = i; if (nextDistributionRecipient == holders.length) { _endDistribution(); } }
The function above shows how distribution is handled in the LiquidInfrastructureERC20.sol contract, from the first pointer in the code above it can be noted that a check is done to ensure that the holder to be distributed to is indeed approved, after the loop is completed nextDistributionRecipient
is updated to "i", the problem is that in situations that a holder is not approved no implementation is done to refund this value to the Althea Protocol instead the function silently just continues, meaning for example if the number of the holders to be distributed to is 40 whether they are all approved or not nextDistributionRecipient
will be updated to 40 without putting what happens to the lost values that unapproved holders would have gotten into consideration.
Manual Review
In a situation isApprovedHolder(recipient) returns false, instead of just silently proceeding with the next Holder, Althea Protocol should add an implementation to ensure the entitlement that such holder would have gotten is not completely lost, it should be added and refunded to the Althea Protocol.
Access Control
#0 - c4-pre-sort
2024-02-22T05:26:03Z
0xRobocop marked the issue as duplicate of #126
#1 - c4-judge
2024-03-05T12:18:44Z
0xA5DF marked the issue as duplicate of #703
#2 - c4-judge
2024-03-05T12:20:22Z
0xA5DF marked the issue as partial-75