Reference

Public protocol for third-party wallets

Besides its own bb_* format, an Ownbit cold wallet can act as the signer for other wallets using published QR standards. The other wallet imports a public key, builds the transaction, and hands Ownbit a request to sign offline. This ships on Android 5.x.

What travels in each direction

Pairing exports public key material only. Signing carries an unsigned request in, and a signature out. No private key ever leaves the phone.

Bitcoin additionally accepts BBQR and PSBT files, and answers in the same UR type the request arrived in.
ChainPairing exportSigning request → response
Bitcoincrypto-account (account XPUB) or a plain addresscrypto-psbt → crypto-psbt
EVMcrypto-hdkey (account node) or a plain addresseth-sign-request → eth-signature
Solanacrypto-multi-accounts or a plain addresssol-sign-request → sol-signature
TRONaddress #0tron-sign-request → tron-signature

How the layers stack

A code is never "a transaction" on its own. Three wrappers sit between the camera and the bytes that get signed, and each one is a published format.

LayerWhat it carries
QR frame(s)One code, or an animated sequence when the payload is too big for a single frame. The scanner reassembles the parts before anything is parsed.
UR envelopeur:<type>/<bytewords> — a registry type name plus a CBOR body. The type is what tells the signer how to read the rest.
Chain payloadThe object itself: a PSBT for Bitcoin, an unsigned transaction plus its derivation path for EVM, a message for Solana.
AnswerThe same envelope with the response type — a PSBT back for Bitcoin, eth-signature for EVM — carrying signatures, never a key.

Both examples below are the engine's own test vectors. They use the public BIP39 test phrase abandon abandon … about with synthetic inputs, so they are reproducible but not broadcastable. Never send funds to these addresses.

Pairing

Bitcoin offers Taproot, Native SegWit, Nested SegWit and Legacy profiles (Native SegWit is the default), plus a BIP48 cosigner export for multisig setups in other wallets. A profile Ownbit itself does not display is labelled accordingly, so funds are never sent somewhere Ownbit cannot show them.

  • EVM exports the account node, or the plain address Ownbit is currently using.
  • Solana exports one account entry, or a plain address.
  • TRON shares address #0 only, because only index 0 matches the standard m/44'/195'/0'/0/0 path.

Worked example: Bitcoin

1. Pair. Ownbit shows ur:crypto-account/… carrying the account XPUB for m/84'/0'/0'. The other wallet imports it and can now derive every receive and change address on its own.

2. The request. The other wallet builds the spend and shows ur:crypto-psbt/…. Its body is a PSBT:

cHNidP8BAFICAAAAAYFwD+scFmeHtvYI22W5llNYndxFPmym4gES
AFLcGZ2oAAAAAAD/////AZBfAQAAAAAAFgAURaXKkYxfBPgdgJnj
4ES6lkXFXPkAAAAAAAEAUgIAAAABAAAAAAAA … (truncated)

3. What Ownbit reads out of it. The PSBT decodes to one input and one output, and the input carries the derivation that proves it belongs to this wallet:

Ownbit shows the amounts and the destination before anything is signed.
FieldValue
Input100,000 sats (witness UTXO)
Output90,000 sats to a P2WPKH script 001445a5ca91…c55cf9
Fee10,000 sats (the difference)
Input derivationm/84'/0'/0'/0/0, master fingerprint 73c5da0a

4. The answer. After approval Ownbit returns the same PSBT with a signature added to input 0, as ur:crypto-psbt/…. The engine reports exactly what it touched:

{ "signedInputs": 1, "signedInputIndexes": [0] }

The online wallet finalises and broadcasts. Ownbit never sees the network.

Worked example: Ethereum

1. Pair. Ownbit shows ur:crypto-hdkey/… for the account node m/44'/60'/0', so the other wallet can add accounts under it.

2. The request. ur:eth-sign-request/… carries the unsigned transaction. Decoded, this vector is:

{
  "type": 2,                                 // EIP-1559
  "chainId": 1,                              // Ethereum mainnet
  "nonce": 7,
  "to": "0x000000000000000000000000000000000000dead",
  "value": "1000000000000000",               // 0.001 ETH
  "gasLimit": "21000",
  "maxFeePerGas": "30000000000",             // 30 gwei
  "maxPriorityFeePerGas": "1000000000"       // 1 gwei
}

3. What Ownbit shows. 0.001 ETH to 0x…dead on Ethereum mainnet, with the fee ceiling and the nonce. Calldata and typed-data requests get the same reading the WalletConnect signing page uses, including known-contract notes.

4. The answer. ur:eth-signature/… carries 65 bytes — r, s, then v:

r  19b076f96801bed5ec2a5babfb4229ce433e66a3e19ffb7d43abc641fd0ac81b
s  21eb9bf221bd8e87177dcaf86a43b9b6aa82efdca75f2b13213f874ced70b35e
v  1b

The online wallet assembles and broadcasts the signed transaction. For this vector the signing address is 0x9858EfFD232B4033E47d90003D41EC34EcaEda94 — account 0 of the test phrase — which is the same address the pairing code produced. That equality is the point: the signature comes from the key the other wallet imported.

Which wallets are eligible

Personal HD wallets on standard derivation paths — both normal and cold. Ownbit MultiSig wallets are excluded: their seed is an Ownbit cosigner and keeps using Ownbit's own MultiSig flow. Private-key-only, watch-only, custom-path and Electrum-seed wallets are excluded too.

Addresses are checked against Ownbit

Before a pairing code is shown, the addresses the protocol engine derives are compared with the ones Ownbit derives from its own stored keys. On a match the panel reads Same as in Ownbit; on a mismatch no code is shown at all.

This turns "the other wallet shows the same balance" into something checked at the moment the code is produced, rather than an assumption.

Scope and limits

  • Available on Android 5.x.
  • Support on the other side follows each wallet's own published QR handling and can change with their releases.
  • Ownbit's own bb_* protocol is unchanged and still used between Ownbit watch and cold wallets.

อัปเดตล่าสุด:

ดาวน์โหลด

ดาวน์โหลด Ownbit

ติดตั้งแอป แล้วตั้งค่ากระเป๋าเย็นหรือมัลติซิกตามที่คุณต้องการ