Skip to content

原子交换 ​

BTC ⇄ RGB 原子交换接口的完整参考。所有路径均带 /api/v1 前缀。交换由节点原生交换引擎执行,链上资产与闪电 HTLC 原子结算。

报价与执行流程 ​

一笔交换的典型流程:

  1. Maker 创建报价 — POST /swap/offers(单跳)或 POST /swap/offers/multihop(多跳),返回 swap_string 与 payment_hash。
  2. Taker 解析并接受 — POST /swap/decode 校验报价内容,POST /swap/accept 提交接受。
  3. Maker 执行 — POST /swap/execute,返回后交换进入 InFlight。
  4. 查询状态 — GET /swap/{payment_hash} 轮询,直到 Settled 或 Failed。

maker_gives_rgb 表示 maker 是否付出 RGB:true 为 maker 出 RGB、taker 付 BTC(买入方向);false 为反向(卖出方向)。

创建报价 ​

POST /api/v1/swap/offers ​

创建单跳报价:RGB 腿与 BTC 腿落在同一条通道上。

请求:

json
{
  "maker_gives_rgb": true,
  "contract_id": "contract:...",
  "asset_amount": "100",
  "btc_amount_msat": "3000000",
  "btc_carrier_amount_msat": "3000000",
  "counterparty_node_id": "02def456...",
  "channel_scid": "144927727168913409",
  "expiry_secs": 3600
}

参数说明:

  • maker_gives_rgb(必填):maker 是否付出 RGB
  • contract_id(必填):交换的 RGB 合约 ID
  • asset_amount(必填):RGB 资产数量(原始单位)
  • btc_amount_msat(必填):BTC 对价(毫聪)
  • btc_carrier_amount_msat(必填):承载 RGB 支付的 BTC 载体金额(毫聪)
  • counterparty_node_id(必填):对手方节点公钥
  • channel_scid(必填):交换绑定的通道 short channel ID
  • expiry_secs(必填):报价有效期(秒)

响应:

json
{
  "swap_string": "swap1...",
  "payment_hash": "abc123..."
}

POST /api/v1/swap/offers/multihop ​

创建多跳报价:RGB 腿与 BTC 腿可绑定不同通道,通过 rgb_path / btc_path 描述两段路由。

请求:

json
{
  "rgb_path": [
    { "node_id": "02def456...", "channel_scid": "144927727168913409" }
  ],
  "btc_path": [
    { "node_id": "03abc789...", "channel_scid": "144948000000000000" }
  ],
  "contract_id": "contract:...",
  "asset_amount": "100",
  "btc_amount_msat": "3000000",
  "btc_carrier_amount_msat": "3000000",
  "maker_gives_rgb": true,
  "expiry_secs": 3600
}

参数说明:

  • rgb_path / btc_path:两段路由,每段为节点数组,每项含 node_id(该段终点节点)与 channel_scid。两段名称为历史命名,不代表通道类型:持有 RGB 资产的通道与承载 BTC 对价的通道可能分属不同段
  • 其余字段与单跳报价一致(无 counterparty_node_id / channel_scid,由 path 决定)

响应: 与单跳报价相同(swap_string、payment_hash)。

填法需与方向匹配

多跳报价的两段 node_id / channel_scid 必须与交换方向(maker_gives_rgb)匹配,填错会被节点以 SwapInvalidRoute、InvalidNodeId 等错误拒绝,或使交换停在 Offered。创建后先用 POST /swap/decode 校验报价内容,再提交执行。

解析、接受与执行 ​

POST /api/v1/swap/decode ​

解析 swap_string,返回交易所含的方向、金额、通道与状态。

请求:

json
{
  "swap_string": "swap1..."
}

响应: 一个交换信息对象,字段见下方 交换信息。

POST /api/v1/swap/accept ​

接受一个报价(由 taker 调用)。接受后 maker 才能执行。

请求:

json
{
  "swap_string": "swap1..."
}

响应:

json
{ "ok": true }

POST /api/v1/swap/execute ​

执行交换(由 maker 调用)。

请求:

json
{
  "swap_string": "swap1...",
  "force": false
}

force 可选;为 true 时跳过对端已接受的严格校验,适用于已知对端已接受但本节点尚未观测到的场景。

响应:

json
{
  "ok": true,
  "payment_hash": "abc123...",
  "status": "InFlight"
}

200 仅表示交换已发起,结算需要轮询 GET /swap/{payment_hash}。

交换状态 ​

GET /api/v1/swap/ ​

按支付哈希查询交换信息。

响应:

json
{
  "payment_hash": "abc123...",
  "role": "Maker",
  "status": "Settled",
  "counterparty_node_id": "02def456...",
  "channel_scid": "144927727168913409",
  "contract_id": "contract:...",
  "asset_amount": "100",
  "btc_amount_msat": "3000000",
  "btc_carrier_amount_msat": "3000000",
  "maker_gives_rgb": true,
  "expiry_secs": 3600,
  "created_at_unix_secs": "1704067200",
  "is_multihop": false,
  "last_error": null
}

GET /api/v1/swap/list ​

列出本节点当前的交换记录。响应为交换信息对象列表,字段与上一节相同。

交换信息 ​

字段说明
payment_hash交换的支付哈希,也是状态查询主键
role本节点角色,Maker 或 Taker
status交换状态,见下表
counterparty_node_id对手方节点公钥
channel_scid绑定的通道 short channel ID
contract_idRGB 合约 ID
asset_amountRGB 资产数量
btc_amount_msatBTC 对价(毫聪)
btc_carrier_amount_msatBTC 载体金额(毫聪)
maker_gives_rgbmaker 是否付出 RGB
expiry_secs报价有效期(秒)
created_at_unix_secs创建时间(unix 秒)
is_multihop是否为多跳交换
last_error失败原因(status=Failed 时给出)

状态取值:

  • Offered:报价已创建,等待对端接受
  • Accepted:对端已接受,等待 maker 执行
  • InFlight:交换执行中
  • Settled:交换原子完成
  • Failed:交换失败,原因见 last_error

多跳交换 ​

多跳交换用于两腿无法落在同一条通路上,或需要通过中间节点/通道路由的场景:

  • 使用 POST /swap/offers/multihop 创建,rgb_path 与 btc_path 分别描述 RGB 腿与 BTC 腿的可达通道
  • 每一跳通过闪电 HTLC 原子结算
  • 最终结果:按方向扣除 RGB 或 BTC,收到对价

多跳交换对通道容量与路由更敏感:任一段的可发送容量、通道单笔 HTLC 上限或储备不足都可能导致执行失败(例如 HTLCMaximum、RetriesExhausted)。创建报价前可先用 网络图谱 与 通道列表 核对容量。

错误处理 ​

  • 400:交换参数无效、路由无效或对端未接受
  • 404:报价不存在或已过期
  • 409:交换余额或状态冲突
  • 410:报价已被接受
  • 422:交换校验失败
  • 500:交换执行错误

交换为原子操作:执行失败时通道余额不变。超时或连接中断后应通过 GET /swap/{payment_hash} 查询真实状态,而不是直接重试执行。

示例 ​

创建单跳报价(maker 出 RGB) ​

bash
curl -X POST https://<你的节点域名>/api/v1/swap/offers \
  -H "Authorization: Bearer <节点凭证>" \
  -H "Content-Type: application/json" \
  -d '{
    "maker_gives_rgb": true,
    "contract_id": "contract:...",
    "asset_amount": "100",
    "btc_amount_msat": "3000000",
    "btc_carrier_amount_msat": "3000000",
    "counterparty_node_id": "02def456...",
    "channel_scid": "144927727168913409",
    "expiry_secs": 3600
  }'

接受并执行交换 ​

bash
# Taker 接受
curl -X POST https://<你的节点域名>/api/v1/swap/accept \
  -H "Authorization: Bearer <节点凭证>" \
  -H "Content-Type: application/json" \
  -d '{ "swap_string": "swap1..." }'

# Maker 执行
curl -X POST https://<你的节点域名>/api/v1/swap/execute \
  -H "Authorization: Bearer <节点凭证>" \
  -H "Content-Type: application/json" \
  -d '{ "swap_string": "swap1...", "force": false }'

查询交换状态 ​

bash
curl -X GET https://<你的节点域名>/api/v1/swap/abc123... \
  -H "Authorization: Bearer <节点凭证>"

交易并保护您的 RGB 资产 | 释放 RGB 协议的全部潜力