Intro
Note: I didn’t proof-read this very hard (at all). Please excuse any errors.
SudoSwap, an NFT exchange previously best known for peer-to-peer, no-fee swaps, released its AMM (automated market maker) for NFTs recently. This generated a lot of hype, but it also generated its fair share of confusion and led to people to ask things like, “so why isn’t this just another NFT marketplace?” My goal here is to help clear up a bit of that confusion.
Before we get into it, some broad reasons you should care to learn about SudoSwap’s AMM model:
Instant liquidity for buying/selling
Fully on-chain (no centralized orderbook)
Cheaper pricing at times
Only 0.5% marketplace fees
No royalty fees (unsurprisingly, this has been a bit controversial)
Aggregators can take advantage of SudoSwap pricing, giving even non-SudoSwap-familiar users better pricing when available
Growing traction
You’ve probably already heard about it on Twitter
Based Ghouls has done 730 ETH volume, Webaverse 755 ETH, CloneX 245 ETH, as some highlights
5k+ ETH total volume, according to Dune
Ability to earn trading fees
Ability to automatically DCA into/out of collections
I’ll divide this up into 4 sections:
NFT Exchanges: Orderbooks vs AMMs
SudoSwap AMM Architecture
Developer’s Note
How to Think About SudoSwap
NFT Exchanges: Orderbooks vs AMMs
Most NFT marketplaces that you’re probably used to, like OpenSea and LooksRare, rely on off-chain orderbooks to facilitate gas-efficient trading. To help you understand what this means, let’s look at an example:
You want to sell a Bored Ape (BAYC) for 100 ETH. You go to an exchange like OpenSea to list it for sale.
OpenSea has you sign a message using your wallet, signaling that you want to sell that BAYC for 100 ETH. You can get more complex here with your orders here, obviously, but let’s keep it basic for this example.
Your signed order is stored in an off-chain orderbook, hosted in a database by the exchange, and displayed on their interface (and exposed via their API) for potential buyers to browse.
Your order sits there until it is either bought or you decide to cancel it:
Bought: Someone decides they like your BAYC enough to spend 100 ETH on it, so they take your order (grabbed from the exchange’s off-chain orderbook) and submit a transaction to fill it. They get the NFT, you get 100 ETH (minus exchange fee + royalty fee).
Cancelled: You have to submit a transaction to cancel it. Since your order was stored in an off-chain orderbook, anyone could submit the transaction to fill it unless you tell the exchange’s smart contract “hey, I want to mark this order as invalid; if someone tries to fill it, don’t let them”.
This model comes with several advantages, including that users do not have to pay gas (after initially approving the exchange contract to move their NFTs) to list or bid on NFTs. Gas is only paid for execution. A downside is that the exchange hosts the entire orderbook off-chain, which can make it tougher to obtain all orders - issues that some developers have had with obtaining OpenSea API keys are a testament to this.
Another downside is that all pricing must be “active”; you cannot specify things like “if my first NFT sells at 1 ETH, try to sell the next one for 1.3 ETH”. On an orderbook-based exchange, your listings would need to be adjusted manually (unless you trusted the exchange enough to give them your private keys to cancel/sign new orders for you - given BAYC holders’ relationship with their private keys, maybe exchanges should look into this for them).
SudoSwap takes a completely different route, using an on-chain AMM model rather than an off-chain orderbook. Let’s walk through the same example as above, selling a BAYC for 100 ETH, using the AMM rather than the orderbook:
You want to sell a BAYC for 100 ETH via an AMM. You go to SudoSwap.
SudoSwap has you deposit the NFT into a “pool” smart contract, and you specify the price you’d like to sell it at.
Your pool contract can be queried to obtain the price of the NFT.
Your NFT sits there until it is either bought or you decide to cancel it:
Bought: Someone comes to SudoSwap and wants to buy your BAYC. They submit a transaction to purchase it, removing it from the pool and directing 100 ETH to you (minus a 0.5% exchange fee, but no royalty fees).
Cancelled: You withdraw your NFT from the pool.
Although the AMM model requires you to pay gas to list your NFTs, it’s all on-chain and publicly query-able. Overall, though, both models seem pretty similar thus far. However, an AMM-based model allows you to do a few interesting things that would not be possible using an orderbook. To understand how, let’s look at how SudoSwap really works.
SudoSwap Architecture
If you’re familiar with Uniswap V2, SudoSwap’s NFT AMM can be roughly thought of as “Uniswap V2, but with multiple, custom liquidity pools for the same token”, where token = NFT collection and custom liquidity pools = optionally different pricing curves and spot prices. These differences make sense given the non-fungible nature of NFTs vs ERC20s.
If that doesn’t make any sense to you, let me try to explain it in a simpler way by focusing on how a single NFT collection works on SudoSwap. We’ll use Based Ghouls as an example. When you pull up the Based Ghouls page on SudoSwap, here’s what you get:
What do the 4 stats up top mean? The “Floor Price” is the cheapest price you can buy at (0.226 ETH). The “Best Offer” is 0.219; this means that it’s possible to instantly sell a Based Ghoul for 0.219 ETH on SudoSwap (how this works will be explained soon). “Offer TVL” means that there is 36.23 ETH in SudoSwap liquidity pools for Based Ghouls (again, will be explained soon), and “Volume” is just how much ETH volume Based Ghouls have seen traded on SudoSwap so far.
Now, the difference between this AMM model and an orderbook model begin to become apparent when you look at the floor NFTs. At the time of writing, there are 21 Based Ghouls listed for 0.226 ETH. This is very different from OpenSea or LooksRare, where you’ll usually see something like 1-3 assets listed at the floor.
The reason for this pricing is that, for NFTs trading on SudoSwap, buying and selling is done through liquidity pools. Most of these floor assets likely reside in the same liquidity pool, and pricing will dynamically change as NFTs are bought (you could not currently go in and buy all 21 floor NFTs for 0.226 each).
But I’m getting ahead of myself here. This whole “pool” situation may be best shown, again, through an example. There are three types of liquidity pools on SudoSwap - “Token”, “NFT”, and “Trade” - but let’s start with an “NFT” pool. This type of pair can be used to sell one or more NFTs from a collection. I don’t own a Based Ghoul (somewhat based), but I DO own a Tubby Cat (ultra based), so here’s what I get when I try to create an NFT-selling pool for my Tubby Cats.
I’ve set up my pool to sell my first NFT for 10 ETH (“Start Price” = 10 ETH) and, for each sale, the price of the next NFT will increase by 0.1 ETH (“Delta” = 0.1 ETH"). This means that, if someone buys my first Tubby Cat NFT, they’ll pay me 10 ETH. If they also want the second one, they’ll pay 10.1 ETH for that one - like I mentioned earlier, the price is being updated as NFTs are sold. You could also make your delta “-0.5” or something, and sell your second NFT for only 9.5 ETH. It’s up to you how you format your pool.
There can (and will) be multiple pools per NFT collection. This makes sense when you think about how different users may want different pricing and deltas depending on their NFT holdings.
Now, all of that may have left you with some questions. Here’s some Q&A that should be key in helping you wrap your head around what’s going on:
What if I just want to sell my NFTs at the same price? Set your delta to 0, and they’ll all be available to buy at your pool’s start price.
What if I own a rare NFT? How can I make sure I sell that one for more than my floor NFTs? You can create a separate pool for your rare NFT, and set the start price to a higher ETH value than your floor NFTs.
How do people know to buy from my pool? This is an especially good question, imo. SudoSwap’s smart contracts do not automatically find you the cheapest pools to route your trades through. Instead, people will know to buy from your pool in 1 of 2 ways:
They want to buy your specific NFT, which can only come from your pool, so they’ll have to buy it from your pool.
They’re “sweeping the floor” - buying, say, 10 NFTs at once for the cheapest prices they can - and your pricing fits into the 10 cheapest NFTs for the collection. If so, SudoSwap (or an aggregator) will know this, as they track pricing across all pools in order to give users best pricing, and route part of the trade through your pool.
What if I want to buy NFTs, not just sell them? You can create a pool for buying NFTs (called a “Token” pool) and fund it with ETH. You set the price at which to buy NFTs, and a delta for how much to adjust your quote price after each trade. You could offer 5 ETH for your first buy, and use a delta of -1 to offer 4 ETH for your next buy; very similar setup to the pool for selling NFTs/
I thought I could instantly sell NFTs on SudoSwap? You can, by selling your NFT into the “buy NFT pool” (“Token” pool) that is offering the highest buy quote. This actually explains how collection offers work as well; to make a collection offer of 0.2 ETH, you simply create a pool that contains 0.2 ETH and specifies “I will buy any NFT in this collection for 0.2 ETH”. Then, someone could come along and sell their NFT into your pool for 0.2 ETH, giving you the NFT.
What about DCAing? If you want to do something like DCAing into a collection, you could create a pool with your initial buy price, and delta that moves in the direction you’d like to DCA in. I guess you could argue this isn’t DCAing, as you’re not buying/selling at clear intervals, but at least you’re buying/selling at clear prices. Perhaps a bonding curve that includes a “timelock” between buys could be implemented in the future, if there was demand for it.
What about trading fees? If you create a “Trade” pool - both offering to buy NFTs at a certain price AND sell NFTs for a slightly lower price - you can specify a % fee to take on each trade.
Developer Note
If you’re not a developer or you just don’t really care about how SudoSwap’s AMM works at a lower level, go ahead and skip this section.
Under the hood, SudoSwap’s LSSVMPairFactory contract is creating new pools (referred to as “Pairs” at the contract level), each pool being a contract called LSSVMPair that is owned by the pool creator and created with custom parameters like pair type (Token, NFT, or Trade), bonding curve type (just linear or exponential, for now), spot price, delta, etc. These pairs can then be monitored for their assets and price quotes (obtained by calling ‘getBuyNFTQuote’, shown below).
The LSSVMRouter contract is used for token approvals (consolidating approvals into one contract) and making swaps. There are multiple swap types (“robust” and “normal”), each handling “what happens if one leg of this trade cannot execute due to slippage or quick price moves?” differently - robust would skip the leg and refund the user, normal would revert if too much slippage is incurred. Also, as a developer, the fact that swap functions directly return the amount of unspent tokens is appreciated.
For various reasons like aggregator inclusion, MEV, etc, you may want to obtain pricing yourself. To do that, you’d need to: track all pools (picked up via LSSVMPairFactory’s NewPair events), track NFTs in pools (via LSSVMPairFactory’s NFTDeposit events - or via the pool’s getAllHeldIds function), track assets in pools (via the pool’s TokenDeposit & TokenWithdrawal events), and get pricing (via pools’ getBuyNFTQuote and getSellNFTQuote functions). I may be forgetting something here, but that’s the gist.
How to Think About SudoSwap
I like to create “mental models” for new products in order to figure out where they fit into the market landscape and what they can be compared to. I actually have no idea what a mental model really is, I’ve just heard that word used a lot lately, but it sounds roughly like what I do.
Looking at SudoSwap as an NFT exchange competitor that utilizes an AMM vs an orderbook seems like generally the right model here. SudoSwap is making tradeoffs, like “increased gas but all on-chain” and “arguably more complex for new users but increased instant liquidity”, and it will be up to users to decide which exchange type they prefer in different scenarios.
I also fully understand that, for many NFT users/traders, AMMs/DeFi are things they don’t care about, have been scarred by, or see as bad words. That said, SudoSwap is still in a good position to gain more volume through integration with aggregators (I’m working on this myself actually, at Flip.xyz), Sudo’s low exchange fees and liquidity that is typically concentrated on the floor means that, for some collections, routing part or all of a batch trade through SudoSwap pools will result in cheaper execution prices for users, without the user needing to even learn about (or know about) SudoSwap.
SudoSwap also, as I mentioned earlier, doesn’t include royalty fees in their trades. This is an interesting choice and has sparked some debate. “Collections can just go LP their own collection on SudoSwap and earn LP fees” has been a common rebuttal to “you’re screwing over the collections and their treasuries”. I don’t have a strong opinion here; it’ll be interesting to see if either side (pro-royalty or no-royalty) caves, or if collections actually try to actively avoid SudoSwap.
Overall, it’s great to see a new protocol design - an NFT AMM - gain some traction and show, in the real world, what the tradeoffs are between NFT AMMs and orderbooks. I look forward to transacting on both.
Really great read, and easy to understand.
Thank you!
Obrigada!