跳到主要内容

买入与卖出

发一个请求,拿回一笔未签名的交易,由你自己的脚本签名并发送。下面的脚本是完整的:填上私钥、代币地址和金额,直接运行。

Flap
PancakeSwap

一个接口覆盖 BNB 链上所有 Flap 代币,不管它在哪:

  • 内盘(联合曲线):从发射到卖出 8 亿枚为止。
  • 外盘(PancakeSwap):毕业之后,在 Flap 迁移过去的池子里。

你只传代币地址;API 从 Flap 的 Portal 读取状态并自动路由,返回里的 venue 会标明是 flap_curve 还是 pancakeswap。税币不需要任何特殊处理,税已经算在报价里。

你需要什么

示例

const { Wallet } = require("ethers");

// ─── 改这三行 ────────────────────────────────────────
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY";
const TOKEN = "0xTHE_TOKEN_ADDRESS";
const AMOUNT = "0.01"; // 买入:要花的 BNB。卖出:"1000" 个代币,或 "100%"
const ACTION = "buy"; // "buy" 或 "sell"
const SLIPPAGE = 5; // 滑点百分比,允许价格对你不利的幅度
// ──────────────────────────────────────────────────────

async function main() {
const wallet = new Wallet(PRIVATE_KEY); // 只用来签名,不连任何节点

const res = await fetch("https://api.shrine.trade/bnb/api/local-trade", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
action: ACTION,
token: TOKEN,
amount: AMOUNT,
slippage: SLIPPAGE,
from: wallet.address,
}),
});

const data = await res.json();
if (data.error) throw new Error(`${data.error}: ${data.message}`);
console.log("预计得到约", data.quote.expectedOutFormatted,
ACTION === "buy" ? "tokens" : data.receive);

// 本地签名,把签好的交易交给 API 广播:私钥不会离开这个脚本,
// 你也不需要自己的 RPC。
for (const tx of data.txs) {
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);
}

if (ACTION === "buy") {
console.log(`买入 ${data.name} (${data.symbol}) ${data.token} 花费 ${data.amountInFormatted} ${data.payWith}`);
} else {
console.log(`卖出 ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} 得到 ${data.quote.expectedOutFormatted} ${data.receive}`);
}
}

main();

保存为 trade.js,然后:

npm install ethers
node trade.js

API 返回什么,脚本就按顺序发什么。买入是一笔交易;某个代币的第一次卖出是两笔:一次性的授权,然后是卖出本身。

交易有防夹子保护:链上 minOut 保证成交不会比滑点允许的更差;签好的交易通过 /api/send 走我们自己的节点广播,不经过公共节点,你也不需要自己的 RPC。

买入上限

有些 Flap 代币限制单个钱包在内盘的累计买入量。报价已经按你剩余的额度计算;超出上限的买入会按上限成交,多出的 BNB 在同一笔交易里退回。代币信息 能看到上限和你还剩多少。

卖出

ACTION 改成 "sell"。金额可以是代币数量,也可以是钱包余额的百分比:

AMOUNT卖出
"1000"1000 枚代币
"50%"一半余额
"100%"全部

只要 Flap 能在卖出时兑换,无论代币用什么计价,收到的都是 BNB。返回里的 receive 会告诉你最终收到的是什么资产。

税币

Flap 上大部分新币都是税币:创作者从每笔买卖里抽一个百分比。税已经算进报价,expectedOut 就是你实际到手的数量。在内盘,税是交易上的额外费用;毕业后,税从经过池子的代币里扣。返回里的 creatorTaxBps 是你这一边的税率。脚本不用改。

以 USD1、股票或其他资产计价的代币

Flap 允许发币时用 USD1、代币化股票(NVDAB、TSLAB、SPYB、XAUT 等,见 支持的计价资产)或另一个 Flap 代币计价,而不是 BNB。脚本同样不用改:买入时 AMOUNT 永远是 BNB,Flap 在交易内部把它换成计价资产。quoteAsset 说明代币用什么计价,payWith 说明从你钱包里出去的是什么。

如果 Flap 无法在买入时兑换(quote_asset_required),就直接用那个资产买:钱包里持有它,请求里加 payWithQuote: true,此时 amount 以该资产为单位。这类代币卖出时收到的是计价资产;任何代币都可以加 receiveQuote: true 来指定收计价资产。

出错了怎么办

错误怎么办
insufficient_funds往钱包充 BNB:交易金额,再加一点 Gas。
insufficient_balance卖出数量超过持仓。"100%" 永远不会超。
token_not_foundFlap 的 Portal 不认识这个地址。确认填的是代币合约,不是 PancakeSwap 池子。
slippage_exceeded报价和发送之间价格跑远了。重试,热门代币把 SLIPPAGE 调高。
buy_quota_exhausted这个钱包在该代币内盘的买入额度已用完。
quote_asset_required代币的计价资产 Flap 无法用 BNB 兑换。持有该资产并设置 payWithQuote

完整列表见 错误

发送

POST https://api.shrine.trade/bnb/api/send 接收一笔签好的交易,通过我们的 BNB 链节点广播,所以脚本完全不需要 RPC。它只转发本 API 构建的交易:Flap 买卖、发币、授权和领取,其他一律以 not_ours 拒绝。

字段
signedTx0x 十六进制签好的交易,即 wallet.signTransaction 的返回值。
wait布尔,可选默认 true:等待回执。false 则节点一接受就返回哈希。
{ "hash": "0x…", "status": "landed", "blockNumber": 120162431, "gasUsed": 514058, "explorer": "https://bscscan.com/tx/0x…" }

statuslanded(已上链)、reverted(已回滚)或 pending(未等待,或 45 秒内未打包,通常是 nonce 或 Gas 卡住)。

请求与返回

POST https://api.shrine.trade/bnb/api/local-trade

请求

字段
action"buy""sell"
token地址Flap 代币。
amount十进制字符串买入:要花的 BNB,与代币的计价资产无关。卖出:代币数量如 "1000",或余额百分比如 "50%""100%"
from地址你的钱包。
slippage数字,可选百分比,默认 5
payWithQuote布尔,可选仅买入、且代币以 ERC-20 计价时:用该资产支付,amount 以它为单位。
receiveQuote布尔,可选仅卖出、且代币以 ERC-20 计价时:收取该资产而不是 BNB。

返回:一个真实的例子,用 0.001 BNB 在内盘买入一个税币:

{
"action": "buy",
"protocol": "FLAP",
"token": "0x2f1952E00F6BA7655993120B8c41E5ab511e7777",
"name": "星际巨舰",
"symbol": "星际巨舰",
"status": "Tradable",
"venue": "flap_curve",
"amountIn": "1000000000000000",
"amountInFormatted": "0.001",
"quoteAsset": {
"address": "0x0000000000000000000000000000000000000000",
"symbol": "BNB",
"decimals": 18,
"isNative": true
},
"payWith": "BNB",
"receive": "TOKEN",
"quote": {
"expectedOut": "160442982903129676642962",
"expectedOutFormatted": "160442.982903129676642962",
"minOut": "152420833757973192810813",
"curveFeeBps": 125,
"creatorTaxBps": 1000,
"shrineFeeBps": 50,
"slippagePct": 5.0
},
"txs": [
{
"to": "0xFLAP_ROUTER",
"data": "0x…",
"value": "1000000000000000",
"gas": 521904,
"maxFeePerGas": "62500000",
"maxPriorityFeePerGas": "50000000",
"nonce": 5,
"chainId": 56,
"type": 2,
"description": "buy"
}
]
}
  • txs:按此顺序签名并广播的交易。三个以 wei 计的字段(valuemaxFeePerGasmaxPriorityFeePerGas)是十进制字符串,其余是普通数字。description 标明每笔交易:buysell,或一次性的 approve / approve_quote
  • name / symbol:从代币合约读取,方便记录交易了什么。
  • status:Flap 的状态,内盘为 Tradable,毕业后为 DEXvenueflap_curvepancakeswap。两种情况下请求完全一样。
  • quoteAsset:代币的计价资产,BNB 或某个 ERC-20。payWith / receive:实际离开或进入你钱包的东西(BNB、计价资产符号,或 TOKEN)。
  • amountIn:你花出去的数量,基础单位:买入是 BNB 的 wei,卖出是代币。
  • quote.expectedOut:扣除 Flap 费用、代币税和我们的费用之后你应到手的数量。minOut 是它再减去滑点,也是合约强制执行的下限。两者都是基础单位,展示时用带 *Formatted 的字段。
  • quote 里的费用:curveFeeBps 是 Flap 在内盘的费用(毕业后为 0,改为 PancakeSwap 的 LP 费),creatorTaxBps 是代币在你这一边的税率,shrineFeeBps 是我们的费用(50 = 0.5%)。