Wallet, terminal & bot integration
This page is for anyone displaying or trading Whale.fun tokens from outside the site — a wallet, a chart terminal, a sniper, an aggregator. It covers the four things such an integration always needs: discover tokens, tell what kind of token it is, price it, and trade it. Every ABI referenced here is downloadable as JSON (see the end of the page), generated from the same definitions the site itself uses.
1 · Discover new tokens
Two launch families, two discovery paths. Fixed-price mint launches come from the launch factories, which emit an event and also expose an enumerable array. Bonding-curve launches come from the curve factories, which expose launchCount() and launches(i) — enumeration is usually more reliable than log scanning here, because free BSC log endpoints are heavily rate-limited (in our own measurements only one public endpoint allowed a 5,000-block getLogs range).
// 内盘曲线:枚举(推荐,不依赖 getLogs)
const n = await factory.read.launchCount();
for (let i = 0n; i < n; i++) {
const token = await factory.read.launches([i]);
const pool = await factory.read.poolOf([token]); // 曲线合约
}
// 固定价铸造:launches(i) 返回结构体,一次拿全
// (token, vault, taxVault, pair, creator, createdAt)
const row = await launchFactoryV2.read.launches([i]);
// ⚠️ 换过工厂 → 必须遍历「当前 + 历代」工厂,否则找不到较早那批币
// 见「已部署地址」页的完整列表与代码2 · Tell what kind of token you are holding
The order matters, because a graduated curve token still answers on the curve factory. Resolve in this order: does any curve factory know it (poolOf ≠ 0)? If yes, read the pool's stats() — if graduated is true, the live liquidity is a normal DEX pair and you should trade there, not on the curve. Only if no curve factory knows it is it a fixed-price mint token or an unrelated ERC-20.
const s = await pool.read.stats();
// s = (token, target, raised, tokensSold, curveSupply,
// priceX18, progressBps, graduated, pair)
if (s[7]) {
// 已毕业:去 s[8] 这个 DEX pair 交易,曲线的 buy/sell 会 revert
} else {
// 内盘中:progressBps/100 = 进度%,raised/target = 距毕业还差多少
}3 · Price it
In-curve tokens have exact on-chain quote views: quoteBuy(quoteIn) and quoteSell(tokenIn). Use them rather than re-implementing the curve — they mirror the fee flooring inside buy() and sell() exactly, so recomputing the maths off-chain drifts by wei. quoteSell returns 0 when the amount exceeds what the curve has actually sold; that is a real constraint, not a failure. Graduated tokens price through the DEX router as usual.
For a USD figure you also need the quote asset's price, and the quote asset is not always the native coin: it can be USDT or a tokenized stock (NVDAB, SPCXB, SPYB, QQQB). Read pool.quoteToken() — zero address means native. Treating any ERC-20 quote as $1 is a mistake we made ourselves and it puts market caps out by two orders of magnitude on stock-quoted tokens.
4 · Trade
In-curve trading does not go through a router. Buy with native quote is buy(minTokensOut) with the amount as msg.value; buy with an ERC-20 quote is buyToken(quoteIn, minTokensOut) after approving the pool. Sell is always sell(tokenIn, minQuoteOut) after approving the pool. Note the approval target: it is the curve contract itself, not a router — approving a router does nothing here, because the curve pulls the funds.
// 内盘买(原生报价)
await pool.write.buy([minOut], { value: amountIn });
// 内盘买(USDT / 股票报价)
await quote.write.approve([poolAddress, amountIn]);
await pool.write.buyToken([amountIn, minOut]);
// 内盘卖(两种报价都一样)
await token.write.approve([poolAddress, amountIn]);
await pool.write.sell([amountIn, minQuoteOut]);
// 毕业后:普通 DEX 路由。代币可能带买卖税 → 用
// swapExactTokensForTokensSupportingFeeOnTransferTokens 这一族5 · Vaults: what a token's mechanism is
A token's tax vault is at token.taxVault(). Vaults are self-describing: vaultUISchema() returns the vault type, a description and the full list of read/write methods with their types, which is how this site renders a vault panel it has never seen. description() returns a live one-line status (for example a countdown to the next burn).
Vaults are 45-byte EIP-1167 clones, so their own bytecode contains no functions. To probe what a vault supports, resolve the implementation out of the clone and look for selectors in the implementation's runtime bytecode. This is how the site decides which aggregates to show without hardcoding a table per vault type.
// 45 字节克隆 → 实现合约
const EIP1167 = /363d3d373d3d3d363d73([0-9a-fA-F]{40})5af43d82803e903d91/;
let code = await client.getBytecode({ address: vault });
const m = code?.match(EIP1167);
if (m) code = await client.getBytecode({ address: `0x${m[1]}` });
// 之后在 code 里找选择子,例如 totalDistributed() = efca2eedABI downloads
Full ABIs as JSON, generated from the same definitions this site uses to talk to the chain — so they never lag behind what is deployed. GET /api/abi lists everything available; GET /api/abi/<name>.json returns one. CORS is open, so a terminal or bot can fetch them directly.
curl https://whalefun.io/api/abi # 清单 curl -O https://whalefun.io/api/abi/curveTaxPool.json # 内盘池(buy/sell/quote/stats) curl -O https://whalefun.io/api/abi/curveTaxFactory.json curl -O https://whalefun.io/api/abi/curveTaxToken.json # 持币分红 curl -O https://whalefun.io/api/abi/launchFactoryV2.json curl -O https://whalefun.io/api/abi/projectTokenV2.json curl -O https://whalefun.io/api/abi/vaultSchema.json # 任意金库的自描述接口