Canto Liquidity Mining Protocol - lukejohn'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: 51/62

Findings: 1

Award: $4.94

QA:
grade-b

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Awards

4.9369 USDC - $4.94

Labels

bug
disagree with severity
downgraded by judge
grade-b
primary issue
QA (Quality Assurance)
sponsor acknowledged
sufficient quality report
Q-30

External Links

Lines of code

https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/callpaths/LiquidityMiningPath.sol#L65-L81

Vulnerability details

Impact

Detailed description of the impact of this finding. LiquidityMiningPath.setConcRewards() fails to check to ensure that weekFrom > timeWeightedWeeklyGlobalConcLiquidityLastSet_[poolIdx]. Similarly, LiquidityMiningPath.setAmbRewards() fails to check to ensure that weekFrom > timeWeightedWeeklyGlobalAmbLiquidityLastSet_[poolIdx]. As a result, if these two constraints are violated, then weekly reward rate is set for PAST weeks that are smaller than lastAccrued time point. Therefore, these rewards will never be distributed since they are already in the past of lastAccrued.

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

LiquidityMiningPath.setConcRewards() allows one to set the weekly reward rate for a range of weeks. However, it is important to ensure that this range of weeks are in the future of the lastAccrued time, which is timeWeightedWeeklyGlobalConcLiquidityLastSet_[poolIdx].

https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/callpaths/LiquidityMiningPath.sol#L65-L72

Otherwise, if the weeks are already past by timeWeightedWeeklyGlobalConcLiquidityLastSet_[poolIdx], then the rewards for them cannot be distributed anymore. See function LiquidityMining. accrueConcentratedGlobalTimeWeightedLiquidity(), which will accrue since lastAccrued.

https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/mixins/LiquidityMining.sol#L39-L65

Similarly, LiquidityMiningPath.setAmbRewards() fails to check to ensure that weekFrom > timeWeightedWeeklyGlobalAmbLiquidityLastSet_[poolIdx]:

https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/callpaths/LiquidityMiningPath.sol#L74-L81

Therefore, it is possible the user is funding for a past week that has been passed by timeWeightedWeeklyGlobalAmbLiquidityLastSet_[poolIdx]. Then, the function LiquidityMining.accrueAmbientGlobalTimeWeightedLiquidity() will not accrue for the weeks since the function accrue rewards since lastAccrued - timeWeightedWeeklyGlobalAmbLiquidityLastSet_[poolIdx].

https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/mixins/LiquidityMining.sol#L198-L222

Tools Used

VSCode

Check both weekFrom > timeWeightedWeeklyGlobalConcLiquidityLastSet_[poolIdx] and weekFrom > timeWeightedWeeklyGlobalAmbLiquidityLastSet_[poolIdx].

function setConcRewards(bytes32 poolIdx, uint32 weekFrom, uint32 weekTo, uint64 weeklyReward) public payable {
+       lastAccrued = timeWeightedWeeklyGlobalConcLiquidityLastSet_[poolIdx];

        // require(msg.sender == governance_, "Only callable by governance");
        require(weekFrom % WEEK == 0 && weekTo % WEEK == 0, "Invalid weeks");
        while (weekFrom <= weekTo) {
+            require(weekFrom > lastAccrued, "the week is in the past.");
            concRewardPerWeek_[poolIdx][weekFrom] = weeklyReward;
            weekFrom += uint32(WEEK);
        }
    }

    function setAmbRewards(bytes32 poolIdx, uint32 weekFrom, uint32 weekTo, uint64 weeklyReward) public payable {
+       lastAccrued = timeWeightedWeeklyGlobalAmbLiquidityLastSet_[poolIdx]

        // require(msg.sender == governance_, "Only callable by governance");
        require(weekFrom % WEEK == 0 && weekTo % WEEK == 0, "Invalid weeks");
        while (weekFrom <= weekTo) {
+           require(weekFrom > lastAccrued, "the week is in the past.");
            ambRewardPerWeek_[poolIdx][weekFrom] = weeklyReward;
            weekFrom += uint32(WEEK);
        }
    }

Assessed type

Invalid Validation

#0 - 141345

2023-10-07T13:36:37Z

set rewards for past date. However in normal operations, gov is expexcted to set rewards in advance, instead of after the period is over.

gov function input validation, QA is more appropriate

#1 - c4-pre-sort

2023-10-07T13:36:44Z

141345 marked the issue as primary issue

#2 - 141345

2023-10-09T15:12:40Z

https://github.com/code-423n4/2023-10-canto-findings/issues/241 mentions liquidity history tracking issue

https://github.com/code-423n4/2023-10-canto-findings/issues/67 talks about user claim before add reward to the past

#3 - c4-pre-sort

2023-10-09T17:32:06Z

141345 marked the issue as sufficient quality report

#4 - c4-sponsor

2023-10-11T10:43:00Z

OpenCoreCH marked the issue as disagree with severity

#5 - c4-sponsor

2023-10-11T10:43:05Z

OpenCoreCH (sponsor) acknowledged

#6 - c4-judge

2023-10-18T20:49:33Z

dmvt changed the severity to QA (Quality Assurance)

#7 - c4-judge

2023-10-18T22:40:30Z

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