Beginner FriendlyFoundryDeFiOracle
100 EXP
View results
Submission Details
Severity: medium
Invalid

contract logic not preventing exchange rate to increase at all times makes it open to liquidity loss

PoC for contract logic not preventing exchange rate to increase at all times makes it open to liquidity loss

Summary

Two invariants are declared in the business logic of the contract:

  1. Asset exchange rate should always increase

  2. The protocol should never lose liquidity provider deposits, it should always go up

The contract's logic makes it impossible to satisfy the first invariant at all times: under certain circumstances, the exchange rate can decrease and therefore the contract can loose liquidity provider deposits given the fact that there are no incentives anymore.

Vulnerability Details

This invariant test script:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {AssetToken} from "src/protocol/AssetToken.sol";
import {ThunderLoan} from "src/protocol/ThunderLoan.sol";
import {StdInvariant} from "forge-std/StdInvariant.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Test, console} from "forge-std/Test.sol";
import {ERC20Mock} from "@openzeppelin/contracts/mocks/ERC20Mock.sol";
import {MockTSwapPool} from "../mocks/MockTSwapPool.sol";
import {MockPoolFactory} from "../mocks/MockPoolFactory.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract Invariant is StdInvariant, Test {
ThunderLoan thunderLoanImplementation;
MockPoolFactory mockPoolFactory;
ERC1967Proxy proxy;
ThunderLoan thunderLoan;
AssetToken assetToken;
ERC20Mock weth;
ERC20Mock tokenA;
uint256 constant AMOUNT = 10e18;
uint256 constant DEPOSIT_AMOUNT = AMOUNT * 100;
uint256 fee;
address liquidityProvider = address(123);
address user = address(456);
function setUp() public virtual {
thunderLoan = new ThunderLoan();
mockPoolFactory = new MockPoolFactory();
weth = new ERC20Mock();
tokenA = new ERC20Mock();
mockPoolFactory.createPool(address(tokenA));
proxy = new ERC1967Proxy(address(thunderLoan), "");
thunderLoan = ThunderLoan(address(proxy));
thunderLoan.initialize(address(mockPoolFactory));
}
function invariant_testNewRateOk() public {
vm.startPrank(liquidityProvider);
tokenA.mint(liquidityProvider, AMOUNT);
tokenA.approve(address(thunderLoan), AMOUNT);
uint256 oldRate = assetToken.getExchangeRate();
thunderLoan.deposit(tokenA, AMOUNT);
vm.stopPrank();
uint256 newRate = assetToken.getExchangeRate();
assertGt(newRate, oldRate);
}
}

Will revert with:

Failing tests:
Encountered 1 failing test in test/fuzz/Invariant.t.sol:Invariant
[FAIL. Reason: EvmError: Revert] invariant_testNewRateOk() (runs: 257, calls: 3840, reverts: 2019)

Impact

The contract's purpose is not sustainable and users might stop wanting to use it given the fact that there are no incentives in doing so.

Medium impact
Medium likelyhood

Tools Used

Lots of discouragement, doubt, chaos and uncertainty.
Foundry invariant fuzz testing.

Recommendations

Review the code..

yeah well...I'm doing my best here...Thanks for you job by the way !! I struggle a lot but learn even more and love it !!

:>

Updates

Lead Judging Commences

0xnevi Lead Judge
over 1 year ago
0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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