LI.FI contest - csanuragjain's results

Bridge & DEX Aggregation.

General Information

Platform: Code4rena

Start Date: 24/03/2022

Pot Size: $75,000 USDC

Total HM: 15

Participants: 59

Period: 7 days

Judge: gzeon

Id: 103

League: ETH

LI.FI

Findings Distribution

Researcher Performance

Rank: 18/59

Findings: 5

Award: $1,222.11

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: hake

Also found by: Kenshin, Ruhum, VAD37, WatchPug, csanuragjain, hickuphh3, hyh, kirk-baird, obront, pmerkleplant, rayn, shw, tintin, wuwe1

Labels

bug
duplicate
2 (Med Risk)
disagree with severity
sponsor acknowledged

Awards

77.3842 USDC - $77.38

External Links

Lines of code

https://github.com/code-423n4/2022-03-lifinance/blob/main/src/Libraries/LibSwap.sol#L29

Vulnerability details

Impact

The from amount in swap must always be transferred from user to the contract. But under certain circumstances contract may end up using its own funds for swapping thereby giving users free funds

Function

swap

Proof of Concept

  1. Attacker uses swapTokensGeneric (GenericSwapFacet.sol) to convert non-native asset say DAI to another asset say USDT with _swapData.fromAmount as 100
  2. Assume contract already had a balance of amount 100 in DAI
  3. The swap ultimately makes calls to swap function in LibSwap.sol#L29
  4. Since LibAsset.getOwnBalance(fromAssetId) < fromAmount is false (100<100) so the if condition at L33 does not get executed and no amount is transffered from user
  5. Swap is completed and USDT amount gets transffered to user even though user never transferred even a single DAI

Remove L33-L35 and revise like below:

function swap(bytes32 transactionId, SwapData calldata _swapData) internal {

... // if (!LibAsset.isNativeAsset(fromAssetId) && LibAsset.getOwnBalance(fromAssetId) < fromAmount) {

// }

if (!LibAsset.isNativeAsset(fromAssetId)) {

LibAsset.transferFromERC20(fromAssetId, msg.sender, address(this), fromAmount); LibAsset.approveERC20(IERC20(fromAssetId), _swapData.approveTo, fromAmount); } .... }

#0 - H3xept

2022-04-12T08:38:05Z

Duplicate of #66

We are aware that the contract allows users to use latent funds, although we disagree on it being an issue as no funds (ERC20 or native) should ever lay in the contract. To make sure that no value is ever kept by the diamond, we now provide refunds for outstanding user value (after bridges/swaps).

Findings Information

🌟 Selected for report: hickuphh3

Also found by: 0xDjango, WatchPug, catchup, csanuragjain, hyh, shw, ych18

Labels

bug
duplicate
2 (Med Risk)

Awards

303.3583 USDC - $303.36

External Links

Lines of code

https://github.com/code-423n4/2022-03-lifinance/blob/main/src/Facets/DexManagerFacet.sol#L62

Vulnerability details

Impact

The function batchRemoveDex will only remove the first dex index passed in argument and rest in _dexs array will never be removed. This is happening since the function is returning once a matching dex is found instead of breaking from loop

Since function will not revert any error, This can lead to non required dexes still be whitelisted even though owner beleives them to be removed

Function:

batchRemoveDex

Proof of Concept

  1. Admin tries to remove dex 1,2 by using batchRemoveDex
  2. Loop runs and s.dexWhitelist[1] = false; is set
  3. Now Loop is run to find index for s.dexs ==1 and once it is found _removeDex is called which removes 1 from s.dexs
  4. But after this return statement executes which completes the function with success even though loop has not yet finished and dex 2 has still not been removed

Instead of return, kindly use break

if (s.dexs[j] == _dexs[i]) { _removeDex(j); break; }

#0 - H3xept

2022-04-11T11:24:04Z

Duplicate of #34

Findings Information

🌟 Selected for report: WatchPug

Also found by: VAD37, catchup, csanuragjain, rayn

Labels

bug
duplicate
2 (Med Risk)
sponsor disputed

Awards

665.807 USDC - $665.81

External Links

Lines of code

https://github.com/code-423n4/2022-03-lifinance/blob/main/src/Libraries/LibAsset.sol#L68

Vulnerability details

Impact

It seems that the approveERC20 function is approving MAX_INT amount instead of the passed amount. This will allow users to spend more than what they are entitled for

Proof of Concept

  1. Admin calls approveERC20 to approve amount 5
  2. Due to below line an amount of MAX_INT instead get approved for spender
SafeERC20.safeApprove(IERC20(assetId), spender, MAX_INT);

Change the function line 68 to below:

SafeERC20.safeApprove(IERC20(assetId), spender, amount);

#0 - H3xept

2022-04-08T10:31:06Z

As our contract communicates with the same dexs all the time we only want to approve each token once and all the other users don't have to pay for it again. As our contract should only hold the funds currently transferred no other tokens can be accessed.

#1 - gzeoneth

2022-04-16T17:01:22Z

Duplicate of #160

Native funds can get lost

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Libraries/LibSwap.sol#L29

  1. It was observed that on calling swap function at LibSwap.sol#L29, below calculation is made for previous balance:
uint256 toAmount = LibAsset.getOwnBalance(_swapData.receivingAssetId);
  1. This will become wrong if user has set _swapData.receivingAssetId as Native Asset as LibAsset.getOwnBalance will include (original balance + msg.value)

Recommendation:

Change this to:

uint256 toAmount = LibAsset.getOwnBalance(_swapData.receivingAssetId) - msg.value;

Awards

61.9811 USDC - $61.98

Labels

bug
G (Gas Optimization)

External Links

  1. It was observed that multiple loop conditions were using postfix increment instead of prefix increment. Kindly consider changing i++ to ++i in order to save gas

  2. It was observed that while swapping operations in multiple facet it was not checked whether amount==0. If yes function should immediately return to save gas

#0 - H3xept

2022-04-11T12:07:10Z

Re prefix increments

We internally decided to avoid previx increments for now.

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