Written by
Tidelaw
Published on
September 12, 2023
Copy link

Solana DeFi: Jupiter Swap UI (2023)

Introduction

Jupiter is a an aggregator of various DEX and AMMs, through these different exchanges the most efficient swaps are found. Jupiter then finds the best priced swap routes for you across other DEXs and AMMs ensuring you get the best price. Whether you simply want to swap to stablecoins or interact with your favorite DeFi game's tokens, interaction with Jupiter is essential.

Jupiter Swap UI: Overview

Learn how to interact with Jupiter programatically through this short guide! This guide will walk you through creating a dApp that uses Jupiter's API to fetch price quotes and execute SOL to USDC swaps based on user input. This app showcases useful functions such as price quotes being fetched in real time and user signed swap transactions. Feel free to refer to the following repository containing all the completed code as you progress through this blog.

Here is the completed repository:

GitHub - Tidelaw/jup-ui

Prerequisites

Ensure the following are installed:

  • Node.js
  • Next.js
  • Tailwind (may be included in Next.js)

Dependencies

Link to Connect Wallet blog

It’s highly recommended to follow the above Connect Wallet blog in order to correctly set up the contexts folder allowing the user to connect their wallet and sign the swap transactions.

The only additional dependencies not included from the initial creation of the project and the connect wallet blog are the @project-serum/anchor and axios packages. It’s recommend to simply copy this package.json so you can simply run npm i to install them all at once.

Swap.tsx

We’ll first be implementing the price quotes functionality, returning the estimated USDC returned for the inputted amount of SOL. This is pretty simple through Jupiter, we only need to provide the input and output mint addresses for the token, as well as the amount we wish to exchange.

A state variable is needed to store the amount of SOL that the user wants to swap. We’ll first set up the inputs: in the code below both the DaisyUI slider and text input are included (both as <input> tags), only one is necessary though. The input tag will need a value and onChange property allowing it to constantly update the state variable.

Now, we can create a useEffect hook whereby when a user inputs a new value of SOL to be converted, we’ll make a request to Jupiter to fetch the quoted price with the amount requested by the user.

Quote.tsx

We can now move to the src/api/ folder where we’ll create a new file called quote.tsx, this is where we’ll make requests to Jupiter for the quoted amounts. To receive the request internally we’ll need to set up the handler function, where we’ll only allow POST requests. After receiving the request from the frontend containing the amount the user wants to swap we only have to change the config’s URL to req.body.amount and make the request to Jupiter.

Here is an example of the returned payload. We’ll pass this object back into the frontend so that we can pass it over to yet another endpoint where we’ll make the swap.

Note the { data } abstraction that accesses the data.data property, with this we can simply pass in data directly back into the frontend through res.status(200).json(data).

Now in the return function we’ll update the quoted state variable and update it when our internal API has responded with the above data. After this, we can access the exact property of USDC, though this needs to be divided by 1 million and rounded to 2 decimal places to reflect the correct USD amount. This is similar to how native SOL is expressed in Lamports and has to be divided by a billion.

Now, we can simply insert it into the HTML and it will be displayed in the frontend.

Jupiter UI: Performing the Swap

Now that we have the simulated quote object, we can create a new function that performs the swap and sends a request to the API endpoint.

We can now create an API endpoint to receive this request, with this file path src/api/swap . This example uses a statically typed wallet address however you can use the useWallet hook and pass that into the endpoint instead. After we make a request to the swap endpoint with the quote object we have a serialized transaction that now only needs to be signed in the frontend. Feel free to test this by logging the object into the console.

After receiving this serialized transaction from the backend, we can now start preparing it to be sent. First, we’ll need to get the transaction buffer, then deserialize it so that it can be signed. Assuming you followed the Connect Wallet Guide from before, you should simply be able to sign this transaction with wallet.signTransaction. After signing the transaction, we’ll serialize it again and send the transaction using the sendRawTransaction function.

Additional functionality could be included like on the actual jup.ag site where transaction signatures are displayed, however at the moment it is only logged in the browser’s console, still being accessible to a technical user.

Conclusion: Getting Started with Helius

This guide has walked you through the creation of a dApp that fetches price quotes and executes SOL to USDC swaps based on a user’s input using Jupiter’s API. Hopefully this guide will be useful to refer to in the future. As always, feel free to ask any questions in the Helius Discord. Additionally, you can use a free Helius RPC to establish a connection. For some ideas on further extensions to this project, see the following. If you've understood the mechanics behind building a dApp that interfaces with Jupiter’s API for price quotes and swaps, the next step is to leverage the power of Helius for monitoring and analytics. As Jupiter itself is an aggregator that finds the best swap routes across various DEXs and AMMs, the data that flows through it is incredibly rich and valuable for understanding market dynamics.

Next Steps

  • Additional property in payload when sending quote object to the swap.ts endpoint.
  • Displayed transaction signature
  • Include other tokens or reversing between USDC and SOL
  • Error/responsivity when wallet isn’t connected
  • Deserialize and send TX in backend to mask RPC?

Resources Used

https://station.jup.ag/docs/apis/swap-api#using-the-api

https://station.jup.ag/api-v6/post-swap