Beginner FriendlyFoundryDeFiOracle
100 EXP
View results
Submission Details
Severity: high
Valid

Atleast one liquidity provider will not be able to `redeem` their funds

Summary

Atleast one liquidity provider will not be able to withdraw their funds because of asset's exchangeRate functionality.

Vulnerability Details

When a LP deposits fund in the pool through ThunderLoan::deposit then this function calculates fee based on amount & token, and updates the asset's exchangeRate(basically it increases the exchangeRate).

Now let's take an example, when a LP deposit 10 tokenA at an exchangeRate of 1:1 then LP receives 10 lpTokenA and the exchangeRate gets updated at 1.12(example). now this LP wanted to redeem its liquidity by giving all 10 lpTokneA, then LP should get 11.2 (10 * 1.12) tokenA but potocol has only 10 token therefore LP will never get their full amount back.

As the protocol size grows more and more LP will be unable to redeem their funds because of increase in exchangeRate.

//here is the POC, and I've taken two LP, one will not be able to withdraw but other will not therefore test will fail.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import { Test, console } from "forge-std/Test.sol";
import { BaseTest, ThunderLoan } from "./BaseTest.t.sol";
import { AssetToken } from "../../src/protocol/AssetToken.sol";
import { MockFlashLoanReceiver } from "../mocks/MockFlashLoanReceiver.sol";
contract ThunderLoanTest is BaseTest {
uint256 constant AMOUNT = 10e18;
uint256 constant DEPOSIT_AMOUNT = AMOUNT * 100;
address liquidityProvider = address(123);
address user = address(456);
address user2 = address(789);
MockFlashLoanReceiver mockFlashLoanReceiver;
function setUp() public override {
super.setUp();
vm.prank(user);
mockFlashLoanReceiver = new MockFlashLoanReceiver(address(thunderLoan));
}
function test_one_LP_will_not_able_to_redeem() public {
// Allowing tokenA to get deposite
vm.prank(thunderLoan.owner());
thunderLoan.setAllowedToken(tokenA, true);
AssetToken assetToken = thunderLoan.getAssetFromToken(tokenA);
//minting tokens to 2 LP (user, user2)
tokenA.mint(user, 2e18);
tokenA.mint(user2, 4e18);
//user is approving and depositing
vm.startPrank(user);
tokenA.approve(address(thunderLoan), 2e18);
thunderLoan.deposit(tokenA, 2e18);
//user2 is approving and depositing
vm.startPrank(user2);
tokenA.approve(address(thunderLoan), 4e18);
thunderLoan.deposit(tokenA, 4e18);
//User is redeeming(he will be able to redeem, if you want to see then comment below user2)
vm.startPrank(user);
thunderLoan.redeem(tokenA, assetToken.balanceOf(user));
//User2 is redeeming(he will not be able to redeem therefore trx will fail)
vm.startPrank(user2);
thunderLoan.redeem(tokenA, assetToken.balanceOf(user2));
}
}

Result

Running 1 test for test/unit/MyTest.t.sol:ThunderLoanTest
[FAIL. Reason: ERC20: transfer amount exceeds balance] testUnApprovedTokenDeposite() (gas: 1336210)
Test result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.64ms
Ran 1 test suites: 0 tests passed, 1 failed, 0 skipped (1 total tests)

Impact

LP will lose their funds.

Tools Used

Manual Review, foundry

Recommendations

Protocol can do 1 thing: Take small amount of fee from LP while depositing.

Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

can't redeem because of the update exchange rate

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.