Beersy
BRC-197

Accumulating Right-of-Sale Listings and Purchase Orders

A seller who wants to offer a standing, unlimited-quantity item on-chain has no good way to do it: a normal can only be spent once, so "buy this as many times as people want" usually means minting a fresh listing for every sale, tracking revenue off-chain, and trusting the seller to actually pay out everyone who bought. This makes it hard to run a reusable storefront listing where many buyers purchase from the same offer and revenue splits between multiple people are enforced automatically rather than by promise.

Ty Everettchanged 1 Oct 202618 min read

Reference for an AI

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

Summary

Why
Sellers need a reusable, repeatedly-purchasable listing whose price accumulation and revenue split among multiple recipients are enforced by the blockchain itself, not by the seller's word.
What
BRC-197 is a Bitcoin Script covenant family for a sale listing UTXO that can be purchased repeatedly, split, merged, paid out and retired while enforcing an immutable descriptor and a unanimously-amendable revenue schedule.
How
A seller creates a genesis transaction locking a listing UTXO with a fixed program and metadata encoding price, reserve, recipients and weights; buyers spend and recreate it with the purchase price added and a one-satoshi receipt output, while the seller separately splits, merges, pays recipients, amends the schedule,…

What this lets you do

  • Let any buyer purchase from a single reusable listing UTXO
  • Accumulate purchase price on-chain without an off-chain ledger
  • Split or merge listing chains under one revenue schedule
  • Pay recipients according to enforced weighted shares
  • Amend the revenue schedule only with every current recipient's consent

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

genesislistingpurchasepayout

The specification

Abstract and status

A reusable sale listing is a . Anyone can purchase by spending it, recreating it with exactly the purchase price added, and recording a recipient-bound purchase. The seller can split and merge sale chains, pay their accumulated revenue, retire a listing, or amend its revenue schedule. Bitcoin Script enforces those transitions and the recipients' shares; the seller cannot bypass them through an administrative branch. Changing recipients or shares requires the consent of every current recipient.

This proposal registers one concrete executable family, https://bsv.brc.dev/tokens/0197#revenue-listing-v1. Its exact program, data encoding, unlocking ABI, reproducible source and transaction corpus are part of this BRC. It also specifies the separate evidence needed to authenticate a lineage and associate a purchase with fulfillment. Script execution does not establish asset ownership, genesis authority, unspentness, mining, or delivery of an off-chain item. Those remain explicit verification obligations.

The artifact and both independent Script checks are available in the family package. They qualify the specified byte-level examples, not a deployed wallet, miner acceptance policy, audited financial product or atomic fair exchange. Implementations must name their enabled family and routes and complete the relevant integration qualification before offering purchases.

1. Descriptor, revenue schedule and authorized genesis

Use BRC-192 canonical JSON and primitive encodings:

type RevenueState = {
  revision: U64;
  recipients: { identity: Identity; weight: U32 }[]
}
type ListingDescriptor = {
  version: 1; chain: Chain; assetId: Hex32; seller: Identity;
  lineageAnchor: Outpoint; purchasePrice: U64; reserve: U64;
  termsDigest: Hex32; scriptFamily: string;
  administration: 'none' | 'seller-v1'; metadataDigest: Hex32;
  initialRevenue: RevenueState
}

Price and reserve are positive and at most 2100000000000000 , the pinned BRC-100 SatoshiValue maximum. The 's chain equals the descriptor and configured verifier chain. scriptFamily is exactly the registered family IRI above. assetId commits to an immutable asset description under the selected domain schema; termsDigest commits to the purchase terms, and metadataDigest to versioned metadata. This base contract does not assume encrypted content or a particular application.

A revenue schedule contains one through eight distinct valid compressed identities, sorted by their 33 raw bytes. Each integer weight is 1 through 10000 and their sum W is at most 10000. The integers define payout quanta: one complete quantum pays recipient i exactly weight[i] satoshis. They need not be reduced fractions; choosing 2:2 specifies a four-satoshi quantum, whereas 1:1 specifies a two-satoshi quantum. Publishers should use reduced weights when they want the smallest exact payout quantum. No recipient is omitted because its allocated output would be small. Initial revision is the string "0".

listingId = digest("sale-listing", descriptor). The descriptor, including the initial revenue schedule, is immutable. Price, seller, asset, terms, reserve, administration or initial schedule changes require another lineage. A permitted amendment changes the current revenue state of a descendant, not the descriptor or listing ID. This distinction lets old purchases and a standing offer retain their meaning while current recipients unanimously authorize a new distribution schedule.

Genesis consumes lineageAnchor at input zero and creates exactly one listing at output zero with value reserve and the exact initial state. Genesis version is 1 or 2, locktime zero, all input sequences final; it has one through eight inputs and one through eleven outputs. No other output is a listing of this family/descriptor or an ROSL operation receipt. Ordinary funding/change outputs are permitted. A seller-signed BRC-192 packet of type sale-genesis, body {version:1,listingId:Hex32,genesis:Outpoint}, authorizes that exact . Verify the consumed anchor, transaction, descriptor, exact script and seller signature; asset authority is checked separately under the selected domain profile. The anchor already exists before the descriptor is signed, avoiding a hash cycle with genesis.

A matching script alone is not a genuine listing. Every accepted descendant requires all permitted predecessor paths back to the authorized genesis, including both branches of every merge. Copying the script into an unrelated transaction does not establish that ancestry. Script preserves state along real spends; lineage verification establishes which initial issuance those spends descend from.

2. Exact locking script and authenticated introspection

The is the following concatenation, with no additional bytes:

4d a8 01 || metadata[424] || 75 || program

4d a8 01 is OP_PUSHDATA2 of 424 bytes and 75 is OP_DROP. All offsets below are zero-based within metadata. Bytes 0–4 are ASCII ROSL followed by version 01. Offset 5 contains (32 bytes), 37 termsDigest (32), 69 purchasePrice (uint64le), 77 reserve (uint64le), 85 seller (33), and 118 the administration flag (00 for none, 01 for seller-v1). The current state begins at 119: revision uint64le, recipient count at 127, then eight fixed 37-byte slots starting at 128. Each used slot is identity[33] followed by weight uint32le. Unused slots are all zero. Thus current state is exactly 305 bytes. Hashes are decoded from display hex without reversing; prevout transaction hashes retain Bitcoin's usual serialized byte order.

The normative program is program.hex, decoded as hex without its trailing newline: 39580 bytes, SHA-256 ae47a6cc9bdc955d6aa73cdc459bbd6bbe493419dcf3ed3fc952a95c8c510716. The complete locking script is 40008 bytes. Exact inverse parsing checks this program, all prefix bytes, descriptor , current state rules and zero padding. Recognizing the data prefix while ignoring the program is forbidden. Alternative executable bytes, optimizations or changed parameter encodings require another immutable family IRI.

RevenueListing.runar.ts and compile.mjs reproduce that program with Rúnar commit b3f08f2cc2349c311904d2c745dc19d65f23e8ca, using the options and source/raw/final hashes in artifact.json. The documented instruction-aware normalization removes the compiler's sole OP_CODESEPARATOR at raw byte 2 so the preimage authenticates the entire script including metadata. It also expands the single OP_2MUL instruction in the preimage binder to OP_2 OP_MUL, equivalent for that bounded integer and usable by both independent interpreters. It never rewrites matching bytes inside pushed data. The build refuses an unexpected compiler layout. The frozen final bytes are authoritative for this version; compiler availability or a matching source file alone is insufficient.

The program's checkPreimage construction binds the transaction preimage through an on-chain ECDSA check, using the technique discussed in BRC-21. It authenticates current outpoint, input value and full scriptCode, complete prevout and sequence hashes, version, locktime and all output bytes with SIGHASH_ALL | SIGHASH_FORKID (0x41). No caller assertion substitutes for this binding; SINGLE, NONE and ANYONECANPAY are forbidden. Every operation has version 1 or 2, locktime zero and final sequence 0xffffffff on all inputs.

There are two through eight total inputs, including at least one external funding input; merge requires three through eight. Non-merge operations consume exactly one listing at input zero. Merge consumes exactly two listings at inputs zero and one. Each invocation proves its own outpoint's required position against the authenticated prevout vector; Bitcoin also rejects duplicate inputs. No additional family listing input can satisfy these same output predicates at another position. Every operation has at most eleven outputs: the route's exact listing outputs, exactly one receipt, exact payout outputs when applicable, and optionally one standard 25-byte change output. The hash of this reconstructed serialization must match . Undeclared outputs, another receipt, or another listing successor cannot be hidden in change.

Satoshi arithmetic is checked before constructing outputs, each of which is positive and no greater than the SatoshiValue maximum. The current listing is at least reserve. Bitcoin input/output additionally holds. Complete prevouts and sequences, not an alleged input index or list of amounts, are bound. For merge, each invocation authenticates the other listing's full previous transaction by its hash and output index, parses it completely and checks the same entire locking script, amount and reserve. Its parser accepts canonical CompactSize up to four-byte lengths, raw predecessor at most 1 MiB, one through eight inputs and one through eleven outputs, and no trailing bytes. It rejects a short read, nonminimal length, oversized value or out-of-range output. This proves both amounts without trusting an off-chain total.

3. Purchase and exact receipt

Operation 1 needs no seller signature. Output zero has the consumed locking script byte-for-byte and value oldValue + purchasePrice. Output one is exactly one satoshi with this locking script:

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

This is followed by one minimal 167-byte data push; the full script is 171 bytes. The program verifies exact prefix/length, listingId, termsDigest and a valid compressed recipient point, using the supplied Y-coordinate witness. The transaction cannot use a malformed point. The domain validator still checks that this recipient is the prepared buyer and that and requestDigest match the selected fulfillment protocol. A valid purchase for a different real recipient can pass Script and fail that domain association; the layers must not be confused.

A standalone domain declares the canonical request and acquisition ID derivation. Under BRC-196, use exactly its prepared acquisitionId and requestDigest. Receipt digests are ordinary 32-byte values, not reversed txids. Recipient linkage is public; this version makes no anonymous-purchase claim.

External funding pays the price increment, one-satoshi receipt and fees. The old listing cannot fund them. One optional P2PKH change output follows the receipt. For a price of 1001 and reserve 1, two successive purchases produce 1002 then 2003 satoshis. Recovery of purchased rights is separate from the current catalogue state or whether the buyer immediately retrieves a private result.

4. Administrative routes and enforced revenue

administration=none enables purchase only: accumulated funds have no withdrawal, amendment or retirement route. The locked-funds consequence must be shown before genesis. BRC-198's settlement requires seller-v1. That mode enables all five administrative operations below; partial route implementations must not advertise complete seller-v1 support.

Every administrative listing input verifies a raw Bitcoin transaction signature by descriptor.seller with final hash-type byte 41, in addition to its covenant predicates. Amendments also verify signatures from every current recipient. These are transaction signatures, not BRC-77 messages or a signature over a free-standing promise. They commit to that input's preimage and the complete transaction outputs. A signature for another amendment, input or transaction cannot be reused. Wallet integrations must support this signing authority explicitly; extracting a wallet identity secret is not an integration method.

The one-satoshi admin receipt immediately follows the continuing listing outputs. Its 90-byte script is 00 6a 4c 56 followed by the 86-byte payload:

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

m and n are the route's exact listing input/output counts. For split/merge commitment is 32 zero bytes. For payout/retire it is SHA-256 of the concatenation of the complete serialized recipient outputs (amount, canonical script length, script), in schedule order. For amend it is SHA-256 of the new 305-byte state. Administrative receipts never create a purchase acquisition.

Split (2) has m=1, n=2 and payout=0. Both output scripts equal the consumed script, both amounts are at least reserve, and their sum equals the old amount. Only an existing balance sufficient for both reserves can be split. Pairwise splitting can create additional independently spendable sale chains; it cannot mint reserve or deduct a fee from proceeds.

Merge (3) has m=2, n=1 and payout=0. Both current scripts, including revenue revision and schedule, must be identical. Output zero uses that script and the exact sum of both authenticated amounts. The two distinct predecessor paths must pass lineage validation. Pairwise merging combines more chains. A newer schedule cannot absorb funds from an older schedule without that old schedule's separately authorized amendment first.

The shared-genesis check is a domain provenance rule, not an additional fact established by merge Script. An implementer traces both current inputs through their purchase/split/merge/amend predecessors to the exact seller-authorized genesis, using the visited DAG procedure in section 6. Missing history is unresolved. An unrelated output with copied metadata is not a second authenticated branch merely because its script is identical.

Distinguish that provenance failure from value forgery. A separately funded copy has real satoshis, and its identical script constrains those satoshis to the same recipients and schedule. A seller-authorized merge of it with a genuine listing can pass Script: the successor receives the exact sum. This does not invent proceeds or remove existing funds. It is economically an additional contribution under the current distribution rules, even though this version’s strict lineage validator rejects it as a claimed same-genesis merge. Conversely, fabricated predecessor bytes/amounts, missing real inputs, a reduced successor or a changed revenue schedule fail authenticated Script checks; no off-chain ancestry assertion can excuse them. Both listing inputs also require the seller’s signature, so an unrelated party cannot force that administrative merge.

A merge receipt is never a purchase receipt and cannot grant a License, release a private result, create a purchase count or assert that added funds came from sales. False ancestry can still corrupt attribution, sale statistics or application eligibility if a consumer treats balances as purchase history. Such domain consequences must be checked explicitly rather than described as on-chain loss of funds. A future contribution/top-up route could deliberately admit externally funded additions with accurate provenance; it must name that behavior and must not fabricate a sale or silently relax this profile’s same-genesis requirement. The conformance package includes a funded-copy merge that passes Script and is rejected by lineage validation to make this boundary observable.

There is also a liveness consequence: merging a genuine branch with an unrelated copy spends the genuine outpoint into a successor that this strict domain profile will not accept. Its descendants cannot repair the missing ancestry, so catalogue admission and further sales under this profile can stop even though the money remains subject to the enforced payout/retirement rules. Administrative clients MUST validate both complete lineages before requesting seller signatures and report unresolved evidence without proceeding. This is a seller-authorized loss of profile eligibility, not an action an outside party can force by merely creating a matching output. Existing valid purchases retain their historical entitlement; a later invalid merge cannot retroactively turn them into invalid purchases.

Payout (4) has m=n=1. The caller selects positive integer payoutUnits q; payout P=q×W. Output zero retains the exact script and oldValue−P, which must be at least reserve. Immediately after the receipt are exactly count P2PKH outputs in schedule order, each locking q×weight[i] satoshis to (identity[i]). No seller-selected substitute destination or aggregate collector output is permitted. A sub-quantum remainder stays in the listing until another payout; it is neither rounded toward one recipient nor silently spent on fees. For oldValue=3004, reserve=1 and weights 7:3, paying 300 quanta distributes 2100 and 900, retaining 4 in the listing.

Retire (5) has m=1, n=0. It pays every recipient, including distribution of the old reserve. To preserve exact shares, q=ceil(oldValue/W) and P=q×W. External funding supplies the explicitly disclosed top-up P−oldValue, between zero and W−1 satoshis, along with receipt and fees. This is the only route whose distributed amount can exceed the consumed listing value. The wallet must display and authorize that exact top-up; it cannot deduct it from someone else's entitlement or round a recipient down. If the operator does not fund it, the listing remains available for ordinary payouts; retirement is optional. With oldValue=2004 and W=10 the top-up is 6. A nonzero residual is never discarded on retirement.

Amend (6) has m=n=1 and payout=0. The successor retains the full old amount. Only the 305-byte state changes: revision must increment exactly once without U64 overflow, and the new schedule must satisfy all count, sorted uniqueness, curve, weight and zero-padding rules. Every identity in the old schedule signs, including a removed recipient; one seller approval or a majority is insufficient. The seller additionally signs even if not a recipient. New recipients need not sign under this profile. Old recipients therefore consent to redirecting the entire retained balance, including accumulated remainders, and all future proceeds of this particular UTXO. Consent must show both schedules and amount. Previously issued purchases/licenses are unaffected.

An amendment concerns its consumed chain only; siblings keep their own current schedules. To update an entire split lineage, gather consent and amend each branch, or merge matching old-state branches before one amendment. It is not possible to change unconsumed outputs globally. All resulting listings keep the immutable descriptor and listing ID. Ordinary split, merge and purchase preserve state byte-for-byte.

For all non-retirement admin operations, sum(listing inputs) = sum(continuing listings) + payout. Retirement instead has oldValue + explicitTopUp = payout. External funding pays every receipt and fee. The optional final output is standard P2PKH change whose exact bytes are committed by all signatures and hashOutputs. Revenue outputs do not prove that a recipient has spent or internalized them, only that the transaction pays the specified locks.

5. Unlocking ABI and construction

There is one public entry point, spend, with exactly fourteen pushed stack arguments in this order:

preimage, prevouts, operation, receipt, recipientY, splitAmount,
 payoutUnits, otherPrevious, newState, newKeyYs, adminSignature,
 consents, changeHash, changeAmount

All pushes use Bitcoin's minimal push encoding; numeric arguments use minimal nonnegative signed-magnitude Script integers (zero is an empty push). preimage is the full 0x41 preimage for this input, bounded to 1 MiB. prevouts is the complete concatenation of serialized txid[32]/index[4] pairs. operation is 1 through 6 and receipt is the complete receipt locking script.

recipientY is the 32-byte big-endian Y coordinate for purchase, empty otherwise; the curve equation, canonical field range and parity of recipient are checked. splitAmount is the first successor amount for split, zero otherwise. payoutUnits is positive only for payout and zero otherwise (retire computes its own). otherPrevious is the complete other listing predecessor transaction for merge, empty otherwise. Each merge input supplies its own counterpart.

newState is exactly 305 bytes and newKeyYs exactly eight 32-byte Y witnesses only for amend; unused Y slots are zero. adminSignature is strict DER, low-S plus byte 41 for admin operations and empty for purchase. consents is empty except for amend, when it is eight 73-byte slots in old schedule order. Each used slot is one unsigned length byte (9–72), that many signature bytes including 41, and zero padding through the slot end; unused slots are zero. Missing, duplicate-as-a-substitute, wrong-key, non-41 or invalid signatures fail. Script verifies each against its old key, rather than trusting a recipient count supplied by the caller.

changeHash is always twenty bytes. When changeAmount=0 it is all zero and there is no change output. Positive changeAmount supplies one last P2PKH output. Fees and change are chosen by funding-wallet policy and then covered by the preimages; they cannot alter required listing/receipt/revenue amounts. The encoder and inverse parser and frozen transactions illustrate this ABI; they are fixture tools without wallet or network authority.

BRC-100 integration must use two-phase construction: request final funded input/output layout with signAndProcess:false and randomizeOutputs:false, verify returned layout and inputs, construct the covenant unlocks and any required administrative/consent signatures against that exact funded transaction, then finalize with signAction. Respect foreign-input unlockingScriptLength estimates and wallet support for the large scripts; check the finalized transaction again. No family signature may be constructed against a draft whose inputs, sequences, output positions, change or locktime the wallet subsequently changes. If the wallet cannot preserve this layout or support the required signing authority, report unsupported before spending. Raw fixture P2PKH signing is not claimed as BRC-100 wallet qualification.

6. Portable lineage and domain checks

The immutable purchase-domain profile is https://bsv.brc.dev/tokens/0197#listing-purchase-v1, distinct from the executable family identifier. 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}[]
}

Transactions are unique and sorted by txid. Each target equals txid, contains its exact raw transaction and supplies verification dependencies or explicitly unresolved references. The union of package entries contains genesis and every listing predecessor path to target, including both sides of merges. An individual entry may use a partial BEEF whose missing transactions are supplied by other entries. First collect and validate every target/raw binding, merge the BEEF dependencies under their exact txids, then verify the resolved graph; never reject a valid entry merely because its sorted position precedes a dependency, or accept an unresolved graph. Funding ancestors and can be carried inside the corresponding BEEF entries. This deduplication does not weaken genesis or predecessor verification. A maximum of 256 distinct listing transactions and 2 MiB decoded package applies; smaller local byte/work/deadline limits take precedence. Deduplicate by txid/outpoint with a visited set, reject cycles and unrelated or missing paths, and validate each transition once. Shared historical ancestors are not counted twice as current sale value. Unresolved evidence never becomes valid merely because a signature or hash matches. An installed bounded resolver can supply missing facts; no arbitrary URL is fetched implicitly.

For each transaction, verify BEEF/Bitcoin validity under the configured chain view, exact descriptor/family bytes, all relevant Script invocations and route structure. Genesis additionally needs the seller authorization and anchor rule. Recursively derive the current state; an amendment is accepted only with its actual predecessor schedule and all Script-verified consents. The target's script and amount must match the supplied transaction output. A copied script without the signed genesis path fails. A local verified cache may reuse immutable facts while reassessing context-dependent placement/currentness. A trusted checkpoint that replaces ancestry requires a separately declared trust profile and cannot claim this full-history profile.

Script checks transaction/introspection binding, amounts, exact successor/receipt/payout bytes, recipient curve membership and transaction signatures. The domain layer checks configured chain, genesis and asset authority, ancestry, installed family, BRC-196 acquisition/request/recipient association and currentness. Neither layer silently replaces the other. A script-valid purchase can fail fulfillment because its recipient or request belongs to another acquisition. A genuine old listing may already be spent. A seller signature cannot establish unspentness.

When used with BRC-196, domainEvidence supplies this package for the prepared input. An issuer verifies the final receipt against frozen preparation terms, including the exact current script/state already committed by that input. BRC-193 publishes coherent spent/created groups. Public replication need not possess private fulfillment data; public replay cannot release it. Reorganizations reassess projections and descendants while retaining historical acquisition/consent records.

A listing that cannot fit another price increment or bounded ancestry is unpurchasable under this profile. Stop offering it and explicitly supersede it with an authorized new lineage; preserve withdrawals and historic rights through their original supported route. Existing application tokens are not relabeled as this covenant. A mixed catalogue uses explicit type/profile tags. Split/merge/admin purchases can race; preparation is not an exclusive on-chain reservation and exact-transaction recovery remains necessary.

7. Qualification

The package includes real locking/unlocking scripts, raw complete transactions, full preimages and public fixture funding keys. Both the pinned BSV SDK and an independent BitcoinX interpreter execute every input. Positive cases exercise purchase, both split branches, merge, retained-remainder payout, unanimous amendment and exact/top-up retirement. Rejections mutate transaction predicates and recreate preimages/signatures so they test the covenant conditions, not merely an old signature over modified bytes. The accompanying evidence corpus exercises signed genesis, BEEF and prepared-purchase bindings separately.

Implementations claiming this family must match exact encoding/inverse parsing and reproduce its applicable acceptance/rejection vectors. Deployment qualification additionally requires supported BRC-100 wallet funding and consent signing, resource and fee acceptance on the intended node policy, exhaustive route/domain integration and independent review of the authenticated-preimage construction and economic rules. The common packet guide distinguishes these claims. Test transactions use disclosed keys and a synthetic chain view; they do not assert mainnet inclusion or a production security audit.

BRC-192 section 10 distinguishes the currently selected Bitcoin spend graph from this family's domain lineage. Its optional non-final reconciliation does not relax this family: every route still requires zero locktime and final sequences. A Script-valid, lineage-invalid successor can consume a genuine predecessor, including the funded-copy merge described above. Domain rejection cannot make that predecessor current again. Source membership and historical purchase/license evidence remain separate from current listing eligibility.

Was this helpful?

Search Beersy

Search standards by number, title, author or topic