Trading Coins | ZORA Docs
Skip to content

Trading Coins

The Coins SDK provides powerful trading functionality through the tradeCoin function, which enables swapping between ETH and ERC20 tokens (including creator coins) using Externally Owned Accounts (EOAs) with permit signatures for secure, gasless approvals.

Overview

The tradeCoin function supports:

  • ETH ↔ ERC20 token swaps with semi-automatic routing
  • Creator coin ↔ Creator coin swaps with semi-automatic routing
  • Content coin ↔ Creator coin swaps with semi-automatic routing
  • ERC20 ↔ ERC20 token swaps using permit signatures
  • Permit-based approvals (via permit2) for secure token spending without separate approval transactions
  • Slippage protection and customizable trade parameters
  • EOA wallet support with smart wallet support coming soon

Currently, only the Base mainnet network is supported. Plans to add base sepolia are coming soon.

Basic Usage

Import the Function

import { tradeCoin, TradeParameters } from "@zoralabs/coins-sdk";

Trading ETH for Creator Coins

import { parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
 
// Set up your account
const account = privateKeyToAccount("0x...");
 
const tradeParameters: TradeParameters = {
  sell: { type: "eth" },
  buy: {
    type: "erc20",
    address: "0x4e93a01c90f812284f71291a8d1415a904957156", // Creator coin address
  },
  amountIn: parseEther("0.001"), // 0.001 ETH
  slippage: 0.05, // 5% slippage tolerance
  sender: account.address,
};
 
const receipt = await tradeCoin({
  tradeParameters,
  walletClient,
  account,
  publicClient,
});

Trading Creator Coin for ETH

const tradeParameters: TradeParameters = {
  sell: { 
    type: "erc20", 
    address: "0x4e93a01c90f812284f71291a8d1415a904957156" // Creator coin address
  },
  buy: { type: "eth" },
  amountIn: parseEther("100"), // 100 tokens (adjust decimals as needed)
  slippage: 0.15, // 15% slippage tolerance
  sender: account.address,
};
 
const receipt = await tradeCoin({
  tradeParameters,
  walletClient,
  account,
  publicClient,
});

Trading USDC for Creator Coin (with Permits)

When trading ERC20 tokens, the function automatically handles permit signatures for secure approvals:

import { TradeParameters, tradeCoin } from "@zoralabs/coins-sdk";
 
const tradeParameters: TradeParameters = {
  sell: {
    type: "erc20",
    address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC address
  },
  buy: {
    type: "erc20", 
    address: "0x9b13358e3a023507e7046c18f508a958cda75f54", // @jacob creator coin
  },
  amountIn: BigInt(4 * 10 ** 6), // 4 USDC (6 decimals)
  slippage: 0.05, // 5% slippage
  sender: account.address,
};
 
const receipt = await tradeCoin({
  tradeParameters,
  walletClient,
  account,
  publicClient,
});

Trading Between ERC20 Tokens

Only creator coins, USDC, and ZORA are supported for trading between ERC20 tokens. Content coins can currently be traded when the creator is the same but the current flow requires selling for ZORA, USDC, or ETH, then buying the new coin separately.

import { TradeParameters, tradeCoin } from "@zoralabs/coins-sdk";
 
const tradeParameters: TradeParameters = {
  sell: {
    type: "erc20",
    address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
  },
  buy: {
    type: "erc20",
    address: "0x9b13358e3a023507e7046c18f508a958cda75f54", // @jacob creator coin
  },
  amountIn: BigInt(4 * 10 ** 6), // 4 USDC (6 decimals)
  slippage: 0.04, // 4% slippage
  sender: account.address,
};
 
const receipt = await tradeCoin({
  tradeParameters,
  walletClient,
  account,
  publicClient,
});

Disabling Transaction Validation

By default, tradeCoin validates transactions before execution. You can disable this for faster execution:

const receipt = await tradeCoin({
  tradeParameters,
  walletClient,
  account,
  publicClient,
  validateTransaction: false, // Skip validation and gas estimation
});

Function Signature

async function tradeCoin({
  tradeParameters,
  walletClient,
  account,
  publicClient,
  validateTransaction = true,
}: {
  tradeParameters: TradeParameters;
  walletClient: WalletClient;
  account: Account;
  publicClient: GenericPublicClient;
  validateTransaction?: boolean;
})

Trade Parameters

The TradeParameters interface supports the following options:

type TradeParameters = {
  sell: TradeCurrency; // Token to sell
  buy: TradeCurrency; // Token to buy
  amountIn: bigint; // Amount to sell (in token's smallest unit)
  slippage?: number; // Slippage tolerance (0-0.99, default: 5%)
  sender: Address; // Sender address (can be smart wallet or EOA)
  signer?: Address; // Must be EOA, defaults to sender if blank
  recipient?: Address; // Recipient address (optional, defaults to sender)
  signatures?: SignatureWithPermit<PermitStringAmounts>[]; // Pre-signed permits (optional)
  permitActiveSeconds?: number; // Permit validity duration (optional, defaults to 20 minutes)
};
 
// Trade currency can be ETH or an ERC20 token
type TradeCurrency = 
  | { type: "eth" }
  | { type: "erc20"; address: Address };

How Permits Work

When trading ERC20 tokens, tradeCoin automatically:

  1. Checks existing allowances for the token being sold
  2. Requests approval if insufficient allowance exists
  3. Generates permit signatures using EIP-2612 standard
  4. Signs typed data with your EOA for secure, gasless approvals
  5. Includes permits in the trade transaction

This eliminates the need for separate approval transactions while maintaining security.

Direct ETH Calls with createTradeCall

For direct ETH trades without the full tradeCoin workflow, you can use createTradeCall:

import { createTradeCall } from "@zoralabs/coins-sdk";
 
// Get trade call data without executing
const quote = await createTradeCall(tradeParameters);
 
const walletClient = createWalletClient({/* ... */});
 
// Execute the call directly
const tx = await walletClient.sendTransaction({
  to: quote.call.target as Address,
  data: quote.call.data as Hex,
  value: BigInt(quote.call.value),
  account,
});

This is useful when you need more control over transaction execution or want to batch multiple operations.

This flow does not currently support the permits feature for selling ERC20 tokens.

Error Handling

The function validates parameters and throws descriptive errors:

// Invalid slippage (must be less than 1.0)
const invalidSlippage: TradeParameters = {
  // ... other parameters
  slippage: 1.5, // > 1.0
};
// Throws: "Slippage must be less than 1, max 0.99"
 
// Zero amount
const zeroAmount: TradeParameters = {
  // ... other parameters
  amountIn: BigInt(0),
};
// Throws: "Amount in must be greater than 0"

Smart Wallet Support

Smart wallet support is coming soon. Currently, the SDK works with:

  • EOA wallets (MetaMask, WalletConnect, etc.)
  • 🔄 Smart wallets (coming soon)

Best Practices

  1. Set appropriate slippage based on market conditions and token liquidity
  2. Use permit signatures for ERC20 trades to save gas on approvals
  3. Validate transactions by keeping validateTransaction: true (default)
  4. Handle errors gracefully with proper try-catch blocks
  5. Test with small amounts before executing large trades
  6. Account for token decimals when setting amountIn values

Network Support

Currently only supports Base mainnet.