跳到主要内容

买入与卖出

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

Pons
Uniswap v4

一个接口覆盖 Robinhood 链上所有 Pons 代币,不管哪一代发的、现在在哪:

  • Pons v2:内盘联合曲线上,毕业后在它的 Uniswap v4 池子里。
  • Pons v1:发射进的那个 Uniswap V3 池子里。
  • Robinhood 链上任何有 Uniswap 池子的代币:代币化股票(NVDA、TSLA、USDG……)和直接发进池子的代币。

你只传代币地址,API 自动判断。返回里的 protocolPONS_V2 / PONS_V1 / UNISWAP)和 venuepons_curveuniswap_v4uniswap_v3)会告诉你结果。

你需要什么

示例

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

// ─── 改这三行 ────────────────────────────────────────
const PRIVATE_KEY = "0xYOUR_PRIVATE_KEY";
const TOKEN = "0xTHE_TOKEN_ADDRESS";
const AMOUNT = "0.01"; // 买入:要花的 ETH。卖出:"1000" 个代币,或 "100%"
const ACTION = "buy"; // "buy" 或 "sell"
const TO_ETH = true; // 卖出以 USDG/NVDA 等计价的代币时,
// 顺便把所得换回 ETH
const SLIPPAGE = 5; // 滑点百分比,允许价格对你不利的幅度
// ──────────────────────────────────────────────────────

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

const res = await fetch("https://api.shrine.trade/rh/api/local-trade", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
action: ACTION,
token: TOKEN,
amount: AMOUNT,
toEth: TO_ETH,
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.quoteAsset.symbol);
if (data.quoteSwap) {
console.log("先用", data.quoteSwap.ethInMaxFormatted, "ETH 买入",
data.quoteSwap.quoteOutFormatted, data.quoteAsset.symbol);
}

// 本地签名,把签好的交易交给 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/rh/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.ethInFormatted ?? data.amountInFormatted} ETH`);
} else if (data.toEth) {
console.log(`卖出 ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} 得到 ${data.toEth.ethOutFormatted} ETH`);
} else {
console.log(`卖出 ${data.amountInFormatted} ${data.name} (${data.symbol}) ${data.token} 得到 ${data.quote.expectedOutFormatted} ${data.quoteAsset.symbol}`);
}
}

main();

保存为 trade.js,然后:

npm install ethers
node trade.js

API 返回什么,脚本就按顺序发什么。通常是一笔交易;第一次卖出,或者买入以 USDG、NVDA 等资产计价的代币,前面可能多一笔一次性的授权。

交易有防夹子保护:Robinhood 链没有公开内存池,排序器排序之前没人能看到你的交易;链上 minOut 保证成交不会比滑点允许的更差。

别在发射的头几秒买

Pons 有狙击保护,发射后约 3 秒内的买入会被征税。

卖出

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

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

以 USDG、NVDA 等计价的代币

很多 Pons 新币不是以 ETH 计价,而是 Robinhood 链上的某个代币化资产。脚本不用改:买入时 AMOUNT 永远是 ETH。对一个以 USDG 计价的代币,"0.001" 的意思是"花 0.001 ETH",API 算出对应多少 USDG(amountIn,单位见 quoteAsset)交给曲线或池子。钱包里已有足够 USDG 就直接用;不够的话交易序列会以一笔用 ETH 买入差额的兑换开头,quoteSwap 说明它的成本。返回里的 ethIn 是你要求花的 ETH。

卖出时得到的是那个资产。加上 toEth: true(脚本里的 TO_ETH)所得会再换成 ETH:毕业代币在同一笔交易里完成,内盘代币则追加一笔按保证最小值执行的兑换。返回里的 toEth 说明最终得到多少 ETH、经过哪些池子。

完整列表见 创建代币

出错了怎么办

错误怎么办
insufficient_funds往钱包充 ETH:交易金额,再加一点 Gas。
insufficient_balance卖出数量超过持仓。试试 "100%"
token_not_found不是 Pons 代币。确认填的是代币,不是池子。
slippage_exceeded价格动了。调高 SLIPPAGE(百分比,默认 5)再试。
graduating代币正在迁移到 Uniswap 池子。等一分钟再试。

完整列表见 错误

发送

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

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

statuslanded(已上链)、reverted(已回滚)或 pending(未等待,或 45 秒内未打包)。发币交易上链后还会带 tokencurve,从工厂事件里读出。

请求与返回

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

请求

字段
action"buy""sell"
token地址Pons 代币。
amount十进制字符串买入:要花的 ETH,与代币计价资产无关。卖出:代币数量("1000")或持仓百分比("50%""100%")。
from地址你的钱包。
slippage数字,可选百分比,默认 5
toEth布尔,可选仅卖出、且代币以 ERC-20 计价时:把所得再换成 ETH。

返回:一个真实的例子,用 0.001 ETH 买入一个以 RDDT 计价的代币:

{
"action": "buy",
"token": "0x77df8B452670deb3DA51B367CD58044422dcE4b0",
"name": "Honest Work",
"symbol": "HONEST",
"curve": "0x07365E838a3f62675b81b3438137824F4B03457e",
"phase": "NotGraduated",
"venue": "pons_curve",
"amountIn": "14171692423151839",
"amountInFormatted": "0.014171692423151839",
"quoteAsset": {
"address": "0x05b37Fb53A299a1b874A619e1c4C404D52C36F4C",
"symbol": "RDDT",
"decimals": 18,
"isNative": false
},
"quote": {
"expectedOut": "819167564794497226305697",
"expectedOutFormatted": "819167.564794497226305697",
"minOut": "778209186554772364990412",
"curveFeeBps": 100,
"creatorTaxBps": 0,
"snipeTaxBps": 0,
"shrineFeeBps": 50,
"slippagePct": 5.0
},
"ethIn": "1000000000000000",
"ethInFormatted": "0.001",
"txs": [
{
"to": "0x05b37Fb53A299a1b874A619e1c4C404D52C36F4C",
"data": "0x\u2026",
"value": "0",
"gas": 80000,
"maxFeePerGas": "580242501",
"maxPriorityFeePerGas": "1",
"nonce": 5,
"chainId": 4663,
"type": 2,
"description": "approve_quote"
},
{
"to": "0xEc20E594D28a17511264dc73a84cd4AA957B0ABc",
"data": "0x\u2026",
"value": "0",
"gas": 400000,
"maxFeePerGas": "580242501",
"maxPriorityFeePerGas": "1",
"nonce": 6,
"chainId": 4663,
"type": 2,
"description": "buy"
}
]
}
  • txs:按此顺序签名并发送。valuemaxFeePerGasmaxPriorityFeePerGas 是以 wei 计的十进制字符串,其余是数字。description 标明每笔交易:buysell,一次性的 approve / approve_quote(曲线)或 approve_permit2 / approve_router(Uniswap),buy_quote_with_eth(买入前的兑换),convert_to_eth(内盘卖出后的兑换)。
  • name / symbol:代币自己的名称和符号,方便脚本记录交易了什么。
  • protocolPONS_V2PONS_V1venue:v2 代币在内盘时为 pons_curve,毕业后为 uniswap_v4,所有 v1 代币为 uniswap_v3。请求在所有情况下都一样。v1 代币永远以 ETH 计价,所以 toEth 和计价资产兑换不适用。
  • quoteAsset:交易的结算资产,ETH 或代币的计价资产。decimals 不一定是 18。
  • amountIn:曲线或池子收到的数量,以 quoteAsset 计。买入以 ERC-20 计价的代币时,ethIn 是你要求的 ETH,amountIn 是它买到的资产数量。
  • quote.expectedOut:你应到手的数量;minOut 已扣滑点并由链上强制执行。基础单位,*Formatted 字段是可读数字。
  • quote 里的费用:curveFeeBpscreatorTaxBps 是 Pons 的,shrineFeeBps 是我们的(50 = 0.5%),snipeTaxBps 是 Pons 此刻对你钱包的开盘税。
  • quoteSwap:仅当钱包缺计价资产、前面加了一笔兑换时出现:买到的 quoteOut、报价的 ethIn、携带的 ethInMax(未用完退回)、经过的池子 route
  • toEth:仅当卖出带 toEth: true 时出现:扣除我们费用后的 ethOut、链上强制的 ethOutMin、经过的池子 route。毕业代币在同一笔交易里完成,内盘代币追加一笔 convert_to_eth