Beersy
BRC-197

Accumulating Right-of-Sale Listings and Purchase Orders

Selling something once on Bitcoin is easy, but selling it over and over from the same listing without the seller babysitting every sale is hard. Normally you would need the seller online to approve each purchase and each payout to collaborators, which breaks down once there are multiple recipients sharing revenue or the seller wants to walk away. This makes it possible to run a listing that buyers can purchase repeatedly, that pays out to a fixed set of recipients automatically, and that anyone can wind down or settle after a deadline even if the seller disappears.

Ty Everettchanged 13 Oct 202614 min read

Reference for an AI

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

Summary

Why
A seller who wants to sell the same right-of-sale listing repeatedly and split the proceeds among several recipients has no way to do so without staying online to approve every purchase and every payout.
What
BRC-197 defines a reusable Bitcoin listing, locked by two frozen Script programs, that buyers can purchase repeatedly, that distributes revenue to a fixed set of recipients, and that anyone can split, pay out, or retire without the seller's ongoing cooperation.
How
A seller sets up a descriptor naming recipients and weights, derives per-role child keys off a protected identity root using derivation, activates the listing by spending a reserve-only stage, and from then on anyone can submit a purchase, trigger a payout, split the listing, or retire it past its expiry…

What this lets you do

  • Sell the same listing to multiple buyers without reissuing it
  • Split revenue automatically among up to eight recipients by weight
  • Let anyone trigger a payout without needing the seller online
  • Split one listing into two independent successor listings
  • Retire a listing and distribute its value after a committed deadline

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

purchase/payouactivation + lvalid route (1

The specification

Abstract

An active listing is a reusable Bitcoin . A buyer adds exactly one price increment and creates a recipient-bound purchase receipt. Anyone can withdraw whole revenue quanta to the committed recipients without the seller's cooperation. The seller can split a listing or retire it early using a protected, publicly derived child signing key. After a committed block height, anyone can retire it and distribute its entire value. The identity root private key never signs a Bitcoin transaction or receives a payment.

This pre-adoption replacement defines one exact family, https://bsv.brc.dev/tokens/0197#revenue-listing-v1. The two frozen, hand-authored Bitcoin Script programs are the conformance boundary. There is a reserve-only activation stage that verifies all public root-to-child links once on chain before a purchase can occur. The active routes are purchase (1), split (2), permissionless payout (4), and retirement (5). Routes 3 and 6 are invalid. Merge and revenue-schedule amendment are outside v1; a changed distribution requires a new descriptor and signed lineage. This family is one concrete exercise of the private-overlay design; separate future BRCs may define other revenue models.

Script does not prove asset authority, seller authorization, chain inclusion, unspentness or private fulfillment. Section 6 mandates domain and in addition to Script.

1. Descriptor, derivation and genesis

Use BRC-192 canonical JSON and primitives:

type RevenueSchedule = { recipients: { identity: Identity; weight: U32 }[] };
type ListingDescriptor = {
  version: 1; chain: Chain; assetId: Hex32; seller: Identity;
  lineageAnchor: Outpoint; purchasePrice: U64; reserve: U64;
  expiryHeight: U32; termsDigest: Hex32; scriptFamily: string;
  metadataDigest: Hex32; initialRevenue: RevenueSchedule
};

scriptFamily equals the IRI above. Price and reserve are positive and at most 2100000000000000 . expiryHeight is in 1 through 499999999 and must be disclosed before a buyer funds a purchase. The belongs to the configured chain. assetId, termsDigest and metadataDigest commit to the selected application's asset, offer terms and metadata. listingId = digest("sale-listing", descriptor). A new price, seller, expiry, recipient or weight requires a new signed lineage.

The schedule contains one through eight distinct valid compressed , sorted by their 33 raw bytes. Every weight is 1 through 10000 and their sum W is at most 10000. A payout quantum pays recipient i exactly weight[i] satoshis. Unused metadata slots are zero. Descriptor validation checks order, uniqueness and ranges before genesis and again during lineage validation. The activation Script checks the key links, used weights, unused slots and weight sum; it does not replace descriptor validation.

This transparent profile gives each identity R one reusable child Q for every BRC-197 role and payout:

protocolID = [2, "3241645161d8"]
keyID = "brc197 authority"
counterparty = anyone (the generator public key G)
invoice = UTF8("2-3241645161d8-brc197 authority")
t = intBE(HMAC-SHA256(compressed(R), invoice)) mod n
Q = R + tG

The derivation follows BRC-42 and BRC-29's invoice grammar, with derivationPrefix="brc197" and derivationSuffix="authority". Repeating this fixed is an explicit, narrow exception to BRC-29's ordinary unique-suffix privacy rule. Identity-to-child linkage is public; this profile makes no privacy claim. The seller's child signs split and early retirement. Each recipient's child is the sole destination of that recipient's revenue outputs. Wallet remittance must identify both fixed derivation fields, the recipient identity, and counterparty=anyone (the generator public key as sender identity). The wallet must verify that the P2PKH hash equals HASH160(Q) before crediting or spending the output. An ordinary per-output BRC-29 receiver is not presumed to support this profile.

Private-key containment is mandatory. Root and child scalars remain inside a protected wallet/signer and never appear in Script, unlocking data, remittance or an application process. A BRC-100-style signer/consumer boundary must return signatures, never private scalars. Since t is public, leakage of one child private scalar reveals the identity root scalar as d_root = d_child − t mod n. The activation witness contains only public points, public t and signatures computable from public values. Seller authorization of genesis uses BRC-77's protocol-derived message-signing child, not the root.

Genesis consumes lineageAnchor at input zero and creates exactly one activation-stage listing at output zero, valued at reserve. The seller signs a BRC-192 packet of type sale-genesis, body {version:1,listingId:Hex32,genesis:Outpoint}, authorizing that exact output. No active listing or purchase receipt occurs in genesis. Domain validation checks the anchor, stage bytes and packet. A copied stage or active Script is not an authorized listing.

Activation spends that stage at input zero with at least one external funding input. It creates one active listing at output zero with identical metadata and reserve, then optionally one P2PKH change output. External funding pays the fee. The stage Script verifies all root-to-child links and the exact active output hash. A direct active output that bypasses activation fails lineage validation.

2. Frozen Script and linkage proof

Each is exactly:

4d cd 02 || metadata[717] || 75 || program

The prefix pushes 717 metadata bytes, then OP_DROP. The stage program is activation.hex and the active program is active.hex, decoded without trailing newline. Their literal opcode listings are activation.asm and active.asm. The component guide specifies the ordered, reusable opcode fragments, byte offsets and size profile; their concatenation must reproduce the full listings. Independent assemblers must reproduce these bytes exactly. No compiler or contract language is part of the family. The artifact manifest pins component and complete-program lengths and SHA-256 digests.

The activation program is 33406 bytes, SHA-256 5152517f75ac4159aa5d34211f45ce12cd85386a8d1414169886b0d64dac1dea; its complete lock is 34127 bytes. The active program is 4906 bytes, SHA-256 5aff350548d3b420bf1a47b48b38af34bb5ecf28be5c797921c4e2a2cddd8dea; its complete lock is 5627 bytes. Any byte change requires a new family IRI after adoption.

OffsetFieldEncoding
0–5marker, version, profileASCII ROSL, 01, 01
6–37; 38–69; termsDigestraw 32-byte digests
70–77; 78–85price; reserveuint64le
86–89expiryHeightuint32le
90–122; 123–155seller root; childcompressed points
156recipient countone byte, 1–8
157–716eight 70-byte slotsroot[33], child[33], weight:uint32le; unused slots all zero

The profile byte is 01 in both stages; program bytes identify the stage. Exact inverse parsing checks the full program, metadata, descriptor and padding. Recognizing only a data prefix is insufficient.

Both programs authenticate the caller-supplied full SIGHASH_ALL | SIGHASH_FORKID (0x41) BIP143 preimage against the actual transaction before using it for introspection. They compare its SHA-256d to the supplied scalar z, then check two fixed-nonce ECDSA binders under the public generator G. They check the canonical 0x41 hash type, listing input at index zero, the complete 2–8 input prevout vector against authenticated hashPrevouts, scriptCode length, input amount, sequence, locktime and . The Script reconstructs every required output, including amounts, scripts and optional final change, and compares SHA-256d of their exact serialization with hashOutputs. Bitcoin independently enforces input/output . SIGHASH_SINGLE, NONE and ANYONECANPAY cannot satisfy these checks.

For the linkage proof, let r2=x(2G) and r3=x(3G) reduced modulo curve order n. For claimed scalar d and authenticated digest scalar z, Script checks low-S DER witnesses s_i = ±(z+r_i d)/i mod n and executes OP_CHECKSIGVERIFY under the claimed point. The two binders use d=1, point G; activation repeats the pair using d=t, point D=Q−R. A bounded slope witness proves that D is the curve difference of valid compressed Q and R. Script recomputes the exact public to check t. Thus it verifies Q=R+tG without on-chain scalar multiplication or a secret signature. The two distinct r_i remove the single-signature ECDSA sign ambiguity; z=0, zero signature numerators and the two binder exceptional digest values are rejected. Both r_i>p−n, so an alternative curve x-coordinate r_i+n is impossible. The family proof note gives the algebra and limits.

An activation builder must precompute and independently execute the complete stage transaction before funding genesis. An exceptional digest can be changed by rebuilding the transaction; a degenerate child requires a new descriptor. Neither permits omitting verification. The family bytes cannot be optimized in place after adoption.

3. Purchase and receipts

Operation 1 needs no seller signature. Output zero has the identical active script and oldValue + purchasePrice. Output one has value one satoshi and this exact 171-byte locking Script:

00 6a 4c a7 || ASCII("ROSL") || 01 || 01
 || listingId[32] || acquisitionId[32] || requestDigest[32]
 || buyerRecipient[33] || termsDigest[32]

Script verifies the buyer recipient's curve point against supplied coordinates and commits to the exact receipt. The domain validator also checks that this is the prepared BRC-196 buyer and that the acquisition and request digests match. A different real buyer's valid Script receipt cannot fulfill someone else's acquisition. External funding pays the price increase, receipt and fee; existing listing value is not deducted.

A provider must reject a new preparation once its current chain view is at or beyond expiryHeight and must disclose the height in the standing Offer. A purchase prepared before that cutoff remains subject to its signed BRC-196 delivery and recovery terms even if expiry occurs before confirmation or a later third party retires the successor. Expiry is not a refund or retroactive invalidation of an already valid purchase receipt.

The one-satoshi administrative receipt has exactly 90 script bytes: 00 6a 4c 56 and this 86-byte payload:

ASCII("ROSL") || 01 || operation[1] || listingId[32]
 || m:uint32le || n:uint32le || payout:uint64le || commitment[32]

It follows all continuing listings. Split's commitment is 32 zero bytes. Payout and retirement commit SHA-256 of all serialized recipient outputs in schedule order. An administrative receipt never creates a purchase right.

4. Value-preserving routes

Split (2) checks a seller-child transaction signature ending in 41. Outputs zero and one are identical active scripts with values at least reserve whose sum is exactly the old listing value. The receipt has m=1,n=2,payout=0. External funding pays receipt and fee. Both successors remain independent branches of the same lineage.

Payout (4) needs no seller or recipient signature. Any caller chooses positive integer q. With P=qW, output zero retains the identical active Script and oldValue−P >= reserve. Output one is the receipt with m=n=1,payout=P. Then exactly one P2PKH output per recipient pays q×weight[i] to HASH160(compressed(child[i])). A sub-quantum remainder stays in the listing. The caller funds receipt and fee externally. No alternate destination or seller-only bypass exists.

Retirement (5) has no continuing listing. A seller-child 0x41 signature permits early retirement. Without it, anyone may retire with authenticated nLockTime >= expiryHeight, nLockTime < 500000000 and nonfinal sequence on the listing input. Under the pinned BSV node's strict IsFinalTx height comparison, the earliest block for nLockTime=expiryHeight is expiryHeight+1; post-Genesis OP_CHECKLOCKTIMEVERIFY is a NOP and is not used. Set q=ceil(oldValue/W), P=qW; after the receipt, pay every recipient q×weight[i]. External funding supplies the exact top-up P−oldValue (0 through W−1 satoshis), receipt and fee. The full balance, including reserve and remainder, is distributed. Buyers and issuers must resolve purchase/retirement races by exact .

Finality follows Bitcoin's applicable rules and BRC-192 section 10; it is not an additional zero-locktime/all-final-sequence domain restriction. Constructors SHOULD normally use nLockTime=0 and 0xffffffff on every input for activation (0), purchase (1), split (2), payout (4) and seller-signed early retirement (5). Validators MUST also accept other locktime/sequence combinations that satisfy the frozen Script and the applicable Bitcoin finality rules, subject to the remaining domain checks. A nonzero locktime or an input sequence below 0xffffffff alone does not make a transaction non-final. In particular, a Script-valid payout with nLockTime=1 and all-final sequences, or with zero locktime and a nonfinal listing or funding sequence, preserves domain lineage when selected as a final spend. Rejecting its successor solely for that construction choice would let a permissionless caller consume a genuine listing into a domain-ineligible successor.

Permissionless expiry retirement (5, empty seller signature) still requires the Script-enforced height nLockTime at least expiryHeight and below 500000000, with the listing input's sequence below 0xffffffff. Every route may otherwise be observed before its locktime matures. Such an otherwise valid candidate is pending finality, not permanently domain-invalid: nonFinal=false retains it without provisional selection, while nonFinal=true may select it only as nonfinal intent, without consuming the listing, creating a spendable successor or authorizing a wallet action. Once final, either setting may select it under the normal dependency, conflict and selected-chain rules. Verified inclusion is evaluated in the containing block's applicable finality context; a valid settled transition cannot be excluded from lineage merely because it was non-final when first observed or differs from the recommended construction. Genesis authorization, activation, asset authority, exact route outputs and all other domain checks remain required. Neither provisional selection nor later maturation by itself constitutes BRC-196 release .

Every operation consumes one listing at input zero and at least one external funding input, with at most eight total inputs and at most one final standard P2PKH change output. Undeclared outputs fail the hashOutputs comparison. Concurrent consumption of another listing is outside this family. The listing balance cannot pay transaction fees.

5. Unlocking ABI

The active program takes fifteen pushed values in this exact order:

preimage, prevouts, operation, acquisitionId, requestDigest,
 buyerKey, buyerX, buyerY, units, changeHash, changeAmount,
 adminSignature, z, binderSignature2, binderSignature3

The stage program takes 99 public proof values first: seller then eight recipient slots, each with:

deltaKey, t, signature2, signature3, rootX, rootY,
 childX, childY, slope, deltaX, deltaY

It then takes the same fifteen common values with operation=0. At entry the active Script requires stack depth exactly 15 and the stage exactly 114. Unused recipient proof slots are empty stack items, checked by Script. Conforming constructors use push-only unlocking Scripts and minimal pushes/nonnegative . Validators execute the actual Bitcoin Script and must not reject an otherwise valid, economically equivalent mined spend solely because a third party used a different unlocking syntax; exact scriptSig bytes are not an authenticated part of the purchase commitment. preimage is the complete input-zero 0x41 preimage; prevouts is the full serialized prevout vector; z is SHA-256d(preimage) interpreted as a big-endian scalar modulo n. Purchase supplies its 32-byte IDs and valid buyer key/coordinates, with empty units and adminSignature. Activation has empty units and adminSignature, zero 32-byte IDs, zero 33-byte buyer key, and empty buyer coordinates. Split and payout likewise require zero IDs/key and empty buyer coordinates; payout also requires empty adminSignature. Retirement requires those unused buyer fields and empty units. units is otherwise the split first amount or payout q. adminSignature is present only for seller-authorized split or early retirement. If there is no change, changeHash is 20 zero bytes and changeAmount=0; otherwise they describe one final P2PKH output. These exact stack and unused-field requirements are consensus checks in the frozen programs, not merely builder recommendations.

The entry checks remove the unused-push txid mutation from the earlier draft: changing a purchase's units from OP_0 to OP_1, or inserting an unmatched listing-input push, now fails. They cannot make a Bitcoin transaction's txid unique. A valid extra push in an external P2PKH funding input changes its scriptSig and txid while leaving the authenticated listing-input preimage, outputs and payment unchanged. So does a OP_0 OP_DROP pair before the listing witness: it restores the required stack depth. The three complete transactions in purchase-variant.json demonstrate both mutations in independent interpreters. A purchase is therefore identified for BRC-196 recovery by the full 32-byte SHA256d(preimage) purchase commitment, with verified txids tracked as aliases. The reduced Script scalar z is not that commitment. Every alias must independently satisfy all input Scripts, the receipt, outputs and lineage; equality of a claimed digest alone never authorizes release. The exact txid remains part of historical release evidence and chain-currentness assessment. A transaction can have two through eight inputs, but only input zero may consume the listing in this family; the others are externally funded. No two conflicting txids can both spend its input-zero outpoint on one selected chain.

BRC-100 construction is two phase: obtain final funded inputs and outputs using signAndProcess:false and randomizeOutputs:false; verify the layout; form preimages and covenant witnesses for those bytes; request the protected seller-child signature when required; then finalize through signAction. Recheck the final transaction, sequences, output order, change and locktime. If the wallet cannot preserve this layout or safely sign/internalize the fixed child, report unsupported before funding a listing. Test fixture scalars are not an integration method.

6. Lineage and domain checks

The purchase-domain IRI is https://bsv.brc.dev/tokens/0197#listing-purchase-v1. Its evidence schema is https://bsv.brc.dev/tokens/0197#lineage-package-v1, serialized as UTF-8 JCS:

type LineagePackage = {
  version:1; descriptor:ListingDescriptor;
  genesis:{body:{version:1,listingId:Hex32,genesis:Outpoint},signature:Bytes};
  target:Outpoint; transactions:{txid:Hex32,beef:Bytes}[]
}

Entries are unique and sorted by txid. Each entry binds exact raw bytes and supplies verification dependencies or explicitly unresolved references. Collect the union before resolving dependencies; sorted order is not topological order. The graph includes genesis, activation and every active predecessor on the target's branch. Verify chain/Bitcoin validity, the exact input source and amount, both Script stages, seller genesis packet and anchor, route outputs and target. A copied active lock or stage-bypass output fails. Reject cycles, missing paths and unrelated copies. Limit the package to 256 distinct listing transactions and 2 MiB decoded bytes, subject to stricter local limits. Unresolved evidence is not valid purchase evidence. A verified cache may reuse immutable ancestors but must recheck current chain placement and unspentness.

The domain validator checks descriptor ordering, uniqueness and commitments, configured chain, asset authority, prepared BRC-196 acquisition/request/recipient association and currentness. It requires the listing at input zero and rejects another family listing among externally funded inputs; all inputs must verify as Bitcoin-valid. Script checks economic transitions, child links, payment destinations and transaction binding. Neither layer replaces the other. BRC-193 publishes coherent spent/created groups; public replay never releases private fulfillment. Reorganizations reassess current projections while preserving valid historical purchase records and the distinction between a historical release txid and a verified equivalent current alias.

7. Qualification and security boundary

The family package contains a connected reserve-stage activation, purchase, split, payout and retirement graph, a separate eight-recipient activation/purchase/payout graph, and fresh-preimage rejection vectors. Every complete transaction has signed external funding inputs. Independent BitcoinX and pinned BSV SDK interpreters execute the bytes. These tests validate examples, not a production wallet, miner policy, chain view, fair exchange or external security audit. Implementations must reproduce exact hashes and relevant acceptance/rejection vectors, then qualify the intended BRC-100 signer, fixed-child remittance, fee/resource policy and end-to-end lineage validation.

A leaked public-counterparty child scalar compromises its root; protected signer separation is a hard security assumption. Recipients must demonstrate ability to spend a fixed-child P2PKH payout before significant value is locked. A listing whose balance cannot fit another price increment remains withdrawable and may be retired, but cannot accept another purchase.

Was this helpful?

Search Beersy

Search standards by number, title, author or topic