原子交换
BTC ⇄ RGB 原子交换接口的完整参考。所有路径均带 /api/v1 前缀。交换由节点原生交换引擎执行,链上资产与闪电 HTLC 原子结算。
报价与执行流程
一笔交换的典型流程:
- Maker 创建报价 —
POST /swap/offers(单跳)或POST /swap/offers/multihop(多跳),返回swap_string与payment_hash。 - Taker 解析并接受 —
POST /swap/decode校验报价内容,POST /swap/accept提交接受。 - Maker 执行 —
POST /swap/execute,返回后交换进入InFlight。 - 查询状态 —
GET /swap/{payment_hash}轮询,直到Settled或Failed。
maker_gives_rgb 表示 maker 是否付出 RGB:true 为 maker 出 RGB、taker 付 BTC(买入方向);false 为反向(卖出方向)。
创建报价
POST /api/v1/swap/offers
创建单跳报价:RGB 腿与 BTC 腿落在同一条通道上。
请求:
{
"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 是否付出 RGBcontract_id(必填):交换的 RGB 合约 IDasset_amount(必填):RGB 资产数量(原始单位)btc_amount_msat(必填):BTC 对价(毫聪)btc_carrier_amount_msat(必填):承载 RGB 支付的 BTC 载体金额(毫聪)counterparty_node_id(必填):对手方节点公钥channel_scid(必填):交换绑定的通道 short channel IDexpiry_secs(必填):报价有效期(秒)
响应:
{
"swap_string": "swap1...",
"payment_hash": "abc123..."
}POST /api/v1/swap/offers/multihop
创建多跳报价:RGB 腿与 BTC 腿可绑定不同通道,通过 rgb_path / btc_path 描述两段路由。
请求:
{
"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,返回交易所含的方向、金额、通道与状态。
请求:
{
"swap_string": "swap1..."
}响应: 一个交换信息对象,字段见下方 交换信息。
POST /api/v1/swap/accept
接受一个报价(由 taker 调用)。接受后 maker 才能执行。
请求:
{
"swap_string": "swap1..."
}响应:
{ "ok": true }POST /api/v1/swap/execute
执行交换(由 maker 调用)。
请求:
{
"swap_string": "swap1...",
"force": false
}force 可选;为 true 时跳过对端已接受的严格校验,适用于已知对端已接受但本节点尚未观测到的场景。
响应:
{
"ok": true,
"payment_hash": "abc123...",
"status": "InFlight"
}200 仅表示交换已发起,结算需要轮询 GET /swap/{payment_hash}。
交换状态
GET /api/v1/swap/
按支付哈希查询交换信息。
响应:
{
"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_id | RGB 合约 ID |
asset_amount | RGB 资产数量 |
btc_amount_msat | BTC 对价(毫聪) |
btc_carrier_amount_msat | BTC 载体金额(毫聪) |
maker_gives_rgb | maker 是否付出 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)
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
}'接受并执行交换
# 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 }'查询交换状态
curl -X GET https://<你的节点域名>/api/v1/swap/abc123... \
-H "Authorization: Bearer <节点凭证>"