rbrc

API

这个网站知道的一切,都可以通过普通 HTTP 读取和写入。你可以用它搭建自己的铸造页面、机器人、图表,或者一个完整的同类网站。

基础地址https://scan.rbrc20.xyzJSON · 无需密钥

本页目录

基础地址与限制

基础地址是 https://scan.rbrc20.xyz,所有响应都是 JSON。不需要密钥,也不需要注册:读取完全开放,唯一的写入接口只接受交易哈希,并在相信任何内容之前先到链上核实。你无法通过请求把虚假内容写进索引,只能让它去查看链上真实存在的东西。

铭文大小
8,192 字节
收录前的区块确认数
3 个区块
上报时限
10 分钟
上报频率
每个 IP 每分钟 20 次
列表每页
最多 200 行

写入流程

索引器不扫描区块。一条铭文要通过上报才会被收录:你自己在链上写入,等待 3 个区块,然后提交交易哈希。服务器会从链上读取这笔交易,记录链上的实际内容,而不是你声称的内容。所以无论从哪个网站或脚本写入,流程都是三步:

  1. 生成 calldata:使用 /encode,或者自己把 data: URI 编码为十六进制。
  2. 用你自己的钱包签名,把它作为一笔发给你自己地址金额为 0 的交易发出。这个服务从不签名,也从不接触私钥。
  3. 等待 3 个区块,并在交易所在区块的时间之后 10 分钟内,用哈希调用 POST /writings

10 分钟规则

一条铭文只有在写入后 10 分钟内上报才会被计入。时间从它所在区块的时间戳开始计算,与服务器核验上报时的时钟比较。超过时限的上报会被永久拒绝。

原因是规则按链上顺序重放铭文。如果没有时限,一条被扣留、事后才上报的铭文会被重放到之后写入的所有内容前面。卖家可以先写入一笔转账但暂不上报,再挂单出售同一批代币,收到付款后再上报那笔转账,让买家的购买无法转移任何代币。用同样方式扣留的更早的部署,也可以抢走别人已经在铸造的代号。任一时刻过去 10 分钟后,就不会再有更早的铭文被加入,那一时刻之前的记录便已确定。

在这条规则出现之前收录的铭文没有保存区块时间,它们的 "blockTime"null,视为已确定。

GET /encode

把文字转换为钱包可以签名的交易字段。不是 data: URI 的内容会被包装成 URI。

curl "https://scan.rbrc20.xyz/encode?text=hello%20chain"

{
  "value": "0x0",
  "data": "0x646174613a2c68656c6c6f20636861696e",
  "text": "data:,hello chain",
  "bytes": 17,
  "note": "send this to your own address with value 0. this service never signs."
}

响应中特意没有 to:铭文是发给你自己的交易,所以由你自己填写地址。如果服务指定一个地址,就给了错误地址混进来的机会。

POST /writings

上报一条已经在链上的铭文。请求体只有一个哈希。已经收录的哈希会立即返回 "already": true,即使已经过了 10 分钟,所以重复上报总是安全的。

curl -X POST "https://scan.rbrc20.xyz/writings" \
  -H "content-type: application/json" \
  -d '{"hash":"0xdf88b6091854894f716e8ce7e88e230b14fb971e369c57ed2b1fdb0404393b03"}'

{
  "recorded": true,
  "already": true,
  "writing": {
      "txHash": "0xdf88b6091854894f716e8ce7e88e230b14fb971e369c57ed2b1fdb0404393b03",
      "block": 51544509, "txIndex": 5,
      "from": "0x8648…1cc5", "to": "0x8648…1cc5",
      "media": "text/plain", "protocol": "rbrc",
      "body": "{\"p\":\"rbrc\",\"op\":\"deploy\",\"tick\":\"hood\",\"max\":\"21000000\",\"lim\":\"1000\"}",
      "bytes": 70, "value": "0", "blockTime": null
  }
}

这是一条真实收录的铭文,即 hood 的部署。它在保存区块时间之前就已收录,所以 blockTime 为 null。

bodydata: URI 逗号之后的内容,不含 data:, 前缀,bytes 只计算这部分的字节数。media 是 URI 头部的媒体类型,头部为空时视为 text/plain

首次上报的响应格式相同,只是没有 already。拒绝时返回 422 和一段文字原因,原因只有以下几种:找不到该哈希的交易、尚未打包进区块、区块太新(稍后重试)、交易在链上执行失败、不是发给自己地址的交易、附带了金额、没有 data: URI、超过 8,192 字节、包含控制字符、上报太晚,或者无法读取区块时间(稍后重试)。唯一的格式例外是购买:购买要付款给卖家,所以购买铭文必须发给另一个地址,并且必须附带金额。

上报太晚时的拒绝原文如下(原因文字为英文):

{ "error": "that inscription was written more than ten minutes ago. an inscription counts only if it is reported within ten minutes of being written" }

"that transaction is not in a block yet"(交易尚未打包进区块)、"that block is too new"(区块太新)和 "could not read when that block was made"(无法读取区块时间)值得重试;发送后最初几秒内,索引器的节点还没看到交易时出现的 "no transaction with that hash"(找不到交易)也一样。无法读取区块时间是读取链失败,不是对交易的判定,所以请在 10 分钟内尽早重试。其他拒绝,包括上报太晚,无论重试多少次都不会改变。

GET /writings

所有人写入的全部内容,按从新到旧排列。可以用 addressprotocol 筛选,用 limit(默认 50,最多 200)和上一页 next 字段中的 before 游标翻页。

curl "https://scan.rbrc20.xyz/writings?protocol=rbrc&limit=2"

{
  "count": 2,
  "next": "61900398.0",
  "writings": [ { "txHash": "0x…", "block": 61900412, "txIndex": 1, "from": "0x…",
                    "protocol": "rbrc", "body": "{\"p\":\"rbrc\",\"op\":\"mint\",…}",
                    "blockTime": 1789312345, … }, … ]
}

要从头重放,请使用 order=asc,并用 after 游标向后翻页。每一页包含游标之后的行,从旧到新排列,next 仍是本页最后一行的游标。

curl "https://scan.rbrc20.xyz/writings?protocol=rbrc&order=asc&limit=200"
curl "https://scan.rbrc20.xyz/writings?protocol=rbrc&order=asc&limit=200&after=51544509.3"

按哈希读取单条铭文:GET /writing/0x…。游标是 block.txIndex 而不是偏移量,所以即使新铭文不断写入,翻页也不会跳过或重复。

GET /tokens

rbrc 协议标识下部署的全部代号。sort=hot(铸造最多,默认)或 sort=new。传入 wallet=0x… 时,每一行还会带上 yourMintsmintsAllowed,这样铸造按钮在显示之前就能知道是否可以点击。

curl "https://scan.rbrc20.xyz/tokens?sort=hot"

{
  "count": 1, "reportWindowSeconds": 600, "now": 1789312900,
  "tokens": [ {
      "tick": "name", "max": "21000000", "lim": "1000",
      "minted": "15000", "percent": 0.07, "soldOut": false,
      "mints": 15, "holders": 3,
      "deployer": "0x…", "block": 61900001, "txHash": "0x…",
      "blockTime": 1789312300, "mintableAt": 1789312900, "settling": false
  } ]
}

blockTime 是部署所在区块的时间,mintableAt 是它加上上报时限,settling 只在 now 早于 mintableAt 时为 true。对于保存区块时间之前收录的部署,这两个字段为 null,settling 为 false。代币处于等待期时,这个网站不会提供铸造:同一代号更早的部署仍可能被上报,那时现在写入的铸造就会属于那个部署。

GET /token/:tick

单个代号,字段相同,只有 holders 不同:这里是前 100 名持有人的列表,而不是 /tokens 给出的数量。没有部署过的代号返回 404{"error": "no such ticker"}。中文代号放进路径时按 UTF-8 百分号编码一次:/token/%E9%BE%99

curl "https://scan.rbrc20.xyz/token/name"

{
  "tick": "name", "max": "21000000", "lim": "1000", "minted": "15000",
  "percent": 0.07, "soldOut": false, "mints": 15,
  "deployer": "0x…", "block": 61900001, "txHash": "0x…",
  "blockTime": 1789312300, "mintableAt": 1789312900, "settling": false,
  "holders": [ { "address": "0x…", "amount": "5000" }, … ]
}

GET /market

在售挂单,按代号分组,每组按单价从低到高排列,并带有该组的地板价。?tick=name 只看一个代号;?flat=1 返回一个不分组的 listings 列表。

curl "https://scan.rbrc20.xyz/market?tick=name"

{
  "tickers": 1, "listings": 3, "reportWindowSeconds": 600, "now": 1789312900,
  "groups": [ {
      "tick": "name", "floor": "1800000000000", "listings": 3, "forSale": "4000",
      "minted": "15000", "holders": 3,
      "rows": [ { "id": "0x…", "amt": "1000", "price": "1800000000000000",
                  "unit": "1800000000000", "seller": "0x…", "block": 61900012,
                  "blockTime": 1789312500, "buyableAt": 1789313100, "settling": true }, … ]
  } ]
}

价格单位是 wei。id 是挂单铭文的交易哈希,购买时就是指明这个 id。buyableAtsettling 的含义与代币字段相同:挂单处于等待期时,卖家仍可能上报一笔在挂单之前写入、会清空其余额的转账,所以在 buyableAt 之前这个网站不会提供购买。

GET /balances/:addr

一个地址在所有代号上的持有情况,包括已用于在售挂单的数量,以及已使用的铸造次数。

curl "https://scan.rbrc20.xyz/balances/0xyouraddress"

{
  "address": "0xyouraddress",
  "balances": [ { "tick": "name", "amount": "5000", "listed": "1000", "free": "4000",
                    "lim": "1000", "max": "21000000", "mintsUsed": 5, "mintsAllowed": 20 } ]
}

GET /activity

事件动态,从新到旧:规则接受的每一次部署、铸造、转账、挂单、取消挂单和购买。可以用 tickaddress 筛选,用 limit(最多 200)限制数量。

curl "https://scan.rbrc20.xyz/activity?tick=name&limit=1"

{
  "events": [ { "kind": "buy", "tick": "name", "who": "0x…", "seller": "0x…",
                  "amt": "1000", "price": "1800000000000000", "block": 61900031, "txHash": "0x…" } ]
}

GET /health

索引器能否访问链,以及已经收录了多少内容。

curl "https://scan.rbrc20.xyz/health"

{
  "ok": true, "protocol": "rbrc", "head": 61900950, "rpcOk": true,
  "writings": 74, "lastWritingBlock": 61900412,
  "reportWindowSeconds": 600, "rulesV1Block": 61834151, "rulesV2Block": null
}

无法读取链的最新区块时,ok 为 false。这期间新的上报无法核验,铭文的上报时限可能因此耗尽;已收录内容的读取不受影响。rulesV2Block 是规则 v2 开始生效的区块,v2 未启用时为 null,目前生产环境就是这样。早于 v2 的索引器不返回这个字段,同样按 null 处理。

操作

代币规则由读取者执行,不在合约里。一个操作是 data: URI 中的紧凑 JSON 对象,协议标识为 rbrc,作为发给自己地址、金额为 0 的交易写入。购买除外,它写在付款交易本身上。数量都是字符串。

deploy    data:,{"p":"rbrc","op":"deploy","tick":"name","max":"21000000","lim":"1000"}
mint      data:,{"p":"rbrc","op":"mint","tick":"name","amt":"1000"}
transfer  data:,{"p":"rbrc","op":"transfer","tick":"name","amt":"1000","to":"0x…"}
list      data:,{"p":"rbrc","op":"list","tick":"name","amt":"1000","price":"1800000000000000"}
cancel    data:,{"p":"rbrc","op":"cancel","id":"0x…listing tx hash…"}
buy       data:,{"p":"rbrc","op":"buy","id":"0x…listing tx hash…"}   (sent to the seller, value >= price)

一条铭文要被计入必须满足的全部规则:代号为 1 到 16 个 a-z0-9- 字符(自区块 61,834,151 起,先把 ASCII 字母 A-Z 转为小写,其他字符不做任何改变),使用不符合这一格式的代号的铭文会被忽略。规则 v2 启用后会增加中文代号,见下文。同一代号只有第一次部署有效,之后的部署都会被忽略。铸造数量必须正好等于 lim,超过 max 会被拒绝,每个钱包每个代号最多铸造 20 次。转账和挂单只能以完整的铸造单位进行,并且只能使用未用于在售挂单的余额。取消挂单必须由卖家发出。取消后挂单立即下架,但自规则 v1 起,数量在取消后仍锁定 10 分钟(规则 v2 起为 20 分钟),这段时间内打包的购买仍会成交,因为发出购买的人还看不到取消。购买只有在付款确实发给了卖家、并且确实足额时才会计入,这两点都从链上读取,所以任何人都无法靠请求拿走代币。

规则 v1,自区块 61,834,151 起

区块 61,834,151 及之后写入的铭文还需满足以下规则。该区块之前写入的铭文按原来的方式读取,所以已有的余额都不会改变。

  • 代号中的 ASCII 字母 A-Z 会在检查之前转为小写,所以用大写写入的代号和用小写写入的是同一个代号。其他字符都不改变:Unicode 小写转换会把开尔文符号变成 k,索引器不会这样做。
  • 所有数量(maxlimamtprice)都必须是规范的正整数:只有数字,不以 0 开头,不为 0,最多 30 位。
  • 部署要求 lim 不大于 max,并且 max 能被 lim 整除,这样总量总能铸造到最后一个单位。
  • 挂单价格必须大于 0。
  • 读取购买时,协议标识不区分大小写。
  • 取消挂单后,挂单的数量在取消所在区块之后仍锁定 10 分钟,这段时间内打包的购买仍会成交。

违反规则的铭文不会在任何地方报错:它会作为铭文被收录,只是不会改变任何余额。

规则 v2:中文代号

规则 v2 已经写好,但处于关闭状态。它从 /healthrulesV2Block 指定的区块开始生效,目前生产环境中该值为 null,所以下面的内容暂不计入。这个区块会在产出之前确定,确定之后不再改变。该区块之前写入的铭文永远保持 v1 的含义:之前写入的中文部署会被忽略,也不会占用代号。

  • 代号要么是 v1 的 ASCII 形式,要么是 1 到 8 个字符、每个字符都在 U+4E00U+9FA5 之间,即 Unicode 1.1 的 CJK 统一汉字基本区。其他字符都不允许,两种形式也不能混用。
  • 中文形式按原样使用:不去除空格,不转换大小写,不做 Unicode 规范化,也不合并异体字或形近字。对任何代号的唯一改变,就是 ASCII 字母 A-Z 转为小写。
  • 只有字符的码位完全相同,两个代号才是同一个。简体和繁体,例如“”和“”,是两个不同的代号,各自以第一次部署为准。
  • 代号在 JSON 解析之后读取,所以 "\u9f99""龙" 是同一个代号。请直接写入汉字本身。
  • 数量、部署限制、挂单价格、上报时限和每个钱包的铸造上限都不变。唯一的变化是取消挂单:自 v2 起,取消后数量锁定 20 分钟(两个上报时限),这段时间内打包的购买仍会成交。

只有当索引器的 head 达到 rulesV2Block 之后,这个网站才会提供中文代号的部署或铸造;当一个代号与已部署的代号只有简繁或形近字差别时,页面会给出提示。这个提示只是建议,规则不会依据它做任何判断。

同一挂单的两笔购买

一个挂单只能被购买一次。如果同一个挂单有两笔购买上链,后一笔付款仍会到达卖家,因为它是普通的 ETH 转账,任何规则都无法阻止,但它不会转移任何代币。在取消挂单的锁定期结束后才上链的购买也是如此(锁定期为 10 分钟,规则 v2 起为 20 分钟)。没有退款机制。所以请在付款前确认挂单仍然有效,也不要购买可能有别人同时在买的挂单。

购买上链后的 10 分钟内仍可能失效。“第一笔”按链上顺序计算,而不是按上报到达的顺序,所以同一挂单一笔更早但尚未上报的购买,可以在它自己的 10 分钟内被上报并拿到挂单。这时你的购买不会转移任何代币,你的 ETH 已经转给卖家,不会退款。

核查索引

每条收录的铭文都注明了它的交易,所以每一条都可以在链上核查:发送方、接收方、金额和完整的 calldata 都可以对比。GET /writings?order=asc 按链上顺序提供全部收录内容,任何人都可以在上面重新执行规则,看是否得到与这个 API 相同的数字。

仅凭链本身无法知道哪些铭文是在时限内上报的。这份列表是索引器的记录,所以每一行都保留了交易和区块时间,让你需要信任的部分尽可能少,也尽可能可以核查。

回到顶部