Next.js
This guide will help you integrate SwapKit into your Next.js application with proper Node.js polyfills and WebAssembly support.
Installation
Section titled “Installation”Install SwapKit and required dependencies:
bun add @swapkit/sdk node-polyfill-webpack-plugin
pnpm add @swapkit/sdk node-polyfill-webpack-plugin
npm install @swapkit/sdk node-polyfill-webpack-plugin
yarn add @swapkit/sdk node-polyfill-webpack-plugin
Additional polyfill dependencies:
bun add buffer crypto-browserify stream-browserify stream-http https-browserify os-browserify path-browserify
pnpm add buffer crypto-browserify stream-browserify stream-http https-browserify os-browserify path-browserify
npm install buffer crypto-browserify stream-browserify stream-http https-browserify os-browserify path-browserify
yarn add buffer crypto-browserify stream-browserify stream-http https-browserify os-browserify path-browserify
Next.js Configuration
Section titled “Next.js Configuration”Update your next.config.mjs
to include necessary polyfills and WebAssembly support:
// @noErrorValidationimport { createRequire } from "module";import NodePolyfillPlugin from "node-polyfill-webpack-plugin";
const require = createRequire(import.meta.url);
/** @type {import('next').NextConfig} */const nextConfig = { reactStrictMode: true,
webpack: (config, { isServer, webpack }) => { if (!isServer) { // Add polyfills for browser config.plugins.push(new NodePolyfillPlugin());
config.plugins.push( new webpack.ProvidePlugin({ global: require.resolve("global"), process: "process/browser", Buffer: ["buffer", "Buffer"], }) );
config.plugins.push( new webpack.DefinePlugin({ "global.crypto": "crypto", "global.msCrypto": "crypto", "global.process": "process", "global.Buffer": "Buffer", }) );
// Configure fallbacks config.resolve.fallback = { ...config.resolve.fallback, buffer: require.resolve("buffer"), crypto: require.resolve("crypto-browserify"), fs: false, stream: require.resolve("stream-browserify"), path: require.resolve("path-browserify"), process: require.resolve("process/browser"), };
// Configure aliases config.resolve.alias = { ...config.resolve.alias, crypto: require.resolve("crypto-browserify"), path: require.resolve("path-browserify"), process: require.resolve("process/browser"), stream: require.resolve("stream-browserify"), http: require.resolve("stream-http"), https: require.resolve("https-browserify"), os: require.resolve("os-browserify/browser"), }; }
// Enable WebAssembly config.experiments = { ...config.experiments, asyncWebAssembly: true, syncWebAssembly: true, topLevelAwait: true, };
return config; },};
export default nextConfig;
Package.json Browser Field
Section titled “Package.json Browser Field”Add browser field to your package.json
to handle Node.js modules:
{ "browser": { "dns": false, "fs": false, "net": false, "perf_hooks": false, "stream": false, "timers": false, "tls": false, "zlib": false }}
SwapKit Setup
Section titled “SwapKit Setup”Create a SwapKit instance configuration:
// @noErrorValidationimport { createSwapKit } from '@swapkit/sdk';import { SKConfig } from '@swapkit/sdk';
// Configure API keys from environment variablesif (process.env.NEXT_PUBLIC_SWAPKIT_API_KEY) { SKConfig.setApiKey('swapKit', process.env.NEXT_PUBLIC_SWAPKIT_API_KEY);}
if (process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID) { SKConfig.setApiKey('walletConnectProjectId', process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID);}
export const swapKitClient = createSwapKit();
React Component with App Router
Section titled “React Component with App Router”Create a client component for wallet interactions:
// @noErrorValidation'use client';
import { useState } from 'react';import { swapKitClient } from '@/lib/swapKit';import { Chain, WalletOption } from '@swapkit/sdk';
export function WalletButton() { const [isConnected, setIsConnected] = useState(false); const [address, setAddress] = useState<string>(''); const [isLoading, setIsLoading] = useState(false);
const connectWallet = async () => { setIsLoading(true); try { await swapKitClient.connectEVMWallet([Chain.Ethereum], WalletOption.METAMASK);
setIsConnected(true); const ethAddress = await swapKitClient.getAddress(Chain.Ethereum); setAddress(ethAddress); } catch (error) { console.error('Failed to connect wallet:', error); } finally { setIsLoading(false); } };
const disconnectWallet = () => { swapKitClient.disconnectWallet(Chain.Ethereum); setIsConnected(false); setAddress(''); };
if (isConnected) { return ( <div> <p>Connected: {address.slice(0, 6)}...{address.slice(-4)}</p> <button onClick={disconnectWallet}>Disconnect</button> </div> ); }
return ( <button onClick={connectWallet} disabled={isLoading}> {isLoading ? 'Connecting...' : 'Connect Wallet'} </button> );}
Context Provider Pattern
Section titled “Context Provider Pattern”For more complex applications, use a context provider:
// @noErrorValidation'use client';
import { createContext, useContext, ReactNode } from 'react';import { SwapKit } from '@swapkit/sdk';import { swapKitClient } from '@/lib/swapKit';
const SwapKitContext = createContext<SwapKit | null>(null);
export function SwapKitProvider({ children }: { children: ReactNode }) { return ( <SwapKitContext.Provider value={swapKitClient}> {children} </SwapKitContext.Provider> );}
export function useSwapKit() { const context = useContext(SwapKitContext); if (!context) { throw new Error('useSwapKit must be used within SwapKitProvider'); } return context;}
Use in your root layout:
// @noErrorValidationimport { SwapKitProvider } from '@/providers/SwapKitProvider';
export default function RootLayout({ children,}: { children: React.ReactNode;}) { return ( <html lang="en"> <body> <SwapKitProvider> {children} </SwapKitProvider> </body> </html> );}
Environment Variables
Section titled “Environment Variables”Create a .env.local
file:
NEXT_PUBLIC_SWAPKIT_API_KEY=your_api_key_hereNEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_project_id_here
Server Components Considerations
Section titled “Server Components Considerations”SwapKit operations that require wallet connections must be performed in client components. For server components, you can only use read-only operations:
// @noErrorValidation// Server component - read-only operationsimport { AssetValue, SwapKitApi } from '@swapkit/sdk';
export async function TokenPrice({ symbol }: { symbol: string }) { const price = await SwapKitApi.getPrice({ identifier: symbol, currency: 'USD' });
return <div>Price: ${price.price_usd}</div>;}
Cosmos Wallets Integration
Section titled “Cosmos Wallets Integration”For Cosmos ecosystem wallets like Keplr and Cosmostation, create a specialized component:
// @noErrorValidation'use client';
import { useState } from 'react';import { swapKitClient } from '@/lib/swapKit';import { Chain, WalletOption } from '@swapkit/sdk';
export function CosmosWalletButton() { const [isConnected, setIsConnected] = useState(false); const [addresses, setAddresses] = useState<Record<string, string>>({}); const [isLoading, setIsLoading] = useState(false);
const connectCosmostation = async () => { setIsLoading(true); try { await swapKitClient.connectCosmostation([Chain.Cosmos, Chain.THORChain, Chain.Kujira]);
setIsConnected(true); const chains = [Chain.Cosmos, Chain.THORChain, Chain.Kujira]; const newAddresses: Record<string, string> = {};
for (const chain of chains) { try { const address = await swapKitClient.getAddress(chain); if (address) { newAddresses[chain] = address; } } catch { // Chain might not be connected, skip it } }
setAddresses(newAddresses); } catch (error) { console.error('Failed to connect Cosmostation:', error); } finally { setIsLoading(false); } };
const disconnectWallet = () => { Object.keys(addresses).forEach(chain => { swapKitClient.disconnectWallet(chain as Chain); }); setIsConnected(false); setAddresses({}); };
if (isConnected) { return ( <div className="space-y-2"> <h3>Connected Cosmos Chains:</h3> {Object.entries(addresses).map(([chain, address]) => ( <p key={chain}> {chain}: {address.slice(0, 8)}...{address.slice(-6)} </p> ))} <button onClick={disconnectWallet}>Disconnect</button> </div> ); }
return ( <button onClick={connectCosmostation} disabled={isLoading}> {isLoading ? 'Connecting...' : 'Connect Cosmostation'} </button> );}
Common Issues
Section titled “Common Issues”WebAssembly errors
Section titled “WebAssembly errors”The webpack configuration should handle WebAssembly modules. If issues persist, check that experiments.asyncWebAssembly
is enabled in your next.config.js
.
Example Repository
Section titled “Example Repository”For a complete working example, check out the Next.js playground in the SwapKit repository.