Build on 归海
Put best-price swaps on BNB Chain inside your bot, agent, wallet or app. Earn your own fee on every swap you route, paid on-chain in the same transaction.
- Up to 0.5% of every swap, straight to your address
- Featured on the showcase and announced on X
- 一键生成 API 密钥、更高限额、为你的用户提供省钱证明
一笔兑换,一笔交易完成分账
- 你的用户收到到他们的钱包
- 归海 手续费归协议
- 你的抽成,最高 0.5%到你的地址
创建 API 密钥
Already have one? Open your 开发者面板 to see your traffic and fees.
你能构建什么
一套 API、一个 MCP server,覆盖链上每一个池子——原生 PancakeSwap 和经 Aggregator Hooks 接入的外部池子都算。
交易机器人
用纯 HTTP 报价、构建并追踪兑换。每条路由都经过检查,每笔兑换发送前都经过模拟。
AI Agent 走 MCP
一个 URL 就能让任何 Agent 获得最优价兑换。Agent 负责准备,用户的钱包负责签名。
钱包与前端
在你的应用内提供 BNB Chain 最优价兑换,还能叠加你自己的抽成。
Hook 数据分析
每个 Aggregator Hook 池子的流动性、交易量与笔数,拿来即可画图。
Telegram 机器人
在聊天里兑换,追踪到结算,分享省钱证明链接。
你能得到什么
0.5%
你路由的每笔兑换都归你抽成
Set partnerFeeBps on your quotes, up to 50 bps. It is paid on-chain to your payout address in the same transaction, right after the 归海 fee. No invoices, no monthly claims.
fee.partner = { bps, amount, recipient }
登墙与公告
通过审核的项目进入 Built on 归海 案例墙,我们会在 X 上公告。
专属密钥,更高限额
API 密钥把默认每分钟 60 次报价提升到 300 次,并在你的面板上展示流量。
为你的用户提供省钱证明
每笔兑换都有公开证明:比 PancakeSwap 最优路由多拿了多少。可分享、可链接、可展示。
工具箱
一切公开。需要更高限额和自己的抽成时,生成一把密钥即可。
The Built on 归海 badge
把它加到你的网站或 README。它链接到本页。
<a href="https://guihaitrade.com/build"><img src="https://guihaitrade.com/badge.svg" alt="基于 归海 构建" height="36"></a>10 分钟上线
一个文件的完整机器人:为你的钱包报价、按提示授权并签名、构建交易、校验、发送、追踪。用你的密钥跑,还能抽成。
// bot.ts: best-price swaps on BNB Chain through 归海. Run: npm i viem && PRIVATE_KEY=0x… API_KEY=… npx tsx bot.ts
import { createPublicClient, createWalletClient, defineChain, getAddress, http, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const BASE = "https://guihaitrade.com/api";
const API_KEY = process.env.API_KEY; // your builder key: higher limits, and your own fee
const PARTNER_FEE_BPS = 30; // 0.30% for you, paid on-chain to your payout address (max 50 bps, capped by your key)
const UNIVERSAL_ROUTER = getAddress("0x204faca1764b154221e35c0d20abb3c525710498");
const PERMIT2 = getAddress("0x000000000022d473030f116ddee9f6b43ac78ba3");
const NATIVE_ETH = "0x0000000000000000000000000000000000000000";
const bnb = defineChain({
id: 56,
name: "BNB Chain",
nativeCurrency: { name: "BNB", symbol: "BNB", decimals: 18 },
rpcUrls: { default: { http: ["https://bsc-dataseed.binance.org"] } },
});
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const wallet = createWalletClient({ account, chain: bnb, transport: http() });
const client = createPublicClient({ chain: bnb, transport: http() });
type Field = { name: string; type: string };
type Permit = {
domain: { name: string; chainId: number; verifyingContract: Hex };
types: Record<string, Field[]>;
message: { details: { token: Hex; amount: string; expiration: number; nonce: number }; spender: Hex; sigDeadline: string };
};
type Step = { kind: "approve"; token: Hex; spender: Hex; tx: { to: Hex; data: Hex } } | { kind: "permit"; token: Hex; typedData: Permit };
type Quote = { id: string; sell: { token: string; amountAtomic: string }; buy: { amount: string; symbol: string }; steps: Step[]; fee: { partner: { amount: string } | null } };
type Built = { quoteId: string; tx: { to: Hex; data: Hex; value: string; chainId: number; gas: string | null } };
type Tracked = { status: "pending" | "confirmed" | "failed" | "unknown"; amountOut: string | null };
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
async function api<T>(path: string, body?: unknown): Promise<T> {
for (let attempt = 0; attempt < 5; attempt++) {
const res = await fetch(BASE + path, {
method: body === undefined ? "GET" : "POST",
headers: { "Content-Type": "application/json", ...(API_KEY ? { "X-Api-Key": API_KEY } : {}) },
body: body === undefined ? undefined : JSON.stringify(body),
});
if (res.status === 429) {
await sleep(Number(res.headers.get("Retry-After") ?? "5") * 1000);
continue;
}
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
return data as T;
}
throw new Error("Still rate limited after 5 attempts.");
}
async function swap(sell: string, buy: string, amount: string): Promise<Tracked> {
const ask = { sell, buy, amount, taker: account.address, slippageBps: 50, ...(API_KEY ? { partnerFeeBps: PARTNER_FEE_BPS } : {}) };
let quote = await api<Quote>("/quote", ask);
// 1. Approve Permit2 once per token, then quote again (the steps change once it lands).
const approve = quote.steps.find((s) => s.kind === "approve");
if (approve) {
if (getAddress(approve.spender) !== PERMIT2 || getAddress(approve.tx.to) !== getAddress(approve.token)) throw new Error("Unexpected approval");
const hash = await wallet.sendTransaction({ to: approve.tx.to, data: approve.tx.data });
if ((await client.waitForTransactionReceipt({ hash })).status !== "success") throw new Error("Approval reverted");
quote = await api<Quote>("/quote", ask);
}
// 2. Sign the Permit2 allowance when asked (no gas). viem builds the EIP712Domain type itself.
let permitSignature: Hex | undefined;
const permit = quote.steps.find((s) => s.kind === "permit");
if (permit) {
const { domain, message } = permit.typedData;
const { EIP712Domain: _domainType, ...types } = permit.typedData.types;
if (getAddress(message.spender) !== UNIVERSAL_ROUTER || getAddress(domain.verifyingContract) !== PERMIT2 || domain.chainId !== 56) throw new Error("Unexpected Permit2 request");
permitSignature = await wallet.signTypedData({
domain,
types,
primaryType: "PermitSingle",
message: { details: { ...message.details, amount: BigInt(message.details.amount) }, spender: message.spender, sigDeadline: BigInt(message.sigDeadline) },
});
}
// 3. Build: simulated on the live chain before it comes back.
const { tx, quoteId } = await api<Built>("/swap", { quoteId: quote.id, permitSignature });
// 4. Verify before signing anything.
const expectedValue = quote.sell.token === NATIVE_ETH ? quote.sell.amountAtomic : "0";
if (quoteId !== quote.id) throw new Error("Refusing: built for another quote");
if (getAddress(tx.to) !== UNIVERSAL_ROUTER) throw new Error("Refusing: tx.to is not the PancakeSwap Universal Router");
if (tx.chainId !== 56) throw new Error("Refusing: wrong chain");
if (tx.value !== expectedValue) throw new Error("Refusing: unexpected BNB value");
// 5. Send, then 6. track until settled.
const hash = await wallet.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), gas: tx.gas ? BigInt(tx.gas) : undefined });
let status = await api<Tracked>("/swaps/track", { quoteId: quote.id, txHash: hash });
while (status.status === "pending") {
await sleep(2_000);
status = await api<Tracked>(`/swaps/${hash}`);
}
console.log(status.status, quote.fee.partner ? `you earned ${quote.fee.partner.amount} ${quote.buy.symbol}` : "");
console.log("Proof of Savings:", `https://guihaitrade.com/proof/${hash}`);
return status;
}
swap("BNB", "USDT", "0.01").catch((err) => {
console.error(err);
process.exit(1);
});
报价也能赚钱
curl -s "https://guihaitrade.com/api/quote?sell=BNB&buy=USDT&amount=0.5&taker=0xYourUser&partnerFeeBps=30" \
-H "X-Api-Key: $HOOKLINE_KEY"
# fee.partner = { bps: 30, amount, amountAtomic, recipient: your payout address }或者交给 Agent
{
"mcpServers": {
"hookline": {
"url": "https://guihaitrade.com/api/mcp",
"headers": {
"X-Api-Key": "your_builder_key (optional)"
}
}
}
}In MCP, pass partner_fee_bps to get_quote. More clients in the MCP 文档.
登上案例墙
- 1
告诉我们
你在构建什么、怎么联系你。等待审核期间,你可以先用自己的 API 密钥上线。
- 2
我们审核
每个项目都有真人来看,通常几天内给结果。零成本,也没有任何绑定。
- 3
登墙
你的项目进入 Built on 归海 案例墙,我们会在 X 上公告。
告诉我们你构建了什么
两分钟填完。每个项目我们都会读。