Skip to content

Commit

Permalink
add basic dutch auction example
Browse files Browse the repository at this point in the history
  • Loading branch information
ggonzalez94 committed Dec 21, 2024
1 parent 019e507 commit 1c516a0
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 5 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@

Auctions are a core mechanism for a wide array of situations where price discovery, liquidity, or allocation of scarce resources is needed. In web3, trustless, on-chain auctions bring transparency, security, and efficiency—empowering anyone, anywhere to participate without intermediaries.
Auction design is a careful balance of encouraging bidders to reveal valuations, discouraging cheating or collusion, and maximizing revenues.
Auctions are everywhere in web3, from NFT sales to MEV, but there's no library that provides teams with base implementations they can extend.
Auctions are everywhere in web3, from NFT sales to liquidations and ICOs, but there's no library that provides teams with base implementations they can extend. This library aims to fill that gap.

## Current Implementations

* [English Auction](src/EnglishAuction.sol): A classic ascending-price auction that allows bids until a deadline and extends time to prevent last-second sniping. Built with extensibility hooks for custom increments, bidder whitelists, and unique asset-transfer logic.
* [Dutch Auction](src/DutchAuction.sol): A descending-price auction that sells multiple identical items. This type of auction is most commonly used for goods that are required to be sold quickly. The default implementation implements a linear decrease in price until the floor price is reached, but this can be overridden to implement a custom price curve.
* [English Auction](src/EnglishAuction.sol): A classic ascending-price auction that allows bids until a deadline and extends time to prevent last-second sniping. Built with extensibility hooks for custom logic like increments and bidder whitelists.

* [Dutch Auction](src/DutchAuction.sol): A descending-price auction that sells multiple identical items. This type of auction is most commonly used for goods that are required to be sold quickly and efficiently. The default implementation uses a linear decrease in price until the floor price is reached, but this can be overridden to implement a custom price curve.

## Examples

You can find examples of how to use the library in the [examples](examples) folder.

## Installation

Expand Down Expand Up @@ -52,17 +57,18 @@ contract MyAuction is EnglishAuction {

## Contributing

We welcome contributions from the community! If you have ideas for new auction types, improvements to the existing code, or better tooling and documentation, please open an issue or submit a PR.
This project is still in early phases of development. We welcome contributions from the community. If you have ideas for new auction types, improvements to the existing code, or better documentation, please open an issue or submit a PR.

## Roadmap

These are some of the next auctions we plan to implement, but it's very early and we're open to suggestions.

* [ ] Dutch Auction
* [x] Dutch Auction
* [ ] Sealed-Bid Auction
* [ ] Vickrey Auction (Second-Price Sealed-Bid Auction)
* [ ] Reverse Auction
* [ ] All-pay auction (also known as a Tullock contest)
* [ ] Support for bidding with ERC20 tokens

## Disclaimer

Expand Down
99 changes: 99 additions & 0 deletions src/examples/NftDutchAuction.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "../DutchAuction.sol"; // Import the provided DutchAuction abstract contract

/**
* @title NftDutchAuction
* @notice Example of a simple NFT collection using the DutchAuction contract.
* For simplicity, all NFTs are pre-minted to the auction contract.
*
*
* Note: This contract is just an example. When launching a new collection,
* you would usually mint the NFTs directly to the buyer instead of holding them in the auction contract.
*/
contract NftDutchAuction is ERC721, DutchAuction {
/// @notice The base URI for the NFT metadata
string private baseTokenURI;

/// @notice The tokenID of the next NFT to sell
uint256 private nextTokenIdToSell;

/**
* @param _seller The address of the seller
* @param _startPrice The initial price per NFT at the auction start
* @param _floorPrice The minimum price per NFT at the auction end
* @param _startTime The timestamp when the auction starts
* @param _duration The duration of the auction in seconds
* @param _inventory How many NFTs will be sold
* @param _baseTokenURI The base URI for token metadata
*/
constructor(
address _seller,
uint256 _startPrice,
uint256 _floorPrice,
uint256 _startTime,
uint256 _duration,
uint256 _inventory,
string memory _baseTokenURI
)
ERC721("ExampleCollection", "EXC")
DutchAuction(_seller, _startPrice, _floorPrice, _startTime, _duration, _inventory)
{
baseTokenURI = _baseTokenURI;

// Pre-mint all NFTs to this contract so they can be sold.
// For simplicity, token IDs start at 1 and go up to _inventory.
// The auction will sell them in order from 1 to _inventory.
for (uint256 i = 1; i <= _inventory; i++) {
_mint(address(this), i);
}

// Set the next token ID to sell
nextTokenIdToSell = 1;
}

/**
* @notice Override the default ERC721 baseURI
*/
function _baseURI() internal view override returns (string memory) {
return baseTokenURI;
}

/**
* @dev Implements the required hook from DutchAuction to transfer purchased items.
* @param buyer The address of the buyer
* @param quantity The number of NFTs to transfer
*
* Since all items are identical (just different token IDs), we give the buyer
* the next `quantity` tokenIDs sequentially.
*/
function _transferAssetToBuyer(address buyer, uint256 quantity) internal override {
// Transfer `quantity` NFTs sequentially from the contract to the buyer.
for (uint256 i = 0; i < quantity; i++) {
uint256 tokenIdToTransfer = nextTokenIdToSell;
nextTokenIdToSell++;
_safeTransfer(address(this), buyer, tokenIdToTransfer, "");
}
}

/**
* @dev Implements the required hook from DutchAuction to transfer unsold items back to the seller.
* @param seller The seller's address
* @param quantity The quantity of unsold NFTs
*
* Since some NFTs remain unsold at auction end, we transfer them all to `seller_`.
*/
function _withdrawUnsoldAssets(address seller, uint256 quantity) internal override {
// Transfer each remaining NFT to the seller.
// At this point, nextTokenIdToSell indicates how many were sold.
// Unsold NFTs are from nextTokenIdToSell to nextTokenIdToSell + quantity - 1.
for (uint256 i = 0; i < quantity; i++) {
uint256 tokenIdToTransfer = nextTokenIdToSell + i;
_safeTransfer(address(this), seller, tokenIdToTransfer, "");
}
// Update nextTokenIdToSell is optional since auction ended. But for completeness:
nextTokenIdToSell += quantity;
}
}
7 changes: 7 additions & 0 deletions src/examples/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Examples

Collection of examples that showcase the usage of the different auction mechanisms, and how they can be integrated with other contracts.

## Dutch Auction

- [NftDutchAuction.sol](./NftDutchAuction.sol): Simple NFT collection that has been pre-minted to the auction contract and all units are equivalent and sold trough a Dutch auction.

0 comments on commit 1c516a0

Please sign in to comment.