A practical developer guide to setting up Solana wallet monitoring from scratch using the MadeOnSol Wallet Tracker API. Covers adding wallets, polling trades, pagination, and building real-time dashboards with the TypeScript SDK.
MadeOnSol·· 8 min read
Building a product on Solana data?
Skip the Geyser pipeline — embed KOL flow, deployer reputation, and the all-DEX firehose over REST, WebSocket, or webhooks. The Business tier (€400/mo) is the self-serve embed license at 500k calls/day — Enterprise adds white-label & redistribution.
MadeOnSol isn't an RPC or another generic token API — it's Solana memecoin intelligence that's painful to build in-house, pulled from dual-region gRPC shred streams: sub-second from the on-chain event to your app.
Signals you'd otherwise build
KOL & smart-money flow from 1,000+ labeled wallets, deployer reputation, coordination clusters, linked-wallet entity resolution, and an all-DEX firehose.
The Business tier (€400/mo, self-serve) licenses you to display MadeOnSol data inside your own product — 500k calls/day, 10 WS + 5 firehose connections. Enterprise above adds white-label & redistribution rights and custom endpoints.
Evaluate first, commit later
Test everything on a free ULTRA key — no commitment. If it fits, we scope volume or white-label pricing.
Combine price dip webhooks, KOL coordination WebSocket streams, and wallet tracker events into a unified Solana alert system. TypeScript code for multi-signal trading decisions — sell when smart money exits, buy when they accumulate.
Building anything on top of Solana on-chain data — a trading dashboard, a copy-trading bot, a portfolio tracker — means you need reliable wallet monitoring at the foundation. Polling an RPC node for every wallet in your watchlist is slow, expensive, and fragile. A dedicated wallet tracking API handles the indexing for you and gives you clean, filterable data over a simple HTTP or WebSocket interface.
This guide walks through setting up wallet monitoring from scratch using the Solana API from MadeOnSol. By the end you will have a working TypeScript implementation that adds wallets to a watchlist, polls swap history with pagination, and surfaces per-wallet statistics — everything you need to build a bot or dashboard on top.
Before writing any code it helps to understand what the API actually indexes. When you add a wallet to your watchlist, the service starts tracking every swap and SPL token transfer that wallet makes. Events are retained for 120 days and are queryable immediately after they are ingested. If you need to follow a program rather than a wallet, our companion guide on how to track Solana program activity — instructions, events, and CPI chains covers that lower-level approach.
The core endpoints you will use:
GET /api/v1/wallet-tracker/watchlist — list all wallets in your watchlist (up to 10 on BASIC, 50 on PRO, 100 on ULTRA)
POST /api/v1/wallet-tracker/watchlist — add a wallet with an optional label
DELETE /api/v1/wallet-tracker/watchlist/{address} — remove a wallet
PATCH /api/v1/wallet-tracker/watchlist/{address} — update a wallet's label
GET /api/v1/wallet-tracker/trades — paginated swap and transfer history, filterable by wallet, action type, and event type
GET /api/v1/wallet-tracker/summary — per-wallet aggregates: swap count, buy/sell split, SOL volume, and last event timestamp
You can get a free API key and start with up to 10 wallets immediately. The full endpoint reference is in the API docs.
Setting Up the TypeScript SDK
The fastest way to get started is with the official TypeScript SDK ([email protected]). Install it alongside the standard Solana web3 library:
Initialize the client in a shared module you can import across your project:
// src/client.ts
import { MadeOnSol } from 'madeonsol';
export const client = new MadeOnSol({
apiKey: process.env.MADEONSOL_API_KEY!,
});
Step 1: Building Your Watchlist
The first thing your monitoring system needs is a list of wallets to track. Let's write a utility that adds wallets in bulk and handles the case where a wallet is already tracked:
// src/watchlist.ts
import { client } from './client';
export async function addWallets(wallets: { address: string; label: string }[]) {
const results: { address: string; success: boolean; error?: string }[] = [];
for (const wallet of wallets) {
try {
await client.walletTracker.addToWatchlist({
address: wallet.address,
label: wallet.label,
});
console.log(`Added ${wallet.label} (${wallet.address.slice(0, 8)}...)`);
results.push({ address: wallet.address, success: true });
} catch (err: any) {
// 409 means already in watchlist — not a real error
if (err.status === 409) {
results.push({ address: wallet.address, success: true });
} else {
console.error(`Failed to add ${wallet.address}: ${err.message}`);
results.push({ address: wallet.address, success: false, error: err.message });
}
}
}
return results;
}
export async function getWatchlist() {
return client.walletTracker.getWatchlist();
}
You can then call addWallets with whatever seed list you have — wallets from an on-site tool like the KOL tracker, whale addresses you have sourced manually, or any other list.
Step 2: Polling Trade History
Once wallets are tracked, the trades endpoint is your primary data source. It returns swap and transfer events sorted by time descending, and supports cursor-based pagination so you can efficiently fetch only new events on each poll cycle.
Single-Page Fetch
Here is the basic fetch, getting the 50 most recent events for a specific wallet:
For a production system you do not want to re-fetch events you have already seen. Use the before cursor parameter to fetch only events newer than your last recorded one:
// src/sync.ts
import { client } from './client';
// In production you would persist this cursor to a database
const cursors = new Map<string, string>();
export async function syncNewTrades(walletAddress: string) {
const cursor = cursors.get(walletAddress);
const allNewTrades: any[] = [];
let page = 0;
while (true) {
const response = await client.walletTracker.getTrades({
wallet: walletAddress,
limit: 100,
...(page === 0 && cursor ? {} : {}), // first page: newest events
// use before cursor on subsequent pages
});
if (response.data.length === 0) break;
allNewTrades.push(...response.data);
// If we have a previous cursor, stop when we hit events we've seen
if (cursor) {
const overlap = response.data.findIndex(t => t.id === cursor);
if (overlap !== -1) {
allNewTrades.splice(allNewTrades.length - (response.data.length - overlap));
break;
}
}
if (!response.next_cursor) break;
page++;
}
// Save the most recent event ID as our new cursor
if (allNewTrades.length > 0) {
cursors.set(walletAddress, allNewTrades[0].id);
}
return allNewTrades;
}
Filtering by Action Type
If you only care about buy swaps (for a copy-trading signal feed, for example), pass action: 'buy' to avoid processing sells:
Supported event_type values are swap and transfer. Supported values are and .
action
buy
sell
Step 3: Using the Summary Endpoint
Polling individual trade events is useful for real-time monitoring, but for building a dashboard that shows wallet-level health you want the summary endpoint. It gives you aggregated stats per wallet without having to crunch raw events yourself:
// src/summary.ts
import { client } from './client';
export async function getWatchlistSummaries() {
const summaries = await client.walletTracker.getSummary();
// Sort by most recently active
return summaries.sort((a, b) =>
new Date(b.last_event_at).getTime() - new Date(a.last_event_at).getTime()
);
}
export function formatSummary(s: any) {
const winRate = s.swap_count > 0
? ((s.buys / s.swap_count) * 100).toFixed(1)
: '0';
return {
label: s.label ?? s.wallet.slice(0, 8) + '...',
swaps: s.swap_count,
buys: s.buys,
sells: s.sells,
solBought: s.sol_bought.toFixed(2),
solSold: s.sol_sold.toFixed(2),
lastSeen: new Date(s.last_event_at).toLocaleString(),
};
}
The sol_bought and sol_sold fields give you net flow — a wallet that consistently buys more SOL-denominated value than it sells is accumulating, which is often a useful signal on its own.
Step 4: Building a Poll Loop
Tie everything together into a poll loop that runs on an interval and processes new events:
// src/monitor.ts
import { getWatchlist } from './watchlist';
import { syncNewTrades } from './sync';
import { getWatchlistSummaries } from './summary';
async function processEvent(event: any) {
// Your logic here: send to Discord, store in DB, trigger a trade, etc.
console.log(
`[${event.action.toUpperCase()}] ${event.wallet.slice(0, 8)} | ` +
`${event.token_symbol} | ${event.sol_amount} SOL`
);
}
async function pollCycle() {
const watchlist = await getWatchlist();
for (const entry of watchlist.data) {
const newTrades = await syncNewTrades(entry.address);
for (const event of newTrades) {
await processEvent(event);
}
}
}
// Run every 30 seconds
setInterval(pollCycle, 30_000);
pollCycle(); // run immediately on start
For higher-frequency monitoring on PRO or ULTRA tiers, consider using the wallet_tracker:event webhook instead of polling — it pushes events to your endpoint the moment they are indexed, eliminating the 30-second lag. The API docs have full webhook configuration details.
Common Pitfalls
Do not poll faster than your plan allows. The API rate limits are per-minute per key. If you have 50 wallets on PRO and poll each one every 10 seconds you will hit limits. Batch summary fetches and use cursors to keep per-poll request counts low.
Persist your cursors. The in-memory Map in the example above resets on restart. In production, store cursor IDs in a database or Redis so you do not miss events across restarts.
Label your wallets. The label field is optional but you will thank yourself later when you have 50 addresses in your watchlist and need to debug a strange trade. Use labels like "KOL: Arthur Hayes" or "Whale: $50M bag".
Check last_event_at before processing. The summary endpoint is cheap. Poll it first to see which wallets have had recent activity, then fetch full trade history only for those wallets.
What to Build Next
With wallet monitoring in place, the natural next steps are:
Copy-trading signal feed — filter buy events above a SOL threshold and forward them to your execution engine. See our guide on how to build a Solana trading bot for the execution side.
Portfolio dashboard — aggregate summaries across your watchlist and display net flow, win rate, and activity heatmaps.
The Solana API also exposes a deployer intel feed and KOL-specific endpoints that you can layer on top of wallet monitoring for richer signal. Get your free API key and start building — the BASIC tier with 10 tracked wallets is enough to validate most use cases before upgrading.