Canto Liquidity Mining Protocol - 0xWaitress's results

Execution layer for original work.

General Information

Platform: Code4rena

Start Date: 03/10/2023

Pot Size: $24,500 USDC

Total HM: 6

Participants: 62

Period: 3 days

Judge: LSDan

Total Solo HM: 3

Id: 288

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 12/62

Findings: 2

Award: $364.87

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Banditx0x

Also found by: 0xDING99YA, 0xWaitress, 0xpiken, 3docSec, Banditx0x, adriro, emerald7017, maanas, twicek

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
upgraded by judge
duplicate-114

Awards

359.9307 USDC - $359.93

External Links

Lines of code

https://github.com/code-423n4/2023-10-canto/blob/main/canto_ambient/contracts/mixins/LiquidityMining.sol#L237

Vulnerability details

Impact

accrueConcentratedGlobalTimeWeightedLiquidity and accrueConcentratedPositionTimeWeightedLiquidity has unbounded while loop; potentially out of gas error if not updated for a long time

liquidity is calculated before it 's changed to count the total time weighted liquidity provision eligible for incentive. They are accrued in both accrueConcentratedGlobalTimeWeightedLiquidity and accrueConcentratedPositionTimeWeightedLiquidity on a per-week basis.

However the liquidity accrual can only be done all the way from the last accrual to the latest block timestamp, in an unbounded while loop, this is problematic since if the pool is not touched for long time then the gas for the update may become bigger than the gas limit / limit for a single tx such that the pool becomes no longer updateable.

    function accrueAmbientPositionTimeWeightedLiquidity(
        address payable owner,
        bytes32 poolIdx
    ) internal {
        bytes32 posKey = encodePosKey(owner, poolIdx);
        uint32 lastAccrued = timeWeightedWeeklyPositionAmbLiquidityLastSet_[
            poolIdx
        ][posKey];
        // Only init time on first call
        if (lastAccrued != 0) {
            AmbientPosition storage pos = lookupPosition(owner, poolIdx);
            uint256 liquidity = pos.seeds_;
            uint32 time = lastAccrued;
            while (time < block.timestamp) {
                uint32 currWeek = uint32((time / WEEK) * WEEK);
                uint32 nextWeek = uint32(((time + WEEK) / WEEK) * WEEK);
                uint32 dt = uint32(
                    nextWeek < block.timestamp
                        ? nextWeek - time
                        : block.timestamp - time
                );
                timeWeightedWeeklyPositionAmbLiquidity_[poolIdx][posKey][
                    currWeek
                ] += dt * liquidity;
                time += dt;
            }
        }
        timeWeightedWeeklyPositionAmbLiquidityLastSet_[poolIdx][
            posKey
        ] = uint32(block.timestamp);
    }

Proof of Concept

Tools Used

Consider updating the liquidity in a checkpoint manner (in 1 go), and liquidity can be tracked through iterating the needed pointer using a binary search.

Assessed type

Loop

#0 - c4-pre-sort

2023-10-07T12:54:52Z

141345 marked the issue as low quality report

#1 - c4-pre-sort

2023-10-07T13:05:43Z

141345 marked the issue as duplicate of #12

#2 - c4-pre-sort

2023-10-09T12:38:04Z

141345 marked the issue as remove high or low quality report

#3 - c4-pre-sort

2023-10-09T16:17:43Z

141345 marked the issue as sufficient quality report

#4 - c4-pre-sort

2023-10-09T16:20:28Z

141345 marked the issue as not a duplicate

#5 - c4-pre-sort

2023-10-09T16:21:23Z

141345 marked the issue as duplicate of #114

#6 - c4-judge

2023-10-18T19:27:43Z

dmvt changed the severity to 3 (High Risk)

#7 - c4-judge

2023-10-18T19:29:28Z

dmvt marked the issue as satisfactory

Awards

4.9369 USDC - $4.94

Labels

bug
grade-b
QA (Quality Assurance)
sufficient quality report
Q-37

External Links

[L-1] unnecessary exposure of setAmbRewards and setConcRewards in LiquidityMiningPath as a public function without access controller

While LiquidityMiningPath is a contract that the CrocSwapDex delegates userCmd or protocolCmd only, and all execution is meant to be done regarding storage on CrocSwapDex, the calling of setAmbRewards and setConcRewards on LiquidityMiningPath does not have access control as a public function that everyone can access. This let other to arbitrarily make change to the storage of relevant data like ambRewardPerWeek_ and concRewardPerWeek_ on the LiquidityMiningPath contract. While this does no harm the operation, this is unnecessary and create additional vulnerability if the logic is upgraded in future to include initialiser / or function that allow self-destruct or changes of the module with reference to its own data.

#0 - c4-pre-sort

2023-10-09T17:23:13Z

141345 marked the issue as sufficient quality report

#1 - c4-judge

2023-10-18T22:28:17Z

dmvt marked the issue as grade-b

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