# Mandala Token Protocol

## BRC-92: Mandala Token Protocol

Deggen (<deggen@kschw.com>)

### 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 Overlays. 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 satoshi assigned to each output.
6. Prefix everything with a UTF8 exclamation point `!` (0x21 in hex) for sake of measuring adoption.

#### Fungible Token

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

#### NFT Script

```xml
21 <assetId> OP_2DROP ...
```

### Transfers

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

![MFT](https://github.com/user-attachments/assets/a4aa7438-3269-40f1-a71f-c3712fdf20c9)

| inputs                  | outputs                                        |
| ----------------------- | ---------------------------------------------- |
| output holding 9 tokens | `21` `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 labels.

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 outpoint 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`.

```js
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](https://github.com/user-attachments/assets/51d63137-f3d6-4e66-b798-886499f449a7)

***

#### 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](https://github.com/user-attachments/assets/a8c0994b-796d-4a34-9549-1ebb8fd0770b)

**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 identity key. This transaction is used as the basis for a particular fungible token.

| inputs | outputs                                                                                            |
| ------ | -------------------------------------------------------------------------------------------------- |
| any    | `21` `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

| inputs                | outputs                                                           |
| --------------------- | ----------------------------------------------------------------- |
| authorized outpoint n | `21` `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.

| inputs                                        | outputs                                                           |
| --------------------------------------------- | ----------------------------------------------------------------- |
| authorized outpoint n                         | `21` `OP_DROP` `boundKey` `OP_CHECKSIG` (authorized outpoint n+1) |
| Any token outpoint with our genesis\_outpoint | no token outputs                                                  |

A chain of authorization outpoints is created such that the transaction DAG works as an immutable linked hash chain 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.

| inputs       | outputs                      |
| ------------ | ---------------------------- |
| Valid tokens | no 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](https://github.com/user-attachments/assets/3ea03c5e-3733-40d1-b94a-063013f89165)

| inputs                | outputs                                                           |
| --------------------- | ----------------------------------------------------------------- |
| authorized outpoint n | `21` `OP_DROP` `boundKey` `OP_CHECKSIG` (authorized outpoint n+1) |
|                       | `21` `assetId` `05` `OP_2DROP` `P2PKH`                            |

***

### Example Transactions

1. [Register](https://whatsonchain.com/tx/99476f7c4a1479e900c9d7901400a36ab949d21bfa3d906aa45f602edfc90e7a)
2. [Issue](https://whatsonchain.com/tx/9230b66fbc021294d35632dd2e8d31568b9c9fac8639a8d2bb5cd515f7957f31)
3. [Transfer](https://whatsonchain.com/tx/906aa812537af107a3ab1a094579f690c42145ec2e7e6a0cd8f16faa42cf1e55)
4. [Redeem](https://whatsonchain.com/tx/906aa812537af107a3ab1a094579f690c42145ec2e7e6a0cd8f16faa42cf1e55)
5. [Burn](https://whatsonchain.com/tx/27f092c784604a94c52fc45acecbac4f868fa41eab90a77290076d22eb2057a4)

### Implementations

Not yet available. Proposal stage.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bsv.brc.dev/tokens/0092.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
