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: 38/133
Findings: 4
Award: $153.74
π Selected for report: 1
π Solo Findings: 0
π Selected for report: horsefacts
Also found by: 0xc0ffEE, IllIllI, Picodes, Sm4rty, berndartmueller, csanuragjain, shenwilly, unforgiven
35.1904 USDC - $35.19
In the EIP721, onERC721Received
is a safeguard to avoid NFTs to be stuck on contracts. But here it could turn out to actually create this situation: it may happen that the NFTs are stuck on PuttyV2
if a user uses a contract not suited to receive NFTs to create and fill orders.
An example scenario would be:
Check in the appropriate case if the maker
or msg.sender
is a contract and if it is the case, if they can receive NFTs
#0 - GalloDaSballo
2022-07-05T01:17:56Z
The finding implies that the caller is a contract, and that the contract was programmed to handle all operations but somehow wouldn't be able to handle the NFTs
#1 - outdoteth
2022-07-05T12:37:57Z
echo what @GalloDaSballo said. It's unlikely a contract will have all the setup required to interact with PuttyV2 but not be able to handle ERC721 tokens. Adding a check via safeMint adds a gas overhead as well as another re-entrancy attack vector so there is a tradeoff.
#2 - outdoteth
2022-07-06T19:37:09Z
Duplicate: Contracts that canβt handle ERC721 tokens will lose their Putty ERC721 position tokens: https://github.com/code-423n4/2022-06-putty-findings/issues/327
π Selected for report: Picodes
Also found by: 0xNineDec, 0xsanson, Metatron, antonttc, berndartmueller, catchup, dirk_y, sseefried, unforgiven
50.1287 USDC - $50.13
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L240 https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L497
Fees are applied during withdraw
, but can change between the time the order is filled and its terms are agreed upon and the withdrawal time, leading to a loss of the expected funds for the concerned users.
The scenario would be:
Mitigation could be:
Order
and verify that they are correct when the order is filled, so they are hardcoded in the struct#0 - outdoteth
2022-07-08T13:26:19Z
Report: Admin can change fee at any time for existing orders
#1 - outdoteth
2022-07-15T10:34:58Z
PR with fix: https://github.com/outdoteth/putty-v2/pull/4
π Selected for report: xiaoming90
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xSolus, 0xf15ers, 0xsanson, AmitN, Bnke0x0, BowTiedWardens, Chom, David_, ElKu, Funen, GalloDaSballo, GimelSec, Hawkeye, IllIllI, JC, JohnSmith, Kaiziron, Kenshin, Lambda, Limbooo, MadWookie, Metatron, MiloTruck, Nethermind, Picodes, ReyAdmirado, Sneakyninja0129, StErMi, TomJ, Treasure-Seeker, TrungOre, Waze, Yiko, _Adam, __141345__, antonttc, async, aysha, catchup, cccz, cryptphi, csanuragjain, danb, datapunk, defsec, delfin454000, dirk_y, doddle0x, durianSausage, exd0tpy, fatherOfBlocks, gogo, hake, hansfriese, horsefacts, hubble, itsmeSTYJ, joestakey, oyc_109, pedroais, peritoflores, rajatbeladiya, reassor, robee, rokinot, samruna, saneryee, sashik_eth, shenwilly, shung, simon135, sseefried, unforgiven, zer0dot, zzzitron
47.238 USDC - $47.24
Here it says:
"It fills the counter offer, and then cancels the original order that the counter offer was made forβ.
In the code it's actually the opposite:
"It cancels the original order the counter offer was made for, and then fills the counter offer.β.
π 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.1794 USDC - $21.18
Instead of using error strings, to reduce deployment and runtime cost, you should use Custom Errors: see https://blog.soliditylang.org/2021/04/21/custom-errors/. This would save both deployment and runtime cost.
exercise
In exercise
, why not directly settling the deal ?
The gas overhead would be minimal has the transfers are already done, and youβd save a ton of gas in the overall flow. Instead of doing a 2 time transfer msg.sender
-> contract
during exercise
and then contract
-> maker
or taker
during withdraw, you could directly do the accounting, burn the position and do the correct transfers in exercise
. There would still be a withdraw
function, but only for non-exercised options.
Especially as the order is immutable, we already know during exercise
than withdraw
will be called, so this optimisation is worth doing to me, although it requires some work.