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: 39/84
Findings: 1
Award: $80.56
🌟 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
80.5583 USDC - $80.56
https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol?plain=1#L116-L119 https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol?plain=1#L270-L277
When rewards are distributed, the entitled tokens for all holders is based on the token's total supply. If a holder is disapproved and still holds a balance, then the entitled tokens will still be distributed to the disapproved holders.
This results in approved holders receiving less entitled tokens since some entitled tokens are unable to be retrieved by disapproved holders.
There are two main code functions that are relevant for this bug:
function disapproveHolder(address holder) public onlyOwner { // AUDIT: this function toggles whether holder approved status. It does not handle the holder's balance. require(isApprovedHolder(holder), "holder not approved"); HolderAllowlist[holder] = false; }
function _beginDistribution() internal { ... uint256 supply = this.totalSupply(); for (uint i = 0; i < distributableERC20s.length; i++) { uint256 balance = IERC20(distributableERC20s[i]).balanceOf( address(this) ); // AUDIT: the entire total supply is used to calculate the entitlement. This can include a disapproved holder's uint256 entitlement = balance / supply; erc20EntitlementPerUnit.push(entitlement);
As you can see, when _beginDistribute is called the entitlement is calculated via uint256 entitlement = balance / supply
. The supply variable takes into account disapproved holder balances. This results in the entitlement equaling less than if the disapproved holder's balances were not accounted for. Approved holders therefore will gain less entitled tokens whenever LiquidInfrastructureERC20.distribute() is called.
Manual inspection
When LiquidInfrastructureERC20.disapproveHolder() is called the protocol should withdraw or burn the holder that is to be disapproved. This will ensure that entitled tokens will be properly distributed.
Error
#0 - c4-pre-sort
2024-02-22T07:08:06Z
0xRobocop marked the issue as duplicate of #703
#1 - c4-judge
2024-03-04T14:42:36Z
0xA5DF marked the issue as satisfactory