Platform: Code4rena
Start Date: 07/09/2022
Pot Size: $20,000 CANTO
Total HM: 7
Participants: 65
Period: 1 day
Judge: 0xean
Total Solo HM: 3
Id: 159
League: ETH
Rank: 22/65
Findings: 2
Award: $146.62
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: hickuphh3
Also found by: 0xNazgul, 0xSky, CertoraInc, Deivitto, Jeiwan, SinceJuly, hansfriese, linmiaomiao, rbserver
664.9949 CANTO - $107.40
Note: I'll use the notation
decimals
here to represent10 ** token.decimals()
, just like th variable defined in theBaseV1Router.getPriceLP()
function.
In the BaseV1Router.getPriceLP()
function, the token0 TVL is calculated in terms of NOTE, by multiplying the TVL in terms of TOKEN, by the price of it in terms of NOTE and dividing by decimals
.
uint token0TVL = assetReserves[i] * (prices[i] / decimals);
However, the price is first divided by decimals
first, and then multiplied by the TVL, which can cause data loss in the division.
We have 2 cases of data loss here:
decimals
, then some data can get loss, but the TVL will remain positive.decimals
. Here the calculation of prices[i] / decimals
will be zero and the whole TVL calculation will be zero.Now, this calculation is done 8 times, for each sample of the TVLs and prices, so each data loss here has 1/8 of the actual effect to the TVL. However, most of the time the price won't change that match (because the samples are taken every 30 minutes) and the average will be zero very fast.
The low TVL can lower the LP token's price, and can cause collateral value loss and probably wrong liquidations.
Let's assume the TVL (in one sample) in the CANTO/NOTE
pool is 50e18
. Now I'll show an example for both of the cases:
2.5 NOTE per CANTO
(> 1e18) (i.e. the price will be 2.5e18
).
The TVL in terms of NOTE will be calculated as such:
50e18 * (2.5e18 / 1e18) = 50e18 * 2 = 100e18
The TVL in this sample will be 100e18
instead of 125e18
, which is pretty bad.0.5 NOTE per CANTO
(<> 1e18) (i.e. the price will be 0.5e18 = 5e17
).
The TVL in terms of NOTE will be calculated as such:
50e18 * (0.5e18 / 1e18) = 50e18 * 0 = 0
The TVL in this sample will be 0
instead of 50e18
, which is also pretty bad.Manual audit
Multiply before you divide, that way no data will be lost:
uint token0TVL = (assetReserves[i] * prices[i]) / decimals;
#0 - nivasan1
2022-09-09T17:42:20Z
duplicate #41
🌟 Selected for report: lukris02
Also found by: 0x040, 0x1f8b, 0x52, 0xA5DF, 0xNazgul, 0xSky, Bnke0x0, Bronicle, CertoraInc, Chom, CodingNameKiki, Deivitto, Diraco, Dravee, EthLedger, IgnacioB, JC, JansenC, Jeiwan, R2, RaymondFam, ReyAdmirado, Rolezn, SinceJuly, TomJ, Tomo, Yiko, a12jmx, ajtra, ak1, codexploder, cryptphi, csanuragjain, erictee, fatherOfBlocks, gogo, hake, hansfriese, hickuphh3, ignacio, ontofractal, oyc_109, p_crypt0, pashov, peritoflores, rajatbeladiya, rbserver, rokinot, rvierdiiev, tnevler
242.8216 CANTO - $39.22
_
mislead the reader. It is better to mark internal functions by adding _
in the beginning of their name.