BRC-165 Tokens

P1Sat Permission Scheme for Basket 1sat

This BRC defines the P1Sat basket permission scheme for BRC-100 wallets: scheme id 1sat under BRC-99 / BRC-116. Storage of collectables remains the plain basket 1sat (BRC-147). Applications request view access with a BRC-99 basket p 1sat (scope names the permission axis ; filter values ride ordinary tags ). Applications request spend authorization by labelin

David Case (david.case@shruggr.cloud) Brandon Cryderman / HandCash (brandongcryderman@gmail.com)

How it connects

Relationships

Authoritative content mirror

Full upstream text

View source
Rendered from tokens/0165.md at the indexed upstream commit

Abstract

This BRC defines the P1Sat basket permission scheme for BRC-100 wallets: scheme id 1sat under BRC-99 / BRC-116.

Storage of collectables remains the plain basket 1sat (BRC-147). Applications request view access with a BRC-99 basket p 1sat <scope> (scope names the permission axis; filter values ride ordinary tags). Applications request spend authorization by labeling createAction with p 1sat input id <key>, where <key> is the bare BRC-164 list key for the held row. Conforming wallets route those requests to a scheme module, normalize storage to 1sat where needed, apply view grants and per-action spend approval as specified below, and MUST NOT treat payment / auto-pay grants as item access.

This document does not redefine 1Sat chain theory, inscriptions, collections, or provenance proofs. It does not replace BRC-147 or retarget BRC-150.

Motivation

Plain BRC-46 baskets only support coarse grant/deny. Collectables need finer app access — one collection, one app, one creator, or the full inventory — without inventing a storage basket per filter and without forcing inventory to live under a p … name.

BRC-99 reserves p <scheme> … for richer permission modules. This BRC defines scheme id 1sat and separates storage from permission routing:

Layer Law
Storage basket 1sat (BRC-147)
View (list) basket p 1sat <scope> (Scopes); axis values in tags; other tags only narrow further
Spend createAction labels p 1sat input id <key> (BRC-164)
Provenance BRC-150 on storage 1sat

Basket Namespace

  1. Scheme ID: 1sat (no spaces; BRC-99)
  2. Basket name format: p 1sat <scope> where <scope> is a fixed axis token from Scopes (required). Basket names use only [a-z0-9 ] per BRC-100. Filter values are not part of the basket name.
  3. Wallet capability: Must implement storage basket 1sat per BRC-147; must route p 1sat … basket operations and p 1sat input id … labels to this scheme’s module; must enforce view grants on list and per-action spend approval on labeled spends
  4. Permission semantics: See View and Spend

Module presence detection uses the BRC-98 protocol p 1sat probe (security level 0); see Module detection. Wallets route by scheme id 1sat (BRC-116). That probe is not the default key-derivation protocol for new inventory tips. New tip key derivation SHOULD follow BRC-147 / wallet policy (e.g. plain protocol names such as onesat).

BRC-123 registry listing for this scheme is deferred (current §3.1 letter-first scheme ids do not admit 1sat).

Specification

Scheme identifier

  • Scheme id: 1sat (no spaces; BRC-99)
  • BRC-98 probe protocol: [0, "p 1sat probe"] (level 0; see Module detection)
  • BRC-99 basket form (view): p 1sat <scope> (scope required; see Scopes)
  • BRC-111 label form (spend): p 1sat input id <key> (<key> = bare BRC-164 list key)

Wallets that do not implement this scheme MUST reject operations under these identifiers per BRC-99 / BRC-98.

Module detection

Applications MAY detect whether scheme 1sat is available by probing a BRC-98 protocol under this scheme. Per BRC-98, protocol names are p <scheme-id> <rest>; the rest token for this probe is probe.

Probe (application behavior): call BRC-100 getPublicKey with:

{
  "protocolID": [0, "p 1sat probe"],
  "keyID": "1sat-module-probe",
  "counterparty": "self",
  "seekPermission": false
}

Notes:

  • Protocol claim: security level 0, protocol name p 1sat probe. Level 0 keeps the probe outside ordinary Level 1/2 protocol-permission UX when the wallet routes it to this scheme’s module (BRC-43, BRC-116).
  • Wallet behavior for supported vs unsupported p … protocols and baskets is already defined by BRC-98, BRC-99, and BRC-116 (route to a registered module by scheme id 1sat, or reject if the scheme is not supported). This BRC does not alter those rules.
  • Conforming module: when the wallet routes this getPublicKey to the 1sat module, the module SHOULD pass the request through (return a public key) so the probe succeeds without a user prompt.
  • keyID: 1sat-module-probe is RECOMMENDED for interoperability among probers; it is not a special wallet-reserved id beyond ordinary BRC-43 key-id rules.
  • seekPermission: false: RECOMMENDED so capability detection does not open a permission UI.
  • Interpretation: applications treat probe success (on a wallet that uses P-module routing) as evidence that scheme 1sat is registered, and a BRC-98/99 unsupported-scheme rejection as evidence it is not. Bare wallets without a permissions manager may not give a reliable signal; applications SHOULD only enable module-mediated labels/baskets when they expect P-module routing.

This probe does not grant view or spend rights. It does not change BRC-111 label rules; spend labels under this scheme still follow BRC-111’s p <scheme> <payload> form as specified in Spend.

Storage vs permissions

  1. Conforming wallets MUST file collectables in storage basket 1sat (BRC-147).
  2. Permission basket ids are p 1sat <scope> only (scope required). They are routing names only; held tips remain in 1sat.
  3. When a request uses a basket beginning with p 1sat (after BRC-46 trim/lowercase), the wallet MUST:
    • treat the request as scheme 1sat;
    • parse scope from the basket name (reject if missing or unknown; values are not in the basket name);
    • require axis tag value(s) on the request when the scope is not all;
    • normalize the storage target to basket 1sat;
    • apply view permission for that scope and value(s) (prompt or prior grant) before returning outputs;
    • enforce axis tags as a mandatory filter; other caller tags only narrow further.

View (listOutputs)

Scopes

After the scheme prefix p 1sat, a scope is required. The scope names a permission axis only. Filter values are not part of the basket name; they use ordinary output tags. The full basket name MUST stay within BRC-100 [a-z0-9 ].

Basket form Scope Meaning
p 1sat all all Entire storage 1sat
p 1sat collection collection Collection-scoped view; values from collection:… tags
p 1sat app app App-scoped view; values from app:… tags
p 1sat creator creator Creator-scoped view; values from creator:… tags
p 1sat id id Single-row lookup; values from id:… tags (BRC-164)

Rules:

  1. Bare p 1sat (no scope token) MUST be rejected. Full inventory uses p 1sat all only.
  2. Scope is exactly one token after p 1sat (all, collection, app, creator, or id). Extra tokens in the basket name MUST be rejected.
  3. Unknown scope tokens MUST be rejected with a clear error (fail closed). Future axes are added by revising this table.
  4. For scopes collection, app, creator, and id, the request MUST include at least one tag with the matching prefix (collection:, app:, creator:, id:). The tag value (after the prefix) is the filter id. For collection, the value is a collection id per BRC-147.
  5. For scope all, no axis tag is required. Caller tags are optional further filters only.
  6. Matching tags follow BRC-147 / BRC-164. Exact tag equality after normal wallet tag normalization.
  7. Scope id is a targeted lookup, not full-inventory access. It MUST NOT require grant all. Conforming wallets MUST allow p 1sat id + id:<key> through the module without a prior collection/app/creator/all grant (auto-allow this narrow query, or an equivalent one-shot / id-scoped grant). Results MUST still be limited to the requested id:… value(s). Spend targeting remains Spend (p 1sat input id <key>), not this scope alone.

Request shape

{
  "basket": "p 1sat collection",
  "tags": [
    "collection:a1b2c3d4e5f6070890abcdef1234567890abcdef1234567890abcdef12345678_0",
    "type:image/png"
  ],
  "tagQueryMode": "all",
  "includeTags": true,
  "includeCustomInstructions": true
}
  • basket: p 1sat <scope> as in Scopes (axis only; scope required).
  • tags: for non-all scopes, MUST include the axis tag(s) carrying the filter value(s). Additional tags (e.g. type:) only narrow further.
  • tagQueryMode: applies to the caller’s tag set as constrained by Scope ceiling.
  • Apps MAY still call listOutputs with plain basket 1sat. That path is ordinary basket access (BRC-46 / BRC-116), not this scheme, unless the wallet elects to route plain 1sat through the same module as local policy.

Normalization

On listOutputs with basket p 1sat <scope>, conforming wallets MUST:

  1. Parse the scope (Scopes); reject bare p 1sat, unknown scopes, and basket names that embed values after the scope token.
  2. For non-all scopes, require at least one matching axis tag on the request; reject if missing.
  3. Require a view grant covering that scope and the requested axis value(s) (or prompt to create one) — see View grants.
  4. Rewrite the storage query basket to 1sat.
  5. Enforce the granted axis tag value(s) as a mandatory filter on results (tagQueryMode: "any" MUST NOT drop them).
  6. Apply any additional non-axis caller tags only inside that ceiling.
  7. Return only outputs that satisfy the grant and the effective tag query.

How the wallet enforces (4)–(6) (query rewrite, post-filter, or equivalent) is an implementation choice.

Denial SHOULD use a distinct error so apps can distinguish “user denied item view” from generic basket denial.

View grants

Item view is not covered by ordinary payment / auto-pay grants.

Each list request has one scope. The scope maps to a tag prefix (or to no prefix for all):

Scope Required tag(s) on the request
all none
collection one or more collection:…
app one or more app:…
creator one or more creator:…
id one or more id:…

The wallet queries storage basket 1sat with those tags (plus any optional extra tags the caller adds). Grant check is on this request’s scope and tag values, not a multi-axis matrix.

  • p 1sat all — requires a standing grant for full inventory (or a prompt that creates one).
  • p 1sat collection / app / creator — requires a standing grant that covers the requested tag value(s) for that scope (or a prompt). Grant all also covers these.
  • p 1sat id — no standing inventory grant; knowing id:<key> is enough to look up that row (see Scopes).

When the user approves a collection/app/creator/all request, the wallet SHOULD persist a grant for that scope and those tag values (or upgrade to all). Storage layout is local.

A later request MAY skip a new prompt when its scope and tag values are already covered by a stored grant (including grant all covering narrower scopes). Otherwise prompt or deny.

Scope ceiling and tag query

The scope’s required tags are mandatory on the result set. Optional extra tags (e.g. type:image/png) only narrow further. tagQueryMode: "any" MUST NOT drop the scope’s required tags.

Spend (createAction)

Spend targeting under this scheme is built on BRC-164 output identity tags. The held row MUST carry an id:<key> tag stamped by the holding wallet. The spend label names that key explicitly; the module resolves it back to the row with tag id:<key> under storage basket 1sat.

Label form

Held row (normative):

p 1sat input id <key>

Rules:

  1. BRC-111-style P-label: scheme id 1sat, payload input id <key>.
  2. <key> is the BRC-164 list key — the substring after id: on the held output’s tags. Non-empty, no spaces, no id: prefix in the label.
  3. Storage basket is implied by the scheme: 1sat.

Example (row tagged id:a1b2c3d4e5f60708):

p 1sat input id a1b2c3d4e5f60708

Multiple such labels MAY appear when the action spends multiple tracked rows. Rows without a BRC-164 id: tag cannot use this form.

Other input payloads. A label p 1sat input <outpoint> whose single payload outpoint is not the keyword id is outside this scheme’s permission model (e.g. naming a beefed external input). It is not a BRC-164 list key and is not further specified here. The normative spend path for wallet-held tips remains p 1sat input id <key>.

Module behavior

When createAction carries one or more p 1sat input id <key> labels, conforming wallets MUST:

  1. Route the call to the 1sat permission module (BRC-116).
  2. Resolve each <key> to a held output in storage basket 1sat via BRC-164 (id:<key>).
  3. Obtain user approval for this action’s spend before spending those outputs. Payment / auto-pay MUST NOT satisfy this. Send approval is per action (inline prompt); this BRC does not define a standing/persisted “can send items” grant.
  4. On approval, authorize only the spend set the user approved. A later createSignature (or equivalent) MUST NOT expand that set without a new approval.

Once an action is classified as a held-tip spend under this scheme (via input id <key> and successful resolution), payment auto-approve MUST NOT apply.

Outpoint spend without labels

Apps MAY still spend by outpoint without a p 1sat input label. That path does not enter this scheme via labels. Wallets SHOULD still refuse to spend storage 1sat outputs under ordinary payment grants (BRC-147 payment separation). Interoperable module-mediated spend targeting uses the input label form above.

Capabilities (summary)

Capability Wire Covers
View listOutputs basket p 1sat <scope> Listing storage 1sat under the module
Send createAction labels p 1sat input id … Per-action approval to spend labeled held rows (not a standing grant)

Receive / internalizeAction insertion into 1sat remains ordinary basket insertion under BRC-147 and wallet basket-access policy. Fine-grained receive grants are out of scope for this BRC.

Relationship to plain basket 1sat

Operation Plain 1sat p 1sat … / input labels
Storage of tips Yes (normative) Never
listOutputs Ordinary basket access Module view + scope grants
Spend targeting Outpoint / local policy p 1sat input id <key> (BRC-164)

Out of scope

  • Origin / sat-ordering / transfer consensus rules
  • Inscription envelope bytes
  • Collection membership proofs
  • BSV-21 fungible storage and permissions
  • Marketplace lock templates
  • Labels other than p 1sat input … under scheme 1sat
  • Fine-grained receive / internalizeAction grants

Security considerations

  • Tag / grant spoofing — View matching on tags is only as trustworthy as the holding wallet’s own stamps. Tags are claims; tip→origin proof is BRC-150.
  • Scheme bypass — Filing collectables only in a non-1sat basket loses this profile’s storage contract.
  • Payment separation — Pay / auto-pay MUST NOT cover view under p 1sat … or spends authorized via p 1sat input id ….
  • Scope ceiling — Extra caller tags MUST NOT widen past the granted axis values.
  • Approval binding — After a spend is approved, signatures MUST NOT authorize a different spend set without a new approval.

Implementations

  • 1sat-sdk — scheme module, input labels, scoped view
  • HandCash Desktop / Mobile — prior art for item view/send separation (storage 1sat)

References

  1. BRC-99: P Baskets
  2. BRC-98: P Protocols
  3. BRC-100: Wallet Interface
  4. BRC-111: Transaction Labels
  5. BRC-116: Wallet Permissions and Counterparty Trust
  6. BRC-147: 1Sat Ordinals Basket Profile
  7. BRC-150: 1Sat Provenance Remittance
  8. BRC-164: Output Identity Tags
  9. BRC-123: Basket Permission Scheme Registry (registry listing deferred; see Basket Namespace)