Wrong precision scaling on ThunderLoan::deposit::mintAmount
& ThunderLoanUpgraded::deposit::mintAmount
& ThunderLoan::deposit::redeem
& ThunderLoanUpgraded::deposit::redeem
& AssetToken::updateExchangeRate
because we're using both the liquidity token and the asset token and the fee and the totalSupply as though they had the same decimals value which isn't forcibly the case for all erc20 tokens on ethereum.
This problem of lack of precision scaling can be found at multiple locations in the codebase.
ThunderLoan::deposit::mintAmount
when converting from liquidity token to asset token
ThunderLoanUpgraded::deposit::mintAmount
when converting from liquidity token to asset token
ThunderLoan::redeem::amountUnderlying
when converting from asset token to liquidity token
ThunderLoanUpgraded::redeem::amountUnderlying
when converting from asset token to liquidity token
AssetToken::updateExchangeRate::fee
when determining the new exchange rate. The fee being in a different precision is added onto the totalSupply
as though they both were of the same decimal precision. Which they aren't for certain tokens like say USDC.
For ThunderLoan::deposit/ThunderLoanUpgraded::deposit
mintAmount
, the amount of assetToken
to be minted for the amount
of liquidity token deposited is derived from the expression
uint256 mintAmount = (amount * assetToken.EXCHANGE_RATE_PRECISION()) / exchangeRate
The exaplanation on AssetToken::s_exchangeRate
says that, s_exchangeRate
is the underlying per asset exchange rate.
ie: s_exchangeRate = 2
means 1 asset token is worth 2 underlying tokens.
Using the initial values of both:
AssetToken::s_exchangeRate = 1e18
and AssetToken::EXCHANGE_RATE_PRECISION = 1e18
this effectively means that, if we deposit 1 unit of liquidity token ( ie amount
= 1 ) we expect to be minted 1 unit of assetToken
. There exist ERC20 tokens with different decimal values. For example:
USDT on eth having a decimal value of 6
USDC on eth having a decimal value of 6
ZIL on eth having a decimal value of 12
Using one such token as the liquidity token means that, the mintAmount
calculated above will be wrong as can be seen in the below calculatioon.
using the above s_exchangeRate
and EXCHANGE_RATE_PRECISION
values. If I deposit 1 USDC ( decimals = 1e6 ), then I expect to receive 1 assetToken
(decimals = 1e18)
uint256 mintAmount = (1e6 * 1e18)/1e18;
ergo,
uint256 mintAmount = 1e6; // < 1e18
We can clearly see that, the LP will be minted less tokens than expected.
test/unit/ThunderLoanTest.t.sol:testDepositMintsAssetAndUpdatesBalance
clearly shows us that, the LP is minted the same numerical value of liquidity he provided regardless of the decimals of the liquidity token he's providing. Herein lies the problem.
For ThunderLoan::redeem/ThunderLoanUpgraded::redeem
Applying a logic similar to the above for the redeem
functions, we notice that, amountUnderlying
has a precision of 18 decimals but it's being transfered on the liquidity token as though the liquidity token has 18 decimals of precision as well. Which we've already established, it doesn't always have 18 decimals of precision. This effectively means that, if the liquidity token is say USDC, we'll be sending the LP more tokens than he initially wanted to redeem and at the expense of the other liquidity providers.
For AssetToken::updateExchangeRate::fee
Applying a logic similar to the above for the updateExchangeRate
, we notice that, newExchangeRate
is smaller or greater than should have been because we're taking fee
which can of a precision greater than or lesser than that of AssetToken
and adding to the totalSupply()
of AssetToken
as though they both have the same precisions. Using USDC as our liquidity token, then newExchangeRate
will be less that what is expected.
For tokens with a precision greater than that of assetToken
LP is minted more assetToken
than expected for the amount of liquidity he deposits.
During redemption, LP is provided with lesser liquidity tokens than was supposed to.
During updateExchangeRate
, the fee is greater than expected
For tokens with a precision lower than that of assetToken
LP is minted less assetToken
than expected for the amount of liquidity he deposits.
During redemption, LP is provided with more liquidity tokens than was supposed to.
During updateExchangeRate
, the fee is lesser than expected
Manual review
We should scale the precision of mintAmount
to that of the assetToken before doing the minting.
This test assumes `s_precisionFee == s_exchangeRate == 1e18`
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.