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

Findings: 3

Award: $1,112.65

Analysis:
grade-b

🌟 Selected for report: 1

🚀 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
edited-by-warden
duplicate-114

Awards

467.9099 USDC - $467.91

External Links

Lines of code

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

Vulnerability details

Impact

Attempts to mint, burn and harvest positions will fail if the concentrated position is across many ticks. This is caused by calls to accrueConcentratedGlobalTimeWeightedLiquidity will always revert as it will exceed the gas limit.

Proof of Concept

The accrue function iterates through every tick in a concentrated liquidity position aside from the first 10 ticks and the last 10 ticks. However, according to current intended configurations of 1bps ticks, a full range tick position will go from min tick of -887272 to max tick of 887272. There is no filter which ensures that this loop iteration is only performed on positions with a small number of ticks.

Performing an iteration loop (887272 * 2 - 20) times will inevitably lead to an 'out-of-gas' error.

There are elements in the loop that will consume gas:

  1. The loop iteration itself.
  2. Reading from storage (tickTracking_[poolIdx][i].length, tickTracking_[poolIdx][i][numTickTracking - 1].exitTimestamp).
  3. Writing to storage (tickTrackingIndexAccruedUpTo_[poolIdx][posKey][i]).

Users often put such wide liquidity widths in concentrated liquidity DEX's such as Uniswap v3 and Ambient. However, ever much more narrower positions have many ticks because each tick is only 1 bps wide.

Tools Used

Manual Review

The rewards program was initially designed for stable pools. Incentives could be targeted to a liquidity range that assumes that the assets will stay pegged to the stable price during the week. Instead of iterating through every tick, the depth of liquidity can be calculated by the formula:

liquidity * time /(upper_tick - lower_tick)

upper_tick - lower_tick returns the "width" of the liquidity position and is hence inversely proportional to the concentration. Dividing by this number means that the CANTO rewards distribution are adjusted for the concentration and hence only the in-range liquidity.

Assessed type

Loop

#0 - c4-pre-sort

2023-10-09T15:59:57Z

141345 marked the issue as duplicate of #114

#1 - c4-pre-sort

2023-10-09T16:43:01Z

141345 marked the issue as sufficient quality report

#2 - c4-judge

2023-10-18T19:29:13Z

dmvt marked the issue as satisfactory

#3 - twicek

2023-10-21T00:43:20Z

Two reports are duplicated for this warden #82 and #114, the issue will only be counted once, right?

#4 - piken

2023-10-21T16:41:38Z

I left a comment in #114. My opinion is that these are two different problems and should not be identified as duplicate.

Findings Information

🌟 Selected for report: Banditx0x

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

Labels

bug
3 (High Risk)
primary issue
selected for report
sponsor confirmed
sufficient quality report
edited-by-warden
H-01

Awards

467.9099 USDC - $467.91

External Links

Lines of code

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

Vulnerability details

Impact

A malicious user can brick minting, burning and harvesting of liquidity for almost all liquidity providers.

Important NOTE: This is a different vector from another gas issue, which is iterating over too many ticks in (int24 i = lowerTick + 10; i <= upperTick - 10; ++i). That issue affects wide liquidity positions, while this attack vector affects even liquidity positions with a relatively small number of ticks.

Proof of Concept

When accrueConcentratedPositionTimeWeightedLiquidity is called, under most conditions, for every potentially eligible tick, it will iterate over every tickTrackingData in tickTracking:

while (time < block.timestamp && tickTrackingIndex < numTickTracking)

tickTracking is iterated by tickTrackingIndex++;

The array mapped by tickTracking_ is increased by 1 for a tick every time a trade through the liquidity pool changes the price from a different tick to this tick. This is implemented in the crossTicks function:

    function crossTicks(
        bytes32 poolIdx,
        int24 exitTick,
        int24 entryTick
    ) internal {
        uint256 numElementsExit = tickTracking_[poolIdx][exitTick].length;
        tickTracking_[poolIdx][exitTick][numElementsExit - 1]
            .exitTimestamp = uint32(block.timestamp);
        StorageLayout.TickTracking memory tickTrackingData = StorageLayout
            .TickTracking(uint32(block.timestamp), 0);
        tickTracking_[poolIdx][entryTick].push(tickTrackingData);
    }

A user could purposely increase the length of the tickTracking_ array and hence cause the gas limit to be reached whenever the array is looped over.

The price impact required to cross a tick is from 0 to 1 bps, as 1 bps as the tick width. This is already extremely small, but the attacker could have the swap amount be a very small fraction of a bps if they first swap to make the price end very close to a tick boundary, and then execute multiple extremely small swaps which bounce the price back and forth over the tick boundary.

Note that the CANTO liquidity rewards are targeted to stable pools. An attacker can be quite confident, for example, that a USDC/USDT pool will trade at around $1, and the ticks closest to $1 will always be eligible for rewards and therefore be looped over by all rewardable positions when accrueConcentratedPositionTimeWeightedLiquidity is called. Therefore the attack can be targeted to just one or two ticks to affect almost every user.

accrueConcentratedPositionTimeWeightedLiquidity is called during minting, burning and harvesting liquidity positions. Therefore this gas griefing attack will make all these functions revert, for almost every user. This would basically break the functionality of concentrated liquidity pools on Ambient.

Contrast the effect to the cost to the attacker: using the aforementioned attack vector the main cost to the attacker will be the gas costs of performing the swaps. This is far lower than the damage that is done to the protocol/users

One additional factor which makes this attack easy to execute that crossing ticks even if the entry and exit is within the same block.timestamp adds to the array length. Tracking this is unnecessary, because the tick was active for 0 blocks, and therefore the time delta and hence allocated rewards is zero.

Tools Used

Manual Review

One immediate step would to pop() tickTrackingData as soon as the exitTimestamp == entryTimestamp. This happens to the last element of the array when crossTicks is called. Tracking this is unnecessary, because the tick was active for 0 blocks, and therefore the time delta and hence allocated rewards is zero.

The documentation stated that CANTO rewards are meant to be distributed for stable pools for this codebase. The term "stable" could have different interpretations, but this reccomendation assumes that this refers to stablecoin-like or pegged asset pairs such as stETH/WETH, USDT/USDC etc.

Instead of iterating through every tick, one could assume a range where the stable assets could lie and then reward all positions that lie within the specified range - in this case +- 10 ticks of the price tick.

This makes an assumption that these "stable assets" will actually stay pegged to each other. However, the current accounting architecture has multiple problems:

  • Given the high number of loops required by the current accounting mechanism, there are multiple reasons that gas could run out. This includes iterating through too many ticks or having too many tick entries/exits

  • The current mechanism increases the gas costs of all minting, burning and harvesting

  • DOS attacks like the one described in this issue are possible.

Assuming a stable price has the downside of misallocating rewards if the stable assets depeg from each other. However, this may be a reasonable tradeoff to prevent this DOS attack.

Assessed type

DoS

#0 - c4-pre-sort

2023-10-08T04:09:32Z

141345 marked the issue as primary issue

#1 - c4-pre-sort

2023-10-09T16:37:39Z

141345 marked the issue as sufficient quality report

#2 - c4-sponsor

2023-10-11T09:02:35Z

OpenCoreCH (sponsor) confirmed

#3 - c4-judge

2023-10-18T19:28:54Z

dmvt marked the issue as selected for report

#4 - piken

2023-10-21T16:35:21Z

I believe that above findings should be grouped two High Risk problems instead of one:

  • malicious tickTracking_ manipulation #114, #68, #221, #253, #276, #61, #11
  • tick iteration flaw #201, #215, #235, #82 The root causes of two grouped problems come from different attack vectors:
  • for malicious tickTracking manipulation, malicious user can quickly increase the length of the tickTracking_ array to make almost every accrueConcentratedPositionTimeWeightedLiquidity() fail due to out of gas caused by tickTracking_ iteration.
  • On the contrary, tick iteration flaw can be produced without any attack from malicious user. As soon as user operates their position in wide tick range, the problem will be produced. I think Banditx0x has described these two problems clearly since he found both two problems: #114 for malicious tickTracking_ manipulation and #82 for tick iteration flaw.

@dmvt Could you take a look at it?

#5 - dmvt

2023-10-21T22:13:03Z

Thanks for the detail provided in your reasoning. To my eye, these are close enough in terms of reason, impact, and resolution to be in effect two different reasons that the same issue (gas limit exceeded in that specific loop) occurs. Many reported issues in every contest I've judged would be split if I allowed for "this can happen accidentally" and "a malicious user can cause this to happen" to be justification for doing so. In my view, for an issue to be distinct with the same code, the attack vector and resolution have to be meaningfully different. That the resolution could be different is not enough. Ruling stands.

#6 - Banditx0x

2023-12-02T23:08:20Z

@dmvt I do not have backstage as my KYC is not going through so I couldn't escalate this issue. Despite this, someone else escalated without my prompting as these are indeed two seperate issues. My report was the selected submission which demonstrates that I did put alot of thought into these submissions.

Here's a simple explanation to demonstrate just how incredibly different these two scenarios are

Difference in Reason:

This submission works by increasing the number of swaps in a liquidity tick which is in the reward range.

Submission #82 is based on the number of ticks for the reward range.

Difference in Impact:

This submission can be a purposeful DOS which applies to a reward range with any number of ticks.

Submission #82 only applies to situations with a wide range of liquidity. It is not possible to create an out-of-gas error with low-number-of-tick liquidity positions with that issue.

Difference in Resolution:

The solution here is to pop some of the tickTracking data needs to be iterated through. Note that tickTracking is NOT the same as ticks. tickTracking is related to number of SWAPS not number of TICKS.

The solution to #82 concerns limiting the number of TICKS that are iterated through.

Different parts of code:

This concerns iterating through the tickTracking. The other submission concerns iterating through ticks.

I did mention these differences in both submissions.

Findings Information

🌟 Selected for report: kutugu

Also found by: Banditx0x, sces60107

Labels

bug
2 (Med Risk)
downgraded by judge
partial-50
sponsor disputed
sufficient quality report
edited-by-warden
duplicate-177

Awards

609.5458 USDC - $609.55

External Links

Lines of code

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

Vulnerability details

Impact

Users get rewarded even for liquidity that is outside of the specified reward ticks, resulting in massive over-allocation of rewards.

This means the reward formula does not fulfil its purpose of incentivising a particular liquidity range/concentration suitable for stable pools. The stable pool reward formula is meant to reward the liquidity concentrated around a narrow within 10 ticks of the stable price, as this is where all the trading is likely to occur.

Proof of Concept

Summary: When concentrated interest is accrued liquidity of a position is calculated by uint256 liquidity = pos.liquidity_; which includes all liquidity, including that which lies outside of the specified reward range. This is in contrast to using uint256 liquidity = curve.concLiq_; which gives the concentrated liquidity in the active tick or adjusting the total liquidity by dividing by the "width" (upperTick - lowerTick) of the position.

According to the specification, the reward program is only supposed to reward the in-range liquidity, within 10 ticks of the current price.

From the ReadMe: "As Canto plans to use LiquidityMining to incentivize stable pools, the range currentTick-10 to currentTick+10 is incentivized."

The reward logic rewards all the liquidity positions that are superset of that range, but also allocates rewards to the liquidity portion outside of that range.

For each position, it iterates through every tick between the lowest 10 and highest 10 ticks:

(int24 i = lowerTick + 10; i <= upperTick - 10; ++i)

For each tick, it checks the tracked tick history. Then, the rewards are added based on the time the tick was active multiplied by the liquidity:

timeWeightedWeeklyPositionInRangeConcLiquidity_[poolIdx][posKey][currWeek][i] +=
                            (tickActiveEnd - tickActiveStart) * liquidity;

The liquidity variable was retrieved from uint256 liquidity = pos.liquidity_;. This liquidity contains sqrt(X*Y) where X and Y are the quantities of the two tokens in the liquidity position. However, there is no adjustment for the liqudity concentration.

Lets say a liquidity position is 1000 ticks wide, and the liqudity supersets the reward range. Only 21 ticks of liquidity is within the reward range, which is ~2% of the entire liqudiity amount. However, since the liquidity is proportional to the enitre pos.liquidity this user gets allocated 49.5x the rewards that they should.

Tools Used

Manual Review

We can adjust for the concentration of liquidity by multiplying the liquidity by the number of ticks in the reward range divided by the number of ticks in the concentrated liquidity position:

conecntrationAdjustedLiquidity =liquidity * 21 / (upperTick - lowerTick)

The rewards should be proportional to the concentrationAdjustedLiquidity instead of the original liquidity variable.

Assessed type

Math

#0 - c4-pre-sort

2023-10-08T03:42:28Z

141345 marked the issue as primary issue

#1 - 141345

2023-10-09T13:22:40Z

The issue here is the flawed way to count eligible liquidity as reward base, focus is overall liquidity in global.

https://github.com/code-423n4/2023-10-canto-findings/issues/98 describes the problem in different aspects.

#2 - c4-pre-sort

2023-10-09T16:45:55Z

141345 marked the issue as sufficient quality report

#3 - OpenCoreCH

2023-10-13T11:02:28Z

Responding to this and #98 here:

The warden seems to assume that curve.concLiq_ is influenced by the width of a position, which is not the case. If someone creates a position with range [0, 1000] and liq. 100 or [480, 520] with liq. 100, curve.concLiq_ will be 100 in both cases when the active tick is 500 (and not 0.1 & 2.5, which seems to be the assumption of the warden). This can be seen in TradeMatcher, LevelBook, and LiquidityMath. The logic is not that simple, but the high level summary is that we store for every tick the liquidity (lots) of positions that have the lower / upper tick here (lvl.bidLots_, lvl.askLots_). When a tick is then crossed, the whole liquidity is added or removed from curve.concLiq_. However, it can also be easily verified by looking at our test. If the assumption of the warden were true, the user in the test (that has a position with width 30) would not receive 100% of the rewards, but only 1/30. Because concLiq_ works this way, the recommendation of the warden would break the system.

Something that is true is point 1 from #98. If a user has a very narrow position (less than 21 ticks), it still contributes to curve.concLiq_.

#4 - c4-sponsor

2023-10-13T11:02:36Z

OpenCoreCH (sponsor) disputed

#5 - c4-judge

2023-10-18T11:19:59Z

dmvt marked issue #177 as primary and marked this issue as a duplicate of 177

#6 - c4-judge

2023-10-18T11:20:06Z

dmvt changed the severity to 2 (Med Risk)

#7 - c4-judge

2023-10-18T11:22:07Z

dmvt marked the issue as partial-50

Findings Information

🌟 Selected for report: kutugu

Also found by: Banditx0x, sces60107

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
sufficient quality report
edited-by-warden
duplicate-177

Awards

609.5458 USDC - $609.55

External Links

Lines of code

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

Vulnerability details

Impact

The rewards are not divided based on the in-range liquidity of eligible positions but also include eligible positions.

The overallInRangeLiquidity and inRangeLiquidityOfPosition have a non-corresponding basis for determining liquidity leading to a miscalculation of rewards

The rewards allocated could exceed the weekly allocated rewards, leading to reward insolvency.

Proof of Concept

When accrueConcentratedGlobalTimeWeightedLiquidity is called, liquidity is determined by:

uint256 liquidity = curve.concLiq_;

The NatSpec comments for the struct CurveState state:

"@param concLiq The total concentrated liquidity active and in range at the current state of the curve."_

Therefore the rewards are divided by the time-aggregated global liquidity, which is the sum of average liquidity active in a tick times the time it was active.

There are 2 problems with this:

Problem 1:

There are non-rewarded positions which are affect the curve.concLiq_; variable, such as liquidity positions that include the active tick but do not superset the tick range which is eligible for rewards. For example, if a user provided a large amount of liquidity concentrated between ticks current_tick - 5 and current_tick + 5, the liqudity would be ineligible for rewards as it does not cover the entire 21 tick range neccessary to qualify for rewards. However, the liquidity will add to uint256 liquidity = curve.concLiq_; which will in turn dilute rewards for current positions.

Problem 2:

The rewards for global liquidity are calculated based on the current tick, while the rewards calculated for individual position liquidity via accrueConcentratedPositionTimeWeightedLiquidity are calculated based on the entire liquidity of a position - uint256 liquidity = pos.liquidity_;, regardless of what tick those positions are. The entire liquidity can deviate massively from a linear correlation to the active liquidity.

For example:

Alice has 50 tokens each of liquidity distributed over 100 ticks. Bob has the same amount of tokens distributed of 10000 ticks. Both of the liquidity ranges cross the "active" liquidity threshold. Even though Bob and Alice have the same liquidity calculated by pos.liquidity used in accrueConcentratedPositionTimeWeightedLiquidity, Alice has 100x the liquidity in the active tick, which is used in curve.concLiq_; in accrueConcentratedGlobalTimeWeightedLiquidity.

When rewards are claimed, the rewards are calculated by WeeklyTotalRewards * InRangeLiquidity / GlobalLiquidityByTime

rewardsToSend += inRangeLiquidityOfPosition * concRewardPerWeek_[poolIdx][week] / overallInRangeLiquidity;

There is an expected invariant that the sum of all inRangeLiquidityOfPosition divided by overallInRangeLiquidity is less than 1. If this invariant is broken, then the aggregate rewards distributed will exceed the total concentrated reward pool per week (concRewardPerWeek_[poolIdx][week]). Since the liquidity basis for individual positions differs from the liquidity calculation basis for the global liquidity, this invariant is broken.

Tools Used

Manual Review

Three suggested changes:

  1. Only eligible liquidity positions should be included for the globalLiquidity used for rewards distribution.

  2. The global liquidity calculation should be adjusted to ensure that the global eligible liquidity is greater or equal to the sum of all liquidity positions. Otherwise the rewards allocated would exceed the weekly allocated rewards, leading to reward insolvency.

  3. Rewards for individual positions should be adjusted for tick size. pos.liquidity should be divided by upperTick - lowerTick

Assessed type

Math

#0 - c4-pre-sort

2023-10-08T03:54:32Z

141345 marked the issue as duplicate of #94

#1 - c4-pre-sort

2023-10-09T13:25:27Z

141345 marked the issue as not a duplicate

#2 - c4-pre-sort

2023-10-09T13:25:32Z

141345 marked the issue as primary issue

#3 - c4-pre-sort

2023-10-09T13:34:42Z

141345 marked the issue as duplicate of #94

#4 - c4-pre-sort

2023-10-09T16:46:14Z

141345 marked the issue as sufficient quality report

#5 - c4-judge

2023-10-18T11:20:06Z

dmvt changed the severity to 2 (Med Risk)

#6 - c4-judge

2023-10-18T11:22:25Z

dmvt marked the issue as satisfactory

Findings Information

Labels

analysis-advanced
grade-b
sufficient quality report
A-04

Awards

35.1935 USDC - $35.19

External Links

Contextualising my Findings

A Nuance in Ambient Liquidity Causes Incorrect Reward Accounting - My Favourite Finding

The CANTO scope was short in terms of lines of code but large in terms of background knowledge. The ambient finance contracts are not well known by auditors, as mentioned by the sponsor. When I read into the documentation I noticed a key fact:

"The first advantage is that instead of accumulating fees in a separate side-pocket, fees accumulated by ambient LP positions auto-compound back into the original position without any manual management"

The CANTO rewards system is designed to accrue interest before every change in liquidity amount, such as before minting and burning functions. However, due to fees compounding and increasing the liquidity position the invariant that the liquidity amount between different accrual periods is broken. This is further elucidated in my issue:

"Fee Compounding is Over-rewarded in Ambient Liquidity Positions"

Gas Problems

There are problems with the gas consumption of the contract. The calls to functions like crossTick when a swap is a cost which affects every swap. This cost is imposed every time the price impact causes a price tick is crossed. With a price tick of only 1 bps, this will happen extremely frequently. The first consequence is that the gas for every swap over a liquidity pool is increased slightly. The second consequence is explained in one of my issues:

"Array Length of tickTracking_ Can be Purposely Increased to Brick Minting and Burning of Most Users' Liquidity Positions"

This issue concerns the fact that every time a tick is entered, the array for tickTrading_ increases by one. By repeatedly making small swaps back and forth across a tick, an attacker can cause the array for a particular tick to grow large. This array is iterated over every time other users call mint and burn, and making the array very large will cause these critical functions to revert due to out of gas.

The second seperate issue with gas concerns the iteration over many ticks for "wide" liquidity positions. The program actually loops through every tick in a liquidity position, except the first 10 and last 10. There can be over 160000 ticks in a liquidity position! Iterating over a loop so many times will cause an out of gas error which is my second gas issue:

"Gas Limit Exceeded Due to Iterrating Through Almost Every Tick"

Accounting Issues

There were 2 accounting issues:

"Calculation For Overall Liquidity Includes Ineligible Positions and Does Not Correspond With the Calculation For Individual Liquidity Positions"

This concerns the overallLiquidity tracking including ineligible positions when only eligible positions should be counted towards the global liquidity.

The next issue:

"Concentrated Pool Rewards are Proportional to The Entire Liquidity Amount For Any Eligible Positions, Even if That Liquidity Is Out of The Reward Range"

This concerns the entire liquidity amount being used for reward calculation rather than just tick based liquidity or in-reward-range liquidity.

Architechtural considerations:

Accounting

Here are three suggested changes to the accounting architecture. This is to address some of the problems raised in the issue submissions.

  1. Only eligible liquidity positions should be included for the globalLiquidity used for rewards distribution.

  2. The global liquidity calculation should be adjusted to ensure that the global eligible liquidity is greater or equal to the sum of all liquidity positions. Otherwise the rewards allocated would exceed the weekly allocated rewards, leading to reward insolvency.

  3. Rewards for individual positions should be adjusted for tick size. pos.liquidity should be divided by upperTick - lowerTick

Gas

There is a larger overall design issue which is the decision to do on-chain liquidity mining by adding calls to reward accounting functions to every swap, mint and burn for a liquidity pool. This is extremely gas intensive and could affect the normal functioning of the protocol. It may even cause important functions to revert.

One simple solution can be done by off-chain rewarding. Perpetual Protocol, which is a concentrated liquidity Perpetual AMM built on-top of Uniswap v3, used off-chain calculations for their liquidity mining program: [LINK].(https://perpprotocol.mirror.xyz/0C9AYnB93z5AZ4c-phO8Wg7jXRFYLt3e9TiZ2VH3DLw) This has huge centralisation downsides, which may go against CATNO's ethos but is the simplest gas solution. Obviously, this is not a smart contract solution so may automatically be unacceptable.

The gas problems may have to be addressed through a complete architectural redesign rather than just normal gas optimisation. Here are some suggestions:

One immediate step would to pop() tickTrackingData as soon as the exitTimestamp == entryTimestamp. This happens to the last element of the array when crossTicks is called. Tracking this is unnecessary, because the tick was active for 0 blocks, and therefore the time delta and hence allocated rewards is zero.

The documentation stated that CANTO rewards are meant to be distributed for stable pools for this codebase. The term "stable" could have different interpretations, but this reccomendation assumes that this refers to stablecoin-like or pegged asset pairs such as stETH/WETH, USDT/USDC etc.

Instead of iterating through every tick, one could assume a range where the stable assets could lie and then reward all positions that lie within the specified range - in this case +- 10 ticks of the price tick.

This makes an assumption that these "stable assets" will actually stay pegged to each other. However, the current accounting architecture has multiple problems:

  • Given the high number of loops required by the current accounting mechanism, there are multiple reasons that gas could run out. This includes iterating through too many ticks or having too many tick entries/exits

  • The current mechanism increases the gas costs of all minting, burning and harvesting

  • DOS attacks like the one described in this issue are possible.

Assuming a stable price has the downside of misallocating rewards if the stable assets depeg from each other.

Time spent:

25 hours

#0 - c4-pre-sort

2023-10-09T17:24:47Z

141345 marked the issue as sufficient quality report

#1 - c4-judge

2023-10-19T16:30:58Z

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