Skip to content

Executing Swaps

Execute swaps between stablecoins on the exchange. Swaps execute immediately against existing orders in the orderbook, providing instant liquidity for cross-stablecoin payments.

By the end of this guide you will be able to execute swaps, get price quotes, and manage slippage protection.

Execute a Swap

demo
1
Create an account, or use an existing one.
2
Add testnet funds to your account.
3
Make Swaps
pnpx gitpick tempoxyz/tempo-ts/tree/main/examples/exchange

Steps

Set up your client

Ensure that you have set up your client by following the guide.

Get a price quote

Before executing a swap, get a quote to see the expected price.

Buy.tsx
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
 
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const betaUsd = '0x20c0000000000000000000000000000000000002'
 
function Buy() {
  const amount = parseUnits('10', 6)
 
  // How much AlphaUSD do I need to spend to receive 10 BetaUSD? 
  const { data: quote } = Hooks.dex.useBuyQuote({ 
    tokenIn: alphaUsd, 
    tokenOut: betaUsd, 
    amountOut: amount, 
  }) 
 
  return <div>Quote: {formatUnits(quote, 6)}</div>
}

Calculate slippage tolerance

Set appropriate slippage based on your quote to protect against unfavorable price movements.

Buy.tsx
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
 
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const betaUsd = '0x20c0000000000000000000000000000000000002'
 
function Buy() {
  const amount = parseUnits('10', 6)
 
  // How much AlphaUSD do I need to spend to receive 10 BetaUSD?
  const { data: quote } = Hooks.dex.useBuyQuote({
    tokenIn: alphaUsd,
    tokenOut: betaUsd,
    amountOut: amount,
  })
 
  // Calculate 0.5% slippage tolerance
  const slippageTolerance = 0.005
  const maxAmountIn = quote 
    ? quote * BigInt(Math.floor((1 + slippageTolerance) * 1000)) / 1000n
    : 0n
 
  return (
    <div>
      <div>Quote: {formatUnits(quote, 6)}</div>
      <div>Max input (0.5% slippage): {formatUnits(maxAmountIn, 6)}</div> // [!code ++]
    </div>
  )
}

Approve Spend

To execute a swap, you need to approve the Stablecoin DEX contract to spend the token you're using to fund the swap.

Buy.tsx
import { Actions, Addresses } from 'tempo.ts/viem'
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
import { useSendCallsSync } from 'wagmi'
 
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const betaUsd = '0x20c0000000000000000000000000000000000002'
 
function Buy() {
  const amount = parseUnits('10', 6)
 
  // How much AlphaUSD do I need to spend to receive 10 BetaUSD?
  const { data: quote } = Hooks.dex.useBuyQuote({
    tokenIn: alphaUsd,
    tokenOut: betaUsd,
    amountOut: amount,
  })
 
  // Calculate 0.5% slippage tolerance
  const slippageTolerance = 0.005
  const maxAmountIn = quote
    ? quote * BigInt(Math.floor((1 + slippageTolerance) * 1000)) / 1000n
    : 0n
 
  const sendCalls = useSendCallsSync() 
 
  return (
    <div>
      <div>Quote: {formatUnits(quote, 6)}</div>
      <div>Max input (0.5% slippage): {formatUnits(maxAmountIn, 6)}</div>
      <button type="button" onClick={() => { 
        const calls = [ 
          Actions.token.approve.call({ 
            amount: maxAmountIn, // Approve the max amount with slippage 
            spender: Addresses.stablecoinExchange, 
            token: alphaUsd, 
          }), 
        ] 
        sendCalls.sendCallsSync({ calls }) 
      }}> // [!code ++]
        Approve Spend // [!code ++]
      </button> // [!code ++]
    </div>
  )
}

Execute a swap

Batch the token approval with the swap in a single transaction for better UX.

Buy.tsx
import { Actions, Addresses } from 'tempo.ts/viem'
import { Hooks } from 'tempo.ts/wagmi'
import { formatUnits, parseUnits } from 'viem'
import { useSendCallsSync } from 'wagmi'
 
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const betaUsd = '0x20c0000000000000000000000000000000000002'
 
function Buy() {
  const amount = parseUnits('10', 6)
 
  // How much AlphaUSD do I need to spend to receive 10 BetaUSD?
  const { data: quote } = Hooks.dex.useBuyQuote({
    tokenIn: alphaUsd,
    tokenOut: betaUsd,
    amountOut: amount,
  })
 
  // Calculate 0.5% slippage tolerance
  const slippageTolerance = 0.005
  const maxAmountIn = quote
    ? quote * BigInt(Math.floor((1 + slippageTolerance) * 1000)) / 1000n
    : 0n
 
  const sendCalls = useSendCallsSync()
 
  return (
    <div>
      <div>Quote: {formatUnits(quote, 6)}</div>
      <div>Max input (0.5% slippage): {formatUnits(maxAmountIn, 6)}</div>
      <button type="button" onClick={() => {
        const calls = [
          Actions.token.approve.call({
            amount: maxAmountIn, // Approve the max amount with slippage
            spender: Addresses.stablecoinExchange,
            token: alphaUsd,
          }),
          Actions.dex.buy.call({ 
            amountOut: amount, 
            maxAmountIn, 
            tokenIn: alphaUsd, 
            tokenOut: betaUsd, 
          }), 
        ]
        sendCalls.sendCallsSync({ calls })
      }}>
        Execute Swap
      </button>
    </div>
  )
}

Recipes

Handling insufficient liquidity

Quote requests will fail with an InsufficientLiquidity error if there isn't enough liquidity in the orderbook to satisfy the requested amount.

Handle this error when fetching quotes:

import { Hooks } from 'tempo.ts/wagmi'
import { parseUnits } from 'viem'
 
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const betaUsd = '0x20c0000000000000000000000000000000000002'
 
function Swap() {
  const amount = parseUnits('10', 6)
 
  const { data: quote, error } = Hooks.dex.useSellQuote({
    tokenIn: alphaUsd,
    tokenOut: betaUsd,
    amountIn: amount,
  })
 
  if (error) {
    if (error.message.includes('InsufficientLiquidity')) {
      return <div>Not enough liquidity available. Try a smaller amount.</div>
    }
    return <div>Error: {error.message}</div>
  }
 
  if (!quote) {
    return <div>Loading quote...</div>
  }
 
  return <div>Quote: {quote.toString()}</div>
}

Best Practices

Always get quotes before swapping

Query the expected price before executing a swap to ensure you're getting a fair rate and to set appropriate slippage protection.

Set appropriate slippage protection

Use minAmountOut or maxAmountIn to protect against unfavorable price movements between quoting and execution.

Learning Resources