Examples
Copy-paste code snippets for the most common blockchain development tasks. All examples use TypeScript with fetch -- no SDK required.
Get ETH Balance
Fetch the native ETH balance for any address on any EVM chain using the standard eth_getBalance RPC method.
const API_KEY = process.env.BOOTNODE_API_KEY!;
async function getEthBalance(
chain: string,
address: string
): Promise<{ wei: string; eth: string }> {
const res = await fetch(
`https://api.bootnode.dev/v1/rpc/${chain}/mainnet`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_getBalance",
params: [address, "latest"],
}),
}
);
const data = await res.json();
const wei = BigInt(data.result);
const eth = (Number(wei) / 1e18).toFixed(6);
return { wei: wei.toString(), eth };
}
// Usage
const balance = await getEthBalance(
"ethereum",
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
);
console.log(`Balance: ${balance.eth} ETH (${balance.wei} wei)`);
// => "Balance: 1234.567890 ETH (1234567890000000000000 wei)"Get ERC-20 Token Balances
Fetch all ERC-20 token balances for a wallet in a single call using the Token API. Returns token symbols, formatted balances, and USD values.
async function getTokenBalances(chain: string, address: string) {
const res = await fetch(
`https://api.bootnode.dev/v1/tokens/${chain}/balances/${address}`,
{
headers: { "X-API-Key": process.env.BOOTNODE_API_KEY! },
}
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
// Usage
const data = await getTokenBalances(
"ethereum",
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
);
for (const token of data.tokens) {
console.log(
`${token.symbol}: ${token.formatted_balance} ($${token.usd_value})`
);
}
// => "USDC: 15230.50 ($15230.50)"
// => "USDT: 8500.00 ($8500.00)"
// => "LINK: 250.75 ($3761.25)"Monitor Wallet Activity with Webhooks
Set up a webhook to get notified whenever a specific wallet sends or receives any transaction.
// 1. Create the webhook subscription
async function monitorWallet(address: string) {
const res = await fetch("https://api.bootnode.dev/v1/webhooks", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.BOOTNODE_API_KEY!,
},
body: JSON.stringify({
url: "https://myapp.com/api/webhooks/wallet-activity",
chain: "ethereum",
event_type: "address_activity",
config: {
addresses: [address],
},
}),
});
const webhook = await res.json();
console.log("Webhook created:", webhook.id);
console.log("Save this secret:", webhook.signing_secret);
return webhook;
}
// 2. Handle incoming events (Next.js API route)
// app/api/webhooks/wallet-activity/route.ts
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";
export async function POST(req: NextRequest) {
const body = await req.text();
const signature = req.headers.get("x-bootnode-signature")!;
const timestamp = req.headers.get("x-bootnode-timestamp")!;
// Verify signature
const payload = `${timestamp}.${body}`;
const expected = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET!)
.update(payload)
.digest("hex");
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}
const event = JSON.parse(body);
console.log(`Activity: ${event.data.from} -> ${event.data.to}`);
console.log(`Value: ${event.data.value} wei (${event.data.asset})`);
// Send notification, update database, etc.
return NextResponse.json({ received: true });
}
// Usage
await monitorWallet("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");Create a Smart Wallet
Create an ERC-4337 smart wallet for a user. The wallet is counterfactually deployed and ready to receive funds immediately.
async function createWallet(ownerAddress: string, chain: string) {
const res = await fetch("https://api.bootnode.dev/v1/wallets/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.BOOTNODE_API_KEY!,
},
body: JSON.stringify({
owner: ownerAddress,
chain,
}),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error.message);
}
return res.json();
}
// Usage
const wallet = await createWallet(
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"base"
);
console.log("Smart wallet address:", wallet.address);
console.log("Status:", wallet.status); // "counterfactual"
console.log("Chain:", wallet.chain); // "base"
// The address is deterministic -- same inputs always produce the same address.
// Users can send funds to this address before the wallet is deployed on-chain.Send a Gasless Transaction
Send a sponsored (gasless) ERC-20 transfer via the bundler. The user pays zero gas -- your gas policy covers the cost.
import { encodeFunctionData, parseAbi } from "viem";
const BASE_URL = "https://api.bootnode.dev/v1";
const API_KEY = process.env.BOOTNODE_API_KEY!;
const ENTRY_POINT = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
async function sendGaslessTransfer(params: {
sender: string;
tokenContract: string;
to: string;
amount: bigint;
chain: string;
policyId: string;
}) {
// 1. Encode ERC-20 transfer
const callData = encodeFunctionData({
abi: parseAbi([
"function transfer(address to, uint256 amount) returns (bool)",
]),
functionName: "transfer",
args: [params.to as `0x${string}`, params.amount],
});
// 2. Build UserOperation
const userOp = {
sender: params.sender,
nonce: "0x0",
callData,
callGasLimit: "0x30000",
verificationGasLimit: "0x50000",
preVerificationGas: "0xc350",
maxFeePerGas: "0x59682f00",
maxPriorityFeePerGas: "0x3b9aca00",
};
// 3. Get paymaster sponsorship
const sponsorRes = await fetch(`${BASE_URL}/gas/sponsor`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
body: JSON.stringify({
chain: params.chain,
policy_id: params.policyId,
user_operation: userOp,
}),
});
const sponsor = await sponsorRes.json();
// 4. Submit to bundler
const bundlerRes = await fetch(
`${BASE_URL}/bundler/${params.chain}/mainnet`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_sendUserOperation",
params: [
{
...userOp,
paymasterAndData: sponsor.paymasterData,
signature: "0x", // Sign with owner key in production
},
ENTRY_POINT,
],
}),
}
);
const result = await bundlerRes.json();
return result.result; // UserOp hash
}
// Usage
const opHash = await sendGaslessTransfer({
sender: "0x7A0b3e4C5F1234567890abcdef1234567890ABCD",
tokenContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
to: "0x9876543210abcdef9876543210abcdef98765432",
amount: 10000000n, // 10 USDC (6 decimals)
chain: "base",
policyId: "gp_x1y2z3w4v5u6",
});
console.log("UserOp hash:", opHash);Subscribe to New Blocks via WebSocket
Open a WebSocket connection and subscribe to new block headers in real-time. Each message includes block number, hash, timestamp, gas used, and base fee.
const API_KEY = process.env.BOOTNODE_API_KEY!;
const ws = new WebSocket(
`wss://api.bootnode.dev/v1/ws/ethereum/mainnet?apiKey=${API_KEY}`
);
ws.onopen = () => {
console.log("Connected to Bootnode WebSocket");
// Subscribe to new block headers
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_subscribe",
params: ["newHeads"],
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
// Subscription confirmation
if (msg.id === 1) {
console.log("Subscribed! ID:", msg.result);
return;
}
// New block
if (msg.method === "eth_subscription") {
const block = msg.params.result;
const blockNum = parseInt(block.number, 16);
const gasUsed = parseInt(block.gasUsed, 16);
const gasLimit = parseInt(block.gasLimit, 16);
const utilization = ((gasUsed / gasLimit) * 100).toFixed(1);
const baseFee = (parseInt(block.baseFeePerGas, 16) / 1e9).toFixed(2);
console.log(
`Block ${blockNum} | ` +
`Gas: ${utilization}% | ` +
`Base fee: ${baseFee} gwei | ` +
`Hash: ${block.hash.slice(0, 10)}...`
);
}
};
ws.onclose = () => console.log("Disconnected");
ws.onerror = (err) => console.error("Error:", err);
// Example output:
// Block 20574335 | Gas: 50.0% | Base fee: 12.50 gwei | Hash: 0xabc123...
// Block 20574336 | Gas: 67.3% | Base fee: 13.12 gwei | Hash: 0xdef456...
// Block 20574337 | Gas: 45.8% | Base fee: 12.85 gwei | Hash: 0x789abc...Get NFT Collection Data
Fetch collection-level metadata and a specific NFT token in a collection.
const API_KEY = process.env.BOOTNODE_API_KEY!;
const BASE = "https://api.bootnode.dev/v1";
// Get collection info
async function getCollection(chain: string, contract: string) {
const res = await fetch(
`${BASE}/nfts/${chain}/collection/${contract}`,
{ headers: { "X-API-Key": API_KEY } }
);
return res.json();
}
// Get specific NFT
async function getNFT(chain: string, contract: string, tokenId: string) {
const res = await fetch(
`${BASE}/nfts/${chain}/metadata/${contract}/${tokenId}`,
{ headers: { "X-API-Key": API_KEY } }
);
return res.json();
}
// Usage
const collection = await getCollection(
"ethereum",
"0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"
);
console.log(`${collection.name}: ${collection.total_supply} NFTs`);
console.log(`Floor: ${collection.floor_price_eth} ETH`);
// => "Bored Ape Yacht Club: 10000 NFTs"
// => "Floor: 12.50 ETH"
const nft = await getNFT(
"ethereum",
"0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
"1234"
);
console.log(`${nft.name} - Owner: ${nft.owner}`);
for (const trait of nft.traits) {
console.log(` ${trait.trait_type}: ${trait.value}`);
}
// => "Bored Ape #1234 - Owner: 0xd8dA...6045"
// => " Background: Aquamarine"
// => " Fur: Dark Brown"Get Real-Time Gas Prices
Fetch current gas price estimates for any chain. Returns slow, standard, and fast options with estimated confirmation times.
async function getGasPrices(chain: string) {
const res = await fetch(
`https://api.bootnode.dev/v1/gas/${chain}/prices`,
{ headers: { "X-API-Key": process.env.BOOTNODE_API_KEY! } }
);
return res.json();
}
// Usage
const gas = await getGasPrices("ethereum");
console.log(`Base fee: ${gas.base_fee_gwei} gwei`);
console.log(`Block: ${gas.block_number}`);
console.log("");
console.log("Speed | Max Fee | Priority | ETA");
console.log("----------|------------|----------|--------");
console.log(
`Slow | ${gas.estimates.slow.max_fee_gwei.padStart(8)} | ` +
`${gas.estimates.slow.max_priority_fee_gwei.padStart(8)} | ` +
`${gas.estimates.slow.estimated_seconds}s`
);
console.log(
`Standard | ${gas.estimates.standard.max_fee_gwei.padStart(8)} | ` +
`${gas.estimates.standard.max_priority_fee_gwei.padStart(8)} | ` +
`${gas.estimates.standard.estimated_seconds}s`
);
console.log(
`Fast | ${gas.estimates.fast.max_fee_gwei.padStart(8)} | ` +
`${gas.estimates.fast.max_priority_fee_gwei.padStart(8)} | ` +
`${gas.estimates.fast.estimated_seconds}s`
);
// Output:
// Base fee: 12.50 gwei
// Block: 20574335
//
// Speed | Max Fee | Priority | ETA
// ----------|------------|----------|--------
// Slow | 14.00 | 0.50 | 60s
// Standard | 16.00 | 1.50 | 15s
// Fast | 20.00 | 3.00 | 5s