code-423n4 / 2024-02-althea-liquid-infrastructure-findings

3 stars 1 forks source link

User will get no rewards if liquidIntrastructureERC20 native balance is greater than its balance of the distribution token #738

Closed c4-bot-5 closed 9 months ago

c4-bot-5 commented 9 months ago

Lines of code

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

Vulnerability details

Impact

Approved Holders receive 0 rewards from distribution.

Proof of Concept

The _beginDistribution() function calculates a holder's entitlement by dividing the contract's balance of the token to be distributed by its own totalSupply, then it multiplies the result by the user's liquidInfrastructure ERC20 token holding. However, this can represent a case of division before multiplication, and using this logic the holders get no rewards from distribution in most cases expecially as it keeps minting tokens to new holders.

    function test_distributions() public {
        vm.startPrank(owner);

        //create mock erc20s to be distributed
        address[] memory add1 = new address[](3);
        add1[0] = address(testERC20A);
        add1[1] = address(testERC20B);
        add1[2] = address(testERC20C);

        uint256[] memory amount1 = new uint256[](3);
        amount1[0] = 0;
        amount1[1] = 0;
        amount1[2] = 0;

        //add tokens to withdrawable ERC20s and set threshold
        liqNFT.setThresholds(add1, amount1);

        //transfer LiquidInfrastructureNFT to the ERC20 contract and add as managed NFT
        liqNFT.transferFrom(owner, address(liqERC20), 1);
        liqERC20.addManagedNFT(address(liqNFT));

        address user1 = address(45);
        address user2 = address(46);
        address user3 = address(47);

        //approve users to hold the infrastructure ERC20 and mint tokens to them

        liqERC20.approveHolder(user1);
        liqERC20.approveHolder(user2);
        liqERC20.approveHolder(user3);

        liqERC20.mint(user1, 15 ether);
        liqERC20.mint(user2, 13 ether);
        liqERC20.mint(user3, 11 ether);

        //send reward tokens to be distributed to the infrastructure NFT
        testERC20A.mint(address(liqNFT), 15 ether);
        testERC20B.mint(address(liqNFT), 13 ether);
        testERC20C.mint(address(liqNFT), 11 ether);

        liqERC20.withdrawFromAllManagedNFTs();

        console2.log(testERC20C.balanceOf(address(liqERC20)));

        //increase block number
        vm.roll(501);

        // user gets 0 rewards from this distribution
        // emit Distribution(recipient: 0x000000000000000000000000000000000000002F, tokens: [0xf6153FE820B65E2bD7348c280323F6d743a48Bc2, 0x4516910C9FfF823CD84B4Aed42E4Da84252bAc57, 0xA19689FF816E1d083788245DE8471EdE71BD1a4D], amounts: [0, 0, 0])
        liqERC20.distributeToAllHolders();
    }

The above POC shows that users receive no rewards after distribution even though they should have.

Tools Used

Manual Review

Recommended Mitigation Steps

Multiply the contracts distribution token balance by the users LiquidInfrastructure token holdings before dividing by totalSupply.

Assessed type

Math

c4-pre-sort commented 9 months ago

0xRobocop marked the issue as duplicate of #638

c4-judge commented 8 months ago

0xA5DF marked the issue as duplicate of #757

c4-judge commented 8 months ago

0xA5DF marked the issue as satisfactory

c4-judge commented 8 months ago

0xA5DF changed the severity to 2 (Med Risk)

c4-judge commented 8 months ago

0xA5DF marked the issue as unsatisfactory: Out of scope

c4-judge commented 8 months ago

0xA5DF marked the issue as unsatisfactory: Out of scope