Skip to main content

EVM: Buy a token

Full flow to buy a token with native ETH on Base.

1. Get a quote

const wallet = new ethers.Wallet(process.env.TRADING_EVM_PKEY!)
const TOKEN = '0xFb31f85A8367210B2e4Ed2360D2dA9Dc2D2Ccc95'

const quote = await api<any>(`/api/v2/quote?` + new URLSearchParams({
  tokenIn: NATIVE,
  tokenOut: TOKEN,
  amount: parseUnits('0.01', 18).toString(), // 0.01 ETH in wei
  slippage: '500',                           // 5%
  trader: wallet.address,
  chain: 'BASE'
}))

if (!quote.success) throw new Error(quote.error)
console.log(`Expected output: ${quote.stats.amountOut}`)
console.log(`Price impact: ${quote.stats.priceImpact}%`)

2. Sign transactions

const signedTrade = await wallet.signTransaction(
  ethers.Transaction.from(quote.transaction.trade)
)

// Sign approval if present (required when selling tokens)
let signedApprove: string | undefined
if (quote.transaction.approve) {
  signedApprove = await wallet.signTransaction(
    ethers.Transaction.from(quote.transaction.approve)
  )
}

// Sign extra tx if present (permit2 or fee tx for some tokens)
let signedExtra: string | undefined
if (quote.transaction.extra) {
  signedExtra = await wallet.signTransaction(
    ethers.Transaction.from(quote.transaction.extra)
  )
}

3. Execute

const result = await api<any>('/api/v2/execute', {
  method: 'POST',
  body: JSON.stringify({
    trade: signedTrade,
    chain: 'BASE',
    mev: false,
    simulation: true,
    quoteId: quote.transaction.quoteId,
    approve: signedApprove,
    extra: signedExtra
  })
})

console.log(`Success: ${result.success}`)
console.log(`TX: ${result.txRes?.explorerUrl}`)
console.log(`Received: ${result.txRes?.received}`)

EVM: Sell tokens

Sell 50% of your token balance back to ETH:
// Use percentage amount format
const sellQuote = await api<any>(`/api/v2/quote?` + new URLSearchParams({
  tokenIn: TOKEN,
  tokenOut: NATIVE,
  amount: '50%',           // sells 50% of balance
  slippage: '500',
  trader: wallet.address,
  chain: 'BASE'
}))

if (!sellQuote.success) throw new Error(sellQuote.error)

const signedSell = await wallet.signTransaction(
  ethers.Transaction.from(sellQuote.transaction.trade)
)

// Approval is almost always required when selling tokens
let signedSellApprove: string | undefined
if (sellQuote.transaction.approve) {
  signedSellApprove = await wallet.signTransaction(
    ethers.Transaction.from(sellQuote.transaction.approve)
  )
}

let signedSellExtra: string | undefined
if (sellQuote.transaction.extra) {
  signedSellExtra = await wallet.signTransaction(
    ethers.Transaction.from(sellQuote.transaction.extra)
  )
}

const sellResult = await api<any>('/api/v2/execute', {
  method: 'POST',
  body: JSON.stringify({
    trade: signedSell,
    chain: 'BASE',
    mev: false,
    simulation: true,
    quoteId: sellQuote.transaction.quoteId,
    approve: signedSellApprove,
    extra: signedSellExtra
  })
})

console.log(`Sold — received ${sellResult.txRes?.received} ETH`)

EVM: Check balance

const bal = await api<any>(
  `/api/v1/balance?wallet=${wallet.address}&token=${TOKEN}&chains=${encodeURIComponent('["BASE"]')}`
)

for (const b of bal.balances) {
  const human = Number(b.balance) / Math.pow(10, b.decimals)
  console.log(`[${b.chain}] ${human}`)
}

EVM: Token info before trading

Check taxes and liquidity before trading:
const info = await api<any>(`/api/v1/token-info?token=${TOKEN}&chain=BASE`)

if (info.success) {
  console.log(`Symbol: ${info.tokenInfo.token.symbol}`)
  console.log(`Pool: ${info.poolInfo.type} — $${info.poolInfo.liquidity} liquidity`)
  console.log(`Buy tax: ${info.misc.buyTax / 100}%`)
  console.log(`Sell tax: ${info.misc.sellTax / 100}%`)
}

Best practices

  • Always sign approve if present — it’s required for the trade to succeed
  • Always sign extra if present — permit2 or fee transactions for specific tokens
  • Use simulation: true — catches reverts before broadcasting. When simulation=true and trader is provided, balance and allowance preflight checks run before quoting. When simulation=false (default), these checks are skipped — useful for quoting sell routes before the trader holds the token.
  • Slippage: 500 bps (5%) for most tokens, 1000+ for low-liquidity. slippage=10000 activates fast mode — skips gas estimation, price impact, and USD valuation. Response contains only path and transaction (no stats).
  • MEV protection: enable mev: true on ETH and BSC for large trades
  • Quotes expire in 30 seconds — sign and execute immediately
  • Check result.success — HTTP 200 doesn’t mean the trade succeeded

Solana

Same flow, different signing. Uses @solana/web3.js and base64-encoded transactions.
import { Keypair, VersionedTransaction } from '@solana/web3.js'
import bs58 from 'bs58'

const keypair = Keypair.fromSecretKey(bs58.decode(process.env.SOL_PRIVATE_KEY!))

// 1. Quote — buy token with 0.1 SOL
const quote = await api<any>(`/api/v2/quote?` + new URLSearchParams({
  tokenIn: NATIVE,
  tokenOut: 'TOKEN_MINT_ADDRESS',
  amount: '100000000', // 0.1 SOL in lamports
  slippage: '500',
  trader: keypair.publicKey.toBase58(),
  chain: 'SOL'
}))

// 2. Sign — decode base64, sign with keypair
const txBuf = Buffer.from(quote.transaction.trade, 'base64')
const tx = VersionedTransaction.deserialize(txBuf)
tx.sign([keypair])
const signedTrade = Buffer.from(tx.serialize()).toString('base64')

// 3. Execute
const result = await api<any>('/api/v2/execute', {
  method: 'POST',
  body: JSON.stringify({
    trade: signedTrade,
    chain: 'SOL',
    mev: false,
    simulation: true,
    quoteId: quote.transaction.quoteId
  })
})

console.log(`TX: https://solscan.io/tx/${result.txRes?.txHash}`)
Solana differences:
  • No approve or extra transactions
  • Transactions are base64-encoded VersionedTransaction, not hex
  • Use lamports (1 SOL = 10^9 lamports)
  • Higher slippage recommended for pump.fun tokens (1000+ bps)