Platform: Code4rena
Start Date: 03/10/2023
End Date: 06/10/2023
Period: 3 days
Status: Completed
Pot Size: $24,500 USDC
Participants: 62
Reporter: thebrittfactor
Judge: LSDan
Id: 288
League: ETH
maanas | 1/62 | $3,294.78 | 2 | 1 | 0 | 1 | 1 | 0 | 0 | 0 |
Satyam_Sharma | 2/62 | $2,934.85 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
ni8mare | 3/62 | $2,934.85 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
adriro | 4/62 | $1,782.52 | 3 | 1 | 0 | 1 | 0 | Grade A | 0 | 0 |
Banditx0x | 5/62 | $1,112.65 | 3 | 1 | 0 | 1 | 0 | 0 | 0 | Grade B |
HChang26 | 6/62 | $1,020.85 | 2 | 0 | 0 | 1 | 0 | Grade B | 0 | 0 |
kutugu | 7/62 | $797.35 | 2 | 0 | 0 | 1 | 0 | Grade B | 0 | 0 |
sces60107 | 8/62 | $614.49 | 2 | 0 | 0 | 1 | 0 | Grade B | 0 | 0 |
0xweb3boy | 9/62 | $386.19 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | Grade A |
0xDING99YA | 10/62 | $364.87 | 2 | 1 | 0 | 0 | 0 | Grade B | 0 | 0 |
Auditor per page
❗️Awarding Note for Wardens, Judges, and Lookouts: If you want to claim your awards in $ worth of CANTO, you must follow the steps outlined in this thread; otherwise you'll be paid out in USDC.
Automated findings output for the audit can be found here within 24 hours of audit opening.
Note for C4 wardens: Anything included in the automated findings output is considered a publicly known issue and is ineligible for awards.
Canto is releasing a new liquidity mining feature, built specifically for Ambient Finance.
We are implementing the feature as a sidecar contract that plugs into Ambient using their proxy contract pattern.
To implement liquidity mining, we introduce 2 new contracts:
LiquidityMiningPath.sol
(provides interfaces for users to interact with the contract)LiquidityMining.sol
(provides all of the logic)The LiquidityMining sidecar was built to implement a liquidity mining protocol for Ambient. Canto plans to use this sidecar to incentivize liquidity for Ambient pools deployed on Canto.
The LiquidityMining sidecar works by incentivizing a specific width of liquidity, based on the current tick. As Canto plans to use LiquidityMining to incentivize stable pools, the range currentTick-10 to currentTick+10 is incentivized. This means that the range in which a user provides liquidity must be a superset of [currentTick-10, currentTick+10] in order for them to receive incentives. If the user's range only includes part of [currentTick-10, currentTick+10], they will not receive incentives. In total, the user must be providing liquidity across at least 21 ticks (the current tick, and 10 on either side).
It is expected that users will provide liquidity with a small buffer on either side of the range to ensure they will always be receiving rewards, even in the case of small price movements.
From a high level, the idea behind the liquidity mining sidecar is to track the time weighted liquidity (global and per-user) for ambient & concentrated (per tick) positions. This enables the protocol to calculate the percentage of in-range liquidity that was provided by a user over a time span and then pays out this percentage of the global rewards to the user.
Let's look at a simple example. If the rewards for 1 week are 10 CANTO, and only LP A
is providing liquidity to the protocol, thenLP A
will receive all 10 CANTO as their reward.
If there are 2 liquidity providers, LP A
and LP B
, and they each provide liquidity for the entirety of the week, they will split the rewards in half and each receive 5 CANTO.
These functions are used to set the weekly reward rate for the liquidity mining sidecar. Reward rates are set by determining a total amount that will be disbursed per week. Governance can choose how many weeks that the reward rate will be set for.
LiquidityMining.sol
contains all of the logic for accruing and claiming rewards. This is the most important part of the codebase and should be the main focus for wardens.
Contract | SLOC | Purpose | Libraries used |
---|---|---|---|
canto_ambient/contracts/callpaths/LiquidityMiningPath.sol | 19 | This contract provides the interface for the CrocSwapDex contract to call with userCmd and protocolCmd | SafeCast |
canto_ambient/contracts/mixins/LiquidityMining.sol | 126 (before formatter) | This contract contains the logic used for liquidity mining | SafeCast |
All other contracts are out of scope. However, for the purpose of this audit, it will be useful to understand other Ambient Finance contracts.
Ambient is a single-contract dex that allows liquidity providers to deposit "ambient" liquidity (uniV2 style) or concentrated liquidity (uniV3 style) into any token pair.
The main contract in Ambient Finance is CrocSwapDex
. This is the only contract that users will ever need to interface with.
Ambient uses proxy contracts called "sidecars" which contain all of the logic that doesn't fit in CrocSwapDex
due to the EVM contract limit. Sidecar contracts are modular in nature and each one is responsible for a unique function.
Sidecar Contracts:
To interact with Ambient, users must send ABI encoded parameters to the CrocSwapDex. For all actions that can be made by users, the userCmd
function is used. For things related to governance, the protocolCmd
function is used.
The userCmd
and protocolCmd
function signatures are as shown:
function protocolCmd (uint16 callpath, bytes calldata cmd, bool sudo) function userCmd (uint16 callpath, bytes calldata cmd)
The callpath
parameter is used to determine which sidecar contract to send the cmd to.
Sidecar paths are defined below:
uint16 constant BOOT_PROXY_IDX = 0; uint16 constant SWAP_PROXY_IDX = 1; uint16 constant LP_PROXY_IDX = 2; uint16 constant COLD_PROXY_IDX = 3; uint16 constant LONG_PROXY_IDX = 4; uint16 constant MICRO_PROXY_IDX = 5; uint16 constant MULTICALL_PROXY_IDX = 6; uint16 constant KNOCKOUT_LP_PROXY_IDX = 7; uint16 constant LIQUIDITY_MINING_PROXY_IDX = 8; uint16 constant FLAG_CROSS_PROXY_IDX = 3500; uint16 constant SAFE_MODE_PROXY_PATH = 9999;
For example, if a user wanted to provide liquidity (which is handled by WarmPath), they would call the userCmd
function with callpath
set to 2.
cmd
is an ABI encoded calldata that is fed to the sidecar contract specified by callpath
. The sidecar will parse the ABI encoded parameters in order to get all of the parameters necessary for the specific action that is desired.
The first parameter that is encoded into cmd
will always be the code
. code
is used to determine which specific function inside the sidecar will be called.
Continuing the example from above, if a user wanted to provide liquidity, they call the WarmPath using code
11, which would would trigger the mintConcentratedQty()
function inside WarmPath.
Here is a sample transaction to provide liquidity, scripted in JS.
const CrocSwapDex = await hre.ethers.getContractFactory("CrocSwapDex"); const dex = await CrocSwapDex.attach(dexAddress); const currentTick = 276324; const ZERO_ADDR = "0x0000000000000000000000000000000000000000"; // Mint concentrated liquidity let mintConcentratedLiqCmd = abi.encode( [ "uint8", "address", "address", "uint256", "int24", "int24", "uint128", "uint128", "uint128", "uint8", "address", ], [ 11, // <== CODE (call function mintConcentratedQty in WarmPath) cNoteAddress, // base token usdcAddress, // quote token 36000, // poolIDX currentTick - 10, // tickLower currentTick + 10, // tickUpper BigNumber.from("5000000000000000000"), // amount of base token to send BigNumber.from("16602069666338596454400000"), // min price BigNumber.from("20291418481080506777600000"), // max price 0, // reserve flag ZERO_ADDR, // lp conduit address (0 if not using) ] ); // use callpath 2 to send cmd to WarmPath, which handles liquidity management tx = await dex.userCmd(2, mintConcentratedLiqCmd, { gasLimit: 6000000 });
LiquidityMining.sol
are called)The following lines are not in Scope. They're provided to easily see how the integration works.
Liquidity Mining Hooks | Line Number | Purpose |
---|---|---|
canto_ambient/contracts/mixins/MarketSequencer.sol | 244 | Initializes tick tracking |
canto_ambient/contracts/mixins/TradeMatcher.sol | 67-68, 103-104, 140-142, 177-178, 244, 270, 342, 440-443, 486 | Logic to accrue rewards on dex actions such as minting and burning liquidity |
Question | Answer |
---|---|
Repository | https://github.com/Canto-Network/CrocSwap-protocol/tree/audit-final |
How many contracts are in scope | 2 |
Total SLoC for these contracts | 145 |
How many external imports are there? | 3 |
How many separate interfaces and struct definitions are there for the contracts within scope? | 1 |
Does most of your code generally use composition or inheritance? | Inheritance |
How many external calls | 0 |
What is the overall line coverage percentage provided by your tests?: | 75 |
Please describe required context: | |
Are there any novel or unique curve logic or mathematical models?: | n/a |
Upgrade of existing system? | False - |
"All that apply" checked: | AMM, ERC-20 Token |
Need to understand other part of codebase: | Yes - |
Other codebase context | This is a liquidity mining protocol for Ambient Dex. As such, an understanding of Ambient Dex will be very helpful for this audit. However, it is not necessary to understand all parts of Ambient. Just an understanding of how providing liquidity works will be sufficient. |
Oracle | No - |
Fork? | False |
If fork, describe your customizations/differences: | |
Unique logic | concentrated liquidity (uni v3 style) |
Does it use a side chain? | False |
If yes, is it EVM-compatible? | |
Areas to focus on/break | This LM protocol will be used to incentivize pools on Canto. We would like to ensure that the amount of incentives released is exactly as we specify and the wallets who receive the incentives are the correct ones (LPing the correct ranges) |
One-Liner: cd canto_ambient && yarn install && npx hardhat compile && npx hardhat test
Check canto_ambient/README.md