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: 10/243
Findings: 4
Award: $1,210.72
🌟 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/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L105 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L125 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/AuctionDemo.sol#L135
Bidders with the highest bid have the potential to double their bidding funds. This can be achieved by consecutively calling the claimAuction
and cancelAllBids
functions, provided that both functions are executed when block.timestamp
is equal to getAuctionEndTime(_tokenid)
.
claimAuction
allows the highestBidder
to cliam the corresponding _tokndid
when the auction is over.
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ //@audit timestamp can be equal to `EndTime` require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); auctionClaim[_tokenid] = true; uint256 highestBid = returnHighestBid(_tokenid); address ownerOfToken = IERC721(gencore).ownerOf(_tokenid); address highestBidder = returnHighestBidder(_tokenid); for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid); (bool success, ) = payable(owner()).call{value: highestBid}(""); emit ClaimAuction(owner(), _tokenid, success, highestBid); } else if (auctionInfoData[_tokenid][i].status == true) { (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid); } else {} } }
Bidders can cancel bids before the auction ends using the function cancelBid
or cancelAllBids
.
These two functions will refund the funds to bidders and mark the status of auctionInfoData
as false.
function cancelBid(uint256 _tokenid, uint256 index) public { //@audit timestamp can be equal to EndTime require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); require(auctionInfoData[_tokenid][index].bidder == msg.sender && auctionInfoData[_tokenid][index].status == true); auctionInfoData[_tokenid][index].status = false; (bool success, ) = payable(auctionInfoData[_tokenid][index].bidder).call{value: auctionInfoData[_tokenid][index].bid}(""); emit CancelBid(msg.sender, _tokenid, index, success, auctionInfoData[_tokenid][index].bid); }
function cancelAllBids(uint256 _tokenid) public { //@audit timestamp can also be equal to EndTime require(block.timestamp <= minter.getAuctionEndTime(_tokenid), "Auction ended"); for (uint256 i=0; i<auctionInfoData[_tokenid].length; i++) { if (auctionInfoData[_tokenid][i].bidder == msg.sender && auctionInfoData[_tokenid][i].status == true) { auctionInfoData[_tokenid][i].status = false; (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); emit CancelBid(msg.sender, _tokenid, i, success, auctionInfoData[_tokenid][i].bid); } else {} } }
However, the timestamp of claimAuction
and cancel*
overlap when block.timestamp == minter.getAuctionEndTime(_tokenid)
. Due to that claimAuction
will only return the funds to bidders but not set the status of auctionInfoData
, bidders could call cancelAllBids
to get the funds again.
Here is an example:
Alice is the highest bidder and she bids with [5, 10, 15, 20].
When block.timestamp
== minter.getAuctionEndTime(_tokenid)
, Alice calls cliamAuction
to get the _tokenid
and ETH=5+10+15=30.
After that, Alice calls cancelAllBids
at the same block.timestamp
, and she will get 5+10+15+20=50 ETH.
In addition to the cancelAllBids
, the cancelBid
can also achieve the same effect.
Manual Review
You can change the lock.timestamp >= minter.getAuctionEndTime(_tokenid)
to lock.timestamp > minter.getAuctionEndTime(_tokenid)
in function claimAuction
to prevent cancellations after claim.
Invalid Validation
#0 - c4-pre-sort
2023-11-14T23:30:35Z
141345 marked the issue as duplicate of #962
#1 - c4-judge
2023-12-01T15:55:25Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-01T15:55:33Z
alex-ppg marked the issue as duplicate of #1788
#3 - c4-judge
2023-12-08T18:17:45Z
alex-ppg marked the issue as satisfactory
1114.2534 USDC - $1,114.25
The MinterContract.sol
fails to guarantee the minting of only one token in each period for Periodic Sale collections. This discrepancy occurs because functions like airDropTokens
, burnOrSwapExternalToMint
, and burnToMint
have the capacity to mint Periodic Sale tokens at any time. Consequently, the mint
function need to wait for additional time to mint Periodic Sale tokens.
As outlined in the docs, Periodic Sale(Option 3) collections are designed to permit the minting of only one token during each time period.
Mints are limited to 1 token during each time period (e.g. minute, hour, day). The minting cost can either stable or have a bonding curve (increase) over time. This allows for long-lived or experimental mints.
In the NextGenMinterContract
, the mint
function is responsible for verifying the salesOption
and updating the lastMintDate
of a collection. The value of lastMintDate
is computed based on the number of tokens already minted in this collection, which is obtained through gencore.viewCirSupply(col)
. If there are 10 tokens minted, then the lastMintDate
should be allowlistStartTime
+period
*9. This logic functions correctly when mint
is the sole function capable of minting Periodic Sale tokens.
function mint(uint256 _collectionID, uint256 _numberOfTokens, uint256 _maxAllowance, string memory _tokenData, address _mintTo, bytes32[] calldata merkleProof, address _delegator, uint256 _saltfun_o) public payable { [....] if (collectionPhases[col].salesOption == 3) { uint timeOfLastMint; if (lastMintDate[col] == 0) { // for public sale set the allowlist the same time as publicsale timeOfLastMint = collectionPhases[col].allowlistStartTime - collectionPhases[col].timePeriod; } else { timeOfLastMint = lastMintDate[col]; } // uint calculates if period has passed in order to allow minting uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[col].timePeriod; // users are able to mint after a day passes require(tDiff>=1 && _numberOfTokens == 1, "1 mint/period"); lastMintDate[col] = collectionPhases[col].allowlistStartTime + (collectionPhases[col].timePeriod * (gencore.viewCirSupply(col) - 1)); } }
However, other functions, including airDropTokens
, burnOrSwapExternalToMint
, and burnToMint
, can also mint Periodic Sale tokens.
For example, the burnToMint
function has the ability to directly mint Periodic Sale tokens without any restrictions. This increases the value of gencore.viewCirSupply(col)
, leading to a larger value for lastMintDate
. Consequently, the mint
function must wait a longer period to mint the next Periodic Sale token.
function burnToMint(uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o) public payable { require(burnToMintCollections[_burnCollectionID][_mintCollectionID] == true, "Initialize burn"); require(block.timestamp >= collectionPhases[_mintCollectionID].publicStartTime && block.timestamp<=collectionPhases[_mintCollectionID].publicEndTime,"No minting"); require ((_tokenId >= gencore.viewTokensIndexMin(_burnCollectionID)) && (_tokenId <= gencore.viewTokensIndexMax(_burnCollectionID)), "col/token id error"); // minting new token uint256 collectionTokenMintIndex; collectionTokenMintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID); require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_mintCollectionID), "No supply"); require(msg.value >= getPrice(_mintCollectionID), "Wrong ETH"); uint256 mintIndex = gencore.viewTokensIndexMin(_mintCollectionID) + gencore.viewCirSupply(_mintCollectionID); // burn and mint token address burner = msg.sender; gencore.burnToMint(mintIndex, _burnCollectionID, _tokenId, _mintCollectionID, _saltfun_o, burner); collectionTotalAmount[_mintCollectionID] = collectionTotalAmount[_mintCollectionID] + msg.value; }
Let's consider a scenario where we have a collection1 with a Periodic Sale type, starting at 1:00 with a period of 1 hour:
At 1:00, user1 mints a token in collection1 using the mint
function. The value of gencore.viewCirSupply(col)
is 1, and the lastMintDate
is set to 1:00 + (1 - 1) = 1:00.
Prior to 2:00, ten users employ burnToMint
to mint tokens in collection1. Consequently, gencore.viewCirSupply(col)
reaches 11.
After 2:00, user1 again invokes the mint
function for collection1. As a result, gencore.viewCirSupply(col)
increases to 12, and the lastMintDate
is recalibrated to 1:00 + (12 - 1) = 12:00.
In this scenario, the mint
function will have to wait an additional 10 hours to mint the next collection1 token. However, burnToMint
can still mint new tokens in collection1.
Manual Review
To resolve this issue, it is essential to implement a restriction in the contract NextGenMinterContract
that ensures only one token can be minted in every period, as specified for Periodic Sale collections.
Invalid Validation
#0 - c4-pre-sort
2023-11-18T13:43:34Z
141345 marked the issue as duplicate of #688
#1 - c4-judge
2023-12-01T21:05:03Z
alex-ppg marked the issue as not a duplicate
#2 - c4-judge
2023-12-06T14:15:57Z
alex-ppg marked the issue as duplicate of #881
#3 - c4-judge
2023-12-07T12:01:43Z
alex-ppg marked the issue as duplicate of #2012
#4 - c4-judge
2023-12-08T21:08:05Z
alex-ppg marked the issue as satisfactory
#5 - alex-ppg
2023-12-08T21:08:25Z
This is the same submission as #632 by the same Warden, perhaps either should be removed/nullified.
1114.2534 USDC - $1,114.25
https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L252 https://github.com/code-423n4/2023-10-nextgen/blob/8b518196629faa37eae39736837b24926fd3c07c/smart-contracts/MinterContract.sol#L295
The mintAndAuction
function may encounter extended wait times to mint and auction a new token due to an incorrect calculation of lastMintDate
.
As documented in the docs, only one token is permitted to be minted and auctioned during each time period.
One token can be minted and auctioned at each time period, thus is essential to call the setCollectionCosts(..) function and set a timeperiod.
The lastMintDate
variable is utilized to monitor the passing of periods (one token per period), and it is calculated based on the total number of minted tokens, determined by gencore.viewCirSupply(col)
. However, it's crucial to acknowledge that other methods, such as mint
and airDrop
, can also mint tokens. Thus, if tokens are minted through these alternative methods between two mintAndAuction
calls, the lastMintDate
will be updated to a timestamp significantly exceeding the current timestamp
.
function mintAndAuction(address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint _auctionEndTime) public FunctionAdminRequired(this.mintAndAuction.selector) { require(gencore.retrievewereDataAdded(_collectionID) == true, "Add data"); uint256 collectionTokenMintIndex; collectionTokenMintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID); require(collectionTokenMintIndex <= gencore.viewTokensIndexMax(_collectionID), "No supply"); uint256 mintIndex = gencore.viewTokensIndexMin(_collectionID) + gencore.viewCirSupply(_collectionID); gencore.airDropTokens(mintIndex, _recipient, _tokenData, _saltfun_o, _collectionID); uint timeOfLastMint; // check 1 per period if (lastMintDate[_collectionID] == 0) { // for public sale set the allowlist the same time as publicsale timeOfLastMint = collectionPhases[_collectionID].allowlistStartTime - collectionPhases[_collectionID].timePeriod; } else { timeOfLastMint = lastMintDate[_collectionID]; } // uint calculates if period has passed in order to allow minting uint tDiff = (block.timestamp - timeOfLastMint) / collectionPhases[_collectionID].timePeriod; // users are able to mint after a day passes require(tDiff>=1, "1 mint/period"); lastMintDate[_collectionID] = collectionPhases[_collectionID].allowlistStartTime + (collectionPhases[_collectionID].timePeriod * (gencore.viewCirSupply(_collectionID) - 1)); mintToAuctionData[mintIndex] = _auctionEndTime; mintToAuctionStatus[mintIndex] = true; }
Let's illustrate this with a scenario. Consider collection1 with a start time at 1:00 and a period of 1 hour:
At 1:00, user1 initiates the minting and auctioning of a token in collection1 via mintAndAuction
. At this point, gencore.viewCirSupply(col)
is 1, and lastMintDate
is set to 1:00 + (1 - 1) = 1:00.
Prior to 2:00, ten users mint tokens in collection1. Consequently, gencore.viewCirSupply(col)
reaches 11.
After 2:00, user1 invokes mintAndAuction
again for collection1. This results in gencore.viewCirSupply(col)
being updated to 12, and the lastMintDate
is recalibrated to 1:00 + (12 - 1) = 12:00.
As a result, mintAndAuction
is forced to wait an additional 10 hours to mint and auction the next token in collection1.
Mannual
To resolve this issue, it is advisable to introduce a new variable, lastMintAndAuctionDate
, dedicated to recording the time when mintAndAuction
is called. This date should be calculated using a separate counter, ensuring precise time period calculations between various minting and auctioning events.
Invalid Validation
#0 - c4-pre-sort
2023-11-18T13:42:30Z
141345 marked the issue as sufficient quality report
#1 - c4-pre-sort
2023-11-19T08:00:34Z
141345 marked the issue as primary issue
#2 - c4-sponsor
2023-11-22T14:37:33Z
a2rocket (sponsor) confirmed
#3 - c4-judge
2023-12-06T13:10:47Z
alex-ppg marked the issue as duplicate of #881
#4 - c4-judge
2023-12-07T12:01:45Z
alex-ppg marked the issue as duplicate of #2012
#5 - c4-judge
2023-12-08T21:07:43Z
alex-ppg marked the issue as satisfactory
71.228 USDC - $71.23
Minting at publicEndTime
may result in higher minting costs for users than they expected.
The Attack idea of Sales Models says that:
Consider ways in which the minting cost price will differ from the actual value based on the parameters set on the setCollectionCosts() function.
When calculating the price of Descending Sale, the getPrice
function checks if the block.timestamp
is less than the publicEndTime
. Therefore, if the block.timestamp
is equal to the collectionPhases[_collectionId].publicEndTime
, getPrice
will directly return a fixed price, which is much higher than the expected minting cost price.
function getPrice(uint256 _collectionId) public view returns (uint256) { uint tDiff; if (collectionPhases[_collectionId].salesOption == 3) { // increase minting price by mintcost / collectionPhases[_collectionId].rate every mint (1mint/period) // to get the price rate needs to be set if (collectionPhases[_collectionId].rate > 0) { return collectionPhases[_collectionId].collectionMintCost + ((collectionPhases[_collectionId].collectionMintCost / collectionPhases[_collectionId].rate) * gencore.viewCirSupply(_collectionId)); } else { return collectionPhases[_collectionId].collectionMintCost; } } //@audit if timestamp == collectionPhases[_collectionId].publicEndTime, this condition is not satisfied and getPrice will return a fixed price. else if (collectionPhases[_collectionId].salesOption == 2 && block.timestamp > collectionPhases[_collectionId].allowlistStartTime && block.timestamp < collectionPhases[_collectionId].publicEndTime){ // decreases exponentially every time period // collectionPhases[_collectionId].timePeriod sets the time period for decreasing the mintcost // if just public mint set the publicStartTime = allowlistStartTime // if rate = 0 exponetialy decrease // if rate is set the linear decrase each period per rate tDiff = (block.timestamp - collectionPhases[_collectionId].allowlistStartTime) / collectionPhases[_collectionId].timePeriod; uint256 price; uint256 decreaserate; if (collectionPhases[_collectionId].rate == 0) { price = collectionPhases[_collectionId].collectionMintCost / (tDiff + 1); decreaserate = ((price - (collectionPhases[_collectionId].collectionMintCost / (tDiff + 2))) / collectionPhases[_collectionId].timePeriod) * ((block.timestamp - (tDiff * collectionPhases[_collectionId].timePeriod) - collectionPhases[_collectionId].allowlistStartTime)); } else { if (((collectionPhases[_collectionId].collectionMintCost - collectionPhases[_collectionId].collectionEndMintCost) / (collectionPhases[_collectionId].rate)) > tDiff) { price = collectionPhases[_collectionId].collectionMintCost - (tDiff * collectionPhases[_collectionId].rate); } else { price = collectionPhases[_collectionId].collectionEndMintCost; } } if (price - decreaserate > collectionPhases[_collectionId].collectionEndMintCost) { return price - decreaserate; } else { return collectionPhases[_collectionId].collectionEndMintCost; } } else { //@audit return the fixed price when `block.timestamp` is equal to `collectionPhases[_collectionId].publicEndTime` // fixed price return collectionPhases[_collectionId].collectionMintCost; } }
Here is an Exponential Descending Sale Example from the document, the price decreases gradually each second until it reaches the resting price 30mins (3 periods) after the start of the sale and stays there until the end of the sale.
As time goes on, the price of the Descending Sale decreases. Therefore, at the publicEndTime
, the price should be the lowest. However, getPrice
returns the original fixed price, which is significantly higher than user expectations.
This can be easily achieved because the checks in the mint
, butnToMint
and burnOrSwapExternalToMint
functions all require that block.timestamp <= collectionPhases[col].publicEndTime
.
[...] //@audit the check in `mint` shows that block.timestamp can be equal to `publicEndTime` } else if (block.timestamp >= collectionPhases[col].publicStartTime && block.timestamp <= collectionPhases[col].publicEndTime) { phase = 2; require(_numberOfTokens <= gencore.viewMaxAllowance(col), "Change no of tokens"); require(gencore.retrieveTokensMintedPublicPerAddress(col, msg.sender) + _numberOfTokens <= gencore.viewMaxAllowance(col), "Max"); mintingAddress = msg.sender; tokData = '"public"'; } [...]
Manual Review
It is advisable to change the block.timestamp < collectionPhases[_collectionId].publicEndTime
in getPrice
to block.timestamp <= collectionPhases[_collectionId].publicEndTime
.
Context
#0 - c4-pre-sort
2023-11-16T01:42:15Z
141345 marked the issue as duplicate of #1391
#1 - c4-judge
2023-12-08T21:42:19Z
alex-ppg marked the issue as satisfactory
#2 - c4-judge
2023-12-09T01:50:25Z
alex-ppg changed the severity to 2 (Med Risk)
🌟 Selected for report: bird-flu
Also found by: 00decree, 0xAadi, AS, Audinarey, DeFiHackLabs, Eigenvectors, Fitro, Hama, Kaysoft, Krace, REKCAH, SovaSlava, The_Kakers, Viktor_Cortess, cartlex_, degensec, devival, evmboi32, funkornaut, jacopod, openwide, peanuts, rotcivegaf, smiling_heretic, xAriextz, xiao
25.2356 USDC - $25.24
This error resulted in the transfer of the highest bid funds to the wrong recipient, leading to a loss of funds for the token owner.
As outlined in the README, the owner of the token should receive the funds.
- The highest bidder will receive the token after an auction finishes, the owner of the token will receive the funds and all other participants will get refunded.
However, during the execution of the claimAuction
function, the funds from the highest bid are erroneously transferred to the owner of the auctionDemo
contract instead of the owner of the _tokenid
.
function claimAuction(uint256 _tokenid) public WinnerOrAdminRequired(_tokenid,this.claimAuction.selector){ require(block.timestamp >= minter.getAuctionEndTime(_tokenid) && auctionClaim[_tokenid] == false && minter.getAuctionStatus(_tokenid) == true); auctionClaim[_tokenid] = true; uint256 highestBid = returnHighestBid(_tokenid); address ownerOfToken = IERC721(gencore).ownerOf(_tokenid); address highestBidder = returnHighestBidder(_tokenid); for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid); //@audit funds should be transferred to the ownerOfToken (bool success, ) = payable(owner()).call{value: highestBid}(""); emit ClaimAuction(owner(), _tokenid, success, highestBid); } else if (auctionInfoData[_tokenid][i].status == true) { (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid); } else {} } }
Mannual Review
To address this issue, it is suggested that the funds be transferred to the owner of the token. Here is the modified code snippet:
diff --git a/smart-contracts/AuctionDemo.sol b/smart-contracts/AuctionDemo.sol index 95533fb..41b52db 100644 --- a/smart-contracts/AuctionDemo.sol +++ b/smart-contracts/AuctionDemo.sol @@ -110,8 +110,8 @@ contract auctionDemo is Ownable { for (uint256 i=0; i< auctionInfoData[_tokenid].length; i ++) { if (auctionInfoData[_tokenid][i].bidder == highestBidder && auctionInfoData[_tokenid][i].bid == highestBid && auctionInfoData[_tokenid][i].status == true) { IERC721(gencore).safeTransferFrom(ownerOfToken, highestBidder, _tokenid); - (bool success, ) = payable(owner()).call{value: highestBid}(""); - emit ClaimAuction(owner(), _tokenid, success, highestBid); + (bool success, ) = payable(ownerOfToken).call{value: highestBid}(""); + emit ClaimAuction(ownerOfToken, _tokenid, success, highestBid); } else if (auctionInfoData[_tokenid][i].status == true) { (bool success, ) = payable(auctionInfoData[_tokenid][i].bidder).call{value: auctionInfoData[_tokenid][i].bid}(""); emit Refund(auctionInfoData[_tokenid][i].bidder, _tokenid, success, highestBid);
Context
#0 - c4-pre-sort
2023-11-18T13:41:15Z
141345 marked the issue as duplicate of #245
#1 - c4-judge
2023-12-08T22:27:45Z
alex-ppg marked the issue as satisfactory
#2 - c4-judge
2023-12-09T00:22:20Z
alex-ppg changed the severity to 2 (Med Risk)