Skip to main content

How to build a token swap dApp with Swap API (Next.js)

An example ERC-20 swap application built on Next.js 13 with 0x Swap API.


This guide will give you a tour of the Swap API demo app (live demo | code) built on Next.js. It covers core concepts that can be easily transferred into any token swapping dApp that you build.

tip

This example is built with Next.js Pages Router. See here for an example with Next.js App Router.

What we will build​

This example app we will be walking through, and it demonstrates many of the same principles used in production-level swapping dApps such as Matcha.xyz.

Checkout with live demo πŸ‘‰ here

Swap API enables your users to easily and conveniently trade tokens at the best prices directly in your app. With one simple integration, 0x unlocks thousands of tokens on the most popular blockchains and aggregated liquidity from 100+ AMMs and professional market makers.

This demo app covers best practices for how to use the 0x Swap API's /price endpoint for indicative pricing and the /quote endpoint for firm quotes.

Video tutorial version here:

Pre-requisites​

Before diving into this walk-through, it's essential to ensure you have the familiarity with the following tools and concepts:

Additionally, we will be building our token swap dApp on the Polygon network, which provides a cost-effective environment for experimentation. You can always modify this app to support any of the 9-EVM compatible chains that Swap API is deployed on.

info

Here is the github repo, feel free to use it to get started quickly for your own project: https://github.com/0xProject/0x-nextjs-demo-app/tree/main

This is a demo, and is not ready for production use. The code has not been audited and does not account for all error handling. Use at your own risk.

Core Concepts​

To build our token swap dApp, we will focus on the following core components:

  • πŸ‘› ConnectKit
  • 🏷 PriceView
  • πŸ’Έ QuoteView
  • πŸͺ™ Token lists

What is it?​

These components play a transferable to almost any token swapping app being built.

Swap dApp Core Concepts

πŸ‘› ConnectKit​

What is it?​

In order for the user to execute a trade, they will need to connect a wallet to our dApp.

ConnectKit is a powerful React component library for connecting a wallet to your dApp, and it supports the most popular connectors and chains, so users are not tied to just one wallet. Under-the-hood, it uses wagmi and viem.

  • Viem is a TypeScript Interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum
  • Wagmi is a React hooks wrapper around Viem (previously Ethers)
  • ConnectKit is a wallet UI library that uses Wagmi and Viem

ConnectKit comes built in with multiple ways to customize it and advanced features such as,

  • Customization - theming, fonts, border radius, colors, avatar, translations
  • Advanced features - chains, providers, Sign In with Ethereum

Below is what the wallet connect experience looks like in our demo app:

ConnecKit

Code​

Setup API keys for ConnectKit​

ConnectKit's Getting Started docs is a quick way to get up to speed with the framework.

ConnectKit relies on WalletConnect's SDK to help with connecting wallets. You will need a a projectId which you can get for free over at WalletConnect Cloud. Replace code here.

ConnectKit also requires an Infura or Alchemy API key depending on which networks your dApp requires. Replace code here.

// Inside /pages/_app.tsx
const config = createConfig(
getDefaultConfig({
// Required API Keys
alchemyId: "REPLACE_WITH_YOUR_KEY",
walletConnectProjectId: "REPLACE_WITH_YOUR_KEY",
...
})

🏷 PriceView​

What is it?​

This component is for users to browse for a price without committing to a trade, aka, get the indicative price. An indicative price is used when users just want to check the price they could receive on a trade, for this we will use the /swap/v1/price endpoint.

Later on in the QuoteView, when a user is actually ready to make a trade, the app will ping /swap/v1/quote which returns an order that is ready to submitted on-chain.

This is also important because /quote returns back an order in which a Market Maker must commit their assets to settle that trade. So if we ping /quote too much when we really are just asking for a price and not ready to submit an order, then this can clog up the system!

UI/UX Walk-through​

And if we look through the UI, here are some notable things to callout:

  • User selects sell and buy tokens from the token selectors
  • Users inputs a sellAmount
  • Users can β€œConnect Wallet” powered by ConnectKit
  • Whenever sellAmount changes, the app fetches a price even if a wallet is not connect
  • Displays returned buyAmount
  • When users find a price they like, they can connect their wallet, and switch to the correct network (e.g. Polygon), the button now says "Approve if the user has enough of the sell token
    • The Approval button allows users to set a token allowance
    • This is standard practice when users need to give a token allowance for a third-party to move funds on our behalf, in this case 0x Protocol’s smart contract, specifically the 0x Exchange Proxy to trade the user’s ERC20 tokens on their behalf.
    • Users can set an amount they are comfortable with, the default we’ve set is a really big number, but they can also choose only the amount they have in their wallet
  • When we are happy with this trade, our approve button is now β€œReview Trade because we already approved the token allowance, so we can move forward

Code​

The code for this component lives in /pages/Price/index.tsx. The logic for when the component appears in UI is in /pages/index.tsx, it is displayed if the user has not clicked "Review Trade" to finalize the price.

Wrapping API calls behind /pages/api​

Under-the-hood, this price query uses GET /swap/v1/price. This API request is wrapped behind /pages/api using Next.js API Routes

Why? To protect our API keys.

Instead, when the user queries for an indicative price, it pings our api setup in pages/api/price and that pings the 0x Swap API using our API key in the header

This example uses a demo key which should not be used in production or outside of this demo; however, you can get your own key by going from the 0x Dashboard and following the Getting Started guide.

In PriceView, we use the useSWR() hook to automatically update the UI with the price whenever the sellAmount changes. See code here.

Token Allowances & Approvals​

While on the PageView, before the user can place a trade, they must have set allowances on all tokens involved in the trade. A token allowance is required if you want a third-party to move funds on your behalf. In short, you are allowing them to move your tokens.

In our case, we would like the 0x Exchange Proxy smart contract to trade our ERC20 tokens for us, so we will need to approve an allowance (a certain amount) for this contract to move a certain amount of our ERC20 tokens on our behalf. Read more about token allowances.

token allowance ui

The logic to check if the user has approved a token allowance the selected sell token is setup here.

  1. First, we need to check if the spender (0x Exchange Proxy) has an allowance already. We can use wagmi's useContractRead() hook to read from the sellToken's "allowance" function.
  2. If there is no allowance, then we will write an approval to the sellToken's smart contract using wagmi's usePrepareContractWrite().
tip

Be aware that approvals cost gas. Looking for a gasless approach? check out Gasless API.

Need to quickly revoke an allowance while testing? To revoke an allowance, you can set the allowance to 0. This can be done programmatically or through a UI such as https://revoke.cash/ .

πŸ’Έ QuoteView​

What is it?​

The QuoteView component provides users with an overview of the transaction details before executing the token swap. Earlier in the PriceView, we provided users an indicative price because they were just browsing for pricing information, so did not need a full 0x order. On the QuoteView, users are ready to fill the order, so we need to provide them a firm quote, and the Market Makers can know to reserve the proper assets to settle the trade.

swap demo quoteview

UI/UX Walk-through​

  • Displays the sell and buy Amounts that the user pays and receives, respectively
    • I’ve formatted it but you can get the symbols, decimal points for formatting from the token list. The amounts are the buy and sell Amounts returned from the quote
  • From here, the user can β€œPlace Order” which creates, signs, and sends a new transaction to the network.

Code​

The code for this component lives in /pages/Quote/index.tsx. The logic for when the component appears in UI is in /pages/index.tsx, it is displayed if the user has approved the token allowance, and clicked "Review Trade" to finalize the trade selection.

Wrapping API calls behind /pages/api​

Pinging /swap/v1/quote is wrapped behind /pages/api, which is triggered by the useSWR() hook as we did in PriceVie (code).

Submitting the transaction to the network​

The logic for this section is as follows:

  • Fetch firm quote (code)
  • Prepare the transaction that will be sent. In this case, use the usePrepareSendTransaction() hook and pass the required params , to and data values we get back from the quote. (code)
  • Send the transaction to the network using the useSendTransaction() hook.

πŸͺ™ Token lists​

What is it?​

Token Lists allow users to select their desired tokens for swapping. For ERC20 tokens, these lists typically include crucial metadata - such as the token names (Wrapped Matic), symbol (MATIC), address, and logoURI - which can be leveraged by apps such as ours.

Thankfully there are several established sources that curate and open-source this information. As developers, we can choose to ingest the entire list or customize our own token lists based off of these sources.

Notable lists​

Code​

In our demo, we curated a token list in /lib/constants.ts. In production level apps, it's common practice to maintain a token list since some apps don't support all available tokens.

Monetize your swap integration​

And as your business grows, Swap API offers low-friction ways to monetize your products.

Web3 teams can leverage Swap API to unlock new revenue streams by easily tapping into affiliate fee and trade surplus features. Regardless of whether you’re on a free or paid plan, monetization options are available to all integrators.

Swap API offers two monetization options out-of-the-box:

  • Collect affiliate fees (i.e. trading fee or commission) <- shown in this demo app
  • Collect trade surplus (i.e. positive slippage)

For more details about monetizing, check out the How to monetize your app using 0x Swap API guide which discusses pricing considerations and shows code samples for how to easily implement these options.

Try it out​

info

Here is code for the demo app, feel free to use it to get started quickly for your own project: https://github.com/0xProject/0x-nextjs-demo-app/tree/main

Conclusion​

By following the best practices outlined in this blog post, you can create a user-friendly and effective dApp that enables trustless token swapping on our 9 supported networks.

Happy swapping!