Ergo-Native Features
Advanced
1-2 weeks

Шаблон аукциона в цепи (Russian аукцион в eUTXO)

Time-bounded auctions with bids as boxes, automatic winner settlement

GitHub

Problem

You want to sell an asset to the highest bidder without trusting a centralized auction house.

Solution

English auction on eUTXO: the auction box holds the asset, bids are separate boxes. Highest bid at deadline wins. Outbid bidders can reclaim their funds. Winner receives asset, seller receives payment.

How It Works

  1. 1Seller creates auction box with asset, minimum bid, and deadline
  2. 2Bidders create bid boxes with their offer amount
  3. 3Each new highest bid must exceed previous by minimum increment
  4. 4Previous highest bidder can reclaim their bid
  5. 5At deadline: highest bidder wins
  6. 6Winner claims asset, seller claims winning bid
  7. 7Unsettled bids can be reclaimed after deadline

Code Examples

{
  // Auction box holding the asset
  // R4: Minimum bid (nanoERG)
  // R5: Minimum increment
  // R6: Deadline (block height)
  // R7: Seller address
  // R8: Current highest bid amount
  // R9: Current highest bidder address
  
  val auctionNFT = SELF.tokens(0)._1  // Auction identifier
  val assetToken = SELF.tokens(1)     // Asset being auctioned
  
  val minBid = SELF.R4[Long].get
  val minIncrement = SELF.R5[Long].get
  val deadline = SELF.R6[Int].get
  val seller = SELF.R7[Coll[Byte]].get
  val currentBid = SELF.R8[Long].get
  val currentBidder = SELF.R9[Coll[Byte]].get
  
  val auctionActive = HEIGHT <= deadline
  val auctionEnded = HEIGHT > deadline
  
  // Place new bid (must be higher than current)
  val placeBid = {
    auctionActive &&
    
    val newAuction = OUTPUTS(0)
    val newBidAmount = newAuction.R8[Long].get
    val newBidder = newAuction.R9[Coll[Byte]].get
    
    // New bid must exceed current by minimum increment
    val validBidAmount = newBidAmount >= currentBid + minIncrement
    
    // Auction continues with updated bid
    val auctionContinues = 
      newAuction.tokens(0)._1 == auctionNFT &&
      newAuction.tokens(1) == assetToken &&
      newAuction.R4[Long].get == minBid &&
      newAuction.R5[Long].get == minIncrement &&
      newAuction.R6[Int].get == deadline &&
      newAuction.R7[Coll[Byte]].get == seller
    
    // Previous bidder gets refund (if there was one)
    val previousBidderRefunded = currentBid == 0 || OUTPUTS.exists(o =>
      o.propositionBytes == currentBidder &&
      o.value >= currentBid
    )
    
    validBidAmount && auctionContinues && previousBidderRefunded
  }
  
  // Settle auction (after deadline)
  val settleAuction = {
    auctionEnded && currentBid > 0 &&
    
    // Winner receives asset
    val winnerReceivesAsset = OUTPUTS.exists(o =>
      o.propositionBytes == currentBidder &&
      o.tokens.exists(t => t._1 == assetToken._1)
    )
    
    // Seller receives payment
    val sellerReceivesPayment = OUTPUTS.exists(o =>
      o.propositionBytes == seller &&
      o.value >= currentBid
    )
    
    winnerReceivesAsset && sellerReceivesPayment
  }
  
  // Cancel auction (seller, if no bids)
  val cancelAuction = {
    currentBid == 0 &&
    OUTPUTS.exists(o =>
      o.propositionBytes == seller &&
      o.tokens.exists(t => t._1 == assetToken._1)
    )
  }
  
  placeBid || settleAuction || cancelAuction
}

Full English auction contract. Handles bidding, automatic refunds to outbid bidders, and final settlement.

Use Cases

  • NFT auctions
  • Token sales
  • Domain name auctions
  • Rare item sales
  • Liquidation auctions

Security Considerations

  • !Ensure automatic refunds for outbid bidders
  • !Set reasonable minimum increments
  • !Consider sniping protection (extend deadline on late bids)
  • !Audit settlement logic thoroughly
  • !Handle edge cases (no bids, single bid)

Real-World Implementations

ErgoAuctions

NFT auction house

SkyHarbor

NFT marketplace with auctions

Level Up Your ErgoScript Skills

Get notified about new patterns, tutorials, and developer resources.

Follow for daily updates