Lines of code
<https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/mixins/LiquidityMining.sol#L237-L253>
<https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/mixins/LiquidityMining.sol#L207-L221>
<https://github.com/code-423n4/2023-10-canto/blob/40edbe0c9558b478c84336aaad9b9626e5d99f34/canto_ambient/contracts/mixins/LiquidityMining.sol#L94-L153>
The whole exploit works due to similar functionality being broken at these 4 instances: here, here, here and here.
An attacker can accrue both Position time weighted liquidity and Global time weighted liquidity for both concentrated and ambient for more weeks than intended by the protocol. This results in attacker being able to claim rewards for more weeks than intended resulting in severe loss of funds to the protocol and hence the high severity.
This issue occurs because of incorrectly updating block.timestamp on first liquidity accrue.
Please refer to the below PoC which uses accrueConcentratedGlobalTimeWeightedLiquidity() function to demonstrate how an attacker can claim rewards for two weeks than one which is intended:
<https://gist.github.com/0xSandyy/8e4d325e6da65554891b69fa86fb9481>
The attack vector with the help of this PoC is explained below:
The main issue is with block.timestamp getting incorrectly updated on the first accrue as it is updated directly to the actual value here instead of being rounded down to nearest week like currWeek and nextWeek is done here.
If the attacker calls claimConcentratedRewards() in around one week after previous rewards claim, the timeWeightedWeeklyGlobalConcLiquidityLastSet_ mapping is updated for two weeks instead of one as only one week has passed and this can be proven by the test_accrueIterationMoreDueToPrecisionLoss() function in this PoC.
NOTE: The claimConcentratedRewards() donβt need to be called in exact 604800 seconds ( 1 week) and this can be tested in test_pocStillWorksWithoutExactOneWeek() function the PoC.
To set up the test file in the cloned repository run the following commands:
forge init --force
forge install openzeppelin/[email protected] --no-commit
forge fmt
Manual Analysis
To mitigate this issue, this block.timestamp on first call should be updated like this on all the four instances here, here, here and here:
./LiquidityMining.sol
timeWeightedWeeklyGlobalConcLiquidityLastSet_[poolIdx] = uint32(
(block.timestamp / WEEK) * WEEK)
);
The test_accrueIterationsMoreDueToPrecisionLossFixed() function of this PoC proves that the above fix works.
Other
The text was updated successfully, but these errors were encountered:
All reactions