Dissecting the price-based market contracts contracts
The spot market contract logic an be best broken down by inspecting the logic of the code therein. The first thing a market needs is a way to create a sale. Now, unlike a traditional smart contract, atomic markets can leverage token contract’s themselves to interact with a market. In that, today when most people interact with an exchange contract, what they are doing is depositing a token into the exchange contract, and then sending a second successive transaction to the same contract telling it to create a sale with the deposited token.
But that’s annoying! It means more transactions for one, and for two it means handing over custody of the asset to this contract until you withdraw it. Instead, using an extension to the NFT contract, we define a function which instead grants a contract address the ability to swap the specified NFT for the seller’s desired price:
The above function is what we use to create sale listings for NFTs. Now, this may be non-obvious as to exactly how it does that. Where do you define the price for the asset, and furthermore, how does the NFT contract know how to tell the market that this is intended to create a market sale listing versus just approving some random third-party an allowance (which is the traditional use-case for allowance functions like this)? That’s best broken into two parts.
First, the price is specified in the _data parameter of the function. We do so by encoding the function call data for the market’s `createSale` function (which is defined later). To encode it we can make use of the following snippet:
As you might see in the above, we set a price for the NFT by passing in the NFT to sell, the address of the seller, and the value that the seller is asking for (in fungible-token terms). Finally we pass in this data directly into the “approveAndCall” function by using something like the following:
The above effectively authorizes the market contract to swap the asset if a matching buy order is met (and it does so without releasing custody of the asset itself)!
Now, the second part of the “approveAndCall” function necessary to satisfy this form of sale creation is a function called “callOperator”. Since what happens inside of that function is best explained in detail in another post, the simple summary is that it is used to look up whether the address being granted this approval defines a successive function that the NFT should invoke after having granted it approval. In this case, the recipient address indeed defines such a function.
When we approved the market contract address, it was able to look up from a registry using the address parameter specified and in return the registry was able to effectively tell the NFT contract what it needs to do next. In this case, in addition to granting approval to the market, the NFT needs to invoke a create sale function in that same recipient address. Voila! This seemingly complex logic flow is what allows the creation of a sale in the spot-market’s order book.
Next, we define an additional function so that we can retrieve all NFTs currently listed for sale in the spot-market:
Summarizing the above, this function returns all of the IDs currently approved for atomic swaps in the market.
No market is complete if all you can do is list a sale! We also need a way to purchase the NFTs listed for sale. To do this, we define a very similar function to the one we defined to create a sale, but this time we do so in our fungible token contract:
This function is what allows the market to satisfy an existing sale listing. Since this function is fundamentally similar to the NFT’s sale creation function, we don’t need to break down how the contained logic works. What is different, however, is the logic found when the registry contract responds to the fungible token contract, and the “_userData” parameter requirement. For this parameter we need to pass it the purchasing data as an encoded parameter. We can do so with the following (and then pass that data into this function in the same way we did so with the NFT approve function):
Also, since we aren’t creating a sale with our fungible tokens, and have instead purposed them as a buying instrument, the registry contract will respond to the “callOperator” invocation with the logic used to buy the specified NFT (which the token contract will successively use):
To summarize this comparatively monster-looking logic, when the market is given approval for an amount of tokens, along with encoded data which can be decoded to find the prescribed sale the buyer is wanting to buy, then the fungible token is will initiate the swap for the seller’s NFT.
Now, while that sums up the majority of how these contracts work, there is one additional functionality contained in this box that serves as an extra bit of icing on the cake:
What market is complete without giving the operator of the market the ability to take a little bit of the profit?! What is described above is the logic that when the buy function is called, part of the profit from the sale is distributed to the owner of the market. This particular cut can be customized and changed to your own heart’s content.
That’s it! However, what might not be obvious yet, is why this is not where the series ends. Without jumping too far ahead, spot markets are not perfect solutions. Many cases require ultimately changing exchange behavior to satisfy the constraints of the complexity of the market, or to disrupt types of behaviors frequently exploited by users of said markets. But that will be the topic of the next post.
Hungry for More Nori?
- Listen to our podcast.
- Review our webinars on different elements of the market design.
- Read our white paper for technical details.
- Follow me on Twitter
- Not an accredited investor, but still want to support? Invest in the public campaign on Republic.