Infinity NFT Marketplace contest - codexploder's results

The world's most advanced NFT marketplace.

General Information

Platform: Code4rena

Start Date: 14/06/2022

Pot Size: $50,000 USDC

Total HM: 19

Participants: 99

Period: 5 days

Judge: HardlyDifficult

Total Solo HM: 4

Id: 136

League: ETH

Infinity NFT Marketplace

Findings Distribution

Researcher Performance

Rank: 37/99

Findings: 4

Award: $175.59

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

11.084 USDC - $11.08

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

External Links

Lines of code

https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L345 https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1229

Vulnerability details

Impact

The rescueETH function is implemented incorrectly and will always fail This is sending msg.value to the destination contract instead of address(this).balance

Note

Same need to be fixed at InfinityExchange.sol#L1229

Proof of Concept

  1. Let's observe the rescueETH function
function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: msg.value}(''); require(sent, 'failed'); }
  1. As we can see this is resuing funds using the passed msg.value instead of using contracts fund

Change the rescueETH function like below:

function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: address(this).balance}(''); require(sent, 'Failed to send Ether'); }

#0 - nneverlander

2022-06-22T11:17:13Z

Duplicate

#2 - HardlyDifficult

2022-07-09T16:45:48Z

Findings Information

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

Awards

84.0967 USDC - $84.10

External Links

Lines of code

https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L336 https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L300

Vulnerability details

Impact

Any extra ETH passed while calling takeOrders function will not be returned by the contract causing user to loose funds

Proof of Concept

  1. Let us see the takeOrders function
function takeOrders(OrderTypes.MakerOrder[] calldata makerOrders, OrderTypes.OrderItem[][] calldata takerNfts) external payable nonReentrant { ....... uint256 execPrice = _getCurrentPrice(makerOrders[i]); totalPrice += execPrice; _takeOrders(makerOrders[i], takerNfts[i], execPrice); unchecked { ++i; } } // check to ensure that for ETH orders, enough ETH is sent // for non ETH orders, IERC20 safeTransferFrom will throw error if insufficient amount is sent if (isMakerSeller && currency == address(0)) { require(msg.value >= totalPrice, 'invalid total price'); } }
  1. Notice the total cost for this order is calculated as totalPrice

  2. So if user has passed a msg.value > = totalPrice, this is executed successfully

  3. But what about the extra ETH msg.value - totalPrice, which is simply kept by contract and not refunded back to the user

Note

Also need to be fixed for takeMultipleOneOrders function

Return the excess funds of msg.value - totalPrice back to user

#0 - KenzoAgada

2022-06-21T12:20:14Z

Duplicate of #244

#1 - nneverlander

2022-06-22T10:12:29Z

Duplicate

#2 - HardlyDifficult

2022-07-10T12:38:13Z

When a user sends more ETH than is required for an order, the surplus is taken as exchange fees instead of being refunded.

Dupe of https://github.com/code-423n4/2022-06-infinity-findings/issues/244

Zero address checks missing

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L375

Issue: In updateInfinityTreasury function it is not verified that _infinityTreasury is not address(0) else rageQuit balance penality will be lost

Recommendation: Add a check to see _infinityTreasury is not address(0)

require(_infinityTreasury!=address(0), "Incorrect address");

Verify receiving end is contract

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1023

Issue: In _transferNFTsAndFees function, it is not checked whether recipient is a contract. If receiver is an EOA not supporting ERC777/ERC1155 , NFT can be lost forever

Recommendation: Check whether recipient is a valid contract by chekcing for extcodesize>0

Missing Index validation

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L88

Issue: In getConfigByIndex, it is not verified if provided index is valid. Same fix is required for getPendingByIndex function as well

Recommendation: Add a check to see that provided index is valid.

require(index>=0 && index<getConfigCount(), "Invalid index");

#0 - nneverlander

2022-06-23T11:26:01Z

Thanks

#1 - HardlyDifficult

2022-07-12T05:12:36Z

If not required - Amount can never be greater than vestedTwelveMonths

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L310

Issue: In _updateUserStakedAmounts function, amount can never be greater than vestedTwelveMonths otherwise user is trying to unstake amount higher than deposit which is not possible due to require check in unstake

Recommendation: Change the implementation like below:

OLD

if (amount > vestedTwelveMonths) { userstakedAmounts[user][Duration.TWELVE_MONTHS].amount = 0; userstakedAmounts[user][Duration.TWELVE_MONTHS].timestamp = 0; } else { userstakedAmounts[user][Duration.TWELVE_MONTHS].amount -= amount; }

New

if (amount > 0) { userstakedAmounts[user][Duration.TWELVE_MONTHS].amount -= amount; }

Zero amount checks

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L260

Issue: Short circuit if user staked amount =0 in getVestedAmount function

Recommendation: Add below check in getVestedAmount function

require(amount!=0, "Insufficient amount");

No need to check complications

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L178

Issue: In matchOneToManyOrders function, No need to check complications.contains(makerOrder.execParams[0]) at InfinityExchange.sol#L184, isUserOrderNonceExecutedOrCancelled at InfinityExchange.sol#L216 as this is already done in isOrderValid call at InfinityExchange.sol#L190 and _matchOneMakerSellToManyMakerBuys call at InfinityExchange.sol#L203

Recommendation: Remove extra complications check and isUserOrderNonceExecutedOrCancelled assignation

Unrequired call made to getVestedAmount

Contract: https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L168

Issue: In getUserTotalVested function, For noVesting there is no need to call getVestedAmount as this will always be userstakedAmounts[user][Duration.NONE].amount

Recommendation: Directly assign userstakedAmounts[user][Duration.NONE].amount instead of calling getVestedAmount function for noVesting condition

#0 - nneverlander

2022-06-23T11:26:59Z

Thanks

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