Base Chain · ERC-20 · TypeScript

Build with $AMPS

The developer toolkit for integrating $AMPS token payments into your apps. Especially built for AI agents that charge tokens per API call.

$ npm install @amplifyworld/sdk
18
Decimals
Base
Chain
0
Dependencies*

*Beyond viem as peer dependency

Installation

Install the SDK and its peer dependency:

Terminal
# npm
npm install @amplifyworld/sdk viem

# pnpm
pnpm add @amplifyworld/sdk viem

# yarn
yarn add @amplifyworld/sdk viem
💡
Why viem?

viem is the modern TypeScript interface for Ethereum with first-class type safety, tree-shaking, and tiny bundle size. It's used by Coinbase, Uniswap, and most major DeFi projects.

Quick Start

Get up and running in under 10 lines:

TypeScript
import { createAmpsClient } from '@amplifyworld/sdk'

// Create a client (read-only, uses public Base RPC)
const amps = createAmpsClient()

// Check any wallet balance
const balance = await amps.getBalance('0x...')
console.log(`Balance: ${balance.formatted} AMPS`)

// Get on-chain token info
const info = await amps.getTokenInfo()
console.log(`Total Supply: ${info.totalSupply} ${info.symbol}`)

Client

createAmpsClient() is your single entry point. It supports three modes:

👁️

Read-Only

Check balances, watch events. No wallet needed.

const amps = createAmpsClient()
🔑

Server-Side

Sign transactions with a private key (for backends/agents).

const amps = createAmpsClient({
  privateKey: process.env.KEY
})
🌐

Browser Wallet

Use MetaMask, Coinbase Wallet, or any EIP-1193 provider.

const amps = createAmpsClient({
  walletClient: yourWalletClient
})
Full Configuration
const amps = createAmpsClient({
  // Custom RPC (recommended for production)
  rpcUrl: 'https://base-mainnet.g.alchemy.com/v2/YOUR_KEY',
  // Private key for server-side signing
  privateKey: '0x...',
})

Balances

TypeScript
const balance = await amps.getBalance('0x...')
console.log(balance.formatted) // "1,500.25"
console.log(balance.value)     // "1500.25"
console.log(balance.raw)       // 1500250000000000000000n
console.log(balance.symbol)    // "AMPS"

// Raw BigInt for computations
const raw = await amps.getRawBalance('0x...')
PropertyTypeDescription
formattedstringDisplay-ready with commas (e.g. "1,500.25")
valuestringRaw decimal string (e.g. "1500.25")
rawbigintWei-level precision for math
symbolstringAlways "AMPS"

Transfers

Send $AMPS to any address. Amounts can be human-readable strings or BigInt.

TypeScript
// Transfer 100 AMPS
const result = await amps.transfer('0xRecipient...', '100')
console.log(`Tx: ${result.hash}`)
console.log(`Status: ${result.receipt.status}`) // "success"

// Transfer with BigInt precision
import { parseAmps } from '@amplifyworld/sdk'
await amps.transfer('0x...', parseAmps('99.99'))
⚠️
Pre-flight balance check

The SDK automatically checks your balance before sending. If insufficient, it throws InsufficientBalanceError without wasting gas.

Approvals

Approve third parties (like AI services) to spend $AMPS on your behalf.

TypeScript
// Approve a service to spend up to 1000 AMPS
await amps.approve('0xServiceWallet...', '1000')

// Check current allowance
const allowance = await amps.getAllowance('0xOwner...', '0xSpender...')
console.log(`Approved: ${allowance.formatted} AMPS`)

// Transfer from approved account (for service providers)
await amps.transferFrom('0xUser...', '0xService...', '0.5')

Events

Subscribe to real-time $AMPS transfer and approval events.

TypeScript
// Watch all incoming transfers to your address
const unwatch = amps.watchTransfers((event) => {
  console.log(`Received ${event.amount} AMPS from ${event.from}`)
  console.log(`Tx: ${event.txHash}`)
}, { to: myAddress })

// Watch approvals for your service
const unwatchApprovals = amps.watchApprovals((event) => {
  console.log(`${event.owner} approved ${event.amount} AMPS`)
}, { spender: myServiceAddress })

// Stop watching
unwatch()
unwatchApprovals()
⚡ AI Payment Gateway

Payment Gateway

The killer feature — charge users in $AMPS per AI API call. Define your pricing table, and the gateway handles allowance checks, on-chain transfers, and receipts.

1
User approves $AMPS spending
2
Agent calls gateway.charge()
3
transferFrom pulls $AMPS
4
Receipt returned
Server — Create Gateway
import { createAmpsGateway } from '@amplifyworld/sdk'

const gateway = createAmpsGateway({
  privateKey: process.env.SERVICE_WALLET_KEY,
  pricing: {
    'chat.completion': '0.5',     // 0.5 AMPS per chat
    'image.generate':  '2.0',     // 2 AMPS per image
    'code.analyze':    '1.0',     // 1 AMPS per analysis
  },
})

// Charge a user
const receipt = await gateway.charge({
  payer: '0xUserAddress...',
  service: 'chat.completion',
})

console.log(receipt.txHash)   // '0x...'
console.log(receipt.amount)   // '0.5'
console.log(receipt.service)  // 'chat.completion'

Sessions

Track approval-based spending within time windows — perfect for AI agents making multiple calls.

TypeScript
const session = await gateway.sessions.create({
  userAddress: '0xUser...',
  serviceAddress: gateway.serviceAddress,
  maxSpend: '100',      // Cap at 100 AMPS
  ttlSeconds: 3600,     // 1 hour
})

// Before each charge, check the session
if (gateway.sessions.canSpend(session.id, '0.5')) {
  await gateway.charge({ ... })
  gateway.sessions.recordSpend(session.id, '0.5')
}

console.log(session.remaining) // '99.5'

Receipts

Verify that a payment actually happened on-chain. Useful for "proof of payment" flows.

TypeScript
import { verifyReceipt, createAmpsClient } from '@amplifyworld/sdk'

const amps = createAmpsClient()

const receipt = await verifyReceipt(amps.publicClient, '0xTxHash...', {
  expectedRecipient: '0xYourWallet...',
  expectedMinAmount: '1.0',
})

console.log(receipt.payer)     // '0x...'
console.log(receipt.amount)    // '1.5'
console.log(receipt.timestamp) // '2026-04-21T16:30:00.000Z'

Dynamic Pricing

Use functions instead of fixed prices to implement usage-based billing.

TypeScript
const gateway = createAmpsGateway({
  privateKey: '0x...',
  pricing: {
    // Fixed price
    'chat.message': '0.5',

    // Price based on token count
    'chat.long': (meta) => {
      const tokens = (meta?.tokens as number) ?? 500
      return String(tokens * 0.001) // 0.001 AMPS per token
    },

    // Price based on image resolution
    'image.generate': async (meta) => {
      const size = (meta?.size as string) ?? '512x512'
      const prices = { '256x256': '1', '512x512': '2', '1024x1024': '5' }
      return prices[size] ?? '2'
    },
  },
})

// Charge with metadata
await gateway.charge({
  payer: '0x...',
  service: 'chat.long',
  metadata: { tokens: 2500 }, // Will cost 2.5 AMPS
})
🛡️ Middleware

Express Paywall

Drop-in middleware that gates Express routes behind $AMPS payments.

TypeScript
import express from 'express'
import { ampsPaywall } from '@amplifyworld/sdk/middleware'

const app = express()

app.post('/api/generate', ampsPaywall({
  price: '1.0',
  recipient: '0xYourWallet...',
}), async (req, res) => {
  // Only runs after on-chain payment verification
  const result = await generateImage(req.body.prompt)
  res.json({ result, receipt: req.ampsReceipt })
})

x402 Pattern

The middleware implements the x402 protocol pattern — when no payment is provided, it returns 402 Payment Required with machine-readable payment instructions:

402 Response
{
  "error": "Payment Required",
  "message": "This endpoint requires 1.0 AMPS payment",
  "payment": {
    "token": "AMPS",
    "chain": "base",
    "chainId": 8453,
    "amount": "1.0",
    "recipient": "0xYourWallet...",
    "contract": "0x1A074F116786248FC79B130E6379293C7EF604a4"
  }
}

AI agents can automatically parse this response, execute the payment, and retry with the tx hash:

Client-Side Flow
// 1. First request → gets 402
const res = await fetch('/api/generate', { method: 'POST' })

if (res.status === 402) {
  const { payment } = await res.json()

  // 2. Pay with AMPS SDK
  const tx = await amps.transfer(payment.recipient, payment.amount)

  // 3. Retry with payment proof
  const paid = await fetch('/api/generate', {
    method: 'POST',
    headers: { 'X-AMPS-Tx-Hash': tx.hash },
  })
}
📚 Reference

Error Handling

All errors extend AmpsError with structured error codes:

Error ClassCodeThrown When
WalletRequiredErrorWALLET_REQUIREDWrite operation without wallet
InsufficientBalanceErrorINSUFFICIENT_BALANCETransfer exceeds balance
InsufficientAllowanceErrorINSUFFICIENT_ALLOWANCEtransferFrom exceeds approval
ServiceNotFoundErrorSERVICE_NOT_FOUNDUnknown service in gateway
SessionExpiredErrorSESSION_EXPIREDSession timed out or exhausted
PaymentVerificationErrorPAYMENT_VERIFICATION_FAILEDTx not found or mismatch
Error Handling
import { InsufficientBalanceError } from '@amplifyworld/sdk'

try {
  await amps.transfer('0x...', '1000000')
} catch (e) {
  if (e instanceof InsufficientBalanceError) {
    console.log(`Need ${e.required}, have ${e.available}`)
  }
}

Utilities

Formatting Helpers
import { parseAmps, formatAmps, formatAmpsDisplay } from '@amplifyworld/sdk'

parseAmps('100')       // 100000000000000000000n
parseAmps('0.5')       // 500000000000000000n

formatAmps(100000000000000000000n)   // "100"
formatAmpsDisplay(1500250000000000000000n) // "1,500.25"

Constants

Exported Constants
import {
  AMPS_CONTRACT_ADDRESS,  // '0x1A074F116786248FC79B130E6379293C7EF604a4'
  AMPS_CHAIN,             // Base chain config (viem Chain object)
  AMPS_TOKEN,             // { name, symbol, decimals, chainId, explorer }
  DEFAULT_RPC_URL,        // 'https://mainnet.base.org'
  ERC20_ABI,              // Human-readable ERC-20 ABI
} from '@amplifyworld/sdk'