Althea Liquid Infrastructure - pynschon'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: 83/84

Findings: 1

Award: $7.18

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/bd6ee47162368e1999a0a5b8b17b701347cf9a7d/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L127-L146

Vulnerability details

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

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/bd6ee47162368e1999a0a5b8b17b701347cf9a7d/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L127-L146

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

https://github.com/code-423n4/2024-02-althea-liquid-infrastructure/blob/bd6ee47162368e1999a0a5b8b17b701347cf9a7d/liquid-infrastructure/contracts/LiquidInfrastructureERC20.sol#L213-L231

Impact

  • Higher gas fees and possibility of denials of service due out gas error.

Proof of Concept

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

Tools Used

Foundry

  • Check if there's a 0 token transfer, and only add addresses that receive non-zero token transfers to the holders array.

Assessed type

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

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