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

Findings: 1

Award: $359.93

🌟 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
duplicate-114

Awards

359.9307 USDC - $359.93

External Links

Lines of code

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

Vulnerability details

Impact

Tick arrays like tickTracking_ can grow unbounded. Could hit gas limit.

As ticks are crossed, new TickTracking elements are pushed:

function crossTicks(
  bytes32 poolIdx, 
  int24 exitTick,
  int24 entryTick
) internal {

  tickTracking_[poolIdx][exitTick].push(
    TickTracking(block.timestamp, 0) 
  );

  tickTracking_[poolIdx][entryTick].push(
    TickTracking(block.timestamp, 0)
  );

}

There is no limit on the size of the tickTracking_ arrays. They can grow indefinitely as ticks are crossed.

This could eventually cause the contract to hit the Ethereum block gas limit by having extremely large storage arrays.

Proof of Concept

function crossTicks: https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/mixins/LiquidityMining.sol#L24-L35

The TickTracking arrays are appended to whenever a tick is crossed in the crossTicks() function:

function crossTicks(bytes32 poolId, int24 exitTick, int24 entryTick) public {

  tickTracking_[poolId][exitTick].push(
    TickTracking(block.timestamp, 0)
  );
  
  tickTracking_[poolId][entryTick].push(  
    TickTracking(block.timestamp, 0) 
  );

}

The core issue is that there is no limit on the size of these tickTracking_ arrays.

Each time crossTicks() is called, the array grows larger. There is no max length check.

Over time as ticks are crossed, the arrays could grow to enormous sizes, consuming large amounts of storage.

For example, if a pool has 2000 total ticks, and each tick is crossed 10 times per day, the tickTracking_ arrays would increase by 40,000 elements per day.

In a year that would be over 14 million elements, which could easily exceed the Ethereum block gas limit.

This is a scenario of how unbounded tickTracking_ growth could cause issues is very useful.


contract TickDoS {

  LiquidityMining liquidityMining;

  constructor(address _liquidityMining) {
    liquidityMining = LiquidityMining(_liquidityMining); 
  }

  function exploitUnboundedTickArrays() public {
  
    bytes32 poolId = 0x1234;

    for(uint i = 0; i < 50000; i++) {
      liquidityMining.crossTicks(
        poolId,
        int24(i), // Exit tick
        int24(i + 1) // Entry tick  
      ); 
    }

  }

}

This contract repeatedly calls the crossTicks() function, passing incremental ticks as the price "walks" up.

Since tickTracking_ arrays grow unbounded, this will quickly increase the array size to extreme lengths.

For example, with only 50,000 ticks crossed, the tickTracking_ arrays would contain over 100,000 elements.

At 8000 array entries per 1M gas, this would already exceed the 15M block gas limit.

And arrays would continue growing indefinitely as crossTicks() is called, eventually making the contract unusable due to gas costs.

Tools Used

Manual

Adding a limit like:

tickTracking_[poolIdx][tick].length <= MAX_TICK_TRACKING_LENGTH

Could help prevent arrays growing too large.

The unbounded growth of the tickTracking_ arrays is a potential risk.

Or

Introducing a max length check like:

require(
  tickTracking_[poolId][tick].length < MAX_LENGTH, 
  "Max length exceeded"
);

Would prevent this by capping the tick arrays at a reasonable size.

Assessed type

DoS

#0 - c4-pre-sort

2023-10-08T12:32:55Z

141345 marked the issue as duplicate of #114

#1 - c4-pre-sort

2023-10-09T16:42:15Z

141345 marked the issue as sufficient quality report

#2 - c4-judge

2023-10-18T19:29:48Z

dmvt 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