How Barter Built a Direct NFT Trading Interface for Real-time Negotiation

How to create an NFT Marketplace | A deep dive into how a ConsenSys Academy student built a NFT trading interface with an on-chain order book to enable real-time negotiation and new item discovery, using Truffle and Infura!

How Barter Built a Direct NFT Trading Interface for Real-time Negotiation

The Meteoric Rise of NFTs

If you’ve been following the crypto space lately, you’ve probably seen that Non-Fungible Tokens (NFTs) have been the talk of almost every artist and creator. From the sale of Beeple’s “Everydays: The First 5000 Days” for $69.3M to NBA Top Shot surpassing $205 million in total sales within six months to EulerBeats generating more than $1.1. Million in royalties during its first week, interest in NFTs is at an all time high. Across the board, we have seen NFTs enable the financialization of digital goods: art, music, content, virtual land, gaming collectibles, and essentially anything that benefits from verified authenticity and provable ownership rights.

While artists have been continuously setting records with their sales, the NFT marketplaces and galleries have also been exceeding expectations. Currently, the gallery model, which curates an exclusive selection of art for buyers like a traditional art gallery, has been generating less volume compared to marketplaces, which are akin to an art bazaar where anyone can display their works for sale. For example, the curated nature of Nifty Gateway and SuperRare limits the number of artists who are allowed on the platforms, creating an allure of brand recognition and exclusivity compared to platforms like OpenSea and Rarible which allow anyone to post their NFT. That being said, both models have experienced immense growth in this NFT boom.

Monthly protocol users for Rarible, a leading NFT marketplace, hit an all time high for March, surpassing 58,000.

Data Source: Dune Analytics

Superare, the top NFT gallery, surpassed $15 million in volume for the month of March.

Data Source: Dune Analytics

Artists sold 2,000 works on SuperRare in March, marking an all-time high for the gallery.

Data Source: Dune Analytics

Currently, NFT aggregators, issuance protocols, and generalized marketplaces are driving the growth of the NFT space and are the more obvious market opportunities. Below are a handful of the leading art platforms and marketplaces today:

Source: Messari

It’s undeniable that the market is assigning real value to provable digital ownership and this new open creative economy is here to stay. Over time, we expect to see value continue to flow into these marketplaces and competition to heat up as new novel platforms are introduced. We also expect that the success of these platforms will ultimately come down to their ability to attract users and creators by devising markets for participants to easily mint, collect, showcase, and trade art and collectibles. The question now becomes: given the current NFT landscape, where are the opportunities and how can we build marketplaces to address the needs of this growing niche?

While there are many NFT marketplaces we could explore, we thought we would take the time to introduce a new project called Barter, recently built by a ConsenSys Academy student. We’ll show you how the project implemented an on-chain order book for NFT trading, and how they plugged in Infura and Truffle to get it off the ground quickly. After you review this project, you can better understand how these marketplaces can be created, and the additional opportunities that exist for them.

How I Built This: Barter

Barter is a project built by Robert Clark, a student from ConsenSys Academy that is specifically engineered for a future where video game assets are tradeable and where the Metaverse (as coined by Neal Stephenson) begins to emerge as a social phenomenon. People already buy, collect, and curate assets inside video games (characters, armor, weapons, etc) so the ability to trade them directly with other players would be explosive. With Barter, a direct trading interface between two people allows for real-time negotiation as well as new item discovery. This creates a more natural trading experience that is already the norm across games like Rocket League and Runescape.

In this section, we walk you through how this developer built Barter from the ground up, using Infura and Truffle.

Project Structure

Barter's user interface is quite simple, consisting of a one-page react app that can toggle between the “trade proposal” page and the “offers” page. Once a user has connected their Metamask account and added the recipient’s address, they click ‘Propose Trade’ and create a trade offer. A transaction prompt appears and allows them to send the offer on-chain. For the user on the other side of the trade, an offer will pop-up for them in the offers box, accessible via the button in the top right corner. This offer will give them a brief overview of the NFT and its price, along with an accept and reject button. If the user clicks accept and sends the prompted transaction, the trade will execute.

On the Solidity side, Barter was set up as an on-chain order book for NFT trading. In order to successfully complete an NFT trade between two users, one user first must create an offer and post it to the contract. Offers are address specific, so the user making the offer must know who they want to trade with ahead of time in order to successfully complete the trade. Once the offeror is done configuring their trade in the UI, they can proceed to posting a TradeOffer, an instance of which is shown below:

struct TradeOffer {
        address payable offerer;
        address payable asker;
        uint[] offer;
        uint[] ask;
        address[] offerContract;
        address[] askContract;
        uint offerLength;
        uint askLength;
        uint offerVal;
        uint askVal;
        uint feePaid;
        State state;
    }

This offer is made up of 4 main pieces of information;

1) the trader addresses,

2) arrays of offered and asked NFT IDs,

3) arrays of offered and asked NFT Contract addresses, and

4) an optional amount of ETH val that can be added to either side of the offer.

The contract tracks an array of every offer posted, and has many safeguards put in place to make sure there are no ways for NFTs or ETH to be sent around without proper completion of an offer. For example, the addOffer function as shown below is made up almost entirely of different require statements. In order to make an offer, the contract first must verify that the offeror actually owns the NFT, has submitted the right amount of ETH as a fee, and has tried to trade at least one NFT, among other verifications.

function addOffer(uint[] memory _offer, address[] memory _offerContract
                    , uint[] memory _ask, address[] memory _askContract
                    , uint _offerVal, uint _askVal, address payable _targetAddress) 
                    public payable stopInEmergency() returns (bool) {
 
        require(_offer.length >= 1 || _ask.length >= 1);
        require(_offer.length == _offerContract.length);
        require(_ask.length == _askContract.length);
        require((_offerVal+fee) == msg.value);
        for(uint i = 0; i < _offer.length; i++) {
            ERC721 con = ERC721(_offerContract[i]);
            require(approvedERC721[_offerContract[i]]);
            require(con.ownerOf(_offer[i]) == msg.sender);
            require(con.isApprovedForAll(msg.sender, address(this)));
        }
 
        for(uint i = 0; i < _ask.length; i++) {
            require(approvedERC721[_askContract[i]]);
        }
 
        emit LogOfferAdded(offerCount, msg.sender);
        offersByAddress[_targetAddress].push(offerCount);
        offerCountByAddress[_targetAddress] = offerCountByAddress[_targetAddress]+1;
        offersCreatedByAddress[msg.sender].push(offerCount);
        offersCreatedCountByAddress[msg.sender] = offersCreatedCountByAddress[msg.sender]+1;
                offers[offerCount] = TradeOffer({offerer: msg.sender
            , asker: _targetAddress
            , offer: _offer
            , offerContract:_offerContract
            , ask: _ask
            , askContract:_askContract
            , offerLength:_offer.length
            , askLength:_ask.length
            , offerVal: _offerVal
            , askVal:_askVal
            , feePaid:fee
            , state: State.Active});
        offerCount = offerCount + 1;
        
        return true;
    }

There is a similar set of checks for accepting a trade, as the original offeror may have ditched all the NFTs they originally had after the offeree took too long to accept. This is slightly redundant from a security standpoint but it protects against offers being created when they have no hope of being accepted.

Plugging in Infura and Truffle

Using Truffle along with Infura made the connection to a testnet (Ropsten) straightforward and easy. There was a declaration of the mnemonic from the HDWalletProvider along with our Infura ProjectID. Then we simply acquired some Ropsten ETH from one of the faucets available and used the boilerplate Truffle code to migrate to Ropsten. Once it was successfully deployed, we got the contract IDs and replaced the contract variables in our React code to point to the correct contracts.

ropsten: {
   provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/${infuraKey}`),
   network_id: 3,       // Ropsten's id
   gas: 5500000,        // Ropsten has a lower block limit than mainnet
   confirmations: 2,    // # of confs to wait between deployments. (default: 0)
   timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
   skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
   }//,

Future State

The on-chain order book design choice of this project has certain limitations. Every offer must be a transaction, which can get expensive when Ethereum is nearing full utilization. But if this project is deployed on a high throughput layer two (L2) solution, potentially one with video game assets with low enough value to merit trading en masse, this interface could be a very useful tool.

Changes to the user interface, from a matching engine perspective, could open up other possible extensions for this project. Unlike the OpenSea bulletin board approach, the trading interface approach could be extended to allow users to set preferences for acquiring different types of items, and a multi-party trade matching engine could sort through different ways to help them acquire that item. Say party 3 has an item you want, and you have what party 2 wants, but not what party 3 wants. The interface could set up a 3 way trade to satisfy all parties involved.

One final nuance that is interesting to consider is that usually when interfaces are built like this, they are for one specific game. Because of the interoperability of ERC-721 this can be extended to trade any two things of value. You could trade a digital painting for Metaverse outfit, or even swap deeds to your homes with a friend.

Conclusion

Overall, we’re fascinated by the increase in interest and evolution of NFTs and expect to see even more activity in the coming year. We’re proud that developers are leveraging Infura to build decentralized apps that allow creators to share art and interact directly with an enthusiastic community of collectors.

Building an NFT project? Infura is a critical part of your toolkit. Sign up for free and unlock robust, scalable tools for Ethereum and IPFS development.


Twitter | Newsletter | Community | Docs | Contact | Open Roles

Huge thanks to Robert Kruszynski and Mattison Asher for their contributions to this guide. For more Web3 tutorials, check out the Infura Blog and ConsenSys Academy.