Althea Liquid Infrastructure - pkqs90's results

Liquid Infrastructure.

General Information

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

Althea

Findings Distribution

Researcher Performance

Rank: 31/84

Findings: 2

Award: $106.29

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

80.5583 USDC - $80.56

Labels

bug
2 (Med Risk)
satisfactory
duplicate-703

External Links

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L216 https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L270-L277

Vulnerability details

Impact

Reward tokens are distributed incorrectly among LiquidInfrastructureERC20 token holders, potentially resulting in a portion of the reward tokens remaining perpetually locked within the LiquidInfrastructureERC20 contract.

Bug Description

If an account is initially approved as a LiquidInfrastructureERC20 token holder and receives some tokens, but is subsequently revoked as a token holder, this account will still possess tokens while no longer being recognized as an approved holder.

In the initial phase of distribution, the erc20EntitlementPerUnit is calculated by dividing the total supply of LiquidInfrastructureERC20 tokens, regardless of unapproved holders still holding some tokens.

>       uint256 supply = this.totalSupply();    
        for (uint i = 0; i < distributableERC20s.length; i++) {
            uint256 balance = IERC20(distributableERC20s[i]).balanceOf(
                address(this)
            );
>           uint256 entitlement = balance / supply;
            erc20EntitlementPerUnit.push(entitlement);
        }

However, during the distribution phase, only approved holders are allocated the reward tokens. This means if there are accounts that, despite holding tokens, are no longer approved as token holders, their entitled share of reward tokens will not be distributed and will instead remain within the LiquidInfrastructureERC20 contract.

        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);
            }
        }

One could argue that the undistributed tokens will be allocated in the next distribution cycle. However, ultimately, there will always be a residual amount of tokens that remain locked in the LiquidInfrastructureERC20 contract. Therefore, this issue is considered to have medium severity.

Proof of Concept

  1. Out of a total of 10000 LiquidInfrastructureERC20 tokens, unapproved accounts possess 1000.
  2. There are 20000 reward tokens set aside for distribution.
  3. In the distribution phase, only 18000 of these will be allocated, leaving 2000 reward tokens still within the LiquidInfrastructureERC20 contract.

Tools Used

Manual review.

Keep track of the amount of LiquidInfrastructureERC20 tokens held solely by approved holders. This can be done by subtracting from the total supply when a holder is disapproved and adding it back when a holder is approved.

Assessed type

Token-Transfer

#0 - c4-pre-sort

2024-02-22T05:24:27Z

0xRobocop marked the issue as duplicate of #703

#1 - c4-judge

2024-03-04T14:41:55Z

0xA5DF marked the issue as satisfactory

Awards

25.7286 USDC - $25.73

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-87

External Links

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L224 https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/main/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L220-L227

Vulnerability details

Impact

If the owner modifies distributableERC20s during the token distribution process, it could disrupt the entire distribution mechanism, leading to the allocation of incorrect amounts of tokens.

Bug Description

In the process of distributing reward tokens, there are two steps:

  1. Determine the quantity of reward tokens allocated for each LiquidInfrastructureERC20 token and record this in erc20EntitlementPerUnit.
  2. Multiply this figure by the amount of LiquidInfrastructureERC20 tokens a user holds to calculate the total reward tokens for each user.

Step 1:

        for (uint i = 0; i < distributableERC20s.length; i++) {
            uint256 balance = IERC20(distributableERC20s[i]).balanceOf(
                address(this)
            );
            uint256 entitlement = balance / supply;
            erc20EntitlementPerUnit.push(entitlement);
        }

Step 2:

                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;
                    }
                }

However, if distributableERC20s is modified in the middle of the distribution process, it could fall out of alignment with erc20EntitlementPerUnit, leading to an incorrect subsequent distribution phase.

Proof of Concept

  1. The distribution process starts.
  2. The owner updates distributableERC20s.
  3. The remainder of the distribution process becomes incorrect.

Tools Used

Manual review.

Don't allow setting distributableERC20s during distribution.

     function setDistributableERC20s(
         address[] memory _distributableERC20s
     ) public onlyOwner {
+        require(!LockedForDistribution, "distribution in progress");
         distributableERC20s = _distributableERC20s;
     }

Assessed type

Invalid Validation

#0 - c4-pre-sort

2024-02-20T07:13:16Z

0xRobocop marked the issue as duplicate of #260

#1 - c4-judge

2024-03-04T15:30:44Z

0xA5DF marked the issue as satisfactory

#2 - c4-judge

2024-03-08T15:13:03Z

0xA5DF changed the severity to 3 (High Risk)

#3 - c4-judge

2024-03-08T15:26:19Z

0xA5DF changed the severity to 2 (Med Risk)

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter