Saltar al contenido principal

Códigos QR a nivel de moneda

ur:crypto-accountur:crypto-hdkeyur:crypto-multi-accountsplain address

Los códigos QR a nivel de moneda usan los mismos tipos UR que otros dispositivos de firma QR (siguen los registros de Blockchain Commons y de Keystone), así que una cartera que ya importa cuentas al estilo Keystone normalmente puede leerlos sin cambios. En la app: Connect › Coin Level y, después, elige una cadena.

CadenaExportación por defectoAlternativa
Bitcoinur:crypto-account con un xpub de cuenta (elige Native SegWit, Taproot, Nested SegWit o Legacy)Dirección simple; xpub de cofirmante multifirma
EVMur:crypto-hdkey, el nodo de cuenta m/44'/60'/0'Dirección simple (índice 0)
Solanaur:crypto-multi-accounts con una clave predefinidaDirección simple
TRONDirección simple de cualquier índice m/44'/195'/0'/0/i—

Cada código QR tiene en la app una sección Payload que muestra el contenido decodificado, exactamente igual que las vistas JSON de esta página. Las claves CBOR enteras se muestran con los nombres de campo del registro; las huellas son enteros de 32 bits (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)
Tipo de direcciónRuta de la cuentaTags del descriptorScript
Native SegWitm/84'/0'/0'404(303(key))wpkh
Taprootm/86'/0'/0'409(303(key))tr (BIP86)
Nested SegWitm/49'/0'/0'400(404(303(key)))sh(wpkh)
Legacym/44'/0'/0'403(303(key))pkh

El crypto-hdkey interior contiene la clave pública de la cuenta (33 bytes), el chain code, la ruta de origen con la huella de origen y la profundidad, la huella del padre y el nombre BitTool Signer. Las direcciones de recepción son …/0/i y las de cambio, …/1/i.

Dos detalles si lo analizas por tu cuenta:

  • El descriptor de salida se escribe como lo escriben Keystone y Sparrow, sin el envoltorio 308(crypto-output) de BCR-2020-015.
  • Taproot usa el tag 409 (tr) con la clave interna sin ajustar (untweaked); aplica el ajuste (tweak) de BIP86 al derivar las direcciones. Las bibliotecas de registro más antiguas no conocen el tag 409 y lo descartan sin avisar (por eso el decodificador de ejemplo de más abajo lee los tags directamente).
m/84'/0'/0' · crypto-accountPrimera dirección de recepción: bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMWTAADDLPDAOWKAXHDCLAOJOKNIDZCPSSAJTPTRPFRCECFKKAMYKJTVTCSBTBDTKCFIYVYOETNEEYKWFNBNYNDAHTAADEHNBAMTAADDYOTADLNCSGHYKAEYKAEYKAOCYJKSKTNBKAXAXAAHDCXGEGUNBPYCLRHUOMDLNNSGLMOOYHSCFGLAXRTWSFHYKADGESWMOWKEOSSKOGHMHZTAYCYKBWFDNUYASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYDPCXPECF
Carga útil decodificada
{
"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"
}
}
}
]
}
Texto del QR
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMWTAADDLPDAOWKAXHDCLAOJOKNIDZCPSSAJTPTRPFRCECFKKAMYKJTVTCSBTBDTKCFIYVYOETNEEYKWFNBNYNDAHTAADEHNBAMTAADDYOTADLNCSGHYKAEYKAEYKAOCYJKSKTNBKAXAXAAHDCXGEGUNBPYCLRHUOMDLNNSGLMOOYHSCFGLAXRTWSFHYKADGESWMOWKEOSSKOGHMHZTAYCYKBWFDNUYASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYDPCXPECF

Cofirmante multifirma de Bitcoin​

Para carteras multifirma, BitTool Signer exporta una clave de cofirmante en crypto-account, en las rutas BIP48:

TipoRuta de la cuentaTags del descriptor
P2WSHm/48'/0'/0'/2'401(303(key)) (wsh)
P2SH-P2WSHm/48'/0'/0'/1'400(401(303(key))) (sh(wsh))

Es un solo participante. No contiene umbral, ni otros cofirmantes, ni dirección final. Tu cartera construye la política completa (por ejemplo, un wsh(sortedmulti(…)) 2 de 3 ordenado) a partir de las exportaciones de todos los cofirmantes.

Vector de prueba del cofirmante P2WSH
Carga útil decodificada
{
"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"
}
}
}
]
}
Texto del QR
UR:CRYPTO-ACCOUNT/OEADCYJKSKTNBKAOLYTAADMETAADDLPDAOWKAXHDCLAOCYFRYKZOYLEMTIWFINMUZCFGUOGABWASFRWMGUDPIHGWVTURTALUTDKPLPUONEDTAHTAADEHNBAMTAADDYOTADLOCSDYYKAEYKAEYKAOYKAOCYJKSKTNBKAXAAAAHDCXRKNBSTSGCMBKLTBAZERHFZPYMHTIWKDEGWWDCWHYBTCLCHIOKBLFFHSRKBDPHGIAAYCYCEWZMSCMASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYVEGWJLEO

EVM: crypto-hdkey​

La exportación EVM es el nodo de cuenta m/44'/60'/0' como crypto-hdkey de nivel superior (EIP-4527), el formato que importan MetaMask, Rabby, imToken y otras:

ClaveCampoValor
2is-privatefalse
3key-dataClave pública comprimida de 33 bytes
4chain-code32 bytes
5use-info305({1: 60})
6origin304({1: [44, true, 60, true, 0, true], 2: fingerprint, 3: 3})
7children304({1: [0, false, [], false]}), es decir, 0/*
8parent-fingerprintuint32
9, 10name, note"BitTool Signer", "BitTool Signer public account"

Deriva …/0/i para obtener las direcciones. La misma clave sirve para todas las redes EVM compatibles.

m/44'/60'/0' · crypto-hdkeyPrimera dirección: 0x9858EfFD232B4033E47d90003D41EC34EcaEda94
UR:CRYPTO-HDKEY/PTAOWKAXHDCLAOWDVEROKOPDINHSEEROISYALKSAYKCTJSHEDPRNUYJYFGROVAWEWFTYGHCEGLRPKGAHTAADEHOYADCSFNAMTAADDYOTADLNCSDWYKCSFNYKAEYKAOCYJKSKTNBKAXAXAAHDCXTPLFJSLUKNFWLAISAXWYPALBJYLSWZAMCXHSCYUYLOZTMWFNLDLGSKPYPTGSDECFAYCYTEDMFEAYATTAADDYOYADLRAEWKLAWKASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYMUFLSAVD
Carga útil decodificada
{
"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"
}
Texto del QR
UR:CRYPTO-HDKEY/PTAOWKAXHDCLAOWDVEROKOPDINHSEEROISYALKSAYKCTJSHEDPRNUYJYFGROVAWEWFTYGHCEGLRPKGAHTAADEHOYADCSFNAMTAADDYOTADLNCSDWYKCSFNYKAEYKAOCYJKSKTNBKAXAXAAHDCXTPLFJSLUKNFWLAISAXWYPALBJYLSWZAMCXHSCYUYLOZTMWFNLDLGSKPYPTGSDECFAYCYTEDMFEAYATTAADDYOYADLRAEWKLAWKASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYMUFLSAVD

Solana: crypto-multi-accounts​

Las claves de Solana son totalmente hardened, así que no hay nada de lo que derivar. La exportación contiene una clave predefinida (la seleccionada en la app) como crypto-hdkey con una clave Ed25519 de 32 bytes:

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
}
PreajusteRuta
Standardm/44'/501'/0'/0'
Trustm/44'/501'/0'
Legacym/44'/501'

La dirección es la codificación Base58 de la clave de 32 bytes.

Carga útil decodificada (preajuste standard)
{
"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"
}
Texto del QR
UR:CRYPTO-MULTI-ACCOUNTS/OXADCYJKSKTNBKAOLYTAADDLOLAOWKAXHDCXWTENDIIDFGOSHPNTVLEENNTYDNBZVOEYYNGYMYSABSHESNGWCAIEVSCTNDTDHDYLAHTAADEHOYADCFADYKAMTAADDYOTADLOCSDWYKCFADYKYKAEYKAEYKAOCYJKSKTNBKAXAAASJTFWINJYGHJLJLJZCXGUINIOJTIHJPBKKSCAFWINJYGHJLJLJZCXGUINIOJTIHJPCXJOKPIDJZINIACXHSIAIAJLKPJTJYAXJTFWINJYGHJLJLJZCXGUINIOJTIHJPAHIHEHDMDYDMDYMSFNHFVA

Direcciones simples​

La opción Address (dirección) exporta solo la dirección como texto del QR: sin esquema URI, sin importe y sin envoltorio UR. Está pensada para carteras de solo lectura que no pueden importar claves. TRON siempre se exporta de esta forma, en el índice que elija el usuario (m/44'/195'/0'/0/i, 0 ≤ i < 231).

ExportaciónTexto del QR
Bitcoin (Native SegWit, índice 0)bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu
EVM (índice 0)0x9858EfFD232B4033E47d90003D41EC34EcaEda94
Solana (standard)HAgk14JpMQLgt6rVgv7cBQFJWFto5Dqxi472uT3DKpqk
TRON índice 0TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH
TRON índice 5TBdYXtwq18cAhi1BA574TrP6tw2G86anu1

Una cartera que se vincula solo por dirección no puede añadir datos de derivación a sus solicitudes de firma. BitTool Signer todavía puede asociar a una cartera las solicitudes que solo contienen la dirección para EVM con índice 0 y para TRON con índices 0–99, pero es preferible usar las exportaciones de claves si piensas firmar.

Cómo decodificarlos todos​

Una sola función para todas las exportaciones a nivel de moneda, usando cborg y conservando los tags del descriptor:

examples/coin-level.mjs
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}`);
}
}