Skip to content

Build a Completely Custom App

This guide shows how to scaffold a Next.js app that uses the @sapience/sdk package for forms and components, and wires data via GraphQL and the Quoter/Auction APIs.

Install

Create a new Next.js app

Prereqs: Node >= 20.14 and pnpm 9.x.

pnpm create next-app@14 my-sapience-app --ts --tailwind --eslint --app --use-pnpm --src-dir
cd my-sapience-app

If your scaffold installs a different Next version, pin the version supported by @sapience/sdk:

pnpm add -E next@14.2.30

Install @sapience/sdk

pnpm add @sapience/sdk

Install peer dependencies

@sapience/sdk expects certain libraries to be provided by your app. Install the core set below, then add optional ones as you use the corresponding components.

Core peer deps:

pnpm add -E next@14.2.30 react@19.1.0 react-dom@19.1.0 react-hook-form@7.53.0 @tanstack/react-query@5.56.2 wagmi@2.14.16 viem@2.23.5 graphql@16.11.0 @apollo/client@3.12.4 lucide-react@0.461.0 lightweight-charts@4.2.1 framer-motion@12.19.1 next-themes@0.3.0

Optional/feature-specific peer deps (install only if needed):

pnpm add -E @rainbow-me/rainbowkit@2.1.6 @tanstack/react-table@8.21.2 date-fns@3.6.0 dayjs@1.11.13 jsbi@3.2.5 react-countup@6.5.3 next-pwa@5.6.0 @uniswap/sdk-core@5.4.0 @uniswap/v3-core@1.0.1 @uniswap/v3-sdk@3.14.0

Tip: You can always check the exact versions in @sapience/sdk's peerDependencies and match them with -E.

Start the dev server

pnpm dev

Import Components and Hooks

import { TradeForm } from '@sapience/sdk/ui';

Connect Data

  • GraphQL: fetch markets, prices, and positions
  • Quoter: size your trades with price constraints
  • Auction WS: submit/receive quotes for Auction Markets
  • MCP: optional agentic tools for research/trading flows
// Quoter URL builder example
function toQuoteUrl(params: {
  base: string;
  chainId: number;
  marketGroupAddress: string;
  marketId: number;
  expectedPrice: number;
  collateralAvailable: bigint;
  maxIterations?: number;
  priceLimit?: number;
}) {
  const { base, chainId, marketGroupAddress, marketId, expectedPrice, collateralAvailable, maxIterations, priceLimit } = params;
  const qs = new URLSearchParams();
  qs.set('expectedPrice', String(expectedPrice));
  qs.set('collateralAvailable', String(collateralAvailable));
  if (maxIterations) qs.set('maxIterations', String(maxIterations));
  if (priceLimit) qs.set('priceLimit', String(priceLimit));
  return `${base}/quoter/${chainId}/${marketGroupAddress}/${marketId}/?${qs.toString()}`;
}

Example Page

import { useMemo, useState } from 'react';
import { TradeForm } from '@sapience/sdk/ui';
 
export default function TradePage() {
  const [baseUrl] = useState('https://api.sapience.xyz');
  const chainId = 1;
  const marketGroupAddress = '0x...';
  const marketId = 1;
 
  const getEstimatedCost = useMemo(() => {
    return async (size: string, direction: 'Long' | 'Short') => {
      // naive example: call quoter to size collateral given a target price
      const expectedPrice = direction === 'Long' ? 0.55 : 0.45;
      const collateralAvailable = BigInt(1e18); // 1 token in wei
      const url = toQuoteUrl({
        base: baseUrl,
        chainId,
        marketGroupAddress,
        marketId,
        expectedPrice,
        collateralAvailable,
      });
      const res = await fetch(url);
      const data = await res.json();
      // return collateral cost estimate string (for demo use expected maxSize)
      return data.maxSize ?? '0';
    };
  }, [baseUrl]);
 
  async function onTradeSubmit(values: { size: string; direction: 'Long' | 'Short'; slippage: string; }) {
    // Integrate with write logic or relayer
    console.log('submit trade', values);
  }
 
  return (
    <TradeForm
      onTradeSubmit={onTradeSubmit}
      getEstimatedCost={getEstimatedCost}
      collateralAssetTicker="sUSDS"
      walletBalanceDisplay="100.0"
    />
  );
}

GraphQL Example

import { GraphQLClient, gql } from 'graphql-request';
 
const client = new GraphQLClient('https://api.sapience.xyz/graphql');
 
const MarketsQuery = gql`
  query Markets {
    markets { id title status }
  }
`;
 
export async function fetchMarkets() {
  return client.request(MarketsQuery);
}

Theming and UI

@sapience/sdk ships with shadcn-like primitives and a Tailwind preset. Import the preset and include it in your Tailwind config.

// tailwind.config.ts
import type { Config } from 'tailwindcss'
import sapiencePreset from '@sapience/sdk/ui/tailwind-preset'
 
export default {
  presets: [sapiencePreset],
  content: [
    './pages/**/*.{ts,tsx}',
    './components/**/*.{ts,tsx}',
    './app/**/*.{ts,tsx}',
    './node_modules/@sapience/sdk/dist/**/*.{js,mjs}'
  ],
} satisfies Config

Next Steps

  • Add market data via GraphQL
  • Use Quoter to compute max size and price constraints
  • Add Auction WS for batch markets and limit-like quotes