Summary
When the ThunderLoan
is upgraded the deposit
function will not update the asset's exchange rate.
Vulnerability Details
The deposit
function in ThunderLoanUpgraded
is missing the lines that update the exchange rate of the asset.
Impact
The assetToken.getExchangeRate()
will return wrong value and malicious users can exploit it.
Tools Used
Manual Review, Foundty
Proof of Concept
Added the following test case in ThunderLoanTest
function testUpdatesBalanceWhenDeposit() public setAllowedToken {
tokenA.mint(liquidityProvider, AMOUNT);
vm.startPrank(liquidityProvider);
AssetToken asset = thunderLoan.getAssetFromToken(tokenA);
uint prevRate = asset.getExchangeRate();
tokenA.approve(address(thunderLoan), AMOUNT);
thunderLoan.deposit(tokenA, AMOUNT);
vm.stopPrank();
uint endRate = asset.getExchangeRate();
assertGt(endRate, prevRate);
}
Test case passes
[PASS] testUpdatesBalanceWhenDeposit() (gas: 1153818)
Now we run the same test assuming we upgraded
[FAIL. Reason: Assertion failed.] testUpdatesBalanceWhenDeposit() (gas: 1148076)
Logs:
Error: a > b not satisfied [uint]
Value a: 1000000000000000000
Value b: 1000000000000000000
Recommendations
Update asset exchange rate
function deposit(IERC20 token, uint256 amount) external revertIfZero(amount) revertIfNotAllowedToken(token) {
AssetToken assetToken = s_tokenToAssetToken[token];
uint256 exchangeRate = assetToken.getExchangeRate();
uint256 mintAmount = (amount * assetToken.EXCHANGE_RATE_PRECISION()) / exchangeRate;
emit Deposit(msg.sender, token, amount);
assetToken.mint(msg.sender, mintAmount);
+ uint256 calculatedFee = getCalculatedFee(token, amount);
+ assetToken.updateExchangeRate(calculatedFee);
token.safeTransferFrom(msg.sender, address(assetToken), amount);
}
Test now passes:
[PASS] testUpdatesBalanceWhenDeposit() (gas: 1153818)