如何在 BNB 链上狙击 Flap 新币
一个脚本跑完整个流程:监听每一次 Flap 发射,跳过不想要的,用固定数量的 BNB 买入,持仓到达止盈或止损时卖出。
你需要什么
- Node.js 22 以上(自带 WebSocket 客户端),并安装 ethers:
npm install ethers。 - 一个钱包私钥,里面有一点 BNB 链上的 BNB,见 Gas 与费用。
- 十分钟。
该按什么过滤
Flap 没有开盘狙击税,所以不用等;但有两件事决定一次发射值不值得买,而且都直接写在发射事件里:
- 税率。 大部分新币是税币。10% 的卖出税意味着你光是回本就要先涨 10%。每条事件都带
buyTaxBps和sellTaxBps。 - 计价资产。
quoteToken是BNB、USD1或NVDAB这样的代号,API 不认识的计价资产则是地址。用 BNB 计价的代币一笔交易就能买;其他的要靠 Flap 在买入时兑换,列出的每一种都可以,但更费 Gas。
有些代币还限制单个钱包在内盘的累计买入量。报价已经按你的额度算好,脚本不会多付,只是买得少。
脚本
const { Wallet } = require("ethers");
// ─── 改这些 ─────────────────────────────────────────
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY";
const BUY_BNB = "0.01"; // 每次发射投入的 BNB
const TAKE_PROFIT = 2.0; // 持仓价值达到买入成本 2 倍时卖出
const STOP_LOSS = 0.5; // ……或者跌到一半
const MAX_POSITIONS = 3;
const MAX_SELL_TAX = 500; // 跳过卖出税高于 5% 的代币(单位 bps)
const ONLY_BNB_PRICED = true; // 跳过以 USD1 或其他资产计价的代币
const DRY_RUN = true; // 只报价和打印,不发送任何交易
// ──────────────────────────────────────────────────────
const API = "https://api.shrine.trade/bnb";
const wallet = new Wallet(PRIVATE_KEY); // 只用来签名,不连任何节点
const positions = new Map(); // 代币地址 -> { paidBnb, symbol }
const post = async (path, body) =>
(await fetch(`${API}${path}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) })).json();
async function send(txs) {
for (const tx of txs) {
if (DRY_RUN) { console.log(" 演练:", tx.description); continue; }
const signed = await wallet.signTransaction({
to: tx.to, data: tx.data, value: BigInt(tx.value), gasLimit: BigInt(tx.gas),
maxFeePerGas: BigInt(tx.maxFeePerGas), maxPriorityFeePerGas: BigInt(tx.maxPriorityFeePerGas),
nonce: tx.nonce, chainId: tx.chainId, type: 2,
});
const sent = await (await fetch("https://api.shrine.trade/bnb/api/send", {
method: "POST", headers: { "content-type": "application/json" },
body: JSON.stringify({ signedTx: signed }),
})).json();
if (sent.error) throw new Error(`${sent.error}: ${sent.message}`);
if (sent.status !== "landed") throw new Error(`${tx.description} ${sent.status}: ${sent.explorer}`);
console.log(" " + tx.description + ": " + sent.explorer);
}
}
async function onLaunch(t) {
if (positions.size >= MAX_POSITIONS || positions.has(t.token)) return;
if (ONLY_BNB_PRICED && t.quoteToken !== "BNB") return;
if ((t.sellTaxBps ?? 0) > MAX_SELL_TAX) return;
console.log(`launch ${t.symbol} ${t.token} tax ${t.buyTaxBps}/${t.sellTaxBps} bps, priced in ${t.quoteToken}`);
const q = await post("/api/local-trade", { action: "buy", token: t.token, amount: BUY_BNB, from: wallet.address });
if (q.error) { console.log(" skip:", q.error, q.message); return; }
console.log(` buying ${BUY_BNB} BNB -> ~${q.quote.expectedOutFormatted} ${q.symbol}`);
await send(q.txs);
positions.set(t.token, { paidBnb: Number(BUY_BNB), symbol: q.symbol });
}
async function checkPositions() {
for (const [token, pos] of positions) {
const q = await post("/api/local-trade", { action: "sell", token, amount: "100%", from: wallet.address });
if (q.error) continue; // 演练模式买入后出现 insufficient_balance 是正常的
const worth = Number(q.quote.expectedOutFormatted); // BNB,已扣税和费用
const ratio = worth / pos.paidBnb;
if (ratio >= TAKE_PROFIT || ratio <= STOP_LOSS) {
console.log(`selling ${pos.symbol}: worth ${worth.toFixed(5)} BNB, ${ratio.toFixed(2)}x`);
await send(q.txs);
positions.delete(token);
}
}
}
const ws = new WebSocket(`${API.replace("https", "wss")}/api/launches/ws?protocols=FLAP`);
ws.onmessage = (e) => { const t = JSON.parse(e.data); if (t.type === "new_launch") onLaunch(t).catch((err) => console.log(" error:", err.message)); };
ws.onclose = () => { console.log("推送已断开"); process.exit(1); };
setInterval(() => checkPositions().catch(() => {}), 10_000);
console.log("正在监听发射,钱包", wallet.address, DRY_RUN ? "(演练模式)" : "");
用 node sniper.js 运行。在输出看起来正确之前保持 DRY_RUN 为 true:演练模式下机器人只打印它会买的发射和会签的交易,什么都不发。
每一部分在做什么
- 推送在区块确认一秒内送达每一次发射,一天几百次。
?protocols=FLAP把毕业事件挡在外面。 - 过滤条件随你扩展。事件里有
name、symbol、creator、tokenType、税率和metaUri(创作者的图片、简介和链接,JSON 格式),所以"只买有官网的"或者一份创作者黑名单,几行就写完。 - 买入用 BNB。报价是 Flap 自己的报价,并以你的钱包身份模拟,税、内盘费用和买入上限都已经在
expectedOut里。 - 持仓检查每十秒跑一次:机器人请求一个全部卖出的报价,把扣掉卖出税之后能拿回的 BNB 和当初花掉的 BNB 比较。
- 状态在内存里。 进程一死它就忘了自己持有什么;用真钱之前,先把
positions写到硬盘。