# Alkanes 代币上交易所技术集成指南(Diesel / Methane / frBTC / dxBTC)-交易所必读
目标:使传统中心化交易所能“安全、正确、高性能”地支持 Alkanes 上的代币充值/提币/内账/撮合。
一、总体架构(高层)
Bitcoin Core 全节点(带 txindex=1)
Alkanes Indexer:解析链上 OP_RETURN / protorunes 格式、维护代币状态(token id、持仓 UTXO、转账记录)
Deposit Service:对外暴露充值/地址管理 API,接收 indexer 事件进行入账
Withdrawal Service:负责 UTXO 选择、构造 Alkanes 合约交易(OP_RETURN)、PSBT 签名、广播、回执确认
Hot Wallet / Cold Wallet 系统(含分层签名/硬件)
风控与监控层(确认阈值、异常检测、审计)
DB(Postgres/ClickHouse)保存代币 ledger、UTXO、tx metadata、audit logs
流程图(文字版):
User → 发含 Alkanes 资产的 BTC tx → Bitcoin P2P → Indexer 解析 → Deposit Service 入账(N 确认)→ 内部撮合/可交易
User Withdraw → Withdrawal API → Withdrawal Service 构造 Alkanes TX (OP_RETURN) → Hot wallet 签名 → 广播 → indexer 确认 → 出账完成
二、Indexers 设计(关键、必须内部实现或用官方 indexer)
功能要求(必须)
实时/重试式扫描 mempool & blocks,解析 OP_RETURN payload
能识别:
Token 创建(mint / deployment)事件
Transfer(转账)事件(UTXO -> UTXO 的代币变更)
Burn / Redeem / 扩展(协议定义的其它状态)
按 UTXO 精确映射“哪一个账户持有多少 token 单位”
提供快照/回滚(处理 chain reorg)
支持 query:getBalance(address), getUTXOs(address), getTokenInfo(tokenId)
提供 webhooks 或 push queue(给 Deposit Service)
数据模型(示例 Postgres schema)
-- tokens
CREATE TABLE tokens (
token_id TEXT PRIMARY KEY,
name TEXT,
symbol TEXT,
decimals INT,
total_supply NUMERIC,
metadata JSONB,
created_at TIMESTAMP
);
-- utxos with token allocation
CREATE TABLE utxos (
outpoint TEXT PRIMARY KEY, -- txid:vout
txid TEXT,
vout INT,
address TEXT,
value_sats BIGINT,
token_id TEXT,
token_amount NUMERIC,
block_height INT,
spent BOOLEAN DEFAULT false,
spent_by TEXT, -- txid spending it
created_at TIMESTAMP
);
-- token transfers
CREATE TABLE token_transfers (
id BIGSERIAL PRIMARY KEY,
token_id TEXT,
txid TEXT,
from_outpoint TEXT,
to_outpoint TEXT,
amount NUMERIC,
block_height INT,
confirmed BOOLEAN,
created_at TIMESTAMP
);
Indexer 算法要点
用 Bitcoin Core RPC (getrawmempool, getrawtransaction, getblock) 或 ZMQ 订阅新 tx/block。
对新 TX:解析输出脚本,检测 OP_RETURN,按 Alkanes 协议 decode payload(注意:实际 decode 需按 Alkanes 规范实现 —— 不要硬编码)。
对于每个被识别的 token 转账事件:更新 utxos、插入 token_transfers、触发 Deposit webhook(若收款地址属于交易所)。
处理 reorg:在区块回滚时 revert 影响的 utxos 与内账(使用 block_height txid 覆盖)。
三、OP_RETURN / 协议消息(占位符 & 注意)
关键点:我不会在这里伪造 Alkanes 的二进制格式;务必用 Alkanes 官方协议规范(或 SDK)来做最终编码/解析。下面给出“格式化接入点”和示例占位符,工程可直接替换为官方编码函数。
OP_RETURN payload 应由官方 SDK 生成/解析(例如 alkanes-sdk.encodeTransfer(params) / alkanes-sdk.decodeOpReturn(payload))。
在 withdrawal 构建中,不要手动拼 bytes 除非你已完全掌握规范;优先使用官方 SDK 的 buildTx() / createContractCall() 等方法。
示例伪格式(仅指示字段,不是实际 bytes):
OP_RETURN:
{
protocol: "alkanes",
version: 1,
action: "transfer", // or mint, burn, redeem, etc
token_id: "<token-id>",
amount: "<decimal-string>",
dest_address: "<btc-address>",
extra: { ... } // metadata / fee hints
}
实现要求:Indexer 使用官方 decode;Withdrawal Service 使用官方 encode。
四、充值(Deposit)实现细节
地址策略
给每个用户分配唯一 BTC 地址(建议每次提现/充值都生成新地址,或使用 HD key 并管理 UTXO 隔离)。
地址后端由 Deposit Service 管理,indexer 只负责监听并回调。
入账确认策略(建议)
对于带 Alkanes 代币的充值,默认等待 N_confirmations:
内部可交易:N = 2(可调整)
对外提现/大户入账:N = 6(合规/风控)
在 indexer 报告新 transfer 时:记录 pending_confirmations,直到达到阈值再做 credit。
Deposit Service 接口(示例)
Webhook from indexer → POST /api/deposit JSON:
{
"txid": "abcd...",
"outpoint": "abcd...:1",
"address": "bc1q...",
"token_id": "diesel-01",
"amount": "12345.678",
"sats": 50000,
"block_height": 100000,
"confirmations": 3
}
Deposit handler:
验证 outpoint 属于交易所地址池(address ownership)
确认非重复(idempotency check)
将余额写入内账(pending/available 状态)并记录 audit log
五、提币(Withdrawal)实现细节(关键难点)
要求
能构造有效的 Alkanes 转账 TX:输入 UTXO(含 token)→ 输出 UTXO(接收地址) OP_RETURN payload 表示 token transfer → 可能有找零输出(含 token 或普通 BTC)
管理 UTXO:避免把多个用户的 token UTXO 混到一起(或在混合时采取明确的 token 分配规则)
支持 PSBT 签名(cold wallet/workflow)
Withdrawal Service 工作流(简化)
用户下单提币(API) → 风控检查(额度、KYC)
Withdrawal Service 调用 UTXO Selection 算法,选择合适的 utxos(包含 token)
使用 Alkanes SDK 构建交易(返回 PSBT 或 raw tx hex)
在 Hot Wallet 签名(或导出 PSBT 给 Cold Wallet 签名)
广播 tx → indexer 追踪 → 完成确认后标记出账成功
UTXO 选择算法(目标:最少输入、保持合规、避免 utxo 污染)
下面给出一个可直接使用的实现(JavaScript),这是工程可马上植入的参考版。
// utxoSelector.js (node)
function selectUtxosForTokenWithdrawal(utxos, requiredTokenAmount, requiredBtcFeeSats) {
// utxos: [{outpoint, value_sats, token_amount, token_id, isLocked}]
// greedy: choose minimum number of utxos that cover token_amount; then ensure BTC fee covered
const tokenUtxos = utxos.filter(u => u.token_amount > 0).sort((a,b) => b.token_amount - a.token_amount);
const result = [];
let tokenSum = 0;
for (const u of tokenUtxos) {
if (u.isLocked) continue;
result.push(u);
tokenSum = Number(u.token_amount);
if (tokenSum >= requiredTokenAmount) break;
}
if (tokenSum < requiredTokenAmount) throw new Error("INSUFFICIENT_TOKEN_UTXOS");
// Now ensure BTC fee coverage (and change output)
// compute total sats in selected utxos
let totalSats = result.reduce((s,u)=>s u.value_sats,0);
// estimate tx size: inputs * 148 outputs * 34 10 (rough)
const estSize = result.length * 148 3 * 34 10; // 3 outputs: recipient, change, op_return (approx)
const estFee = Math.ceil(estSize * (requiredBtcFeeSats)); // feeRate in sats/vByte pass as requiredBtcFeeSats
if (totalSats < estFee 1000) {
// try to add pure BTC utxos to cover fee
const btcOnly = utxos.filter(u=>u.token_amount===0 && !u.isLocked).sort((a,b)=>b.value_sats-a.value_sats);
for (const b of btcOnly) {
result.push(b);
totalSats = b.value_sats;
if (totalSats >= estFee 1000) break;
}
}
// final check
if (totalSats < estFee 1000) throw new Error("INSUFFICIENT_BTC_FOR_FEE");
return { selectedUtxos: result, estFee };
}
构造交易(PSBT)示例(TypeScript bitcoinjs-lib placeholder Alkanes SDK)
注意:alkanesSdk.buildTransferTx(...) 是占位,请用官方 SDK 的交易构建接口替换。
import * as bitcoin from "bitcoinjs-lib";
import AlkanesSDK from "alkanes-sdk"; // 占位
async function buildWithdrawalPsbt({selectedUtxos, toAddress, tokenId, amount, feeRate}) {
// 1) call alk sdk to create op_return payload
const payload = AlkanesSDK.encodeTransfer({ tokenId, amount, toAddress }); // placeholder
// 2) construct psbt
const network = bitcoin.networks.bitcoin; // or testnet
const psbt = new bitcoin.Psbt({ network });
let totalIn = 0;
for (const u of selectedUtxos) {
// need raw tx hex to add input (or txid vout nonWitnessUtxo / witnessUtxo)
psbt.addInput({
hash: u.txid,
index: u.vout,
nonWitnessUtxo: Buffer.from(u.rawTxHex, "hex") // preferred to provide full tx hex
});
totalIn = u.value_sats;
}
// outputs:
// - recipient: typically 1 sat output OP_RETURN encodes token transfer semantics
// Add OP_RETURN output:
const opReturnScript = bitcoin.script.compile([bitcoin.opcodes.OP_RETURN, Buffer.from(payload, "hex")]);
psbt.addOutput({ script: opReturnScript, value: 0 });
// - change output: return leftover sats to hot wallet change address
const estSize = selectedUtxos.length * 148 3 * 34 10;
const fee = Math.ceil(estSize * feeRate);
const changeValue = totalIn - fee;
if (changeValue <= 0) throw new Error("INSUFFICIENT_FEE_COVERAGE");
const changeAddress = getHotChangeAddress(); // implement according to your wallet
psbt.addOutput({ address: changeAddress, value: changeValue });
// PSBT ready to be signed
return psbt.toHex(); // or base64
}
签名与广播:PSBT 发送给 Hot Wallet Service 或导出给 Cold Wallet(HSM / HWW)签名;签名后广播到节点(或使用 Alkanes SDK broadcast)。
六、API 规范(交易所内部对接用)
1. Deposit webhook(来自 Indexer)
POST /api/internal/deposit
{
"txid":"...",
"outpoint":"txid:vout",
"address":"bc1q...",
"token_id":"diesel-01",
"amount":"10000.5",
"sats":50000,
"block_height":100000,
"confirmations":3
}
2. Withdrawal request (external/internal)
POST /api/withdrawals
{
"user_id": "12345",
"token_id": "diesel-01",
"amount": "100.5",
"to_address": "bc1q...",
"memo": "optional"
}
返回:
{
"withdrawal_id": "wd-001",
"status": "pending",
"estimated_fee_sats": 1200
}
3. Withdrawal status
GET /api/withdrawals/{withdrawal_id} → 返回 { status: pending/signed/broadcasted/confirmed/failed, txid, confirmations }
4. Admin: Build PSBT (for manual review)
POST /api/admin/build-psbt
BODY: selected utxo list to_address token_id amount feeRate
返回 psbt hex/base64 for offline signing
七、风控 & 合规清单(must-have)
确认阈值:不同 token/额度设置不同 confirmations(默认用户可用 2,大额 6)
白名单/黑名单合约:交易所应在 indexer 层或 Deposit Service 检查 token 是否来自官方合约(token_id 白名单)
重复/重放检测:基于 outpoint 去重;对相同 txid 的重复 webhook 需幂等处理
Untagged/unknown OP_RETURN:一旦 indexer 发现未知 OP_RETURN payload,记录审计并暂缓入账(人工核验)
提币阈值审批:大额提币需手动审批(Cold Wallet)
监控:
未确认 tx 数、失败广播数、indexer lag(s), reorg 频次
平均费率、被拒绝 tx 数
审计日志保留(至少 1 年以上,带 rawTxHex、psbt、签名证据)
灾备:indexer 的快照和恢复流程(backup snapshots of utxos 状态)
八、测试矩阵(必做)
功能:
mint(若需要交易所做 mint 操作)→ indexer 能索引 -> deposit入账
transfer(小额 / 大额 / 多 UTXO)
burn/redeem 流程(若代币支持)
边界:
UTXO dust 效应(50 sat、小于 dust)
多输入合并/拆分场景
fee spike(网络拥堵)下的失败重试、替代费(RBF)策略
恢复:
chain reorg 回滚恢复(indexer revert)
数据库 crash & restore 后的状态一致性测试
安全:
PSBT 恶意篡改检测(签名前后校验)
黑盒测试:发送错误/恶意 OP_RETURN,保证系统不入账
建议用 Alkanes 提供的 testnet 或 signet 来做全部 E2E 测试。
九、部署建议与时间估算
Indexer 开发/集成:4–8 周(取决于是否使用官方 indexer 或自研)
Deposit/Withdrawal Service Wallet 集成(含 HSM):3–6 周
测试 & 上线灰度(含审计、合规):2–4 周
总体:2–3 个月(保守)到1 个月(若可复用官方 indexer 经验团队)
十、交付给工程组的最小可交付文件(立即可用)
Indexer: Node service DB schema webhook publisher
Deposit Service: webhook receiver address ownership checker credit ledger writer
Withdrawal Service: UTXO selector PSBT builder (with Alkanes SDK calls) signer interface broadcaster
Wallet infra: hot/backup address pool hardware signer workflow
Admin UI: 手动构建 PSBT / 审核提币 / 查看 utxo / replay 含 reorg 工具
Alerts/metrics: Prometheus Grafana dashboard(indexer lag、pending withdrawals、failed broadcast)
十一、示例运维监控指标(Prometheus)
indexer_block_height (gauge)
indexer_lag_seconds (gauge)
pending_deposits (gauge)
pending_withdrawals (gauge)
failed_broadcasts_total (counter)
reorg_events_total (counter)
十二、常见问题与注意事项(工程师须知)
不要把 token 余额直接等同于 BTC UTXO 值:token 持有量是存在 UTXO 的 metadata/OP_RETURN 中。
不要在没有官方 SDK 的情况下自行拼 OP_RETURN bytes。如果短时间内必须自研,至少要做 exhaustive tests 与对照官方 indexer 的解码。
UTXO 隔离:尽量避免合并不同用户 token UTXO 成单一 UTXO;若必须合并,务必记录来源并对后续撤回做映射。
小额 / dust 管理:对 dust UTXO 设最低提款/入账阈值,或提供批量清理策略。
法律/合规:因为这些代币在 BTC L1,法律角度更接近“on-chain assets”,请与法务确认相关 KYC/AML 要求。
十三、交付清单(工程可直接拿去做)
确认 Alkanes 官方 SDK 版本与 RPC/Indexer 接口(取代占位 encode/decode)
部署 Bitcoin Core (txindex=1) Alkanes Node (if required)
部署/配置 Indexer(配置 PostgreSQL / ClickHouse)
实现 Deposit webhook consumer & ledger写入
实现 Withdrawal Service(UTXO selector PSBT 构建)
集成 Hot/Cold wallet 签名(HSM / hardware wallet)
实施风控规则、白名单 token_id、确认阈值
E2E 测试(testnet),审计并灰度上线