Multi-chain payment protocol for AI agents. Enable pay-per-call monetization for MCP servers with automatic stablecoin micropayments across EVM, Solana, and Cardano.
| Chain | Token(s) | Pattern | Network |
|---|---|---|---|
| Base (EVM) | USDC | EIP-3009 (gasless) | Mainnet / Sepolia |
| Solana | USDC | PST (gasless via facilitator) | Mainnet / Devnet |
| Cardano | ADA, iUSD, USDM, DJED, USDCx | Signed tx via Lucid | Mainnet / Preprod |
The x402 payment system uses a secure 6-layer architecture with process isolation:
sequenceDiagram
autonumber
participant Client as 🤖 MCP Client<br/>(Claude/Cursor)
participant Vault as 🔐 Encrypted Vault<br/>(~/.x402/vault.enc)
participant Signer as 🔏 x402 Signer<br/>(Isolated Process)
participant Policy as 📋 Policy Engine<br/>(~/.x402/policy.json)
participant Proxy as 🔄 x402 Proxy<br/>(Local)
participant Server as ☁️ MCP Server<br/>(mcp.openmm.io)
participant KMS as 🔑 AWS KMS<br/>(ES256)
participant Facilitator as 💳 x402.org<br/>(Facilitator)
participant Chain as ⛓️ Base L2<br/>(USDC)
%% PHASE 1 — CLIENT SECURITY (Startup)
rect rgb(232, 245, 233)
Note over Vault, Signer: 🛡️ PHASE 1 — Client Security (Startup)
Signer->>Vault: Unlock vault with password
Note right of Vault: AES-256-GCM + PBKDF2<br/>decryption
Vault-->>Signer: Private key decrypted
Note right of Signer: Keys loaded in isolated<br/>memory — NEVER in<br/>agent process
Note over Client, Signer: 🔒 SECURITY LAYER 1: Encrypted Vault (AES-256-GCM)<br/>~/.x402/vault.enc → wallet private key (payments)<br/>🔒 SECURITY LAYER 2: Process Isolation (keys never in agent memory)
end
%% PHASE 2 — TOOL CALL + PAYMENT
rect rgb(227, 242, 253)
Note over Client, Facilitator: 💰 PHASE 2 — Tool Call + Payment
Client->>Proxy: tools/call (get_ticker)
Proxy->>Server: Forward request
Server-->>Proxy: HTTP 402 + payment requirements<br/>(payTo, amount, chainId)
Proxy->>Policy: Check spending limits
Note right of Policy: maxSpendPerTx: 10 USDC<br/>maxSpendPerDay: 100 USDC<br/>allowedChains: [base]<br/>allowedRecipients: [0x...]
alt Policy REJECTED
Policy-->>Proxy: ❌ Limit exceeded / recipient blocked
Proxy-->>Client: Error: Payment policy denied
else Policy APPROVED
Policy-->>Proxy: ✅ Approved (within limits)
end
Note over Policy: 🔒 SECURITY LAYER 3: Policy Engine<br/>(spending limits, allowlists, audit log)
Proxy->>Signer: Request signature (IPC)
Note right of Signer: Sign EIP-3009<br/>TransferWithAuthorization<br/>(gasless)
Signer-->>Proxy: Signature only (key stays in signer)
Proxy->>Server: Retry with X-PAYMENT header
end
%% PHASE 3 — ON-CHAIN SETTLEMENT
rect rgb(255, 243, 224)
Note over Server, Chain: ⛓️ PHASE 3 — On-Chain Settlement
Server->>Facilitator: Settlement request<br/>(payment payload)
Facilitator->>Chain: Execute USDC transfer<br/>(EIP-3009 authorization)
Chain-->>Facilitator: Transaction confirmed ✅
Facilitator-->>Server: Payment receipt + tx hash
Note over Chain: 🔒 SECURITY LAYER 4: On-chain settlement<br/>(verifiable, immutable, Base L2)
end
%% PHASE 4 — JWT ISSUANCE (post-settlement)
rect rgb(237, 231, 246)
Note over Server, KMS: 🔑 PHASE 4 — JWT Issuance (post-settlement receipt)
Note right of Server: Payment confirmed on-chain ✅<br/>tx hash available → embed in JWT
Server->>KMS: Sign JWT (ES256)
Note right of KMS: JWT Payload:<br/>{user_id, exchange,<br/>tool, payment_tx, exp}<br/>↑ payment_tx = on-chain proof
KMS-->>Server: Signed JWT
Note over KMS: 🔒 SECURITY LAYER 5: AWS KMS JWT signing<br/>(keys never leave HSM, ES256)
Server-->>Proxy: JWT (proof-of-payment receipt)
Proxy-->>Client: Forward JWT to client
end
%% PHASE 5 — AUTHENTICATED LOCAL EXECUTION
rect rgb(252, 228, 236)
Note over Client, Proxy: 🚀 PHASE 5 — Authenticated Local Execution
Client->>Proxy: Tool request + JWT
Proxy->>Proxy: Verify JWT signature (cached public key)
alt JWT INVALID
Proxy-->>Client: ❌ Error: Invalid or expired JWT
else JWT VALID
Proxy->>Proxy: Decrypt exchange API keys<br/>from ~/.openmm/vault.enc
Note right of Proxy: Exchange keys encrypted<br/>in ~/.openmm/vault.enc<br/>(AES-256-GCM)<br/>NEVER sent to cloud<br/>NEVER exposed to AI agent
Proxy->>Proxy: Execute on exchange API (MEXC/Binance/etc)
Proxy-->>Client: Return ticker data to Claude
end
Note over Proxy: 🔒 SECURITY LAYER 6: Local API Key Isolation<br/>(encrypted in ~/.openmm/vault.enc,<br/>NEVER sent to cloud,<br/>NEVER exposed to AI agent)
end
%% SECURITY SUMMARY
Note over Client, Chain: ══════════ SECURITY LAYERS SUMMARY ══════════<br/>Layer 1: Encrypted Vault (~/.x402/vault.enc — wallet key, AES-256-GCM)<br/>Layer 2: Process Isolation (keys never in agent memory)<br/>Layer 3: Policy Engine (spending limits, allowlists, audit)<br/>Layer 4: On-chain Settlement (verifiable, immutable)<br/>Layer 5: AWS KMS JWT Signing (HSM-backed, post-settlement)<br/>Layer 6: Local API Key Isolation (encrypted vault + never leaves machine)
| Layer | Component | Protection |
|---|---|---|
| 1. Encrypted Vault | ~/.x402/vault.enc |
Wallet key encrypted at rest (AES-256-GCM + PBKDF2) |
| 2. Process Isolation | x402-signer |
Keys never enter AI agent process memory |
| 3. Policy Engine | ~/.x402/policy.json |
Spending limits, allowlists, audit logging |
| 4. On-chain Settlement | Base L2 | Verifiable, immutable USDC transfers |
| 5. AWS KMS JWT | ES256 signing | Server keys never leave HSM |
| 6. Local API Keys | ~/.openmm/vault.enc |
Exchange credentials encrypted, never sent to cloud |
| Vault | Path | Contents |
|---|---|---|
| x402 Vault | ~/.x402/vault.enc |
Wallet private key (for payments) |
| OpenMM Vault | ~/.openmm/vault.enc |
Exchange API keys (for trading) |
Both use AES-256-GCM encryption with PBKDF2 key derivation.
Private keys should never be exposed to AI agents. The x402 security layer provides three protection mechanisms:
┌───────────────────────────┐ ┌───────────────────────────┐
│ AI AGENT PROCESS │ │ x402-signer PROCESS │
│ │ │ (isolated) │
│ ┌─────────────────────┐ │ │ ┌─────────────────────┐ │
│ │ AI Agent (Claude) │ │ │ │ Encrypted Vault │ │
│ │ │ │ │ │ ~/.x402/vault.enc │ │
│ │ NO KEY ACCESS │ │ │ │ (AES-256-GCM) │ │
│ └──────────┬──────────┘ │ │ └──────────┬──────────┘ │
│ │ │ │ │ │
│ ┌──────────▼──────────┐ │ │ ┌──────────▼──────────┐ │
│ │ x402 Client Proxy │ │ │ │ Policy Engine │ │
│ │ │◄┼─────┼─►│ - Max per tx │ │
│ │ Forwards sign reqs │ │ IPC │ │ - Max per day │ │
│ └─────────────────────┘ │ │ │ - Allowed addresses │ │
│ │ │ └──────────┬──────────┘ │
└──────────────────────────┘ │ │ │
│ ┌──────────▼──────────┐ │
│ │ Sign → Wipe Memory │ │
│ └─────────────────────┘ │
└───────────────────────────┘
| Layer | Component | Protection |
|---|---|---|
| Encrypted Vault | ~/.x402/vault.enc |
Keys encrypted at rest (AES-256-GCM, PBKDF2) |
| Process Isolation | x402-signer |
Keys never enter AI agent process |
| Policy Engine | ~/.x402/policy.json |
Spending limits, allowlists, audit log |
# Initialize new vault (generates key)
x402 vault init
# Import existing key
x402 vault import
x402 vault import --from-env X402_PRIVATE_KEY
# Show wallet address (no decryption needed)
x402 vault address
# Change password
x402 vault passwd// ~/.x402/policy.json
{
"rules": {
"maxSpendPerTx": { "amount": "10", "currency": "USDC" },
"maxSpendPerDay": { "amount": "100", "currency": "USDC" },
"allowedChains": ["base"],
"allowedRecipients": ["0xfacilitator..."]
},
"audit": {
"enabled": true,
"logFile": "~/.x402/audit.log"
}
}# View current policy
x402 policy show
# Set spending limits
x402 policy set maxSpendPerTx 10 USDC
x402 policy set maxSpendPerDay 100 USDC
# View spending history
x402 policy spending
x402 policy spending --week
# View audit log
x402 policy audit- Multi-Client Support — Works with Claude Code, Claude Desktop, Cursor, Windsurf, and any MCP client
- Client Proxy — Automatic payment signing via stdio transport
- Server Middleware — Payment gating with zero tool-level changes
- Payment-Aware Fetch — Drop-in replacement for
fetch()with payment handling - Multi-Chain — Base (EVM), Solana, and Cardano with unified API
- Gasless Payments — Users don't need native tokens for gas (EVM via EIP-3009, Solana via facilitator fee payer)
- Multi-Token (Cardano) — Accept ADA or stablecoins: iUSD, USDM, DJED, USDCx
- Testnet Ready — Base Sepolia, Solana Devnet, Cardano Preprod
npm install @qbtlabs/x402x402 works with any MCP client that supports stdio transport. Configure your preferred client below:
Add to ~/.claude.json (or ~/.claude/mcp_servers.json):
{
"mcpServers": {
"openmm": {
"command": "npx",
"args": ["@qbtlabs/x402", "client-proxy", "--target", "https://mcp.openmm.io/mcp"],
"env": {
"X402_PRIVATE_KEY": "0xYOUR_PRIVATE_KEY"
}
}
}
}Add to your Claude Desktop config:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Linux: ~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"openmm": {
"command": "npx",
"args": ["@qbtlabs/x402", "client-proxy", "--target", "https://mcp.openmm.io/mcp"],
"env": {
"X402_PRIVATE_KEY": "0xYOUR_PRIVATE_KEY"
}
}
}
}Add to .cursor/mcp.json in your workspace (or ~/.cursor/mcp.json for global):
{
"mcpServers": {
"openmm": {
"command": "npx",
"args": ["@qbtlabs/x402", "client-proxy", "--target", "https://mcp.openmm.io/mcp"],
"env": {
"X402_PRIVATE_KEY": "0xYOUR_PRIVATE_KEY"
}
}
}
}Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"openmm": {
"command": "npx",
"args": ["@qbtlabs/x402", "client-proxy", "--target", "https://mcp.openmm.io/mcp"],
"env": {
"X402_PRIVATE_KEY": "0xYOUR_PRIVATE_KEY"
}
}
}
}The x402 proxy uses stdio transport, so it works with any MCP-compatible client. The configuration pattern is the same — just point your client to npx @qbtlabs/x402 client-proxy.
That's it! Your AI agent will now automatically pay for tool calls.
import { createPaymentFetch } from '@qbtlabs/x402';
// Create a payment-aware fetch function
const paymentFetch = createPaymentFetch({
privateKey: process.env.X402_PRIVATE_KEY,
chainId: 84532, // Base Sepolia
});
// Use like regular fetch — payments happen automatically
const response = await paymentFetch('https://mcp.openmm.io/mcp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'tools/call',
params: { name: 'get_ticker', arguments: { exchange: 'mexc', symbol: 'BTC/USDT' } },
id: 1,
}),
});import { withX402Server, setToolPrices, configure } from '@qbtlabs/x402';
// Configure payment recipients (multi-chain)
configure({
evm: { address: process.env.X402_EVM_ADDRESS },
solana: { address: process.env.X402_SOLANA_ADDRESS },
cardano: { address: process.env.X402_CARDANO_ADDRESS },
testnet: process.env.X402_TESTNET === 'true',
});
// Set tool pricing
setToolPrices({
list_exchanges: 'free',
get_ticker: 'read', // $0.001
get_orderbook: 'read', // $0.001
place_order: 'write', // $0.01
});
// Your MCP request handler
async function handleMcpRequest(request: Request): Promise<Response> {
const body = await request.json();
// ... handle MCP JSON-RPC
return Response.json({ jsonrpc: '2.0', id: body.id, result: { /* ... */ } });
}
// Wrap with x402 payment gating
export default {
fetch: withX402Server({
handler: handleMcpRequest,
}),
};The middleware automatically:
- Passes free tools and non-tool requests through
- Returns 402 with payment requirements for all configured chains
- Verifies payments via the appropriate facilitator (x402.org for EVM, PayAI for Solana)
- Settles payments after successful execution
import { configure, setToolPrices, getActiveChains } from '@qbtlabs/x402';
// Configure payment settings (multi-chain)
configure({
evm: { address: '0x...' }, // Base USDC receiving address
solana: { address: 'So...' }, // Solana USDC receiving address
cardano: { address: 'addr1q...' }, // Cardano receiving address
testnet: true, // Use testnets (Sepolia, Devnet, Preprod)
facilitatorUrl: 'https://x402.org', // EVM facilitator
solanaFacilitatorUrl: 'https://facilitator.payai.network', // Solana facilitator
});
// Check which chains are configured
const chains = getActiveChains();
// ['eip155:84532', 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', 'cardano:preprod']
// Set pricing for tools
setToolPrices({
'tool_name': 'free', // $0
'tool_name': 'read', // $0.001
'tool_name': 'analysis', // $0.005
'tool_name': 'write', // $0.01
'tool_name': 0.05, // Custom price in USD
});Creates a fetch function that automatically handles 402 responses.
import { createPaymentFetch } from '@qbtlabs/x402';
const paymentFetch = createPaymentFetch({
privateKey: '0x...', // Wallet private key
chainId: 84532, // Chain ID (84532 = Base Sepolia, 8453 = Base)
});
const response = await paymentFetch(url, options);Middleware that wraps a request handler with payment gating.
import { withX402Server } from '@qbtlabs/x402';
const handler = withX402Server({
handler: async (request: Request) => Response,
extractToolName: (body: unknown) => string | null, // Optional custom extractor
});Creates a stdio-to-HTTP proxy with payment handling.
import { createClientProxy } from '@qbtlabs/x402';
const proxy = createClientProxy({
targetUrl: 'https://mcp.openmm.io/mcp',
privateKey: '0x...',
chainId: 84532,
});
await proxy.start();Creates a full MCP passthrough proxy.
import { createPassthroughProxy } from '@qbtlabs/x402';
await createPassthroughProxy({
targetUrl: 'https://mcp.openmm.io/mcp',
privateKey: '0x...',
mode: 'stdio',
});import { signPayment, buildPaymentPayload, parsePaymentRequired } from '@qbtlabs/x402';
// Parse 402 response
const requirements = parsePaymentRequired(response);
// Sign a payment
const signature = await signPayment({
privateKey: '0x...',
to: requirements.payTo,
value: requirements.maxAmountRequired,
chainId: 84532,
});
// Build the X-PAYMENT header value
const paymentHeader = buildPaymentPayload(signature, requirements);import {
buildFacilitatorRequirements,
verifyWithFacilitator,
settleWithFacilitator,
} from '@qbtlabs/x402';
// Build 402 response requirements
const requirements = buildFacilitatorRequirements('get_ticker');
// Verify a payment
const result = await verifyWithFacilitator(paymentPayload, 'get_ticker');
// Settle after execution
await settleWithFacilitator(paymentPayload, 'get_ticker');The Solana adapter uses a Partially Signed Transaction (PST) pattern. The user signs a transfer, and the facilitator adds its signature as fee payer — making payments gasless for the user.
import { solana } from '@qbtlabs/x402';
// Client: Sign a USDC payment (gasless — facilitator pays SOL fees)
const payload = await solana.signSolanaPayment({
privateKey: keypair.secretKey, // 64-byte Solana keypair
to: 'MerchantPubkey...', // USDC recipient
amount: 0.01, // USD amount
network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', // mainnet
feePayer: '2wKupLR9q6wXYppw...', // facilitator fee payer (from 402 response)
});
// Server: Verify payment structure (no network calls)
const result = await solana.verifyPayment(
payload,
0.01, // expected USD amount
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
);
// { valid: true, payer: 'ClientPubkey...' }Instruction layout (strict order per x402 spec):
SetComputeUnitLimit— compute budgetSetComputeUnitPrice— priority fee (≤5M microlamports)TransferChecked— USDC transferMemo— 16-byte nonce for replay protection
The Cardano adapter uses Lucid Evolution for client-side transaction building and CML for server-side verification. Supports ADA and multiple stablecoins.
import { cardano } from '@qbtlabs/x402';
// Client: Sign a payment (iUSD example)
const payload = await cardano.signCardanoPayment({
seed: 'word1 word2 ... word24', // BIP-39 mnemonic
toAddress: 'addr1q...', // merchant address
amount: 10_000n, // 0.01 iUSD (6 decimals)
token: 'iUSD', // ADA | iUSD | USDM | DJED | USDCx
blockfrostProjectId: 'mainnetXXX',
network: 'Mainnet', // or 'Preprod'
});
// { transaction: 'hex-cbor-signed-tx' }
// Server: Verify payment structure
const result = await cardano.verifyCardanoPayment(
payload,
'addr1q...', // expected recipient
10_000n, // expected amount
'iUSD', // expected token
);
// { valid: true }
// Settlement: Submit via Blockfrost
const { txHash } = await cardano.submitCardanoTx(
payload.transaction,
'https://cardano-mainnet.blockfrost.io/api/v0',
'mainnetXXX',
);Helper utilities:
// Convert USD to token units
cardano.usdToCardanoUnits(0.01, 'iUSD'); // → 10_000n
cardano.usdToCardanoUnits(2.00, 'ADA'); // → 2_000_000n (lovelace)
// Get wallet balances (useful for multi-token acceptance)
const balances = await cardano.getCardanoWalletBalances({
seed: 'word1 ...',
blockfrostProjectId: 'mainnetXXX',
});
// { lovelace: 125000000n, iUSD: 50000n, USDM: 0n, DJED: 0n, USDCx: 0n }
// Detect network from address
cardano.detectNetwork('addr1q...'); // → 'cardano'
cardano.detectNetwork('addr_test1...'); // → 'cardano-preprod'src/
├── index.ts # Main exports
├── config.ts # Configuration (addresses, testnet, chain detection)
├── pricing.ts # Tool pricing tiers
├── verify.ts # Payment verification
├── client.ts # Client-side signing (EVM)
├── facilitator.ts # x402.org integration
├── chains/
│ ├── index.ts # Chain module exports
│ ├── evm.ts # EVM/Base: EIP-3009 gasless transfers
│ ├── solana.ts # Solana: PST pattern, USDC, gasless via facilitator
│ └── cardano.ts # Cardano: Lucid/CML, ADA + stablecoins
├── types/
│ └── cardano.types.ts # Cardano token registry & types
├── transport/
│ ├── payment-fetch.ts # Payment-aware fetch
│ └── server.ts # Server middleware
├── proxy/
│ ├── client-proxy.ts # Client proxy factory
│ └── passthrough.ts # MCP passthrough proxy
├── middleware/
│ └── mcp.ts # Legacy tool-level middleware
└── scripts/
└── client-proxy.ts # CLI entry point
| Variable | Description | Required |
|---|---|---|
X402_PRIVATE_KEY |
EVM wallet private key for signing payments | For EVM |
X402_CHAIN_ID |
EVM Chain ID (84532=Sepolia, 8453=Mainnet) | No (default: 84532) |
BLOCKFROST_PROJECT_ID |
Blockfrost API key for Cardano | For Cardano |
CARDANO_SEED |
BIP-39 mnemonic (24 words) for Cardano wallet | For Cardano |
| Variable | Description | Required |
|---|---|---|
X402_EVM_ADDRESS |
EVM USDC receiving wallet address | For EVM |
X402_SOLANA_ADDRESS |
Solana USDC receiving wallet address | For Solana |
X402_CARDANO_ADDRESS |
Cardano receiving address (bech32) | For Cardano |
X402_TESTNET |
Use testnets (Sepolia, Devnet, Preprod) | No (default: false) |
X402_FACILITATOR_URL |
Custom EVM facilitator URL | No |
X402_SOLANA_FACILITATOR_URL |
Custom Solana facilitator URL | No (default: PayAI) |
| Tier | Price | Use Case |
|---|---|---|
free |
$0.00 | Discovery, listing |
read |
$0.001 | Market data, queries |
analysis |
$0.005 | Computed insights |
write |
$0.01 | Transactions, mutations |
| Network | Chain ID | USDC Contract |
|---|---|---|
| Base Sepolia | 84532 | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
| Base Mainnet | 8453 | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| Network | CAIP-2 Identifier | USDC Mint |
|---|---|---|
| Mainnet | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp |
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| Devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 |
4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU |
| Network | Identifier | Supported Tokens |
|---|---|---|
| Mainnet | cardano:mainnet |
ADA, iUSD, USDM, DJED, USDCx |
| Preprod | cardano:preprod |
ADA, iUSD, USDM, DJED, USDCx |
Cardano Stablecoins:
| Token | Description | Policy ID |
|---|---|---|
| iUSD | Indigo Protocol synthetic USD | f66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b69880 |
| USDM | Mehen fiat-backed stablecoin | c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad |
| DJED | COTI/IOG overcollateralised USD | 8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd61 |
| USDCx | Circle xReserve USDC-backed | 1f3aec8bfe7ea4fe14c5f121e2a92e301afe414147860d557cac7e34 |
- openmm-mcp — MCP server using x402
- x402 Protocol — Payment facilitator
- MCP SDK — Model Context Protocol
Runs all mocked tests. No network calls, no wallet needed.
npm testTo run only Cardano adapter tests:
npm test -- --testPathPattern=cardanoRequires a Blockfrost mainnet project ID, a funded wallet seed phrase, and a recipient address.
BLOCKFROST_PROJECT_ID=mainnetXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
CARDANO_TEST_SEED="word1 word2 word3 ... word24" \
CARDANO_MERCHANT_ADDRESS="addr1q..." \
npm test -- --testPathPattern=cardanoWhat runs with credentials:
| Test file | What it covers |
|---|---|
cardano.integration.test.ts |
ADA + iUSD live transfers, structural verify, Blockfrost submission |
cardano.e2e.test.ts |
Full HTTP 402 → sign → verify → 200 flow with iUSD |
cardano.insufficient-balance.test.ts |
USDM/USDCx throw clear errors when wallet has zero balance |
Get a Blockfrost API key: https://blockfrost.io (free tier available, select Mainnet)
Get test ADA (Preprod): https://docs.cardano.org/cardano-testnets/tools/faucet
MIT © QBT Labs