DEV Community

Cover image for NFT Arbitrage Bots: ERC-721/ERC-1155 + Metaplex Cross-Chain Trading
Wallet Guy
Wallet Guy

Posted on

NFT Arbitrage Bots: ERC-721/ERC-1155 + Metaplex Cross-Chain Trading

NFT Arbitrage Bots: Building Cross-Chain ERC-721/ERC-1155 and Metaplex Trading Infrastructure

NFT arbitrage bots live and die by execution speed — your bot spotted the price discrepancy between an ERC-721 on Ethereum and its wrapped equivalent on Solana, but if your wallet infrastructure can't keep up, the opportunity is gone before the next block. Building reliable NFT arbitrage infrastructure means solving a stack of hard problems simultaneously: cross-chain wallet management, gas optimization, policy-based risk controls, and multi-protocol DeFi integration — all without writing a custom signing layer from scratch.

The Real Problem: Execution Infrastructure, Not Alpha

Most developers building NFT arbitrage systems spend 80% of their time on alpha discovery — floor price feeds, rarity sniping, wash trade detection — and assume the execution layer will "just work." It won't. The execution layer is where arb bots die.

The problems stack up fast:

  • Cross-chain coordination: An ERC-721 opportunity on Ethereum requires different signing, gas estimation, and confirmation semantics than a Metaplex NFT on Solana. You need unified wallet infrastructure that handles both without context-switching your entire stack.
  • Gas timing: Executing an NFT buy at peak gas prices can erase your entire spread. You need conditional execution that gates transactions on gas price thresholds.
  • Risk controls: An unguarded bot with signing authority over a funded wallet is one bug away from draining itself. You need spending limits, contract whitelists, and approval gates before you deploy real capital.
  • Multi-protocol access: Buying the NFT is step one. Bridging proceeds, swapping into a hedge position, or staking idle capital between opportunities all require DeFi protocol access on the same infrastructure.

WAIaaS is a self-hosted Wallet-as-a-Service that addresses the execution layer directly. It's open-source, Docker-deployable, and gives your bot a REST API with 39 route modules covering transactions, DeFi actions, NFT operations, and policy enforcement — without you building any of it.

NFT Support: ERC-721/ERC-1155 and Metaplex

WAIaaS supports NFTs on both sides of the cross-chain equation: ERC-721 and ERC-1155 on EVM chains, and Metaplex on Solana, with metadata caching built in. The daemon handles the chain-specific mechanics — Metaplex account structures on Solana, ERC-1155 batch operations on EVM — so your bot talks to one consistent API regardless of which chain the opportunity is on.

Your bot can list NFTs in the wallet, fetch metadata for valuation logic, and execute transfers — all through the same session token.

For an EVM NFT transfer:

curl -X POST http://127.0.0.1:3100/v1/transactions/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer wai_sess_<token>" \
  -d '{
    "type": "NftTransfer",
    "to": "recipient-address",
    "amount": "0.1"
  }'
Enter fullscreen mode Exit fullscreen mode

The transaction schema supports 7 types in a discriminated union — Transfer, TokenTransfer, ContractCall, Approve, Batch, NftTransfer, and ContractDeploy — which means your bot can construct arbitrage sequences that combine NFT transfers with token swaps or contract calls in a single structured payload.

The 7-Stage Transaction Pipeline

Understanding how your transactions flow through WAIaaS matters for latency-sensitive arbitrage. Every transaction goes through a 7-stage pipeline: validate → auth → policy → wait → execute → confirm.

The policy stage is where your risk controls live. The wait stage is where gas conditional execution happens — your bot can specify that a transaction should only proceed when gas meets a threshold, letting you queue the execution and let WAIaaS handle the polling rather than building that loop yourself.

The dry-run API lets your bot simulate the full pipeline without executing, so you can validate that a proposed NFT transfer will pass policy checks before committing:

curl -X POST http://127.0.0.1:3100/v1/transactions/send \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer wai_sess_<token>" \
  -d '{
    "type": "TRANSFER",
    "to": "recipient-address",
    "amount": "0.1",
    "dryRun": true
  }'
Enter fullscreen mode Exit fullscreen mode

Run this before every live execution during development. A POLICY_DENIED error in dry-run mode is much cheaper than one that surfaces mid-execution.

Policy Engine: Risk Controls Your Arb Bot Actually Needs

Deploying a bot with unrestricted signing authority is how you lose a wallet. WAIaaS has a policy engine with 21 policy types and a default-deny enforcement model — if ALLOWED_TOKENS or CONTRACT_WHITELIST aren't configured, those transaction categories are blocked entirely.

For an NFT arbitrage bot, the relevant policy stack looks like this:

SPENDING_LIMIT — 4-tier security based on USD value. Transactions below instant_max_usd execute immediately. Above delay_max_usd, they require your approval.

curl -X POST http://127.0.0.1:3100/v1/policies \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{
    "walletId": "<wallet-uuid>",
    "type": "SPENDING_LIMIT",
    "rules": {
      "instant_max_usd": 100,
      "notify_max_usd": 500,
      "delay_max_usd": 2000,
      "delay_seconds": 900,
      "daily_limit_usd": 5000
    }
  }'
Enter fullscreen mode Exit fullscreen mode

The four tiers are: INSTANT (execute immediately), NOTIFY (execute + send notification), DELAY (queue for delay_seconds, cancellable), and APPROVAL (require human sign-off via WalletConnect or Telegram).

CONTRACT_WHITELIST — Default-deny contract call whitelist. Your bot should only be able to call the NFT marketplace contracts you've explicitly approved. This stops a compromised session token from draining the wallet through an arbitrary contract.

APPROVE_AMOUNT_LIMIT — Blocks unlimited token approvals. If your bot interacts with ERC-721 marketplaces that require ERC-20 approvals (WETH for bids, etc.), this policy caps the approval amount so a buggy approval call doesn't expose the full token balance.

RATE_LIMIT — Caps transactions per period. Useful for detecting runaway bot behavior — if your bot is normally sending 5 transactions per hour and suddenly tries to send 50, that's a signal something is wrong.

ALLOWED_NETWORKS — Restricts which chains the bot can transact on. For a focused Ethereum/Solana NFT arb strategy, there's no reason your bot should have signing authority on chains it doesn't need.

The 3-layer security model — session auth → time delay + approval → monitoring + kill switch — means you have multiple intervention points if something goes wrong. The session layer isolates your bot's credentials from your master password. The policy layer enforces limits automatically. The approval layer gives you a human gate for large transactions.

Cross-Chain Execution: Bridge + Swap in One Stack

NFT arbitrage often requires moving capital between chains to capitalize on opportunities. WAIaaS integrates 15 DeFi protocol providers including LI.FI and Across for cross-chain bridging, Jupiter for Solana swaps, and Drift for perpetual hedging — all accessible through the same session token your NFT transfer calls use.

A typical cross-chain arb flow might look like:

  1. Bot detects underpriced Solana NFT relative to Ethereum floor
  2. Check USDC balance on Solana via getBalance
  3. Execute NFT purchase via NftTransfer transaction
  4. Bridge proceeds when selling back via LI.FI or Across
  5. Swap residual tokens via Jupiter if needed

Each step is a separate API call to the same daemon:

# Step 3: Execute DeFi action — swap for purchase capital
curl -X POST http://127.0.0.1:3100/v1/actions/jupiter-swap/swap \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer wai_sess_<token>" \
  -d '{
    "inputMint": "So11111111111111111111111111111111111111112",
    "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "1000000000"
  }'
Enter fullscreen mode Exit fullscreen mode

The DeFi protocol integrations include the full list you'd expect for sophisticated strategies: Aave v3 for lending, Hyperliquid for perpetual futures (including sub-accounts), Kamino, Pendle, Polymarket for prediction markets, and ZeroX and dCENT swap for EVM-side execution.

Account Abstraction for EVM NFT Bots

If your EVM NFT strategy needs gasless transactions or smart account functionality, WAIaaS has ERC-4337 Account Abstraction support with a UserOp build/sign API. This matters for bots operating on L2s where AA infrastructure is more mature — you can batch multiple NFT operations into a single UserOp, reducing gas overhead per transaction.

The 45 MCP tools include build-userop, sign-userop, and related Account Abstraction tooling, accessible if you're integrating your bot with Claude or another AI agent framework through the MCP interface.

TypeScript SDK Integration

If you're building your bot in TypeScript rather than making raw curl calls, the @waiaas/sdk gives you typed methods with async/await:

import { WAIaaSClient, WAIaaSError } from '@waiaas/sdk';

const client = new WAIaaSClient({
  baseUrl: process.env['WAIAAS_BASE_URL'] ?? 'http://localhost:3100',
  sessionToken: process.env['WAIAAS_SESSION_TOKEN'],
});

// Check balance before attempting NFT purchase
const balance = await client.getBalance();
console.log(`Balance: ${balance.balance} ${balance.symbol} (${balance.chain}/${balance.network})`);

// Send NFT transfer and poll for confirmation
const sendResult = await client.sendToken({
  type: 'TRANSFER',
  to: 'recipient-address',
  amount: '0.001',
});

const POLL_TIMEOUT_MS = 60_000;
const startTime = Date.now();
while (Date.now() - startTime < POLL_TIMEOUT_MS) {
  const tx = await client.getTransaction(sendResult.id);
  if (tx.status === 'COMPLETED') {
    console.log(`Transaction confirmed! Hash: ${tx.txHash}`);
    break;
  }
  if (tx.status === 'FAILED') {
    console.error(`Transaction failed: ${tx.error}`);
    break;
  }
  await new Promise(resolve => setTimeout(resolve, 1000));
}
Enter fullscreen mode Exit fullscreen mode

Error handling is typed — WAIaaSError gives you structured error codes like INSUFFICIENT_BALANCE, POLICY_DENIED, and TOKEN_EXPIRED so your bot can make branching decisions based on failure mode rather than parsing error strings.

The Python SDK (waiaas) offers the same async/await pattern for bots built in Python.

Quick Start: Deploying Your NFT Arb Infrastructure

Step 1: Deploy the daemon

git clone https://github.com/waiaas/WAIaaS.git
cd WAIaaS
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

The Docker image runs as non-root (UID 1001), binds to 127.0.0.1:3100 by default, and includes a healthcheck. For production, use the secrets overlay:

mkdir -p secrets
echo "your-secure-password" > secrets/master_password.txt
chmod 600 secrets/master_password.txt
docker compose -f docker-compose.yml -f docker-compose.secrets.yml up -d
Enter fullscreen mode Exit fullscreen mode

Step 2: Initialize and create wallets

npm install -g @waiaas/cli
waiaas quickset --mode mainnet
Enter fullscreen mode Exit fullscreen mode

Or manually via the CLI's 20 commands — wallet create for each chain you need, session prompt to generate bot session tokens.

Step 3: Create your wallet and session via API

# Create Solana wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{"name": "nft-arb-solana", "chain": "solana", "environment": "mainnet"}'

# Create session token for your bot
curl -X POST http://127.0.0.1:3100/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-Master-Password: my-secret-password" \
  -d '{"walletId": "<wallet-uuid>"}'
Enter fullscreen mode Exit fullscreen mode

Step 4: Apply risk policies before adding capital

Apply SPENDING_LIMIT, CONTRACT_WHITELIST, and ALLOWED_TOKENS policies using the policy API shown above. Don't skip this step — default-deny means your bot won't be able to transact at all until you configure which contracts and tokens it's allowed to touch.

Step 5: Verify with dry-run

Run a dry-run of your first transaction type before funding the wallet. Confirm the pipeline returns success, then fund and go live.

The OpenAPI spec is auto-generated at /doc and the interactive Scalar API reference is at /reference — useful for exploring the full 39-route API surface during integration.

Authentication Architecture

WAIaaS uses 3 auth methods with distinct privilege levels:

  • masterAuth (Argon2id): Creates wallets, manages sessions, sets policies. Your bot never touches this.
  • sessionAuth (JWT HS256): What your bot uses for all trading operations. Scoped to a specific wallet, with per-session TTL and maxRenewals.
  • ownerAuth (SIWS/SIWE): Used for approving high-value transactions that exceed your delay_max_usd threshold.

This separation matters operationally: if your bot's session token is compromised, an attacker can only do what the session policies allow. They can't create new wallets, change policies, or access other wallets.

What's Next

The WAIaaS monorepo is a 15-package system — if you want to go deeper than the REST API, the actions package contains all 15 DeFi protocol integrations as composable providers, and the mcp package exposes all 45 tools through the Model Context Protocol for AI-augmented trading strategies. The full codebase, Docker setup, and documentation are at github.com/waiaas/WAIaaS, and the official site with additional guides is at waiaas.ai.

Top comments (0)