How To Build An Auction Marketplace On Cardano
Tags: Nft Marketplace, Cardano, Ada Blobs, Open Source, Nft

Today I am excited to launch the ADA Blobs smart contract marketplace on Cardano! This is the first auction NFT marketplace on the Cardano Blockchain and I will explain how it works in this Blob post.

The ADA Blobs project is entirely open source. You can follow along with the website source code as well as the Plutus source code. This Blob post will show you how to create an auction contract with Haskell and Plutus along with building an submitting transactions to the Cardano Blockchain with Javascript, the Cardano Serialization Library, and the Nami Wallet.

An adorable ADA Blob named Bob

Introduction

Cardano uses the extended UTxO model which is similar the UTxO model used by Bitcoin, but with the additional ability to add arbitrary data to the transactions.

UTxO stands for “Unspent Transaction Output” and works similarly to how you would pay with cash at a store. Let’s say you wanted to buy an adorable stuffed animal Blob for $10 at the toy store, but you only have a $20 bill. You would give the entire $20 bill to the cashier and they would give you back a $10 bill in change. Now lets say you similarly wanted to send someone 10 ADA (10₳) but you only have 1 UTxO in your Cardano wallet with 20₳ on it. The input to the transaction would be the UTxO with 20₳ and you would get back a UTxO with 10₳ in change.

The Bitcoin UTxO model

This model works well for sending and validating transaction on the blockchain but there is a fundamental limitation. We cannot create more complex transactions because we do not have access to additional additional blockchain data or programmable validators.

A vicious and aggressive ADA Blob named Yolg

The eUTxO Model

To solved this problem, the eUTxO model was developed for Cardano. This gives developers access to the Plutus language which allows them to create custom on-chain validators. Along with Plutus, the eUTxO model allows developers to attach data called datum to a transaction as well as supply data called the redeemer when a UTxO sitting at a script address is trying to be spent.

The example below showcases Bob sending funds to a script address and Yolg withdrawing those funds after a Plutus Validator evaluates to “true” for the transaction.

Bob sending funds to a Plutus script address

Yolg withdrawing funds from a script address

In the above example, Bob sends 40₳ to a script address. He supplies a 100₳ UTxO as input and instructs the output to be a 60₳ UTxO back to Bob as change and a 40₳ UTxO to the script address. Bob also supplies a datum called State 0. The Plutus Validator evaluates to true and the script is send 40₳.

Now Bob’s friend Yolg wants to withdraw some of the funds that Bob sent to the script address. Yolg creates a new transaction with the UTxO at the script address being used as input and the outputs are a UTxO with 20₳ to Yolg and another UTxO with 20₳ back to the script address. Yolg supplies a “Withdraw” redeemer and the datum on the output UTxO at the script transitions from State 0 to State 1.

A Plutus Validator will take in 3 inputs and return true or false. Validator(Datum, Redeemer, ScriptContext) = True. If the validator evaluates the true, the transaction succeeds. If not, the transaction fails.

A compressible ADA Blob named Glob

Creating the ADA Blobs Validator

To create the Plutus Auction Validator for ADA Blobs, we need to handle 3 possible user actions:

Starting a auction

Bidding on an auction

Closing an auction

Starting an Auction

To start an auction for a Blob NFT, we need to send our script address a UTxO with the Blob NFT along with a datum that will be used by the Plutus Validator to determine how others can bid on the Blob.

For example, if our datum has a minimum bid value and a bidder tries to bid less than that value, the bidder’s transaction will return false and fail.

Haskell data types for our Auction Datum

As you can see from above, our AuctionDatum will have 2 parts, an AuctionDetails and a Maybe BidDetails.

We want the auction details to always be the same throughout the auction so we will set the auction details when starting the auction. We won’t set the bid details yet as we will let the bidders set that value when they bid for our ADA Blobs.

Later in this Blob post I will show you how we can actually build the transaction off chain for starting an auction using Javascript the Cardano Serialization Library.

Bob starting an auction for a Blob NFT

Bidding on an Auction

Now that we have submitted a transaction to start our blob auction, we need to give others a way to bid on the auction.

The bidder will supply a new datum with their updated bid as well as a “Bid” redeemer (action) to spend the UTxO that exists at the script address. The validator script will than check to make sure the a bid is valid (larger than all other bids and the reserve amount) and that we set the next datum correctly (validating that the bidDetails data is the same as how much ₳ the bidder actually sent to the script address).

ADA Blobs Plutus Validator for the “Bid” redeemer

Glob bidding 100₳ for a Blob NFT

As an example lets say Glob bids 100₳ for the Blob NFT that Bob put up for auction. Now the script address has 101₳ and a Blob NFT.

Note: The extra 1₳ is because Cardano native tokens cannot be at a script address with no ₳. This is because then you would not be able to send the token because you would not be able to pay the Cardano Blockchain fees.

Yolg bidding 200₳ for a Blob NFT. This outbids Globs 100₳

Now Yolg comes along and wants to bid 200₳ for the Blob NFT. Yolg will send 200₳ to the script address, and 100₳ sitting at the script address will be returned to Glob.

We have to ensure with the bid transaction that if a bidder gets outbid, that their funds are correctly returned to them. All of this validation is performed in the bid section of the validator. The full source code contains additional helper functions for this process. You can follow along with the full Plutus source code here.

Closing an auction

After an auction is complete, anyone can close the auction which will send the bid funds to the seller, and the Blob NFT to the bidder. We require the “Close” Redeemer to close the auction. The validation for closing the auction includes code that ensures the auction deadline has passed. You can view the code for the close portion of the validator below.

ADA Blobs Plutus Validator for the “Close” redeemer

In our example, lets say the auction has closed. Yolg would get the Blob NFT and 1 ₳ at the script address and Bob would get the 200₳ at the script address.

Yolg gets 1₳ and the Blob NFT while Bob gets 200₳ when the auction closes

A rare and squishy ADA Blob named Rooboo

Building the Transactions with Javascript

Plutus is split up into On Chain and Off Chain code. The above contents address the On Chain validation code, but we still need to build the transactions and submit them to the Cardano Blockchain. While this project was being created, the Plutus Backend Application (PAB) had difficultly integrating with wallets. So instead of using Haskell to build the transactions that will be submitted to the Cardano Blockchain, ADA Blobs uses Javascript and the Cardano Serialization Library.

The code for constructing all 3 types of transactions can be found in this source code.

Building the Start Auction Transaction

In order to start our auction we need to construct our initial AuctionDatum, construct the desired outputs of the transaction, and select our input UTxOs that must contain the Blob NFT that we are intending to auction.

Typescript datatypes that matches the Haskell datatypes

We now need to take our typescript object and convert it into data that Plutus can understand. For that we need to use the Cardano Serialization Library. However, we need to add some custom functionality for it to work properly at the time of writing this. Originally SpaceBudz implemented a custom version of this library to build the transactions correctly. I copied their implementation here.

Cardano requires our data to be in a specific format in order to properly submit the transactions. I suggest reading this page on the Cardano Documentation in order to understand the JSON format that is required.

In my datum.ts file. I have commented the JSON structure that corresponds to the Haskell datatype that the function is trying to build. The easiest way to understand how to build the datum with the Cardano Serialization Library is the read the START_DATUM function I have created here.

JSON structure that will be submitted to the Cardano Blockchain for the Auction Datum Haskell datatype

A blobby ADA Blob named Oobby

With our Datum constructed we now need to create our desired outputs and select our input UTxOs. For our outputs we want to create a UTxO with a Blob NFT. Along with this, it is good practice at this time to include the datum as Metadata in the transaction so we can view it later in our bid off chain Javascript code. The below code constructs such an output.

Constructing the Start Auction output

Finally, we need to select our input UTxOs for the transaction. To do this we will use the random improve coin selection algorithm. I don’t want to get too technical into this algorithm here so I have provided a link to the algorithm from IOHK above. Essentially, the algorithm selects UTxOs in such a way that the outputs will allow future payments with a minimum number of inputs.

For ADA Blobs, I copied the algorithm implementation from SpaceBudz in the CoinSelection.ts file. I suggest copying this as well.

Finally with our datum, inputs, and outputs we can construct, sign, and submit the transaction.

Submitting our Auction Transaction!

An overly large ADA Blob named Blurp

Building the Bid Transaction

We will be building the bid transactions in a very similar way to the auction transactions. The differences occur in our bid transaction output and the requirement that we set a transaction time to live (ttl). For our output, if there is already an existing bid for our ADA Blob, we need send the previous bidder’s funds back to their address with the code below.

Paying back the previous bidder in our transaction outputs

We also need to set a validity start interval and time to live since bid validation will depend on the time that the bid transaction occurs.

Setting a validity start interval and ttl for our bid transaction

With this data set along with our updated datum, outputs, and inputs we can sign and submit our bid transaction!

A small and squeaky ADA Blob named Peep

Building the Close Transaction

We are almost done! We need to build our close transaction to give the highest bidder the ADA Blob NFT and the seller the highest bid. There is a case we also have to cover where nobody bids on the adorable pet Blob that is up for auction (but realistically that will never happen because they are so cute). For completeness however, we should include that in our “Close” code.

The close outputs which will give the bidder the Blob NFT and the seller the highest bid

The code above will give the highest bidder the adorable Blob NFT and the seller the highest bid amount. The “splitAmount” function you see there splits the output between the seller and the ADA Blobs marketplace fee which is 1%. The On Chain validation code takes this fee into account which you can see in the source code.

Along with the outputs we will need to set a time to live (ttl) for the Close transaction as well because the close transaction also depends on time.

A tasty chocolate ADA Blob named Broogr

Summary

After a few weeks of testing on the Cardano testnet and mainnet the ADA Blobs project is working perfectly! There are 300 adorable pet Blob NFTs that will be released 1 a week for the next 6 years. I’m excited to release this project and open source it to the community for everyone to learn from.

If you would like to join the Blob community, we’ve got a Discord Server and a Twitter for all your Blob needs.

Cardano projects are ramping up very quickly now and it is an exciting time to be a part of the community. Feel free to check out the ADA Blobs source code to use in your own projects!

ADA Blobs website source code: https://github.com/NicholasMaselli/ADABlobs

ADA Blobs Plutus smart contract source code: https://github.com/NicholasMaselli/ADABlobsPlutus

A legendary ADA Blob named Bluub. None have seen this Blob and lived to tell the tale