Beersy
BRC-92

Mandala Token Protocol

Token schemes tend to accumulate rules until they are hard to implement twice the same way. This keeps issuing, transferring, recovering and redeeming a token as small as it can reasonably be.

Darren Kellenschwiler5 min read
registerissuetransferredeem

Summary

Why
Bitcoin outputs only carry amounts, so there was no shared way to mark an output as representing a specific real-world asset that wallets, , and contracts could all recognize and verify the same way.
What
BRC-92 (Mandala Token Protocol) is a minimal pattern for tagging Bitcoin transaction outputs as fungible or non-fungible tokens, using a genesis output as the asset's identifier.
How
A token output pushes a prefix marker, the genesis transaction's id and output index as the asset id, and (for fungible tokens) an amount, then drops that data before any further script logic, and every transfer must balance input and output amounts per asset id, checked by an overlay watching for this pattern.

What this lets you do

  • Tag any transaction output as a token by pushing an asset id and amount onto its script
  • Transfer tokens by balancing input and output amounts under the same asset id
  • Issue new fungible tokens through a chained authorized controlled by the issuer
  • Redeem or recover tokens by spending them without creating replacement outputs
  • Mint an NFT whose ownership is provable via a key derived from an issuer

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

Reference for an AI

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

The specification

Abstract

Minimalist protocol for tokenization, issuance, transfer, recovery, and redemption.

Motivation

There is a lack of clarity with respect to how tokens can be defined and managed within the context of . This proposal aims to demonstrate the minimim viable solution for tokens, having considered all available options, picked the most viable, and made small improvements to allow for simple extension of functionality.

Specification

  1. Use a genesis transaction output as an assetId concatenating the txid and vout.
  2. Push that assetId to the stack in any output script you want to send that token to so that overlays, wallets, and smart contracts can evaluate it.
  3. Push the amount of tokens the output represents if it's a fungible token.
  4. Drop the data so that you can use whatever functional logic you like thereafter ...
  5. 1 assigned to each output.
  6. Prefix everything with a UTF8 exclamation point ! (0x21 in hex) for sake of measuring adoption.

Fungible Token

21 <assetId> <amount> OP_DROP OP_2DROP ...

NFT Script

21 <assetId> OP_2DROP ...

Transfers

The sum of input token amounts must equal the sum of output token amounts of the same assetId.

MFT

inputsoutputs
output holding 9 tokens21 assetId 04 OP_DROP OP_2DROP ...
21 assetId 05 OP_DROP OP_2DROP ...

The order of inputs and outputs is disregarded.

Design Justification

Include Genesis Output and Protocol Identifier In Every Output

Token outputs each refer to the genesis output as a way to avoid collisions when identifying the asset they represent. This acts as a universal asset identifier for enabling swap contracts and token based payment protocols. The randomness helps us avoid things like people competeing to claim the "USD" assetId or other potentially popular .

They also include a prefix of ! in utf8 as a way to tag outputs for tracking global adoption of the protocol; to reduce the cost of recovery from archival services; and for use within the context of IPv6 multicast group address routing.

Why Push Data Formatting?

The only reason to include the data in the outputs at all is for access to the data in smart contracts, any metadata ought to be kept in the application layer if needed.

Bitcoin Number format is used for the token amount.

Transaction format is used for the genesis outpoint information.

This is to ensure smart contracts can more easily parse the data within a transaction to enforce conditional logic based on token values, and enforce token type in a format which is already incorporated into the transaction format itself.

Single Satoshi Outputs

All outputs have 1 satoshi assigned to avoid AML problems like sending “a worthless bean token” to someone which actually has 100 BSV under it.

Tokenization: Deep Dive

NFTs

Non-Fungible tokenization is the process of associating something with a particular transaction output which will thereafter represent a claim to that something. We assume that the issuer has already registered a public key as associated with them: identityPublicKey.

const details = {
	entity: 'Local Comedy Troupe',
	asset: 'Ticket for show on 9/01/2024',
	address: '412 E 6th St, Austin, TX 78701'
}

const commitment = hash(details)
const anyone = new PrivateKey(1)
const pubkey = identityPublicKey.deriveChild(anyone, commitment)

We propose this key be referred to as a BoundKey.

The output looks like a regular P2PK but if you know the owner’s identity public key and the token details you are able to verify the association. The txid and vout of this transaction form the assetId for this NFT.

boundKeyNFT


Fungible Tokens

Fungible tokens sometimes require administrative management: multiple issuances to increase available supply, redemptions to reduce supply, recovery from loss in case of errors or theft. These things require an known issuer to steward the token system as a whole while keeping individual transactions private.

boundKeyFT

Registration

There is an issuer who is responsible for maintaining the relationship between tokens and the real world assets they represent. Before we issue any tokens, we register a public key by creating an authorized outpoint with a key derived from the issuer’s . This transaction is used as the basis for a particular fungible token.

inputsoutputs
any21 OP_DROP boundKey OP_CHECKSIG (the genesis outpoint, assetId, and authorized outpoint 0)

Issue

Once registered, tokens can be issued by creating a single transaction which:

  • spends the genesis outpoint
  • creates token outputs
  • creates the next authorized outpoint
inputsoutputs
authorized outpoint n21 OP_DROP boundKey OP_CHECKSIG (authorized outpoint n+1)
21 assetId 09 OP_2DROP P2PKH (creates 9 tokens)

Redeem

Redemption transactions spend token outputs without creating new ones, taking them out of circulation. The boundKey in this case could incorporate data associated with a withdrawal of funds from an associated bank account for example.

inputsoutputs
authorized outpoint n21 OP_DROP boundKey OP_CHECKSIG (authorized outpoint n+1)
Any token outpoint with our genesis_outpointno token outputs

A chain of authorization outpoints is created such that the transaction DAG works as an immutable linked of all administrative actions taken since genesis. Public audit-ability. No hidden issuances or redemptions. The token supply is known and provable.


Burning ⇒ Loss

When a token owner creates a valid BSV transaction which does not conform to the token transfer rules, the tokens are burned, and the transaction will not be accepted by the token overlay, despite perhaps being broadcast on the blockchain itself.

inputsoutputs
Valid tokensno token outputs, or too few

In this case, tokens in does not equal tokens out.


Recovery

Post burning, tokens which were lost can be recovered by the issuer by spending and creating an authorized output while including metadata into the derivation of a pubkey to indicate which txids are to be processed as having been spent invalidly.

recovery

inputsoutputs
authorized outpoint n21 OP_DROP boundKey OP_CHECKSIG (authorized outpoint n+1)
21 assetId 05 OP_2DROP P2PKH

Example Transactions

  1. Register
  2. Issue
  3. Transfer
  4. Redeem
  5. Burn

Implementations

Not yet available. Proposal stage.

Was this helpful?

Search Beersy

Search standards by number, title, author or topic