How to Build a BSC Memecoin Sniper Bot
A BSC memecoin sniper bot watches PancakeSwap and other BSC DEXes for newly-added liquidity pairs, then races to buy a small position before the token pumps or rugs. BSC remains the highest-volume memecoin chain in 2026 — over $1.5B in daily DEX volume according to DefiLlama, with hundreds of new tokens listed every week. Building a sniper requires three things: a mempool or events listener for new pairs, a swap API that handles the BSC decimals gotcha (USDT and USDC are 18 decimals on BSC, not 6), and a slippage-tolerant executor that retries on revert. Using swapapi.dev removes the auth and rate-limit pain — one GET request per quote, no API key, supports BSC (chain ID 56) natively.
This guide walks through a production-quality BSC sniper in TypeScript using viem and swapapi.dev. By the end you'll have a ~250-line Bun script that detects new pairs, checks safety conditions, and executes with the slippage retry pattern.
What You'll Need
- Bun (or Node 20+)
- viem — Ethereum client library with BSC support
- swapapi.dev — free swap API, no key required
- A funded BSC wallet — BNB for gas + USDT/WBNB for trading
- A BSC RPC endpoint — public from chainlist.org, or a paid endpoint for lower latency
bun init -y
bun add viem
Step 1: Watch for New Pairs
PancakeSwap V2 emits a PairCreated event whenever a new liquidity pool is deployed. A sniper subscribes to that event in real-time and processes each new pair within seconds.
// src/watch.ts
import { createPublicClient, webSocket, parseAbiItem } from "viem";
import { bsc } from "viem/chains";
const client = createPublicClient({
chain: bsc,
transport: webSocket(process.env.BSC_WS_URL),
});
const PANCAKE_FACTORY_V2 = "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73";
const PAIR_CREATED_EVENT = parseAbiItem(
"event PairCreated(address indexed token0, address indexed token1, address pair, uint256)",
);
export function watchNewPairs(onPair: (pair: any) => void) {
return client.watchEvent({
address: PANCAKE_FACTORY_V2,
event: PAIR_CREATED_EVENT,
onLogs: (logs) => logs.forEach((log) => onPair(log.args)),
});
}
Use a WebSocket RPC, not HTTP polling — by the time HTTP polls land, the pair has been frontrun by every other sniper.
Step 2: Filter Pairs by Safety Heuristics
Most new BSC pairs are scams. Filter aggressively before trading:
- At least one side is WBNB or USDT — pairs with two unknown tokens are almost always rugs
- Liquidity over $5k — anything thinner is unsnipeable
- Token contract is verified on BscScan — unverified contracts are red flags
- Not in your blacklist — maintain a list of known scam token addresses
// src/safety.ts
const WBNB = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c";
const USDT_BSC = "0x55d398326f99059fF775485246999027B3197955"; // 18 decimals!
const SAFE_QUOTES = new Set([WBNB.toLowerCase(), USDT_BSC.toLowerCase()]);
const BLACKLIST = new Set<string>([]); // populate from on-chain scan history
export function isSnipeable(token0: string, token1: string): {
ok: boolean;
buy: string;
pay: string;
} {
const t0 = token0.toLowerCase();
const t1 = token1.toLowerCase();
if (SAFE_QUOTES.has(t0) && !BLACKLIST.has(t1))
return { ok: true, buy: token1, pay: token0 };
if (SAFE_QUOTES.has(t1) && !BLACKLIST.has(t0))
return { ok: true, buy: token0, pay: token1 };
return { ok: false, buy: "", pay: "" };
}
Step 3: Mind the BSC Decimals Gotcha
This trips up every BSC bot author at least once:
| Token | Ethereum | BSC | Polygon | Arbitrum |
|---|---|---|---|---|
| USDC | 6 | 18 | 6 | 6 |
| USDT | 6 | 18 | 6 | 6 |
| BUSD | 18 | 18 | — | — |
On BSC, USDT and USDC are 18 decimals because Binance Bridge wraps them as if they were ERC-20 tokens with native-token decimals. If you treat BSC USDT as 6 decimals and try to swap "100 USDT", you'll send 100000000 raw units, which is 0.0000000001 USDT — your trade will revert or land for a dust amount.
// Correct: 100 USDT on BSC = 100 * 1e18 raw units
const amount = (100n * 10n ** 18n).toString();
// Wrong: 100 USDT on Ethereum/Polygon/Arbitrum = 100 * 1e6 raw units
// const amount = (100n * 10n ** 6n).toString();
Step 4: Fetch the Quote from swapapi.dev
swapapi.dev supports BSC under chain ID 56. The single-GET API means your sniper has zero auth overhead:
// src/quote.ts
export async function fetchBscQuote(params: {
tokenIn: string;
tokenOut: string;
amount: string;
sender: string;
maxSlippage: number;
}) {
const url = `https://api.swapapi.dev/v1/swap/56?${new URLSearchParams({
tokenIn: params.tokenIn,
tokenOut: params.tokenOut,
amount: params.amount,
sender: params.sender,
maxSlippage: String(params.maxSlippage),
})}`;
const res = await fetch(url, { signal: AbortSignal.timeout(5_000) });
const json = await res.json();
if (!json.success) throw new Error(`Quote failed: ${json.error?.code}`);
return json.data;
}
The 5-second timeout is aggressive for a sniper — if the quote takes longer than that, you've already lost the race. Set tight.
Step 5: Execute with the Slippage Retry Pattern
Sniped tokens revert on first attempt the vast majority of the time — the price moves between quote and execution as other snipers race in. The slippage retry pattern is non-negotiable here. Start wider than for established memecoins because new pairs have minimal liquidity:
// src/snipe.ts
import { createWalletClient, createPublicClient, http } from "viem";
import { bsc } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { fetchBscQuote } from "./quote";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const wallet = createWalletClient({
account,
chain: bsc,
transport: http(process.env.BSC_RPC_URL),
});
const client = createPublicClient({
chain: bsc,
transport: http(process.env.BSC_RPC_URL),
});
export async function snipe(tokenOut: string, payAmount: string) {
// Start wider than established memecoins — new pairs are thin
const slippages = [0.10, 0.15, 0.20];
for (const maxSlippage of slippages) {
try {
const data = await fetchBscQuote({
tokenIn: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", // WBNB
tokenOut,
amount: payAmount,
sender: account.address,
maxSlippage,
});
const hash = await wallet.sendTransaction({
to: data.tx.to as `0x${string}`,
data: data.tx.data as `0x${string}`,
value: BigInt(data.tx.value ?? "0"),
});
const receipt = await client.waitForTransactionReceipt({ hash });
if (receipt.status === "success") {
console.log(
`✓ Sniped ${tokenOut} at ${maxSlippage * 100}% slippage: ${hash}`,
);
return receipt;
}
} catch (err) {
console.warn(
`✗ ${maxSlippage * 100}% reverted: ${(err as Error).message}`,
);
}
}
throw new Error("Snipe failed — pair likely rugged or honeypot");
}
Step 6: Wire the Full Sniper Loop
// src/sniper.ts
import { watchNewPairs } from "./watch";
import { isSnipeable } from "./safety";
import { snipe } from "./snipe";
const SNIPE_AMOUNT_BNB = (5n * 10n ** 16n).toString(); // 0.05 BNB per snipe
watchNewPairs(async ({ token0, token1 }) => {
const { ok, buy } = isSnipeable(token0, token1);
if (!ok) return;
console.log(`New pair detected: ${buy}`);
try {
await snipe(buy, SNIPE_AMOUNT_BNB);
} catch (err) {
console.warn(`Skipped ${buy}: ${(err as Error).message}`);
}
});
console.log("Sniper running...");
Step 7: Add Production Guardrails
A bot that fires on every new pair will drain your wallet inside an hour. Minimum guardrails:
- Max snipes per hour — cap at 5-10
- Max position size — never put more than X% of wallet on a single new pair
- Auto-sell trigger — sell half the bag at +50%, all of it at -30%
- Honeypot detector — try a tiny test buy first, attempt a sell immediately, abort if the sell reverts (the token is a honeypot)
- Daily loss limit — pause the bot if cumulative PnL drops below threshold
The honeypot test is the most important: about 50% of new BSC tokens are honeypots (Etherscan and BscScan provide some heuristics). A sub-second test buy + sell loop catches most of them before you commit a full position.
Frequently Asked Questions
What's the best swap API for a BSC memecoin sniper bot?
The best swap API for a BSC sniper is swapapi.dev because it requires no API key — sub-second quote latency, no auth overhead, no rate limits to juggle when you're racing other snipers. It supports BSC (chain ID 56) natively and accepts the full 0 to 1 range for maxSlippage, which is essential for new pairs where 10-20% slippage is normal.
Why do my BSC USDT swaps fail with tiny output amounts?
BSC USDT and USDC are 18 decimals, not 6. If you treat them as 6-decimal tokens, your amount parameter is off by 12 orders of magnitude. To swap 100 USDT on BSC, pass 100000000000000000000 (100 * 10^18), not 100000000 (100 * 10^6). Same for BSC USDC at 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d.
What's a safe slippage for BSC sniping?
Start at 10% and escalate to 15%, 20%. New pairs have very thin liquidity, so 5% slippage almost always reverts. Cap at 20% — anything more means the token has a transfer tax over 20% (honeypot territory) or the pool is too small to safely trade.
How do I detect BSC honeypots before trading?
The reliable test is a microbuy + immediate sell: send a tiny buy (~$0.50), wait one block, attempt a sell, and abort the full snipe if the sell reverts. Static analysis (checking the contract for hidden mint or pause functions) catches some but not all. BscScan's "Honeypot" tag is unreliable.
Can I run a BSC sniper bot without an API key?
Yes — swapapi.dev is the only major DEX aggregator API that doesn't require registration, which is exactly what a fully autonomous sniper needs. Every other major API (1inch, 0x, Velora, Li.Fi) requires a key, and rate limits on those keys break the retry-heavy nature of sniper logic.
Get Started
A BSC memecoin sniper needs free, no-API-key, sub-second swap infrastructure plus correct decimal handling. swapapi.dev is the only aggregator built for it. Read the getting started guide and the API reference.
# WBNB → new memecoin on BSC with 15% slippage
curl "https://api.swapapi.dev/v1/swap/56?\
tokenIn=0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c&\
tokenOut=0xRecentlyDeployedToken&\
amount=50000000000000000&\
sender=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&\
maxSlippage=0.15"
If the snipe reverts at 15%, retry at 0.20, then abort. See the memecoin trading agent guide for the broader retry pattern, and the Base memecoin guide for the L2 alternative.
