Platform: Code4rena
Start Date: 14/10/2022
Pot Size: $100,000 USDC
Total HM: 12
Participants: 75
Period: 9 days
Judge: GalloDaSballo
Total Solo HM: 1
Id: 171
League: ETH
Rank: 8/75
Findings: 1
Award: $4,066.59
🌟 Selected for report: 1
🚀 Solo Findings: 0
4066.5857 USDC - $4,066.59
https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/libraries/SwapHelper.sol#L59-L65 https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBPair.sol#L329-L330 https://github.com/code-423n4/2022-10-traderjoe/blob/79f25d48b907f9d0379dd803fc2abc9c5f57db93/src/LBRouter.sol#L124-L125
LBpair contracts' fees fall short by 0.1% on single bin with the deficit growing exponentially with multi-bin swaps.
This report will refer to this difference in fees, that is, the difference between the expected fees and the actual collected fees as the "Fee Deficit".
The exponential growth of the Fee Deficit percentage is concerning, considering that the vast majority of the fees collected by LPs and DEXs are during high volatility periods. Note that the peak Fee Deficit percentage of 1.6% means that 1.6% of expected fees would not be collected.
With an assumed average total fee of 1% (higher than usual due to variableFee
component) and average Fee Deficit percentage of 0.4%;
The total Fee Deficit from a period similar to May 7th 2022 - May 14th 2022, with approximately $1.979B in trading volume, would be $79,160 over one week.
SwapHelper.getAmounts carries most of the blame for this error.
3 main causes have been identified and will be discussed in this report.
LBPair.sol
LBRouter.sol
SwapHelper.sol
FeeHelper.sol
SwapHelper.sol
LBRouter.sol
LBPair.sol
As mentioned earlier, most issues arise from SwapHelper.getAmounts . The SwapHelper library is often used for the Bin type. (Example in LBPair). The proposed solution includes the new functions SwapHelper.getAmountsV2 and FeeHelper.getAmountInWithFees.
LBPair.swap uses _bin.getAmounts(...) on the active bin to calculate fees. (See here)
Inside of SwapHelper.getAmounts, for a given swap, if a bin has enough liqudity, the fee is calculated using (FeeHelper.getFeeAmountFrom). This results in smaller than expected fees.
LBRouter.getSwapOut relies on SwapHelper.getAmounts to simulate swaps. Its simulations adjust to the correct fee upon using SwapHelper.getAmountsV2 (LBRouter.getSwapOut, SwapHelper.getAmounts, SwapHelper.getAmountsV2)
LBRouter.getSwapIn has a fee calculation error which is independent of SwapHelper.getAmounts. (See here)
As of right now the LBPair.swap using getAmountsV2 uses 3.8% more gas.
Will now use example numbers:
fees = fp.getFeeAmountDistribution(fp.getFeeAmount(_maxAmountInToBin)); if (_maxAmountInToBin + fees.total <= amountIn) { //do things }
_maxAmountInToBin
before doing so on amountIn
means we are not checking to see whether amountIn
afterConsider the following:
fees = fp.getFeeAmountDistribution(fp.getFeeAmount(amountIn)); if (_maxAmountInToBin < amountIn - fees.total) { //do things }
amountIn
._maxAmountInToBin < amountIn
.LBRouter.getSwapIn(, amountOut, )
needs this question answered. At a given price, how many tokens must a user send, to receive amountOut
?
amountOut
and price to work backwards to the amountInToBin
.amountInToBin
. (See here)amountIn
. (As we discussed in Incorrect use of getFeeAmountFrom)SwapHelper.getAmounts needs to know what hypothetical amountIn
would end up as maxAmountInToBin
after fees. This is needed to be able to avoid Incorrect amountIn overflow
To install dependencies, run the following to install dependencies:
forge install
To run tests, run the following command:
forge test --match-contract Report -vv
#0 - 0x0Louis
2022-10-31T16:48:27Z
(clicked too fast, didn't mean to remove the risk tag)
#1 - GalloDaSballo
2022-11-14T14:11:51Z
The warden has shown an incorrect application of the fee formula, which results in an exponentially growing reduction in fees taken.
While the report is thorough, the maximum impact is a loss of up to 2% of the total fees (98% of fees are collected).
Because of the reduced order of magnitude for the impact, I think the appropriate severity to be Medium as the finding will cause a loss of yield as shown by the Warden.
#2 - c4-judge
2022-11-14T14:12:02Z
GalloDaSballo changed the severity to 2 (Med Risk)
#3 - c4-judge
2022-11-14T14:12:08Z
GalloDaSballo marked the issue as primary issue
#4 - c4-judge
2022-11-16T21:31:42Z
GalloDaSballo marked the issue as selected for report