Some Details About Ergo Auction House

This is honestly amazing, thank you so much!

1 Like

In this thread, I am going to discuss a solution for having NFT Royalty functionality on Ergo.
Our goal is to pay the artist each time his artwork is auctioned and sold with some percentage of the amount.
To achieve that, we can enforce the box with the same ID as the NFT to be provided to the auction contract. Then the contract can make sure that some percentage of the auction amount goes to the contract that is (was) protecting that box - that contract is the artist’s address or a proxy contract which is also spendable by the artist.


The following is the new auction contract that supports custom tokens (e.g., SigUSD), royalties, and timestamp as auction duration:

  val seller = SELF.R4[Coll[Byte]].get
  val endTime = SELF.R5[Long].get
  val minBidDelta = SELF.R6[Long].get
  val currBidder = SELF.R8[Coll[Byte]].get

  // auction currency can be any token like SigUSD
  val isCurrencyERG = SELF.tokens.size == 1
  val getAuctionCurrency = {(b: Box) => {
     if (isCurrencyERG) Coll[Byte]()
     else SELF.tokens(0)._1
  val getAuctionBid = {(b: Box) => {
     if (isCurrencyERG) b.value
     else SELF.tokens(0)._2
  val currBid = getAuctionBid(SELF)

  val extendThreshold = 30 * 60 * 1000L // 30 mins
  val extendNum = 40 * 60 * 1000L // 40 mins

  // this is a bid
  val auctionLogic = if (CONTEXT.preHeader.timestamp < endTime) {
     val newSelf = OUTPUTS(0) // new auction box
     val oldBidRefundBox = OUTPUTS(1) // refund box

     // we extend the auction end time if the bid is placed near the very end
     val newEndTime = if (endTime - HEIGHT <= extendThreshold) endTime + extendNum
                      else endTime

     // preserve auctioned tokens
     newSelf.tokens(0) == SELF.tokens(0) &&
     // correct value and contract for the new box
     getAuctionBid(newSelf) >= getAuctionBid(SELF) + minBidDelta &&
     newSelf.propositionBytes == SELF.propositionBytes &&
     // shouldn't be able to add tokens - will change the currency from ERG to a worthless token
     SELF.tokens.size == newSelf.tokens.size &&
     // currency must be the same
     getAuctionCurrency(SELF) == getAuctionCurrency(newSelf) &&
     // refund the previous bidder
     oldBidRefundBox.propositionBytes == currBidder &&
     getAuctionBid(oldBidRefundBox) >= currBid &&
     // preserve the auction config
     newSelf.R4[Coll[Byte]].get == seller &&
     newSelf.R5[Long].get == newEndTime &&
     newSelf.R6[Long].get == minBidDelta &&
     newSelf.R9[Coll[Byte]] == SELF.R9[Coll[Byte]] &&
     newSelf.R7[Coll[Byte]] == SELF.R7[Coll[Byte]]

  // auction has ended
  } else {
     val winnerBox = OUTPUTS(0)
     val sellerBox = OUTPUTS(1)
     val feeBox = OUTPUTS(2)

     val artistRoyalty = OUTPUTS(3)
     val originalIssuanceBox = artistRoyalty.R4[Box].get
     val dataInput = CONTEXT.dataInputs(0)
     val auctionFee = currBid / dataInput.R4[Int].get
     val feeTo = dataInput.R5[Coll[Byte]].get
     val artistShare = currBid / dataInput.R6[Int].get

     val artistGetsHisShare = { == blake2b256(originalIssuanceBox.bytes) && // the box has integrity == SELF.tokens(0)._1 && // the same ID as the NFT
       getAuctionBid(artistRoyalty) >= artistShare && // gets at least the percentage defined in the auction config box
       artistRoyalty.propositionBytes == originalIssuanceBox.propositionBytes // goes to the artist

     dataInput.tokens(0)._1 == auctionTwinToken &&
     feeBox.value >= auctionFee &&
     feeBox.propositionBytes == feeTo &&
     winnerBox.tokens(0) == SELF.tokens(0) &&
     winnerBox.propositionBytes == currBidder &&
     sellerBox.value >= currBid - auctionFee - maxFee * 2 &&
     sellerBox.propositionBytes == seller &&

@kushti @scalahub and others, please audit when you find the time - at least the changed/added parts.


Even royalties!! That is a godsend, thank you so much!
A brief guide on how royalties will work would be greatly appreciated


A predefined percentage of every auction will go to the original artist. The percentage is a global config and can be modified.


This is really great! I’m sure it will boost adoption of ergo NFTs :pray:t2:.

Maybe it is worth to make an EIP out of it ?


very good upgrade for artists

1 Like

As @kushti said, will be good to have an EIP for this. Few details to be clarified:

  1. What does R7 contain?
  2. What is tokens(1) in non-Erg auctions? I am assuming tokens(0) is the NFT/tokens being auctioned and tokens(1) is the auction currency in non-Erg auctions

Can you add comments at the beginning of the code to explain? (example below)

// R4 The seller's sigmaProp
// R5 The end time in millis
// R6 min bid delta
// R7 ...
// R8 Current bidder's sitmaProp
// R9 ...

// tokens(0) the tokens being auctions (if I understood correctly)
// tokens(1) the auction currency for non-erg auctions, otherwise empty

// dataInput(0) ...

This seems incorrect:

// preserve auctioned tokens
newSelf.tokens(0) == SELF.tokens(0) && // tokens(0) preserved
// correct value and contract for the new box
getAuctionBid(newSelf) >= getAuctionBid(SELF) + minBidDelta &&
// tokens(0) not preserved above

because getAuctionBid operates on tokens(0) and so the tokens are preserved in one and not in the other line. This is related to next comment.

Also, the following seems incorrect:

val getAuctionCurrency = {(b: Box) => {
   if (isCurrencyERG) Coll[Byte]()
   else SELF.tokens(0)._1
val getAuctionBid = {(b: Box) => {
   if (isCurrencyERG) b.value
   else SELF.tokens(0)._2

do you mean following?

val getAuctionCurrency = {(b: Box) => {
   if (isCurrencyERG) Coll[Byte]()
   else b.tokens(1)._1 // should be b instead of SELF, and tokens(1)
val getAuctionBid = {(b: Box) => {
   if (isCurrencyERG) b.value
   else b.tokens(1)._2 // should be b instead of SELF, and tokens(1)

In preserving the auction config for a bid case, we also need to ensure that R8 is a Coll[Byte], otherwise someone may set it to another type and make the box unspendable.

I’ll add more comments if any after the above is clarified

1 Like

Sure, will do that with addressing comments also.


Trying to list an NFT using Yoroi wallet is there any instructions thanks. NFT is an image

Here you go! @Ergosmergo

How To Issue an Artwork NFT Auction

1 Like

Thanks, I’ll check out the video here is an example of my NFT. I am also going to work with an artist to bring a limited collection of NFT if I get success with my first ERGO collection I will create more. Is there any option to add an IPFS hash to the image within the auction for the winning bidder so that the higher-res images can be downloaded?

Here is an example of what I can up with this is AI art generated by a neural network.

I am still thinking up some ideas. Since ETH blockchain is pricey for NFT I am pointing my artist friends more towards ERGO.


Ergo Auction House and Ergo Utils now support IPFS.
Any artwork (picture, audio) issued from now on, will be upload to IPFS.

Stay tuned for more updates.


Another use-case for recently found property - using spent boxes as proof in ergo script:

An NFT collection is a category to which some NFTs belong. In the simplest case, an artist can have a “modern arts” collection and mint his modern arts in that collection. This way, an artist can have multiple collections to better present his artworks. This thread is a solution on how to handle collections in a decentralized way on Ergo.

Let’s consider each collection as an NFT on the blockchain with some properties like collection name, description, cover image, etc.
The artist can create a collection NFT and own it in his wallet. Once he wants to mint an artwork in that collection, he can simply mint the NFT by putting the box containing the collection NFT in the first input of his minting transaction. The artwork NFT ID will be equal to the box ID containing the collection NFT. This way, not only it is possible to verify that artwork belongs to a specific collection off-chain, but also it is possible to do so in ergo script. The way to do that is by simply providing the spent collection box to the contract, then the artwork NFT ID must be equal to the provided box’s ID and the provided box must include the collection NFT. It is obvious that no one but the artist can mint artwork in that collection!


Good idea, how we can calculate number of artwork tokens in a particular Collection ?


If you mean off-chain, some app that cares (e.g., auction house) will keep track of collections. Then when an artwork is issued it is obvious that it is in one of the collections that we are keeping track of because the NFT ID is among the collection IDs.

1 Like