LoopFi - sldtyenj12'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: 12/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
edited-by-warden
duplicate-33

External Links

Lines of code

https://github.com/code-423n4/2024-05-loop/blob/main/src/PrelaunchPoints.sol#L240-L266 https://github.com/code-423n4/2024-05-loop/blob/main/src/PrelaunchPoints.sol#L492-L505

Vulnerability details

Impact

User can lock low amount worth of any token different than WETH and get as much lpETH as he wants.

Proof of Concept

The user will lock via lock() function, then after some time when the owner calls the convertAllETH() function and everybody is able to claim or stake their lpETH, the user will send ether to the contract and immediately call claim() or claimAndStake() functions. No matter which function he will call, because they are both leading to the following block of code in the _claim() function:

} else {
            uint256 userClaim = userStake * _percentage / 100;
            _validateData(_token, userClaim, _exchange, _data);
            balances[msg.sender][_token] = userStake - userClaim;

            // At this point there should not be any ETH in the contract
            // Swap token to ETH
            _fillQuote(IERC20(_token), userClaim, _data);

            // Convert swapped ETH to lpETH (1 to 1 conversion)
            claimedAmount = address(this).balance;
            lpETH.deposit{value: claimedAmount}(_receiver);
        }
        emit Claimed(msg.sender, _token, claimedAmount);

It deposits the ETH balance of the contract to the receiver, assuming that there is no ETH left in the contract after the convertAllETH() function is called. This sabotages the whole idea of the locking mechanism, making it easy for users to trick the system

Tools Used

Manual review

return the boughtETHAmount from _fillQuote function and deposit it, instead of depositing the ETH balance of the contract

Assessed type

Other

#0 - c4-judge

2024-05-15T14:38:19Z

koolexcrypto marked the issue as duplicate of #6

#1 - c4-judge

2024-05-31T09:58:24Z

koolexcrypto marked the issue as duplicate of #33

#2 - c4-judge

2024-06-05T09:54:32Z

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