Platform: Code4rena
Start Date: 29/06/2022
Pot Size: $50,000 USDC
Total HM: 20
Participants: 133
Period: 5 days
Judge: hickuphh3
Total Solo HM: 1
Id: 142
League: ETH
Rank: 3/133
Findings: 5
Award: $2,830.87
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: kirk-baird
Also found by: Lambda, csanuragjain, hansfriese, minhquanym
Function PuttyV2.acceptCounterOffer()
is used in case users see better deal and want to cancel their own order before filling the new one. But attacker can abuse this function by front-run calling fillOrder()
before it is cancelled in acceptCounterOffer()
.
Attackers have motivation to do this (for example: premium). And users who willing to sell only 1 BAYC now may be forced to sell 2 BAYC
Scenario
acceptCounterOffer()
with Bob’s long call order. But Bob frontruns Alice by filling Alice’s short call order first.Manual Review
Make sure users cannot cancel()
order when the position is minted.
#0 - 0xlgtm
2022-07-05T07:40:23Z
#1 - outdoteth
2022-07-06T18:08:32Z
Duplicate: It’s possible to fill an order twice by accepting a counter offer for an already filled order: https://github.com/code-423n4/2022-06-putty-findings/issues/44
🌟 Selected for report: zzzitron
Also found by: Kenshin, Metatron, PwnedNoMore, danb, minhquanym
Takers who fill short-call orders may unable to exercise their long-call position. Attackers can abuse it to take premium from takers for free.
In PuttyV2.fillOrder()
function, when taker fill short-call order, order’s maker only has to transfer erc20Assets
and erc721Assets
in but floor assets is ignored.
After takers filled short-call orders, they will receive long-call position. And because maker didn’t transfer any floor assets in, positionFloorAssetTokenIds[orderHash]
is empty, when takers call exercise()
the TX will be reverted when trying to transfer floor assets out in this line
Scenario
fillOrder()
to fill Alice’s order. In this step, Bob get long call position which should allow him to buy a BAYC from Alice so Bob has to pay Alice premium
.exercise()
to exercise his right but the TX is always reverted.Manual Review
In case fillOrder()
with short call order, should make sure this order do not use floorAssets
if (!order.isLong && order.isCall) { require(order.floorTokens.length == 0); }
#0 - 0xlgtm
2022-07-05T08:20:21Z
#1 - outdoteth
2022-07-06T18:06:02Z
Short call with floorTokens will result in a revert when exercising: https://github.com/code-423n4/2022-06-putty-findings/issues/369
🌟 Selected for report: cccz
Also found by: IllIllI, minhquanym
622.994 USDC - $622.99
Judge has assessed an item in Issue #253 as Medium risk. The relevant finding follows:
#0 - HickupHH3
2022-07-16T00:49:01Z
Recommended Mitigation Steps NFTX protocol has implemented a way to handle the transfer of both standard and non-standard ERC721 tokens. The relevant implementation can be found here.
dup of #16
🌟 Selected for report: hyh
Also found by: Treasure-Seeker, csanuragjain, minhquanym
420.5209 USDC - $420.52
Judge has assessed an item in Issue #253 as Medium risk. The relevant finding follows:
#0 - HickupHH3
2022-07-16T00:47:44Z
The result is in some case, the fee to admin may even higher than premium, cause owners of short call position in loss.
dup of #373
🌟 Selected for report: GalloDaSballo
Also found by: 0v3rf10w, 0x1f8b, 0xA5DF, 0xDjango, 0xHarry, 0xKitsune, 0xNazgul, 0xNineDec, 0xc0ffEE, 0xf15ers, 0xkatana, 0xsanson, ACai, Aymen0909, Bnke0x0, BowTiedWardens, Chom, ElKu, Fitraldys, Funen, Haruxe, Hawkeye, IllIllI, JC, JohnSmith, Kaiziron, Kenshin, Lambda, Limbooo, MadWookie, Metatron, MiloTruck, Picodes, PwnedNoMore, Randyyy, RedOneN, ReyAdmirado, Ruhum, Sm4rty, StErMi, StyxRave, TerrierLover, TomJ, Tomio, UnusualTurtle, Waze, Yiko, _Adam, __141345__, ajtra, ak1, apostle0x01, asutorufos, c3phas, cRat1st0s, catchup, codetilda, cryptphi, datapunk, defsec, delfin454000, durianSausage, exd0tpy, fatherOfBlocks, gogo, grrwahrr, hake, hansfriese, horsefacts, ignacio, jayfromthe13th, joestakey, ladboy233, m_Rassska, mektigboy, minhquanym, mrpathfindr, natzuu, oyc_109, rajatbeladiya, reassor, rfa, robee, rokinot, sach1r0, saian, sashik_eth, simon135, slywaters, swit, z3s, zeesaw, zer0dot
21.1705 USDC - $21.17
When evaluating boolean expressions (logical AND and OR) you can stop as soon as you find the first condition which satisfies or negates the expression.
This can be used to optimize gas by reordering conditions in expressions. For example, this expression has 2 conditions
block.timestamp > positionExpirations[longPositionId] || isExercised
First condition reading from storage obviously cost more gas than second condition which simply a boolean variable in stack. We can swap their orders to optimize gas like
isExercised || block.timestamp > positionExpirations[longPositionId]