Beersy
BRC-214Draft (proposed number, not a BSVA assignment)

Wallet Asset Profiles

A wallet can hold many different of value, like Bitcoin, other coins, collectable items, and tokens, but there has been no shared rule for keeping them separate when an app asks to see or spend them. Without that, an app given permission to spend a small amount of Bitcoin could end up able to grab an item or token it was never meant to touch, and apps have no clean way to ask a wallet what kinds of value it even holds before trying.

About Permissions, what an app is allowed to do with your wallet.

AlsoWallet callsRulebooks

Brandon Cryderman / HandCashchanged 29 Oct 20269 min read

Reference for an AI

Everything an assistant needs to answer questions about BRC-214 accurately, including what it depends on.

Summary

Why
Wallets need a shared way to separate different kinds of held value, like coins, items and tokens, so that permission to spend one kind can never leak into spending another.
What
BRC-214 defines a fixed set of named "asset " for a BRC-100 wallet, each with its own storage, proof, viewing method, spending method and permission , plus a listAssetProfiles call so apps can discover what a wallet supports.
How
A wallet calls listAssetProfiles to publish the ids, , spend and specs it supports for each profile, and every grant, view call and move call is then scoped to exactly one of those profiles, never crossing into another.

What this lets you do

  • Call listAssetProfiles to see which asset kinds a wallet supports before trying anything
  • Tell coins (BSV, Litecoin, Bitcoin, Dogecoin, Bitcoin Cash) apart from items and tokens by profile id
  • Keep a payment budget grant from ever being usable to move a token or item
  • Check a token profile's bnt flag before calling it a Bitcoin Native Token
  • Refuse or reject a request that mixes profiles instead of partially executing it

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

bsv

The specification

Abstract

A BRC-100 wallet holds more than one of value: BSV, coins of other chains, items, Bitcoin Native Tokens (BNT) and Issuer-Permissioned Tokens (IPT). Each kind has its own storage, its own proof of authenticity, and its own way for applications to see and move it.

This document calls those kinds asset profiles. A is the unit of everything an application can be granted. It fixes six things:

  • where the value lives;
  • what proves it;
  • how an application views it;
  • how an application moves it;
  • which actions exist;
  • which spending covers it.

Three rules make profiles safe to combine:

  1. Every held asset belongs to exactly one profile, for life.
  2. A grant in one profile never grants anything in another.
  3. Only coin profiles share the payment budget.

The document registers seven profiles (bsv, coin:<chain>, 1sat, bntft, bntnft, iptft, iptnft), which token profiles are BNT, and defines one read method, listAssetProfiles, so applications can learn what a wallet holds and accepts before asking.

Motivation

Each asset format so far has specified its own , permission scheme and actions in isolation. Each wallet then decides for itself how they interact:

  • Does Auto-pay cover a token transfer?
  • Does permission to view items show tokens?
  • Is a Litecoin balance a collectable?

Different answers in different wallets are a security problem, not a style choice. An application granted a payment budget must not be able to spend an item out of it.

Applications face the opposite gap. They cannot tell whether a wallet holds Litecoin or Issuer-Permissioned Tokens without calling methods and handling failures.

Relationship to other documents

ProfileSpecified by
bsvBRC-100, with budgets from BRC-73
coin:<chain>Draft BRC-213 (native UTXO-chain coins, #337)
1satBRC-147 storage, BRC-150 authenticity, BRC-165 permissions
bntftDraft BRC-255 (#335), with the BNT tests of draft BRC-251 (#320)
bntnftDraft BRC-255 (#335)
iptft, iptnftDraft BRC-253 (#333)

A peer paying an identity, not an application, learns which coin profiles that identity receives from its signed receiving record (BRC-213 §7.2), whose coin:<chain> entries are the profile ids here.

Market listings and direct offers for the asset profiles are draft BRC-254 (#334). Draft BRC-255 (#335) is the compact BNT format: its tokens file in bntft and its items in bntnft. A compact countersigned asset is BRC-253 §15, under its own marker ipt, and files in iptft or iptnft. Readers tell formats apart by their tags, never by profile.

A Bitcoin Native Token (BNT) passes the six tests of draft BRC-251: in the script, valid from transactions alone, moved by its holder alone, rules fixed at deploy, settled by Bitcoin, and peer to peer. bntft and bntnft hold only BNT. iptft and iptnft hold Issuer-Permissioned Tokens (IPT, BRC-253), never BNT.

Terms

  • Profile: a named kind of held value with the fields of §1.
  • Coin profile: a profile whose value is a plain payment unit (bsv, coin:<chain>).
  • Asset profile: any other profile. Its value has identity, is issued by someone, and is proven back to an or deploy.
  • Grant: anything a user gives an application that outlives one call: a view permission, a spend scope, an automatic-payment budget, a BRC-73 spendingAuthorization.

Specification

1. Profile fields

FieldMeaning
idLowercase identifier. Coin profiles of other chains are coin:<chain id>
HoldsWhat one unit is
CustodyWhere the value lives and whose key moves it
AuthenticityWhat proves a held unit is what it claims
ViewHow an application lists it, and which grant that needs
MoveHow an application spends it, and which consent that needs
ActionsThe application methods that act on it, each its own consent
Spending scopepayment (shares the per-application payment budget) or per-action (always its own prompt, never in a budget)
BNTToken profiles only: whether every unit is a Bitcoin Native Token (BRC-251)

2. Registered profiles

idHoldsCustodyAuthenticityViewMoveSpending scope
bsvWallet keys on BSVBRC-67 getBalance, listOutputs on the application's own basketscreateActionpayment
coin:ltcLitoshiThe wallet's coin key on Litecoin (BRC-213 §2)Burial 6 deep on the wallet's own Litecoin header chain (BRC-213 §4)listCoins({ chain: "ltc" })sendCoins({ chain: "ltc", … })payment
coin:bchSatoshiThe wallet's coin key on Bitcoin CashBurial 6 deep on its own Bitcoin Cash header chainlistCoins({ chain: "bch" })sendCoins({ chain: "bch", … })payment
coin:btcSatoshiThe wallet's coin key on BitcoinBurial 3 deep on its own Bitcoin header chainlistCoins({ chain: "btc" })sendCoins({ chain: "btc", … })payment
coin:dogeKoinuThe wallet's coin key on DogecoinBurial 20 deep on its own Dogecoin header chainlistCoins({ chain: "doge" })sendCoins({ chain: "doge", … })payment
1satOne-sat ordinal itemsOwner key on BSVBRC-150 proof to the originBasket p 1sat <scope> (BRC-165)createAction labeled p 1sat input id <key>per-action
bntftBNT fungible tokensOwner key on BSVBRC-255 §7 to the deployBasket p bntft <scope>Wallet methods only (BRC-255)per-action
bntnftBNT items (supply 1)Owner key on BSVBRC-255 §7 to the deployBasket p bntnft <scope>, with BRC-165 scopesWallet methods only (BRC-255)per-action
iptftCountersigned fungible tokens (IPT, not BNT)Owner key, plus the issuer's key set for each transferThe issuer's countersignature in each transferBasket p iptft <scope>Wallet methods only (BRC-253)per-action
iptnftCountersigned items (supply 1, IPT, not BNT)As iptftAs iptftBasket p iptnft <scope>Wallet methods only (BRC-253)per-action

coin:<chain> registers one profile per BRC-213 binding. A wallet lists only the chains it supports.

3. Rules

  1. One profile, for life. A held asset belongs to exactly one profile from the moment the wallet records it. Nothing moves an asset between profiles. Even a countersigned asset whose issuer released it stays iptft or iptnft.
  2. Grants never cross. A grant in one profile gives nothing in another. Permission to view 1sat items shows no tokens, a bntft view never shows an item, and a payment budget never covers an asset profile.
  3. One payment budget. All coin profiles share one budget per application: any automatic-payment budget the wallet keeps, and any BRC-73 spendingAuthorization grant. A payment in coin:<chain> counts at its BSV-equivalent fiat value (BRC-213 §10). An application cannot route around its budget by paying on another chain.
  4. Asset actions stay per-action. A transfer, mint, issue, listing, purchase or offer that moves an asset profile is never approved automatically, even when it also pays satoshis. The satoshis it pays do not open a payment-budget path for the asset.
  5. Separate views. A wallet shows each profile in its own place, and never counts an IPT in a BNT balance. Coins are balances, never collectables or tokens. Items are never mixed into token lists. A retired or migrated record of an earlier format is not shown as value in any profile.
  6. Refuse by profile. A request that names one profile but would move value of another is refused, not partly executed.
  7. No profile, no value. A wallet MUST NOT count, price or offer value it cannot place in a profile it supports.

4. listAssetProfiles()

This method requires a connected application and shows no further prompt. It tells the application which profiles the wallet supports and how to reach each. It reveals no balances.

{
  "profiles": [
    { "id": "bsv", "scope": "payment", "spec": ["BRC-100"] },
    { "id": "coin:ltc", "scope": "payment", "spec": ["BRC-213"],
      "chain": "ltc", "decimals": 8, "minConfirmations": 6,
      "methods": ["getCoinAddress", "listCoins", "sendCoins"] },
    { "id": "1sat", "scope": "per-action", "spec": ["BRC-147", "BRC-150", "BRC-165"],
      "basket": "p 1sat", "spendLabel": "p 1sat input id" },
    { "id": "bntft", "scope": "per-action", "spec": ["BRC-251", "BRC-255"], "basket": "p bntft", "bnt": true },
    { "id": "bntnft", "scope": "per-action", "spec": ["BRC-255"], "basket": "p bntnft", "bnt": true },
    { "id": "iptft", "scope": "per-action", "spec": ["BRC-253"], "basket": "p iptft", "bnt": false },
    { "id": "iptnft", "scope": "per-action", "spec": ["BRC-253"], "basket": "p iptnft", "bnt": false }
  ]
}
  • spec lists the documents the wallet implements for that profile, so an application can tell a draft-level implementation apart.
  • basket is the prefix of the view basket, and spendLabel the prefix of the spend label, where they exist.
  • Coin profiles carry the BRC-213 binding facts an application needs to show amounts and waiting times.
  • bnt is present on token profiles only. An application MUST NOT call an asset a Bitcoin Native Token unless its profile has bnt: true.

A wallet MUST list only profiles whose full rule set it enforces. An application MUST treat a missing profile as unsupported, and MUST NOT probe for it with spending calls.

5. Registering a profile

A new profile is registered by a document that fixes every field of §1 and states how it satisfies §3. A profile whose units can pay for anything SHOULD be a coin profile and join the payment budget. A profile whose units have identity MUST be per-action.

Security considerations

  • Budget escape. Without rule 3, an application limited to $10 a day in BSV could pay unlimited Litecoin. Without rule 4, a budget sized for small payments could move a valuable item that happens to cost one satoshi to send.
  • Confused deputy. Rule 6 stops a request built for one profile from reaching inputs of another, such as a createAction spend label that selects an output filed elsewhere.
  • Fingerprinting. listAssetProfiles reveals which profiles a wallet supports, not what it holds. A wallet MAY answer it only after connection, as specified, to avoid exposing even that to unconnected sites.

Rationale

  • The profile is the unit of consent. Users reason about "my Litecoin" or "my items", not baskets or script templates. Grants that follow that line are the ones users can predict.
  • Format is not profile. A profile names a class, not an encoding. What a holder can do with an asset depends on whether it is native or countersigned, not on how its lock is encoded.
  • Native is objective. BNT is decided by six tests a reader checks from the token's rules, not by who issued it, so the bnt flag is a fact about the profile and never a rating.
  • Coins share one budget, assets never do. Coins are interchangeable at a price, so one fiat budget is meaningful. Assets are not interchangeable, so no budget can describe them.

Open questions

  1. Per-profile budgets. Some users may want a smaller budget for one chain. That would narrow rule 3 without breaking it, because the shared budget stays an upper bound.

Implementations

HandCash Desktop and Mobile (@handcash/wallet-ui) implement every profile in §2, with coin bindings coin:ltc, coin:bch, coin:btc and coin:doge. The code is in src/wallet/assetProfiles.ts (listAssetProfiles), and the profile table is in docs/asset-actions-and-permissions.md §0.

References

Was this helpful?

Search Beersy

Search standards by number, title, author or topic