Skip to main content
Code examples for common swap scenarios using the Stableswapper program.
These examples assume you’ve completed the Quickstart setup steps (dependencies, environment variables, and IDL/ABI).

Setup

Use these Base Sepolia addresses in your examples. For mainnet, replace with your production addresses from Key Addresses.
import { ethers } from "ethers";

// Base Sepolia addresses
const STABLESWAPPER_ADDRESS = "0x57AB1E2c6289aCe985Bd5c5571EbF6d98CD41Ab7";
const USDC_ADDRESS          = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
const CBTUSD_ADDRESS        = "0x57AB1EFE59b1C7b36b1Dc9315B4782bCcBb83721";

const ERC20_ABI = [
  "function approve(address spender, uint256 amount) returns (bool)",
  "function allowance(address owner, address spender) view returns (uint256)",
  "function balanceOf(address account) view returns (uint256)",
  "function decimals() view returns (uint8)",
];

const STABLESWAPPER_ABI = [
  "function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, address recipient) external",
  "function feeBasisPoints() view returns (uint16)",
  "function feeRecipient() view returns (address)",
  "function isTokenListed(address token) view returns (bool)",
  "function isTokenSwappable(address token) view returns (bool)",
  "function isFeatureEnabled(uint8 feature) view returns (bool)",
  "function isAllowlisted(address addr) view returns (bool)",
  "function getTokenDecimals(address token) view returns (uint8)",
  "function getListedTokens() view returns (address[])",
  "function getReservedAmount(address token) view returns (uint256)",
];

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);

const stableSwapper = new ethers.Contract(STABLESWAPPER_ADDRESS, STABLESWAPPER_ABI, signer);

Swap USDC for custom token

async function swapUsdcForCustomToken() {
  const usdc = new ethers.Contract(USDC_ADDRESS, ERC20_ABI, signer);

  const amountIn = ethers.parseUnits("0.1", 6);      // 0.1 USDC (6 decimals)
  const minAmountOut = ethers.parseUnits("0.09", 6);  // Allow up to 10% for fees/slippage

  // Approve the Stableswapper to spend USDC
  const currentAllowance = await usdc.allowance(signer.address, STABLESWAPPER_ADDRESS);
  if (currentAllowance < amountIn) {
    const approveTx = await usdc.approve(STABLESWAPPER_ADDRESS, amountIn);
    await approveTx.wait();
  }

  // Execute swap
  const swapTx = await stableSwapper.swap(
    USDC_ADDRESS,      // tokenIn
    CBTUSD_ADDRESS,      // tokenOut
    amountIn,          // amountIn
    minAmountOut,      // minAmountOut
    signer.address     // recipient
  );

  const receipt = await swapTx.wait();
  console.log("Swap successful:", receipt.hash);
}

Swap custom token for USDC

async function swapCustomTokenForUsdc() {
  const cbtusd = new ethers.Contract(CBTUSD_ADDRESS, ERC20_ABI, signer);

  const amountIn = ethers.parseUnits("0.1", 6);      // 0.1 CBTUSD (6 decimals)
  const minAmountOut = ethers.parseUnits("0.09", 6);  // Allow up to 10% for fees/slippage

  // Approve the Stableswapper to spend CBTUSD
  const currentAllowance = await cbtusd.allowance(signer.address, STABLESWAPPER_ADDRESS);
  if (currentAllowance < amountIn) {
    const approveTx = await cbtusd.approve(STABLESWAPPER_ADDRESS, amountIn);
    await approveTx.wait();
  }

  // Execute swap
  const swapTx = await stableSwapper.swap(
    CBTUSD_ADDRESS,      // tokenIn
    USDC_ADDRESS,      // tokenOut
    amountIn,          // amountIn
    minAmountOut,      // minAmountOut
    signer.address     // recipient
  );

  const receipt = await swapTx.wait();
  console.log("Swap successful:", receipt.hash);
}

Swap to a different recipient

On Base, you can send swap output directly to another address by specifying a different recipient.
async function swapToRecipient(recipientAddress: string) {
  const usdc = new ethers.Contract(USDC_ADDRESS, ERC20_ABI, signer);

  const amountIn = ethers.parseUnits("1.0", 6);
  const minAmountOut = ethers.parseUnits("0.99", 6);

  const currentAllowance = await usdc.allowance(signer.address, STABLESWAPPER_ADDRESS);
  if (currentAllowance < amountIn) {
    const approveTx = await usdc.approve(STABLESWAPPER_ADDRESS, amountIn);
    await approveTx.wait();
  }

  const swapTx = await stableSwapper.swap(
    USDC_ADDRESS,
    CBTUSD_ADDRESS,
    amountIn,
    minAmountOut,
    recipientAddress    // output tokens go to this address
  );

  const receipt = await swapTx.wait();
  console.log("Swap to recipient successful:", receipt.hash);
}

Query contract state

Read contract state before executing swaps for validation and fee calculation.
async function queryContractState() {
  // Check fee configuration
  const feeBps = await stableSwapper.feeBasisPoints();
  console.log("Fee (basis points):", feeBps.toString());

  // Check token status
  const usdcListed = await stableSwapper.isTokenListed(USDC_ADDRESS);
  const usdcSwappable = await stableSwapper.isTokenSwappable(USDC_ADDRESS);
  console.log("USDC listed:", usdcListed, "swappable:", usdcSwappable);

  // Check if swaps are enabled
  const swapsEnabled = await stableSwapper.isFeatureEnabled(0); // 0 = SWAP
  console.log("Swaps enabled:", swapsEnabled);

  // Check allowlist status (only relevant if allowlist feature is enabled)
  const allowlistEnabled = await stableSwapper.isFeatureEnabled(2); // 2 = ALLOWLIST
  if (allowlistEnabled) {
    const isAllowed = await stableSwapper.isAllowlisted(signer.address);
    console.log("Wallet allowlisted:", isAllowed);
  }

  // Get all listed tokens
  const listedTokens = await stableSwapper.getListedTokens();
  console.log("Listed tokens:", listedTokens);
}

Swap between two custom stablecoins

The contract supports swapping between any two listed and swappable tokens — not just USDC pairs. To swap between two custom stablecoins, use their respective addresses as tokenIn and tokenOut. Both tokens must be listed and have swapping enabled.

Reference

Complete swap instruction parameters and accounts

Production Readiness

Helper functions and best practices

Quickstart

Get up and running in 10 minutes

Key Addresses

Program IDs and deployed addresses