Intermediate · ~20 minutes

Multi-Chain Wallet
8 chains, one API

Generate a multi-chain agent wallet, aggregate balances across all 8 supported chains, send transfers, estimate gas fees, and monitor transactions. Full JavaScript code for every operation.

5 steps
8 chains supported
JavaScript focus
Updated March 2026

Prerequisites

Registered Purple Flea agent Node.js 18+ Basic JavaScript knowledge

8 supported chains

Every Purple Flea agent wallet supports all 8 chains from a single API key. No separate accounts needed per chain.

Ethereum
ETH
EVM
Solana
SOL
Native
🟦
Bitcoin
BTC
Native
🔒
Monero
XMR
Privacy
Tron
TRX
Native
🟤
Polygon
MATIC
EVM
🧀
BNB Chain
BNB
EVM
Avalanche
AVAX
EVM
🌐 One key, all chains

Your Purple Flea API key authenticates across all 8 chains. The Wallet API abstracts each chain's native transaction format. You send a unified JSON request and Purple Flea handles signing, broadcasting, and fee management per chain.

01

Generate your multi-chain wallet

A single API call provisions addresses on all 8 chains, derived from one root key managed by Purple Flea. Your agent gets a stable address per chain immediately.

~500ms — all 8 addresses generated
generate-wallet.js
JS
const WALLET = 'https://purpleflea.com/api/wallet';
const API_KEY = process.env.PF_API_KEY;

const headers = {
  'Authorization': `Bearer ${API_KEY}`,
  'Content-Type': 'application/json'
};

async function generateWallet() {
  const res = await fetch(`${WALLET}/generate`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      chains: ['ETH', 'SOL', 'BTC', 'XMR', 'TRX', 'MATIC', 'BNB', 'AVAX'],
      label: 'main-treasury'   // optional label
    })
  });

  const wallet = await res.json();

  // Print addresses for all chains
  for (const [chain, info] of Object.entries(wallet.addresses)) {
    console.log(`${chain.padEnd(6)}: ${info.address}`);
  }

  console.log(`\nWallet ID: ${wallet.wallet_id}`);
  // Store wallet_id for subsequent calls
  return wallet;
}

generateWallet();
Response (201 Created)
{
  "wallet_id": "wlt_Kx9mNpQ3rX7vZ",
  "addresses": {
    "ETH":  { "address": "0x4a2f...c91b",       "chain_id": 1 },
    "SOL":  { "address": "7K8m...Pg2Q",         "chain_id": "mainnet-beta" },
    "BTC":  { "address": "bc1q...x4kz",         "format": "bech32" },
    "XMR":  { "address": "49...long_xmr_addr",  "view_key": "..." },
    "TRX":  { "address": "TKmN...3pRq"         },
    "MATIC":{ "address": "0x4a2f...c91b",       "chain_id": 137 },
    "BNB":  { "address": "0x4a2f...c91b",       "chain_id": 56 },
    "AVAX": { "address": "0x4a2f...c91b",       "chain_id": 43114 }
  }
}
💡 EVM address sharing

ETH, MATIC, BNB, and AVAX share the same EVM address (your 0x... address) but operate as separate chains with separate balances. Purple Flea tracks them independently. XMR uses a unique stealth address format with a separate view key for balance scanning.

02

Aggregate balances across all chains

One call returns native balances, USDC balances, and USD-equivalent totals for all 8 chains. Essential for portfolio management and treasury decisions.

~800ms (parallel chain queries)
aggregate-balances.js
JS
async function getPortfolio() {
  const res = await fetch(`${WALLET}/balances`, { headers });
  const portfolio = await res.json();

  let totalUSD = 0;

  console.log('=== Agent Portfolio ===');
  console.log('Chain   | Native        | USDC      | USD Value');
  console.log('--------|---------------|-----------|----------');

  for (const chain of portfolio.chains) {
    const native = chain.native_balance.toFixed(4).padEnd(13);
    const usdc   = chain.usdc_balance.toFixed(2).padEnd(9);
    const usd    = chain.usd_value.toFixed(2);
    console.log(`${chain.symbol.padEnd(7)} | ${native} | ${usdc} | $${usd}`);
    totalUSD += chain.usd_value;
  }

  console.log(`\nTotal portfolio value: $${totalUSD.toFixed(2)} USD`);
  console.log(`Last updated: ${portfolio.updated_at}`);

  // Price oracle data included
  console.log(`\nPrices used:`);
  for (const [sym, price] of Object.entries(portfolio.prices)) {
    console.log(`  ${sym}: $${price}`);
  }

  return portfolio;
}

getPortfolio();
Response (200 OK)
{
  "total_usd_value": 487.32,
  "chains": [
    { "symbol": "ETH",  "native_balance": 0.0821, "usdc_balance": 150.00, "usd_value": 352.18 },
    { "symbol": "SOL",  "native_balance": 1.4400, "usdc_balance": 0.00,   "usd_value": 204.48 },
    { "symbol": "BTC",  "native_balance": 0.0000, "usdc_balance": 0.00,   "usd_value": 0.00   },
    { "symbol": "XMR",  "native_balance": 0.0000, "usdc_balance": 0.00,   "usd_value": 0.00   },
    { "symbol": "MATIC","native_balance": 45.800, "usdc_balance": 50.00,  "usd_value": 95.62  }
  ],
  "prices": { "ETH": 2465, "SOL": 142, "MATIC": 0.92, "BNB": 608, "AVAX": 38 },
  "updated_at": "2026-03-04T12:00:00Z"
}
03

Transfer funds between addresses

Send native tokens or USDC on any supported chain. Specify the chain, recipient, amount, and asset. Purple Flea handles signing and broadcasting.

15s–30min depending on chain
transfer-usdc.js
JS
async function transferUSDC(chain, toAddress, amount) {
  // First estimate gas
  const estimate = await estimateGas(chain, toAddress, amount, 'USDC');
  console.log(`Estimated fee: ${estimate.fee_usd} USD on ${chain}`);

  if (estimate.fee_usd > amount * 0.1) {
    console.warn('Warning: fee exceeds 10% of transfer amount');
  }

  const res = await fetch(`${WALLET}/transfer`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      chain,                      // 'ETH' | 'SOL' | 'MATIC' etc.
      asset: 'USDC',
      to: toAddress,
      amount,                     // in USDC
      speed: 'standard',         // 'slow' | 'standard' | 'fast'
      memo: 'Payment for services'  // optional
    })
  });

  const tx = await res.json();
  console.log(`TX submitted: ${tx.tx_hash}`);
  console.log(`Explorer:     ${tx.explorer_url}`);
  return tx;
}
transfer-native.js
JS
async function transferNative(chain, toAddress, amount) {
  const assetMap = {
    ETH: 'ETH', SOL: 'SOL', BTC: 'BTC',
    XMR: 'XMR', TRX: 'TRX', MATIC: 'MATIC',
    BNB: 'BNB', AVAX: 'AVAX'
  };

  const res = await fetch(`${WALLET}/transfer`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      chain,
      asset: assetMap[chain],
      to: toAddress,
      amount,         // in native units (ETH, SOL, BTC, etc.)
      speed: 'standard'
    })
  });

  const tx = await res.json();

  if (!res.ok) {
    throw new Error(`Transfer failed: ${tx.error} (${tx.code})`);
  }

  console.log(`${amount} ${chain} sent`);
  console.log(`Hash: ${tx.tx_hash}`);
  console.log(`Est. confirmation: ${tx.estimated_confirm_time}`);
  return tx;
}

// XMR note: transfers are unlocked after 10 confirmations (~20min)
// BTC note: 1 confirmation (~10min) for standard, 6 for high-value
04

Gas estimation and fee calculation

Always estimate before sending. Gas costs vary wildly between chains and between slow, standard, and fast speed tiers. Build fee-aware logic into your agent.

~200ms — no on-chain action
gas-estimation.js
JS
async function estimateGas(chain, to, amount, asset) {
  const res = await fetch(`${WALLET}/estimate`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ chain, to, amount, asset })
  });
  return await res.json();
}

// Fee-aware transfer: pick cheapest chain for USDC transfers
async function cheapestUSDCTransfer(to, amount) {
  const evm_chains = ['ETH', 'MATIC', 'BNB', 'AVAX'];

  // Estimate fees on all EVM chains in parallel
  const estimates = await Promise.all(
    evm_chains.map(async chain => {
      const est = await estimateGas(chain, to, amount, 'USDC');
      return { chain, fee_usd: est.standard.fee_usd, ...est };
    })
  );

  // Sort by fee ascending
  estimates.sort((a, b) => a.fee_usd - b.fee_usd);

  console.log('Fee comparison for $100 USDC transfer:');
  estimates.forEach(e => {
    console.log(`  ${e.chain.padEnd(6)}: $${e.fee_usd.toFixed(4)} USD`);
  });

  const best = estimates[0];
  console.log(`\nCheapest: ${best.chain} at $${best.fee_usd.toFixed(4)} USD`);
  return best;
}

// Example output:
// Fee comparison for $100 USDC transfer:
//   MATIC : $0.0012 USD
//   BNB   : $0.0045 USD
//   AVAX  : $0.0110 USD
//   ETH   : $1.4300 USD
// Cheapest: MATIC at $0.0012 USD
⚠ Gas fee volatility

ETH gas can spike 50-100x during network congestion. For routine USDC transfers between agents, Polygon (MATIC) offers near-zero fees with fast finality. Reserve ETH for operations requiring Ethereum mainnet finality.

Estimate Response (200 OK)
{
  "chain":  "MATIC",
  "asset":  "USDC",
  "amount": 100,
  "slow":     { "fee_gwei": 30,  "fee_usd": 0.0008, "eta_seconds": 120 },
  "standard": { "fee_gwei": 50,  "fee_usd": 0.0012, "eta_seconds": 15  },
  "fast":     { "fee_gwei": 100, "fee_usd": 0.0024, "eta_seconds": 5   }
}
05

Monitor transactions

Poll for transaction status or use webhook callbacks. Essential for multi-agent workflows where downstream agents must wait for payment confirmation before starting work.

Poll or webhook
monitor-tx.js
JS
async function waitForConfirmation(txHash, chain, maxWaitMs = 300000) {
  const pollIntervals = {
    ETH:   15000,   // 15s
    SOL:   1000,    // 1s (fast finality)
    BTC:   60000,   // 60s
    XMR:   60000,   // 60s
    TRX:   3000,    // 3s
    MATIC: 5000,    // 5s
    BNB:   5000,    // 5s
    AVAX:  5000     // 5s
  };

  const interval = pollIntervals[chain] || 10000;
  const deadline = Date.now() + maxWaitMs;

  while (Date.now() < deadline) {
    const status = await fetch(
      `${WALLET}/tx/${chain}/${txHash}`,
      { headers }
    ).then(r => r.json());

    if (status.confirmed) {
      console.log(`Confirmed after ${status.confirmations} blocks`);
      console.log(`Block: ${status.block_number}`);
      console.log(`Fee paid: ${status.fee_paid} ${chain}`);
      return status;
    }

    if (status.failed) {
      throw new Error(`TX failed: ${status.failure_reason}`);
    }

    console.log(`Pending (${status.confirmations}/${status.required_confirmations})...`);
    await new Promise(r => setTimeout(r, interval));
  }

  throw new Error(`TX not confirmed within ${maxWaitMs/1000}s`);
}
webhook-setup.js
JS
// Register a webhook to receive TX confirmations
async function registerWebhook() {
  const res = await fetch(`${WALLET}/webhooks`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      url: 'https://my-agent.example.com/tx-callback',
      events: ['tx.confirmed', 'tx.failed', 'deposit.received'],
      chains: ['ETH', 'MATIC', 'SOL'],
      secret: process.env.WEBHOOK_SECRET  // used to verify signatures
    })
  });
  const wh = await res.json();
  console.log(`Webhook registered: ${wh.webhook_id}`);
  return wh;
}

// Webhook payload received at your callback URL:
// {
//   "event":    "tx.confirmed",
//   "tx_hash":  "0xabc...",
//   "chain":    "MATIC",
//   "amount":   100,
//   "asset":    "USDC",
//   "to":       "0x...",
//   "block":    52847123,
//   "signature":"hmac-sha256:..."
// }

Cross-chain swap

Swap any supported asset to any other across chains. Purple Flea routes through the best available bridges and DEXes and returns a single signed quote.

cross-chain-swap.js
JS
async function swapAssets() {
  // Get a quote first
  const quote = await fetch(`${WALLET}/swap/quote`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      from_chain: 'ETH',
      from_asset: 'USDC',
      from_amount: 500,           // 500 USDC on ETH
      to_chain: 'SOL',
      to_asset: 'USDC',           // receive USDC on Solana
      slippage_bps: 50            // 0.5% max slippage
    })
  }).then(r => r.json());

  console.log(`From: ${quote.from_amount} USDC on ETH`);
  console.log(`To:   ${quote.to_amount} USDC on SOL`);
  console.log(`Fee:  ${quote.total_fee_usd} USD`);
  console.log(`Route: ${quote.route.join(' → ')}`);
  console.log(`ETA:  ${quote.estimated_time_seconds}s`);

  // Accept and execute the swap
  const swap = await fetch(`${WALLET}/swap/execute`, {
    method: 'POST',
    headers,
    body: JSON.stringify({ quote_id: quote.quote_id })
  }).then(r => r.json());

  console.log(`\nSwap initiated: ${swap.swap_id}`);
  console.log(`Track at: ${swap.tracker_url}`);
  return swap;
}

Full portfolio manager

A complete agent treasury management script that checks balances, concentrates dust into one chain, and reports P&L.

portfolio-manager.js
JS
/**
 * portfolio-manager.js
 * Agent treasury manager: aggregate, consolidate dust, report P&L.
 * Usage: PF_API_KEY=... node portfolio-manager.js
 */
const WALLET = 'https://purpleflea.com/api/wallet';
const hdr = {
  'Authorization': `Bearer ${process.env.PF_API_KEY}`,
  'Content-Type': 'application/json'
};
const get  = url => fetch(url, { headers: hdr }).then(r => r.json());
const post = (url, body) => fetch(url, {
  method: 'POST', headers: hdr, body: JSON.stringify(body)
}).then(r => r.json());

const CONSOLIDATE_TO = 'MATIC';      // cheapest fees for USDC
const DUST_THRESHOLD_USD = 1.0;      // skip swapping tiny amounts
const MIN_NATIVE_RESERVE = 0.001;    // keep for future gas

async function manageTreasury() {
  console.log('=== Treasury Management Run ===');

  // 1. Get all balances
  const portfolio = await get(`${WALLET}/balances`);
  console.log(`Total portfolio: $${portfolio.total_usd_value.toFixed(2)}`);

  // 2. Find USDC balances above dust threshold on non-consolidation chains
  const toConsolidate = portfolio.chains.filter(c =>
    c.symbol !== CONSOLIDATE_TO &&
    c.usdc_balance > 0 &&
    c.usdc_balance * portfolio.prices['USDC'] > DUST_THRESHOLD_USD
  );

  // 3. Consolidate to MATIC for cheapest fees
  for (const chain of toConsolidate) {
    console.log(`Consolidating ${chain.usdc_balance} USDC from ${chain.symbol}...`);
    const swap = await post(`${WALLET}/swap/execute`, {
      from_chain:   chain.symbol,
      from_asset:   'USDC',
      from_amount:  chain.usdc_balance,
      to_chain:     CONSOLIDATE_TO,
      to_asset:     'USDC',
      slippage_bps: 50
    });
    console.log(`  Swap ${swap.swap_id} submitted`);
  }

  // 4. Generate report
  const report = await get(`${WALLET}/report?period=7d`);
  console.log(`\n7-day P&L: $${report.pnl_usd.toFixed(2)}`);
  console.log(`Total inflows:  $${report.inflows_usd.toFixed(2)}`);
  console.log(`Total outflows: $${report.outflows_usd.toFixed(2)}`);
  console.log(`Fees paid:      $${report.fees_paid_usd.toFixed(2)}`);
}

manageTreasury().catch(console.error);

Chain reference

ChainUSDC SupportAvg ConfirmationAvg Fee (USDC transfer)Notes
ETH Native USDC ~15s $0.50–$5.00 Highest security. Use for large transfers only.
SOL USDC (SPL) <1s ~$0.001 Fastest finality. Great for high-frequency agent payments.
BTC No USDC ~10min BTC only Native BTC only. 6 confirmations for large amounts.
XMR No USDC ~2min XMR only Privacy chain. 10-block unlock (~20min). Needs view key for balance scan.
TRX USDT/USDC ~3s ~$0.001 Very cheap. Large stablecoin ecosystem. TRX bandwidth model.
MATIC Native USDC ~5s ~$0.001 Best for routine agent-to-agent USDC transfers. Recommended default.
BNB USDC (BSC) ~5s ~$0.005 Fast and cheap. Large DeFi ecosystem on BSC.
AVAX Native USDC ~2s ~$0.010 Near-instant finality. Good for time-sensitive agent operations.

Start managing your agent's treasury.

One API key. 8 chains. USDC transfers in seconds. Get free USDC from the faucet to begin.

Get Free USDC → Wallet API Docs