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
Rank: 15/72
Findings: 1
Award: $330.18
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: RaymondFam
Also found by: 0x1f8b, 0x52, 0xSmartContract, 0xc0ffEE, 0xhacksmithh, 8olidity, Awesome, BClabs, Bnke0x0, Chom, Deivitto, Hashlock, IllIllI, Josiah, KingNFT, Nyx, R2, ReyAdmirado, Rolezn, SamGMK, Sathish9098, SinceJuly, V_B, Vadis, Waze, a12jmx, adriro, ajtra, aphak5010, bearonbike, bin, brgltd, carlitox477, carrotsmuggler, cccz, ch0bu, chaduke, datapunk, delfin454000, erictee, fatherOfBlocks, fs0c, horsefacts, jayphbee, ktg, ladboy233, pashov, perseverancesuccess, rbserver, ret2basic, tnevler, zaskoh
330.1837 USDC - $330.18
https://github.com/code-423n4/2022-11-looksrare/blob/e3b2c053f722b0ca2dce3a3eb06f64859b8b7a6f/contracts/LooksRareAggregator.sol#L46 https://github.com/code-423n4/2022-11-looksrare/blob/main/contracts/LooksRareAggregator.sol#L153-L163 https://github.com/code-423n4/2022-11-looksrare/blob/e3b2c053f722b0ca2dce3a3eb06f64859b8b7a6f/contracts/LooksRareAggregator.sol#L228
The smart contracts that integrate with LooksRareAggregator fail all the transactions if the proxy fee is updated to be higher value. One more impact that is it is difficult for the other contracts or normal users to find the fee basis points to have the successful trading.
Currently the document states that "Before executing a trade, the client should fetch each proxy's fee data and include the returned basis points in the trade data's maxFeeBp parameter to prevent the fee basis points from suddenly increasing beyond the buyer's acceptable fee levels". But in the implementation of the contract: the _proxyFeeData is private data and there is no get function to get the fee.
mapping(address => FeeData) private _proxyFeeData;
There is the setFee function so the owner can update the fees to a higher values.
function setFee( address proxy, uint256 bp, address recipient ) external onlyOwner { if (bp > 10000) revert FeeTooHigh(); _proxyFeeData[proxy].bp = bp; _proxyFeeData[proxy].recipient = recipient; emit FeeUpdated(proxy, bp, recipient); }
If the other users constructed the transaction based on the old feeData, then the check at Line228 will return maxFeeBpViolated is true, then the transaction will skip the trade if the isAtomic input is false, or revert if isAtomic input is true.
maxFeeBpViolated = singleTradeData.maxFeeBp < feeData.bp;
This is a medium issue because the core functionality of the protocol is impacted. Since there is no way to get the _proxyFeeData, then it is very difficult for other contracts to integrate LooksRareAggregator to create a successful trade.
The below scenario is possible. The other contract implemented the accept the fee level of "x" amount of fees based on the current documentation. But The owner of LooksRareAggregator update fees to a higher value than x => Then all the trade transactions will fail. The other contract should update the implementation.
The following scenarios is possible
Step 0: The client contract implement the accept the fee level of "x" amount based on the current documentation Step 1: The The owner of LooksRareAggregator update fees to a higher value than x Step 2: The client contract fails all transactions. Step 3: The client contract should wait for the new announcement of the fees from the LooksRare team or investigate the failures by transactions history of LooksRareAggregator contract.
The POC written in Foundry: testExecuteHigherFee in file LooksRareAggregatorTrades.t.sol: Just replace the current file in test folder with this new file https://drive.google.com/file/d/1NNawMrXzRRntmbdGuDrybMQQ6x9QdHAm/view?usp=sharing
To run test
FOUNDRY_PROFILE=local forge test -m testExecuteHigherFee --use solc:0.8.17
The Log of the test failed: https://drive.google.com/file/d/1_HMN6wXIIPc8kYjTdBhE417_KT0AAEMD/view?usp=sharing The log of the test case with correct feeData and passed: https://drive.google.com/file/d/1SMBvHw1DodLNtrld0VzLzXK8Yhwcm1Ql/view?usp=share_link
So notice that the test case testExecuteReentrancy passed. In the test case testExecuteHigherFee the _proxyFeeData.bp updated by the owner has higher fee , the transaction with same trade data as in testExecuteReentrancy but the transaction fails.
The git diff vs commit e3b2c053f722b0ca2dce3a3eb06f64859b8b7a6f is here: https://drive.google.com/file/d/1moLcr6-I59I6OAXbjLMFGwrMqCQ-ynP_/view?usp=sharing To apply the patch
git apply POC.patch
VSCode, Foundry
Should change the _proxyFeeData to public or implement the getter functionality
#0 - Picodes
2022-11-21T16:48:32Z
I think this is the intended behavior and LooksRare will implement an API or an offchain source to fetch the fees, but it's correct that there is currently no getters.
#1 - Picodes
2022-11-21T16:49:57Z
Anyway functionality is not impacted (users can always read the storage directly, or input parameters and simulate the transaction before sending it) so downgrading to QA
#2 - c4-judge
2022-11-21T16:50:05Z
Picodes changed the severity to QA (Quality Assurance)
#3 - c4-judge
2022-11-21T16:50:12Z
Picodes marked the issue as grade-a
#4 - 0xhiroshi
2022-11-23T00:17:04Z
We will have a SDK to call the contract and the fee basis point is hard coded there. We don't think the fee will change very often at all and we are the one who set it.
#5 - c4-sponsor
2022-11-23T00:17:13Z
0xhiroshi marked the issue as sponsor disputed
#6 - c4-judge
2022-12-12T10:11:25Z
Picodes marked the issue as grade-b
#7 - c4-judge
2022-12-12T10:12:02Z
Picodes marked the issue as grade-a