Palindrome Crypto Pay - Blockchain Escrow Payment Solution

Create SDK

Create Palindrome SDK

Before you can use any of the SDK functions, you need to properly initialize and configure the required clients.

These docs target @palindromepay/sdk v3.x (currently 3.0.4). Earlier SDK versions use different signatures — see the SDK README changelog if you are migrating.

The SDK supports both production (Base mainnet) and testnet (Base Sepolia) environments via the testnet parameter.

Setup & Initialization

Public Client (on-chain reads)

// config/viem.ts
import { createPublicClient, http } from 'viem';
import { baseSepolia } from 'viem/chains'; // Testnet
// import { base } from 'viem/chains';     // Production

export const publicClient = createPublicClient({
  chain: baseSepolia, // Testnet
  // chain: base,     // Production
  transport: http(),
});

SDK Factory & Wallet Connection

// lib/createSDK.ts
import { PalindromePaySDK } from '@palindromepay/sdk';
import { createWalletClient, custom, WalletClient } from 'viem';
import { baseSepolia } from 'viem/chains'; // Testnet
// import { base } from 'viem/chains';     // Production
import { publicClient } from '@/config/viem';
import { apolloClient } from '@/config/apollo';

export const createPalindromeSDK = (walletClient?: WalletClient) => {
  return new PalindromePaySDK({
    publicClient,
    walletClient: walletClient ?? undefined,
    apolloClient, // required — the SDK throws without it
    testnet: true, // Base Sepolia; set to false for Base mainnet
  });
};

export const connectAndInitSDK = async () => {
  if (!window.ethereum) throw new Error('MetaMask not detected');

  const walletClient = createWalletClient({
    chain: baseSepolia, // Testnet
    // chain: base,     // Production
    transport: custom(window.ethereum),
  });

  const [address] = await walletClient.requestAddresses();
  await walletClient.switchChain({ id: baseSepolia.id });

  const sdk = createPalindromeSDK(walletClient);

  console.log('Palindrome SDK ready for:', address);
  return { sdk, address, walletClient };
};

Every code example in these docs uses this setup:

import { connectAndInitSDK } from '@/lib/createSDK';

const { sdk, walletClient } = await connectAndInitSDK();

Testnet vs Production

TestnetProduction
ChainBase Sepolia (chainId 84532)Base (chainId 8453)
SDK paramtestnet: truetestnet: false (default)
Escrow contract0x84786faacb03eb2972c691af6c7ec78d0d75b439Set automatically by the SDK

Configuration options

publicClient and apolloClient are required; everything else is optional.

OptionTypeDefaultDescription
publicClientPublicClient— (required)viem client for on-chain reads
apolloClientApolloClient— (required)Apollo client for subgraph queries; the constructor throws without it
walletClientWalletClientundefinedDefault wallet for write operations (can also be passed per call)
chainChainhardhatviem chain object; usually set implicitly via testnet
testnetbooleanfalsetrue = Base Sepolia, false = Base mainnet
cacheTTLnumber5000Escrow cache time-to-live in ms
maxCacheSizenumber1000Max entries in the LRU escrow cache
enableRetrybooleantrueRetry failed contract reads
maxRetriesnumber3Retry attempts per read
retryDelaynumber1000Delay between retries in ms
gasBuffernumber20Percent added on top of gas estimates
receiptTimeoutnumber60000How long to wait for transaction receipts in ms
skipSimulationbooleanfalseSkip pre-flight simulateContract calls
defaultGasLimitbigint500000nFallback gas limit when estimation fails
loggerSDKLoggerconsoleCustom logger implementation
logLevelLogLevelMinimum log level

Escrow ID types: bigint vs string

On-chain methods (deposit, confirmDelivery, getEscrowByIdParsed, …) take escrowId as a bigint (e.g. 42n). Subgraph queries (getEscrowDetail, getDisputeMessages, …) take it as a string (e.g. "42"), since The Graph returns IDs as strings.

You can now call any SDK method:

const escrows = await sdk.getEscrows();
const escrow = await sdk.getEscrowByIdParsed(5n);
await sdk.deposit(walletClient, 5n);

Pro Tip

You can set up your own database to manage the data independently. While The Graph specializes in indexing blockchain events and providing efficient querying, managing your own database gives you full control over data structure, storage, and custom queries.

Previous
Getting started