幣種層級 QR Code
幣種層級 QR Code 使用與其他 QR 簽名器相同的 UR 類型(遵循 Blockchain Commons 與 Keystone 的 registry),因此已能匯入 Keystone 風格帳戶的錢包,通常無須修改即可讀取。在 App 中:Connect › Coin Level,然後選擇一條鏈。
| 鏈 | 預設匯出 | 替代選項 |
|---|---|---|
| Bitcoin | 含一個帳戶 xpub 的 ur:crypto-account(可選 Native SegWit、Taproot、Nested SegWit 或 Legacy) | 純地址;多重簽名共同簽名者 xpub |
| EVM | ur:crypto-hdkey,即 m/44'/60'/0' 帳戶節點 | 純地址(索引 0) |
| Solana | 含一把預設組合金鑰的 ur:crypto-multi-accounts | 純地址 |
| TRON | 任意索引 m/44'/195'/0'/0/i 的純地址 | — |
每個 QR Code 在 App 中都有一個 Payload 區段,顯示解碼後的內容,與本頁的 JSON 檢視完全相同。整數 CBOR 鍵會以其 registry 欄位名稱顯示;指紋是 32 位元整數(1942346250 = 0x73C5DA0A)。
Bitcoin:crypto-account
crypto-account = {
1: master-fingerprint (uint32),
2: [ output-descriptor ] ; exactly one
}
output-descriptor = script tag(s) wrapping 303(crypto-hdkey)
| 地址類型 | 帳戶路徑 | 描述元標籤 | 腳本 |
|---|---|---|---|
| Native SegWit | m/84'/0'/0' | 404(303(key)) | wpkh |
| Taproot | m/86'/0'/0' | 409(303(key)) | tr(BIP86) |
| Nested SegWit | m/49'/0'/0' | 400(404(303(key))) | sh(wpkh) |
| Legacy | m/44'/0'/0' | 403(303(key)) | pkh |
內部的 crypto-hdkey 帶有帳戶公鑰(33 位元組)、chain code、含來源指紋與深度的 origin 路徑、父指紋,以及名稱 BitTool Signer。收款地址為 …/0/i,找零地址為 …/1/i。
如果你要自行解析,請注意兩個細節:
- 輸出描述元的寫法與 Keystone 和 Sparrow 相同,沒有 BCR-2020-015 中的
308(crypto-output)包裝。 - Taproot 使用標籤 409(
tr),搭配 未經 tweak 的內部金鑰;衍生地址時請套用 BIP86 tweak。較舊的 registry 函式庫不認得標籤 409,會默默將它捨棄(因此下方的範例解碼器直接讀取標籤)。
- Native SegWit
- Taproot
- Nested SegWit
- Legacy
{
"master-fingerprint": 1942346250,
"output-descriptors": [
{
"witness-public-key-hash": {
"crypto-hdkey": {
"is-private": false,
"key-data": "02707a62fdacc26ea9b63b1c197906f56ee0180d0bcf1966e1a2da34f5f3a09a9b",
"use-info": {
"crypto-coin-info": {}
},
"origin": {
"crypto-keypath": {
"components": [
84,
true,
0,
true,
0,
true
],
"source-fingerprint": 1942346250,
"depth": 3
}
},
"chain-code": "4a53a0ab21b9dc95869c4e92a161194e03c0ef3ff5014ac692f433c4765490fc",
"parent-fingerprint": 2129865691,
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
}
}
]
}
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMWTAADDLPDAOWKAXHDCLAOJOKNIDZCPSSAJTPTRPFRCECFKKAMYKJTVTCSBTBDTKCFIYVYOETNEEYKWFNBNYNDAHTAADEHNBAMTAADDYOTADLNCSGHYKAEYKAEYKAOCYJKSKTNBKAXAXAAHDCXGEGUNBPYCLRHUOMDLNNSGLMOOYHSCFGLAXRTWSFHYKADGESWMOWKEOSSKOGHMHZTAYCYKBWFDNUYASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYDPCXPECF
{
"master-fingerprint": 1942346250,
"output-descriptors": [
{
"taproot": {
"crypto-hdkey": {
"is-private": false,
"key-data": "03418278a2885c8bb98148158d1474634097a179c642f23cf1cc04da629ac6f0fb",
"use-info": {
"crypto-coin-info": {}
},
"origin": {
"crypto-keypath": {
"components": [
86,
true,
0,
true,
0,
true
],
"source-fingerprint": 1942346250,
"depth": 3
}
},
"chain-code": "c61a8f27e98182314d2444da3e600eb5836ec8ad183c86c311f95df8082b18aa",
"parent-fingerprint": 55734490,
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
}
}
]
}
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADNLTAADDLPDAOWKAXHDCLAXFPLFKSOELOHHLURHLYFDBZLGBBJYIAFZMSOYKKSWFWWZFNWNSFAATNIDNYSWWTZOAHTAADEHNBAMTAADDYOTADLNCSHFYKAEYKAEYKAOCYJKSKTNBKAXAXAAHDCXSWCYMYDIWLLYLFEHGTDKFYTNFMHNBARELSJTSPPMCSFNLNSRBYYTHLYAAYDNCSPKAYCYAXGMJOTNASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYKSBBMKFG
{
"master-fingerprint": 1942346250,
"output-descriptors": [
{
"script-hash": {
"witness-public-key-hash": {
"crypto-hdkey": {
"is-private": false,
"key-data": "02f1f347891b20f7568eae3ec9869fbfb67bcab6f358326f10ecc42356bd55939d",
"use-info": {
"crypto-coin-info": {}
},
"origin": {
"crypto-keypath": {
"components": [
49,
true,
0,
true,
0,
true
],
"source-fingerprint": 1942346250,
"depth": 3
}
},
"chain-code": "6eaae365ae0e0a0aab84325cfe7cd76c3b909035f889e7d3f1b847a9a0797ecb",
"parent-fingerprint": 1023803253,
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
}
}
}
]
}
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMHTAADMWTAADDLPDAOWKAXHDCLAOWNWFFLLDCWCXYLHFMNPLFMSOLNNERSRPKGSGRPWFHDEYJLBEWPSSCNHFRYGOMUNTAHTAADEHNBAMTAADDYOTADLNCSEHYKAEYKAEYKAOCYJKSKTNBKAXAXAAHDCXJTPKVLIHPLBABKBKPYLREYHHZEKETSJZFRMHMHECYALDVDTEWNROFLPTNBKKKBSBAYCYFSAHZMKPASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYZCOYAYKE
{
"master-fingerprint": 1942346250,
"output-descriptors": [
{
"public-key-hash": {
"crypto-hdkey": {
"is-private": false,
"key-data": "03774c910fcf07fa96886ea794f0d5caed9afe30b44b83f7e213bb92930e7df4bd",
"use-info": {
"crypto-coin-info": {}
},
"origin": {
"crypto-keypath": {
"components": [
44,
true,
0,
true,
0,
true
],
"source-fingerprint": 1942346250,
"depth": 3
}
},
"chain-code": "3da4bc190a2680111d31fadfdc905f2a7f6ce77c6f109919116f253d43445219",
"parent-fingerprint": 358337113,
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
}
}
]
}
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMUTAADDLPDAOWKAXHDCLAXKTGSMEBSTKATZSMTLOJTOSMWWTTLSGWENYZEDYQZGRLSYLVOBWRKMOMUBAKIWKRYAHTAADEHNBAMTAADDYOTADLNCSDWYKAEYKAEYKAOCYJKSKTNBKAXAXAAHDCXFSOXRFCFBKDSLABYCAEHZSURUOMHHEDRLBJZVDKEJLBENLCFBYJLDAFSFXFYGMCFAYCYBZHPSGHKASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYGUTNWNDL
Bitcoin 多重簽名共同簽名者
對於多重簽名錢包,BitTool Signer 會在 BIP48 路徑上,以 crypto-account 匯出一把 共同簽名者 金鑰:
| 類型 | 帳戶路徑 | 描述元標籤 |
|---|---|---|
| P2WSH | m/48'/0'/0'/2' | 401(303(key))(wsh) |
| P2SH-P2WSH | m/48'/0'/0'/1' | 400(401(303(key)))(sh(wsh)) |
這只代表單一參與者,不含門檻值、其他共同簽名者,也沒有最終地址。你的錢包需根據所有共同簽名者的匯出內容建構完整的策略(例如排序後的 2-of-3 wsh(sortedmulti(…)))。
P2WSH 共同簽名者測試向量
{
"master-fingerprint": 1942346250,
"output-descriptors": [
{
"witness-script-hash": {
"crypto-hdkey": {
"is-private": false,
"key-data": "021a3bf5fbf737d0f36993fd46dc4913093beb532d654fe0dfd98bd27585dc9f29",
"use-info": {
"crypto-coin-info": {}
},
"origin": {
"crypto-keypath": {
"components": [
48,
true,
0,
true,
0,
true,
2,
true
],
"source-fingerprint": 1942346250,
"depth": 4
}
},
"chain-code": "bba0c7ca160a870efeb940ab90d0f4284fea1b5e0d2117677e823fc37e2d5763",
"parent-fingerprint": 485660438,
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
}
}
]
}
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMETAADDLPDAOWKAXHDCLAOCYFRYKZOYLEMTIWFINMUZCFGUOGABWASFRWMGUDPIHGWVTURTALUTDKPLPUONEDTAHTAADEHNBAMTAADDYOTADLOCSDYYKAEYKAEYKAOYKAOCYJKSKTNBKAXAAAAHDCXRKNBSTSGCMBKLTBAZERHFZPYMHTIWKDEGWWDCWHYBTCLCHIOKBLFFHSRKBDPHGIAAYCYCEWZMSCMASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYVEGWJLEO
EVM:crypto-hdkey
EVM 匯出內容是以頂層 crypto-hdkey(EIP-4527)表示的帳戶節點 m/44'/60'/0',也就是 MetaMask、Rabby、imToken 等錢包所匯入的格式:
| 鍵 | 欄位 | 值 |
|---|---|---|
| 2 | is-private | false |
| 3 | key-data | 33 位元組的壓縮公鑰 |
| 4 | chain-code | 32 位元組 |
| 5 | use-info | 305({1: 60}) |
| 6 | origin | 304({1: [44, true, 60, true, 0, true], 2: fingerprint, 3: 3}) |
| 7 | children | 304({1: [0, false, [], false]}),即 0/* |
| 8 | parent-fingerprint | uint32 |
| 9, 10 | name, note | "BitTool Signer"、"BitTool Signer public account" |
衍生 …/0/i 即可取得地址。同一把金鑰適用於所有支援的 EVM 網路。
{
"is-private": false,
"key-data": "02eae4b876a8696134b868f88cc2f51f715f2dbedb7446b8e6edf3d4541c4eb67b",
"use-info": {
"crypto-coin-info": {
"type": 60
}
},
"origin": {
"crypto-keypath": {
"components": [
44,
true,
60,
true,
0,
true
],
"source-fingerprint": 1942346250,
"depth": 3
}
},
"chain-code": "d882718b7a42806803eeb17f7483f20620611adb88fc943c898dc5aba94c2819",
"parent-fingerprint": 3543024904,
"children": {
"crypto-keypath": {
"components": [
0,
false,
[],
false
]
}
},
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
UR:CRYPTO-HDKEY/PTAOWKAXHDCLAOWDVEROKOPDINHSEEROISYALKSAYKCTJSHEDPRNUYJYFGROVAWEWFTYGHCEGLRPKGAHTAADEHOYADCSFNAMTAADDYOTADLNCSDWYKCSFNYKAEYKAOCYJKSKTNBKAXAXAAHDCXTPLFJSLUKNFWLAISAXWYPALBJYLSWZAMCXHSCYUYLOZTMWFNLDLGSKPYPTGSDECFAYCYTEDMFEAYATTAADDYOYADLRAEWKLAWKASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYMUFLSAVD
Solana:crypto-multi-accounts
Solana 金鑰全部採用強化衍生,因此沒有可再往下衍生的節點。匯出內容只包含 一把 預設組合金鑰(即 App 中所選的那一把),以含 32 位元組 Ed25519 金鑰的 crypto-hdkey 表示:
crypto-multi-accounts = {
1: master-fingerprint,
2: [ 303({ 2: false, 3: <32-byte public key>, 5: 305({1: 501}), 6: 304(<path>), 9: name, 10: note }) ],
3: "BitTool Signer", ; device
5: "1.0.0" ; version
}
| 預設組合 | 路徑 |
|---|---|
| Standard | m/44'/501'/0'/0' |
| Trust | m/44'/501'/0' |
| Legacy | m/44'/501' |
地址就是這把 32 位元組金鑰的 Base58 編碼。
{
"master-fingerprint": 1942346250,
"keys": [
{
"crypto-hdkey": {
"is-private": false,
"key-data": "f036276246a75b9de3349ed42b15e232f6518fc20f5fcd4f1d64e81f9bd258f7",
"use-info": {
"crypto-coin-info": {
"type": 501
}
},
"origin": {
"crypto-keypath": {
"components": [
44,
true,
501,
true,
0,
true,
0,
true
],
"source-fingerprint": 1942346250,
"depth": 4
}
},
"name": "BitTool Signer",
"note": "BitTool Signer public account"
}
}
],
"device": "BitTool Signer",
"version": "1.0.0"
}
UR:CRYPTO-MULTI-ACCOUNTS/OXADCYJKSKTNBKAOLYTAADDLOLAOWKAXHDCXWTENDIIDFGOSHPNTVLEENNTYDNBZVOEYYNGYMYSABSHESNGWCAIEVSCTNDTDHDYLAHTAADEHOYADCFADYKAMTAADDYOTADLOCSDWYKCFADYKYKAEYKAEYKAOCYJKSKTNBKAXAAASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYAXJTFWINJYGHJLJLJZCXGUINIOJTIHJPAHIHEHDMDYDMDYMSFNHFVA
純地址
Address(地址)選項只會把地址匯出為 QR 文字:沒有 URI scheme、沒有金額,也沒有 UR 包裝。它適用於無法匯入金鑰的觀察錢包。TRON 一律以這種方式匯出,索引可由使用者任意選擇(m/44'/195'/0'/0/i,0 ≤ i < 231)。
| 匯出 | QR 文字 |
|---|---|
| Bitcoin(Native SegWit,索引 0) | bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu |
| EVM(索引 0) | 0x9858EfFD232B4033E47d90003D41EC34EcaEda94 |
| Solana(standard) | HAgk14JpMQLgt6rVgv7cBQFJWFto5Dqxi472uT3DKpqk |
| TRON 索引 0 | TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH |
| TRON 索引 5 | TBdYXtwq18cAhi1BA574TrP6tw2G86anu1 |
只透過地址配對的錢包,無法在簽名請求中加入衍生資料。BitTool Signer 仍能比對 EVM 索引 0 與 TRON 索引 0–99 的純地址請求,但如果你打算簽名,請優先使用金鑰匯出。
一次解碼所有格式
一個函式即可處理所有幣種層級匯出,使用保留描述元標籤的 cborg:
import { URDecoder } from '@ngraveio/bc-ur';
import { decode, Tagged } from 'cborg';
import { HDKey } from '@scure/bip32';
import { base58 } from '@scure/base';
// Output-descriptor tags (BCR-2020-010) → script names.
const SCRIPT = { 400: 'sh', 401: 'wsh', 403: 'pkh', 404: 'wpkh', 409: 'tr' };
const options = { useMaps: true, strict: true, tags: Tagged.preserve(303, 304, 305, 400, 401, 403, 404, 409) };
const fingerprint = (n) => n.toString(16).padStart(8, '0');
const pathOf = (keypath) => { // Tagged(304, Map{1: [index, hardened, …]})
const c = keypath.value.get(1), parts = [];
for (let i = 0; i < c.length; i += 2) parts.push(`${c[i]}${c[i + 1] ? "'" : ''}`);
return `m/${parts.join('/')}`;
};
const accountOf = (hdkey) => { // crypto-hdkey map: 3 key, 4 chain code, 6 origin, 8 parent fp
const origin = hdkey.get(6).value.get(1);
return {
path: pathOf(hdkey.get(6)),
masterFingerprint: fingerprint(hdkey.get(6).value.get(2)),
xpub: new HDKey({ publicKey: hdkey.get(3), chainCode: hdkey.get(4), depth: origin.length / 2,
index: origin.at(-2) + (origin.at(-1) ? 0x80000000 : 0), parentFingerprint: hdkey.get(8) }).publicExtendedKey,
};
};
/** Reads any coin-level export from BitTool Signer. */
export function readCoinLevelQR(frames) {
if (frames.length === 1 && !/^ur:/i.test(frames[0])) return { kind: 'address', address: frames[0].trim() };
const decoder = new URDecoder();
for (const frame of frames) decoder.receivePart(frame);
if (!decoder.isSuccess()) throw new Error('Incomplete or invalid QR');
const ur = decoder.resultUR();
const cbor = decode(ur.cbor, options);
switch (ur.type) {
case 'crypto-account': { // Bitcoin: {1: master fp, 2: [output descriptor]}
let node = cbor.get(2)[0];
const script = [];
while (node.tag !== 303) { script.push(SCRIPT[node.tag]); node = node.value; } // e.g. sh → wpkh
return { kind: 'bitcoin', script: script.join('-'), ...accountOf(node.value) };
}
case 'crypto-hdkey': // EVM account node
return { kind: 'evm', ...accountOf(cbor) };
case 'crypto-multi-accounts': { // Solana: {1: master fp, 2: [crypto-hdkey with a 32-byte key]}
const key = cbor.get(2)[0].value;
return { kind: 'solana', masterFingerprint: fingerprint(cbor.get(1)), path: pathOf(key.get(6)), address: base58.encode(key.get(3)) };
}
default:
throw new Error(`Not a pairing QR: ${ur.type}`);
}
}