Never ending refundable dutch#
Medium Risk
A canvas can be put on refundable dutch auction. When setting up an auction, the seller defines totalQuantity
. The auction is considered to be over when the amount of tokens minted matches the canvas.totalQuantity
.
However, that value can be set so high (intentionally or unintentionally) that the auction never ends. Or there simply is not enough interested buyers.
Since the auction is considered as ongoing, funds cannot be withdrawn from contract.
Recommendation#
Allow withdrawing even if totalQuantity
is not reached, as long as dutchEndTime
is. In that case you can be sure that the end price will equal canvas.dutchEndPrice
. So you can take canvas.dutchEndPrice
instead of ds.canvasSystem[canvasId].dutchEndPrice
(which is set when last token is minted) to calculate how much was earned so far and how much can be refunded. Notice that in such case, it would also be important to track how much was paid out so far. It would be recommended to limit how long an auction can last, otherwise if canvas.dutchEndTime
is set too far in the future, this solution will not help.
In payoutAction
you can do it like this:
if (canvas.refundableDutch) {
uint endPrice = ds.canvasSystem[canvasId].dutchEndPrice
if(endPrice == 0) {
if(canvas.dutchEndTime > block.timestamp) revert SaleOngoing();
endPrice = canvas.dutchEndPrice;
}
uint tokenIdCounter = ds.canvasSystem[canvasId].tokenIdCounter;
revenue = (tokenIdCounter - ds.canvasSystem[canvasId].payoutCounter) * endPrice;
ds.canvasSystem[canvasId].payoutCounter = tokenIdCounter;
if(tokenIdCounter == canvas.totalQuantity) {
ds.canvasSystem[canvasId].auctionPayout = true;
}
}
ds.canvasSystem[canvasId].payoutCounter
is added.
In claimRefundableDutch
you can do it like this: