Platform: Code4rena
Start Date: 30/10/2023
Pot Size: $49,250 USDC
Total HM: 14
Participants: 243
Period: 14 days
Judge: 0xsomeone
Id: 302
League: ETH
Rank: 78/243
Findings: 2
Award: $35.61
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: smiling_heretic
Also found by: 00decree, 00xSEV, 0x180db, 0x3b, 0x656c68616a, 0xAadi, 0xAleko, 0xAsen, 0xDetermination, 0xJuda, 0xMAKEOUTHILL, 0xMango, 0xMosh, 0xSwahili, 0x_6a70, 0xarno, 0xgrbr, 0xpiken, 0xsagetony, 3th, 8olidity, ABA, AerialRaider, Al-Qa-qa, Arabadzhiev, AvantGard, CaeraDenoir, ChrisTina, DanielArmstrong, DarkTower, DeFiHackLabs, Deft_TT, Delvir0, Draiakoo, Eigenvectors, Fulum, Greed, HChang26, Haipls, Hama, Inference, Jiamin, JohnnyTime, Jorgect, Juntao, Kaysoft, Kose, Kow, Krace, MaNcHaSsS, Madalad, MrPotatoMagic, Neon2835, NoamYakov, Norah, Oxsadeeq, PENGUN, REKCAH, Ruhum, Shubham, Silvermist, Soul22, SovaSlava, SpicyMeatball, Talfao, TermoHash, The_Kakers, Toshii, TuringConsulting, Udsen, VAD37, Vagner, Zac, Zach_166, ZdravkoHr, _eperezok, ak1, aldarion, alexfilippov314, alexxander, amaechieth, aslanbek, ast3ros, audityourcontracts, ayden, bdmcbri, bird-flu, blutorque, bronze_pickaxe, btk, c0pp3rscr3w3r, c3phas, cartlex_, cccz, ciphermarco, circlelooper, crunch, cryptothemex, cu5t0mpeo, darksnow, degensec, dethera, devival, dimulski, droptpackets, epistkr, evmboi32, fibonacci, gumgumzum, immeas, innertia, inzinko, jasonxiale, joesan, ke1caM, kimchi, lanrebayode77, lsaudit, mahyar, max10afternoon, merlin, mrudenko, nuthan2x, oakcobalt, openwide, orion, phoenixV110, pontifex, r0ck3tz, rotcivegaf, rvierdiiev, seeques, shenwilly, sl1, slvDev, t0x1c, tallo, tnquanghuy0512, tpiliposian, trachev, twcctop, vangrim, volodya, xAriextz, xeros, xuwinnie, y4y, yobiz, zhaojie
0 USDC - $0.00
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/AuctionDemo.sol#L124-L130
At auction, token is sold at a very low price close to zero. This is in fact the same as losing token.
Any bidder can withdraw the bid without any restriction through AuctionDemo.sol#cancelBid
function as follows.
File: AuctionDemo.sol 124: function cancelBid(uint256 _tokenid, uint256 index) public { 125: require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); 126: require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true); 127: auctionInfoData[_tokenid][index].status = false; 128: (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}(""); 129: emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid); 130: }
Therefore, the attacker makes a very low-price bid at the beginning of the auction and then registers a very high-price bid further, preventing other competitors from making a bid. If a high-price bid is withdrawn just before the auction is over, the attacker can buy the token at a low price.
Here is the attacking scenario.
Manual Review
Modify AuctionDemo.sol#cancelBid
function and impose penalty on the highest-priced bidder (msg.sender == returnHighestBidder (_tokenid)
).
Do not impose penalty when he is not the highest-priced bidder.
Error
#0 - c4-pre-sort
2023-11-15T09:41:48Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-02T15:13:13Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-02T15:16:48Z
alex-ppg marked the issue as duplicate of #1784
#3 - c4-judge
2023-12-07T11:49:39Z
alex-ppg marked the issue as duplicate of #1323
#4 - c4-judge
2023-12-08T17:26:48Z
alex-ppg marked the issue as partial-50
#5 - c4-judge
2023-12-08T17:28:19Z
alex-ppg marked the issue as satisfactory
#6 - c4-judge
2023-12-08T18:20:59Z
alex-ppg marked the issue as partial-50
35.614 USDC - $35.61
https://github.com/code-423n4/2023-10-nextgen/blob/main/smart-contracts/MinterContract.sol#L540
The buyers who buy tokens at the end of the sale may not buy or buy tokens at unexpected high prices.
If salesOption==2
, the selling price of token decreases linearly or exponentially with time.
In the decreaing price sale, the buyer will want to buy a token at the end of the sales period to buy token as cheaply as possible if tokens have no fear of being sold all before the deadline.
However, by the following code in the MinterContract.sol#getPrice
function, the price of token will jump to the initial selling price at the end of the sale.
File: MinterContract.sol 540: } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){
That is when block.timestamp == collectionPhases[_collectionId].publicEndTime
, an initial price, not a decreased price, is applied.
Here is the reproducing scenario.
timePeriod
is one hour and sales period is one day.1000 - 30 * 23 = 310
.MinterContract.sol#mint
function at just the end time of sales.MinterContract.sol#getPrice
jumps to 1000
at the end of sales, the buyer does not buy tokens or buys tokens at the high price of 1000
eth.Manual Review
In MinterContract.sol#L540
modify <
with <=
as follows.
File: MinterContract.sol 540: - } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){ 540: + } else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp <= collectionPhases[_collectionId].publicEndTime){
Math
#0 - c4-pre-sort
2023-11-16T01:43:22Z
141345 marked the issue as duplicate of #1391
#1 - c4-judge
2023-12-08T21:42:47Z
alex-ppg marked the issue as partial-50