* bip139: wallet metadata format * bip139: add the Version header to the preamble * bip139: keep a single psbts field and fix the spend status link * bip139: fold the version section and bip field into the version value * bip139: capitalize Bitcoin Core and clarify the change_descriptor note * bip139: replace the three account birth time fields with birth_block * bip139: drop descriptor_id and change_descriptor_id * bip139: drop field aliases, keeping name and labels * bip139: restrict descriptor and change_descriptor to a string * bip139: make version, type, descriptor, key, txid, outpoint and tweak mandatory * bip139: move field definitions to a companion registry * bip139: add the wallet survey behind these decisions * bip139: replace the wallet description field with a backup note * bip139: add the backup date field * bip139: add the account gap_limit field * bip139: add the multi_bip380 account type * bip139: give the bip352_labels range an explicit encoding * bip139: add a general coin object * bip139: move signers above the account * bip139: add signer modality and device records * bip139: add bip85 application and index * bip139: add Bitkey to the wallet survey * bip139: state how to derive birth_block from a creation date * bip139: define the timestamp format once * bip139: rename the transaction time field to block_time * bip139: keep last_height on the account only * bip139: state that type names the descriptor language * bip139: drop output_type, the descriptor already states it * bip139: replace the account active flag with a status enum * bip139: add mutinynet and scope a backup to one network * bip139: record that the label gap belongs to BIP-329 * bip139: record that proprietary needs no change * bip139: make the survey annex-ready * bip139: record that mainnet mnemonics stay out of scope * bip139: reword the mnemonic evidence heading * bip139: correct the birth_block evidence, Sparrow stores a height * bip139: type and descriptor fit every surveyed wallet * bip139: correct the addr descriptor solvability note * bip139: re-assess every partial score against fillability * bip139: store psbts once at wallet level, reference them per account * bip139: store transactions once at wallet level, reference them per account * bip139: txid is the transaction map key, not a field * bip139: refresh the matrix after the fillability re-assessment * bip139: electrum holds no bip39 mnemonic at all * bip139: sp_output.label has no constituency * bip139: collapse the survey to a two-value scale * bip139: drop the obsolete partial-score analysis * bip139: size the matrix field column from the data * bip139: cut the survey down to the table and its results * bip139: recompute liana compat against the current draft * bip139: correct the liana breaking-change count * bip139: make network mandatory * bip139: network no longer breaks liana on import * bip139: render wallet fields as a wrapped table * bip139: render account fields as a wrapped table * bip139: render every field section as a wrapped table * bip139: the registry is part of the bip, not a reference to it * bip139: drop the registration process from the registry intro * bip139: put field rationale in the cell, not below the table * bip139: keep code spans whole when wrapping cells * bip139: render field tables as preformatted blocks * bip139: drop link definitions the tables no longer use * bip139: use a bordered grid for the field tables * bip139: give birth_block an estimation formula and drop the enum underscore * bip139: merge silent payment outputs into the coin object * bip139: restore spend_status and give the sp label scalar a home * bip139: register the transaction fee field * bip139: rebuild the survey matrix against the current field set * bip139: drop survey findings the draft now addresses * bip139: bar passphrase-protected seeds from bip39_mnemonic * bip139: record the missing-field decisions in the survey * bip139: cut the survey down to its revision list and matrix * bip139: reword the survey as a wallet to field mapping * bip139: reference the wallet support annex from the spec * bip139: list the mandatory fields in the registry tables * bip139: point the spec at the registry as the complete field list * bip139: spell out mandatory and optional in the registry req column * bip139: mark only the optional fields in the registry tables * bip139: retitle and reframe the BIP around moving between wallets * bip139: call the artefact an export throughout * bip139: scope the mnemonic advice to exports kept as backups * bip139: say that most metadata cannot be recovered from the chain * bip139: clarify account and signer metadata fields * bip139: cut the registry cells back to the field description * bip139: reword the registry field descriptions * bip139: give the device record its own registry table * bip139: keep an unknown enum value from failing the import * bip139: define the device transports field * bip139: point the devices row at the device object * bip139: backup -> export in README * bip139: clarify export fields and remove survey annex * bip139: Drop Version header in absence of Changelog
10 KiB
BIP: 139
Layer: Applications
Title: Wallet Metadata Export Format
Authors: Pyth <pythcoiner@wizardsardine.com>
Status: Draft
Type: Specification
Assigned: 2026-05-11
License: BSD-2-Clause
Discussion: https://groups.google.com/g/bitcoindev/c/ylPeOnEIhO8
Abstract
This document specifies a format for exporting the metadata of a wallet: its accounts, descriptors, key information, signers, labels, transactions, coins, and partially signed Bitcoin transactions (PSBTs). The format gives these records a common structure and common field names, so that what one wallet application writes another can read. Each object structure defines a few mandatory fields; all other fields are optional. The base structure must include at least one account entry.
The fields of the format are collected in a companion field registry, which acts as a central repository where a wallet implementer can register their usage of a field and share that usage through a test vector.
Copyright
This BIP is licensed under the BSD 2-clause license.
Motivation
BIP-0032 and
BIP-0039 let a
user carry keys from one application to another, and
BIP-0329 does the
same for the labels attached to a wallet's records.
There is no specification targeting the entire set of metadata a wallet can carry:
- list of accounts attached to this wallet and their descriptors.
- list of signers holding a key in the descriptor & how to interact with these signers.
- when an account has been created & what the last seen chain tip is.
- which outputs are owned by the account & which of them have been frozen by the user.
- etc.
A big part of this metadata cannot be recovered from the chain, so a user willing to migrate from one wallet to another has to re-enter it by hand or do without it. A format that two applications can both write and read removes that cost, and the lock-in that follows from it.
Rationale
Several wallet applications already export their whole state, each in a form only they
can read.
Because each format is specific to one application, moving between any two of them
means writing a converter for that pair.
This proposal introduces a structured format, leveraging JSON to store wallet
metadata in a portable way.
The format is flexible and extensible, allowing wallet developers to include as much
or as little information as they think necessary.
By keeping the mandatory set of metadata small and keeping every other field
optional, this spec accommodates diverse use cases and preferences.
Wallet developers can include only the fields relevant to their software while
maintaining structural integrity.
Specification
A wallet export is a UTF-8 encoded text file containing a single valid JSON object
representing the wallet.
This object includes wallet-level metadata, multiple accounts, and associated key
data.
Every timestamp in this format and its registry is an integer representing a Unix
timestamp in seconds.
Block heights are integers and are never interchangeable with timestamps.
Field Registry
The fields of every object structure are defined in the field registry rather than in this document, so new fields could be added without amending this BIP. The registry records field and object definitions and marks mandatory fields, so each object's structure can be read from its table. A registry pull request may add or change optional fields only. The mandatory fields are fixed by this BIP, and making a field mandatory is a change to this BIP. Registration of a new field must state the field name, the object it belongs to, its type, and a short description, and should link a test vector or an implementation using it when available. A field name must not conflict with an already registered field of the same object.
Wallet Object Structure
The top-level JSON object must contain the version and network fields and at
least one account in the accounts array.
Its fields are listed in the field registry.
version: Mandatory string identifying the version of the export format. Must beBIP139-<version>, where<version>is an integer. The export format version is incremented only for changes that are not backward compatible, such as adding a mandatory field.network: Mandatory string naming the network the export covers.
Must be one ofbitcoin(mainnet),testnet3,testnet4,signet,mutinynetorregtest.
An export covers a single network. A wallet holding accounts on more than one writes one export per network.accounts: Mandatory array of account objects.
Must contain at least one account.
See Account Object Structure.
The optional signers array holds information about devices that hold key material
present in at least one account's descriptor. See Signer Object Structure.
Account Object Structure
Each account object in the accounts array represents a single account within the
wallet and must contain the type and descriptor fields.
Its fields are listed in the field registry.
type: Mandatory string naming the account descriptor type.
Must be one ofbip380(output descriptor),multi_bip380(a set of BIP-0380 output descriptors),bip388(wallet policies), orbip392(silent payments).descriptor: Mandatory value representing the account descriptor, with structure defined bytype.
The value is a string for every type exceptmulti_bip380, which uses an array of strings.
A multi_bip380 account groups several BIP380 descriptors without further restriction.
This can be needed for wallets such as Electrum.
Signer Object Structure
Each entry in the signers array describes one holder of key material: a hardware
device, a piece of software, or a remote service. A signer must contain the
fingerprints field, and the field must not be empty.
The signer object's fields are listed in the field registry.
fingerprints: Mandatory array of BIP32 fingerprints held by this signer, in hexadecimal form.
The field is a list because one signer can hold several master keys, as with a device
that has more than one mnemonic loaded, or several keys generated using the BIP-0039
passphrase mechanism.
The relation is many-to-many: a key restored onto two devices appears in the
fingerprints of two signers.
Signers are listed in the wallet object rather than inside each accounts object because
a signer can be related to several accounts and none of its metadata should change
between accounts. A signer used by three accounts is written once, so the copies
cannot drift.
Key Object Structure
Keys in the keys dictionary are indexed by their
BIP32 fingerprint.
Each key object records how this account uses the key and must contain the key
field. Its fields are listed in the field registry.
What the key is, independent of any account, belongs in the wallet-level signers
array instead. The fingerprint is the shared key that reconciles the two.
key: Mandatory string representing the public key fingerprint in hexadecimal form.
Transaction Object Structure
Values of the wallet's transactions map are JSON objects, each describing a single
transaction. Each is keyed by its transaction id, so the object itself carries no
identifier. Its fields are listed in the field registry.
Coin Object Structure
Each entry in the coins array is a JSON object describing a single output owned by
the account and must contain the outpoint field.
The coin object's fields are listed in the field registry.
A coin object records wallet state: what the account owns and what the user has
decided about it. Silent payment outputs are coins too, and carry a tweak alongside
the rest.
outpoint: Mandatory string representing the outpoint in the form<txid>:<vout>.
Importing
When importing a file defined by this specification, software should follow these guidelines:
- Software should validate the structure, ensure at least one account is present, and check that every object carries its mandatory fields before attempting import.
- Software, during import, should preserve all metadata it supports and discard unsupported fields.
- Software should warn users if essential data cannot be restored.
- Wallets may truncate labels or other string fields if necessary, but should warn users when truncation occurs.
Encryption
This format can be encrypted following BIP-138.
Security Considerations
- The format MUST NOT include mainnet secret signing keys or mnemonics, since an export kept as a backup may be stored online or in cloud storage. A BIP-0392 descriptor may include a private silent payment scan key, which is allowed on mainnet.
- Care should be taken to ensure that proprietary metadata does not contain sensitive information.
Backwards Compatibility
This format is extensible and allows future additions without breaking compatibility.
New fields are added through the field registry, and
wallets should gracefully handle unknown entries by ignoring them.
For all enum types, if the field is optional and the enum type is unknown, the field must not be imported, but import of the file SHOULD NOT fail.
Reference Implementation
TBD