面向开发者 / 应用 API

应用 API

四个第一方服务坐在这条链旁边。它们没有一个是这条链,没有一个有版本号,而且每一个都以自己的方式失败,这正是本分区存在的意义。

这些是什么

这条链的接口是 JSON-RPC。这些页面上的一切,都是某个应用为自己造出来、然后就留在那里可以够到 的东西:一个建在排序器日志流之上的 Postgres 索引、一个持有密钥的进程、一个游戏循环。它们很 方便,它们是第一方的,而它们不是权威。

从它们之一读一次,不等于从链上读一次

这里每一个数字都经过了一个索引器、一个缓存,或者两者。一个停掉的索引器会继续用它最后的 状态作答,而响应里没有任何字段说明这一点;唯一会告诉你的是那些健康路由,而你得去问它们。 如果这个答案要决定钱,就去读链。

A read-only view of what the Pepper indexer has derived from the chain's logs: constant-product pools, concentrated pools, swaps, liquidity events and positions. It reads Postgres rather than the chain, deliberately.

技术栈
Python, standard-library ThreadingHTTPServer, psycopg pool of at most 8 connections, HTTP/1.1
挂载于
/api/ on the Pepper origin

The archive the node deliberately is not. Blocks, mini-blocks, transactions, receipts, logs, call traces, decoded transfers, accounts, tokens, NFTs and the name-service record, all from a Postgres index fed by the sequencer's own log spool.

技术栈
Python, standard-library ThreadingHTTPServer, psycopg pool of at most 12 connections, plus live reads against the node
挂载于
/api/ on the explorer origin

The only first-party service that WRITES to the chain. It holds the faucet operator key and submits the drip on your behalf, which is why the page needs no wallet.

技术栈
Python, standard-library SimpleHTTPRequestHandler serving a static site as well as the API, signing with eth-account
挂载于
its own origin; the home origin re-exposes two of its routes

A WebSocket server for the games, with a small HTTP surface beside it for health and for the figures the site's chrome draws. The socket is the interface; the HTTP routes are a snapshot of it.

技术栈
Node, `ws` in noServer mode behind a plain http server, one event loop for eight game rooms
挂载于
/api/ and /ws/ on the arcade origin

它们在哪里应答

服务基础 URL
浏览器 APIhttps://explorer.picklechain.xyz/api/域名服务站点和工具箱站点也在 /api/ 下挂载了它
Pepper DEX APIhttps://pepper.picklechain.xyz/api/仅限同源;另一个来源上的浏览器调不了它
水龙头https://faucet.picklechain.xyz主站来源重新暴露了 POST /drip 和 GET /faucet-status
Arcadehttps://minigame.picklechain.xyz/api/以及 wss://minigame.picklechain.xyz/ws/<room> 上的 socket

这些服务没有一个有自己的主机名。每一个都是某个前端来源上的一个 /api/ 挂载点, 这让公开的基础地址成为一个 nginx 事实而不是一个服务事实:一次搬动站点的部署会把它的 API 一起 搬走,而里面的路径保持不变。在你自己运行的一套栈上,同样这些服务改在回环地址上应答, 端口由各自那一页点名。

任何地方都没有版本号

这四个里没有 /v1,没有版本请求头,也没有任何弃用策略。仓库里也没有 OpenAPI 文档,没有 JSON Schema,所以一个字段可以在两次部署之间改变形态,而没有任何东西可以对照。 请防御性地读:忽略你不认识的键,也不要因为一个键消失了就失败。

认证

这四个没有一个要认证,而真正要紧的差别,是它们各自在没有认证的情况下能做什么。

  • 浏览器、DEX API 和 Arcade 都不要认证。它们是只读且公开的。浏览器对每一个 POST 都回答 405;DEX API 除 GET 之外没有实现任何动词。
  • 水龙头也不要认证,而它会写到链上。这正是它的配额严格、并且在签任何东西 之前就先预留的全部原因。

Arcade socket 没有任何认证,而那个进程持有一把密钥

它前面没有认证层,也不打算有:代理把升级请求转发过去,仅此而已。保护它的是一次连接的每一个 维度都有界,连接数、来源、帧大小、消息速率、缓冲字节数,而每一次溢出都是丢弃而不是排队。 客户端在那个 socket 上说的任何话都不授权任何事;决定谁可以玩的是那些合约。

从浏览器里调用其中一个

CORS 是逐服务设置的,而且它们并不一致,所以第一件要弄清楚的事,是你那个来源上的页面到底能不能 调用你想调的那一个。

  • DEX API 不发送任何 CORS 头,也没有 OPTIONS 处理器。从浏览器发起的跨源 fetch 会直接失败,而同样的请求从服务器发出却会成功,这正是那种会被赖到网络头上 的 bug。请代理它,或者从后端调它。
  • 浏览器和水龙头各自保留一份允许名单。来自不在名单上的来源的预检请求会被以 403 拒绝,那至少是一个清楚的答案。
  • Arcade 在升级请求上检查 Origin,并在握手之前就以 403 拒绝, 所以那个 socket 是根本不打开,而不是打开之后没了动静。

限制与分页

只有浏览器限制请求速率。其余三个靠一个钳制、一份配额或一个连接上限来代替。

服务限制
Pepper DEX API`limit` is clamped to 1..500 on every list route and defaults to 50. There is no request-rate limit in the service.
Explorer API300 requests per minute per client address, then 429. Request bodies are capped at 600,000 bytes. Live streams are capped at 32 concurrent.
FaucetQuota is reserved before the transaction is signed: 5 a day per address seen, 2 a day per funded address, 1000 a day in total. Request bodies are capped at 4096 bytes.
Arcade server256 sockets in total and 8 per source address, then the upgrade is refused 429. Inbound frames are 4 KiB at most and rate-limited per socket. A socket more than 512 KiB behind is cut.

一份被钳制的列表就是一份悄悄变短的列表

向 DEX API 要一千笔兑换,你拿到五百笔,配上一个 200,而没有任何东西说这个答案 被裁过。向浏览器要两百个区块,你拿到一百个。这两个服务在多数列表路由上都不返回总数,所以 没有一个字段可以拿来和你这一页的长度作比较:唯一说明还有更多的信号,就是你拿到的正好是那个 钳制值。

凡是有分页的地方,用的都是 limit 和 offset,不是游标。这意味着一份 在头部增长的列表会在你翻两页之间挪动:你已经见过的行会再次出现,而你没见过的行会被跳过。对任何 必须完整的东西,请按一个你自己控制的键分页,比如一个区块号、一个哈希,而不是按偏移量。

约定

约定Value
VersioningNone of them is versionedno /v1, no version header, no deprecation policy. A field can change shape between two deployments. Read defensively and pin nothing.
SchemaThere is no OpenAPI documentand no JSON Schema anywhere in the repository. Every shape documented here was read out of a route handler, which is why each record names the line.
Errors{"error": "..."}a human-readable string, occasionally with a second key. There are no error codes and no stable error strings - match on the HTTP status, never on the message.
Cachingcache-control: no-storeon every route of all four services, without exception. Nothing here is safe to cache, and nothing offers you an ETag to revalidate against.
Content typeJSONwith two exceptions: the explorer's logo route returns raw image bytes, and its live route is an event stream.
Unitsnot uniformtoken amounts and wei are DECIMAL STRINGS, not numbers, because they do not survive a double. Mini-block timestamps are in MICROSECONDS. Concentrated-pool swap amounts are SIGNED.

金额是字符串,而且其中有些是带符号的

代币数量、wei 和余额自始至终都以十进制字符串回来,因为它们挺不过一个 double。请用大整数类型 解析它们。在集中流动性池的路由上,这些金额还是带符号的,每一笔兑换都有一条腿是负的,而那就是 这笔交易的方向,所以一个不取绝对值的求和会把一整个市场加成零。

javascript
// The shape of a careful call against any of these: a timeout, a status check
// before the body, and a big-integer parse of anything that looks like money.
const res = await fetch(`${BASE}/pools`, { signal: AbortSignal.timeout(5000) });
if (!res.ok) throw new Error(`pools: ${res.status}`);          // never the message
const { pools } = await res.json();                              // an object, not an array
const reserve0 = BigInt(pools[0].reserve0);                      // a decimal string

当其中一个挂了

这四个各自以不同的方式失败,而其中只有一种失败从外面看起来像失败。

  • DEX API 回答 503 index not ready,发生在数据库连不上、或者索引器从未运行过因而那些表不存在的时候。那是诚实的情形。不诚实的 那一种,是一个已经停掉的索引器:每一条路由都继续用它到达过的状态作答,而只有 /health 上的 lagBlocks 会说出来。
  • 浏览器在节点连不上时继续提供索引,而一个答案里需要实时读取的那些部分, 一个余额、一条域名服务记录、费用路由器的待付余额,会回来是 null 或者干脆缺席,而不是报错。/stats 上的 indexLag 字段是该盯的那个数字。
  • 水龙头回答 502,发生在节点不响应的时候,而那时什么都还没签。一个 503 表示它没钱了,或者那次 滴水 revert 了。
  • Arcade 的 /ready在它连到节点的 socket 断掉时回答 503,或者在它最后施加的那个迷你区块超过五秒之前 时回答 503。改用到达时间来衡量的话,一个卡死的进程会在什么都没动的情况下回答 200。
重试那个状态查询,不要重试那次写入

只有水龙头会写,而它返回的一个 502 意味着什么都没提交,那一个重试是安全的。 交易已经发出去之后的一个 503 不是:那次滴水可能已经落地,而配额预留已经被 回滚了,所以请去链上轮询那份回执,而不是再发一次。

哪些东西记录在别处

  • The node. Chain state, transactions, logs and subscriptions are JSON-RPC and are documented in this reference's own RPC pages, not here.
  • Contracts. What the pools, the faucet and the games actually do on chain - their functions, their events and their revert reasons - is the contract reference.
  • Prices. Several answers here carry a dollar figure or a price snapshot. Those fields come from a layer this page does not own; read its own reference for what the number means, how old it is and when it is absent.