> For the complete documentation index, see [llms.txt](https://bsv.brc.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bsv.brc.dev/tokens/0161.md).

# BSV-21 Fungible Tokens (JSON / Legacy)

Open Protocol Labs (<info@opl.dev>)

**Authors:** David Case (<dcase@opl.dev>), Luke Rohenaz (<luke@opl.dev>)

**Contributors:** Kurt Wuckert Jr. (<kurt@opl.dev>), Michael Boyd (<root@opl.dev>), Dan Wagner (<dan@opl.dev>)

## Abstract

This document specifies the **legacy JSON wire encoding** of BSV-21 fungible tokens: an `ord` inscription with content type `application/bsv-20`. Token balances live in UTXOs. Each token is identified by the outpoint of its **deploy** output. Two supply models are supported:

1. **Fixed supply** — the entire supply is created in one deploy output.
2. **Auth (authority)** — deploy creates minting authority; later spends of authority mint new supply.

A binary script-prefix encoding of the same token model is described in [BRC-162](/tokens/0162.md).

## Motivation

Issuers need fungible tokens that:

* have a **stable id** that is not a global ticker race,
* move as **UTXOs** (split, merge, parallel spends), and
* support both **fixed supply** and **issuer-controlled minting**.

BSV-21 identifies each token by its **deploy outpoint** and carries balances on outputs. The token fields are a **prefix on the locking script**: they do not replace the spend condition. Any script can follow — P2PKH, multisig, covenants, marketplace templates, and other contract locks — so token value and Bitcoin script stay **composable**. Indexers enforce per-token supply and authority rules; consensus does not run a separate token VM.

The JSON encoding in this document puts those fields in an `ord` inscription (`application/bsv-20`). The envelope and 1-sat output are only the **carrier** ([BRC-160](/tokens/0160.md), [BRC-159](/tokens/0159.md)). Token identity, transfers, mints, and burns follow the UTXO and authority rules here — **not** 1Sat sat-ordering or origin tracking.

BSV-21 builds on an earlier **BSV-20** inscription format, which is **deprecated**. It keeps the same content type and JSON `"p": "bsv-20"` so existing inventory stays readable.

## Relationship to other documents

| Concern                      | Document                   |
| ---------------------------- | -------------------------- |
| UTXOs as tokens (philosophy) | [BRC-45](/tokens/0045.md)  |
| 1Sat origin and sat ordering | [BRC-159](/tokens/0159.md) |
| Inscription envelopes        | [BRC-160](/tokens/0160.md) |
| Offline BEEF validity proofs | [BRC-176](/tokens/0176.md) |

This BRC does **not** define marketplace locks, overlay topic naming, or BRC-100 basket profiles for tokens.

## Specification

### Token identification

* A **token id** is the outpoint of the deploy output that created the token.
* The `id` field MUST use the form `<txid>_<vout>`: 64 lowercase hex txid characters, underscore, non-negative decimal `vout`.
* That same underscore form is the token id everywhere else — APIs, storage, topic names, comparison. A token id is a BSV-21 identifier, not a general outpoint reference, so it does not take the [BRC-36](/outpoints/0036.md) dot form.
* The token id is fixed for the life of the token. Transfers never change it.

### UTXO model

BSV-21 balances are carried on transaction outputs. Spending a valid token (or authority) input and creating valid token (or authority) outputs is how supply moves, splits, merges, mints, or burns. Any Bitcoin locking script MAY lock a token output (P2PKH, multisig, covenant, marketplace template, …).

### Content type and inscription

JSON BSV-21 fields live in a 1Sat / `ord` **inscription** on the output locking script:

* Content type MUST be `application/bsv-20`.
* Body MUST be a JSON object.
* Protocol field `"p"` MUST be the string `bsv-20`.

Inscription envelope rules are defined in [BRC-160](/tokens/0160.md). Unrecognized JSON keys MUST be ignored; only fields defined here affect validity.

### Relationship to 1Sat Ordinals

The `ord` envelope is only the **carrier** for the BSV-21 JSON payload. Token identity, transfers, mints, and burns follow the UTXO balance and authority rules in this document — **not** [BRC-159](/tokens/0159.md) sat ordering or origin tracking.

A spend moves tokens because valid value (or authority) inputs fund valid outputs of the same token id. Whether the 1-satoshi lands in a particular output under ordinal theory is irrelevant to BSV-21 admission.

### Supply models

#### Fixed supply — `deploy+mint`

One output creates the token and holds the entire initial supply.

| Field  | Required | Description                                                |
| ------ | -------- | ---------------------------------------------------------- |
| `p`    | Yes      | `bsv-20`                                                   |
| `op`   | Yes      | `deploy+mint`                                              |
| `amt`  | Yes      | Total supply as decimal string, max `2^64 - 1`             |
| `dec`  | No       | Decimal precision 0–18; default 0; **string** integer only |
| `sym`  | No       | See [Symbol (`sym`)](#symbol-sym)                          |
| `icon` | No       | See [Icon (`icon`)](#icon-icon)                            |

```json
{
  "p": "bsv-20",
  "op": "deploy+mint",
  "amt": "21000000",
  "sym": "GOLD",
  "dec": "8",
  "icon": "abc123…def456_0"
}
```

Token id = this output's outpoint.

#### Authority supply — `deploy+auth`

Deploy creates **no** token value. The deploy output is the first **authority** UTXO. Later authority spends mint value.

| Field  | Required | Description                       |
| ------ | -------- | --------------------------------- |
| `p`    | Yes      | `bsv-20`                          |
| `op`   | Yes      | `deploy+auth`                     |
| `dec`  | No       | Decimals 0–18, default 0 (string) |
| `sym`  | No       | See [Symbol (`sym`)](#symbol-sym) |
| `icon` | No       | See [Icon (`icon`)](#icon-icon)   |
| `amt`  | No       | **MUST NOT** be present           |

```json
{
  "p": "bsv-20",
  "op": "deploy+auth",
  "sym": "STABLE",
  "dec": "2",
  "icon": "abc123…def456_0"
}
```

### Deploy under a contract

The **deploy** output may be locked with a covenant (or other contract) in the same transaction that creates the token.

In the fixed-supply model, the whole initial supply is born under the contract’s spend rules. In the authority model, minting capability is born the same way. Later holders still receive ordinary value outputs; what the contract enforces is whatever it locks (deploy, authority, or both).

### Deploy display fields

`sym`, `icon`, and `dec` are optional **deploy-only** display metadata. They are set on `deploy+mint` / `deploy+auth` and inherited for wallets and indexers on all later operations. They MUST NOT appear as required fields on `mint`, `auth`, `transfer`, or `burn`. Missing or malformed display fields do **not** invalidate the deploy or the token id.

#### Symbol (`sym`)

|            |                                                                                                                                    |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Presence   | Optional on deploy                                                                                                                 |
| Type       | JSON string                                                                                                                        |
| Meaning    | Short human-readable ticker / name for UI                                                                                          |
| Uniqueness | **Not** enforced. Many tokens MAY share the same `sym`. Applications MUST key tokens by deploy outpoint id, never by symbol alone. |

Empty string and omission are both treated as "no symbol."

#### Icon (`icon`)

|          |                                                        |
| -------- | ------------------------------------------------------ |
| Presence | Optional on deploy                                     |
| Type     | JSON string                                            |
| Meaning  | Pointer to on-chain image bytes used as the token icon |

When present, `icon` MUST be an **outpoint** naming the output that holds the image:

* Format: `<txid>_<vout>` (64 hex txid, underscore, non-negative decimal `vout`).
* Relative form: `_N` (underscore + decimal vout) MAY be used when the image output is in the **same transaction** as the deploy. Indexers expand this to `<deploy_txid>_N`.

The referenced outpoint SHOULD be one of:

1. **Inscription** — a 1Sat / `ord` inscription whose body is image (or other display) content ([BRC-160](/tokens/0160.md)); or
2. **B protocol** — a Bitcom B protocol file output (`19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut`) whose payload is the image bytes.

`icon` is a **pointer only**. It is not embedded image data, not an HTTP(S) URL, and not required for token validity. Wallets resolve the outpoint (e.g. via OrdFS `/content/{outpoint}`) to fetch bytes and content type. If the outpoint is missing, unresolvable, or not image-like, UIs SHOULD fall back to a placeholder; the token remains valid.

Same-tx example (image inscribed on output 0, token deploy on output 1):

```json
{
  "p": "bsv-20",
  "op": "deploy+mint",
  "amt": "1000",
  "sym": "TEST",
  "icon": "_0"
}
```

### Operations after deploy

#### `mint`

Creates new supply by spending at least one valid authority input of the same token.

| Field | Required | Description                                  |
| ----- | -------- | -------------------------------------------- |
| `p`   | Yes      | `bsv-20`                                     |
| `op`  | Yes      | `mint`                                       |
| `id`  | Yes      | Token id (`txid_vout` of deploy)             |
| `amt` | Yes      | Amount minted in this output (string uint64) |

Any number of `mint` outputs MAY be created from a single authority spend. Minted amounts are **created**, not drawn from input balances.

#### `auth`

Continues, splits, merges, or transfers minting authority. Does not carry token value.

| Field | Required | Description             |
| ----- | -------- | ----------------------- |
| `p`   | Yes      | `bsv-20`                |
| `op`  | Yes      | `auth`                  |
| `id`  | Yes      | Token id                |
| `amt` | No       | **MUST NOT** be present |

Authority capabilities:

* **Split** — one auth in → many auth out
* **Combine** — many auth in → one auth out
* **Transfer** — auth to a new locking script
* **End** — spend auth with no replacement auth out (that auth is destroyed; minting for the token ends only when **no** auth outputs remain)

#### `transfer`

Moves existing supply.

| Field | Required | Description                           |
| ----- | -------- | ------------------------------------- |
| `p`   | Yes      | `bsv-20`                              |
| `op`  | Yes      | `transfer`                            |
| `id`  | Yes      | Token id                              |
| `amt` | Yes      | Amount in this output (string uint64) |

#### `burn`

Explicitly removes supply from circulation. Burn outputs are recorded for supply accounting (mints − burns) but carry **no** spendable token value. Spending a burn output later has no effect on token validation.

| Field | Required | Description                                  |
| ----- | -------- | -------------------------------------------- |
| `p`   | Yes      | `bsv-20`                                     |
| `op`  | Yes      | `burn`                                       |
| `id`  | Yes      | Token id                                     |
| `amt` | Yes      | Amount burned in this output (string uint64) |

### Field validation summary

| Field  | Rules                                                                                                                                        |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `amt`  | Required: `deploy+mint`, `mint`, `transfer`, `burn`. Prohibited: `deploy+auth`, `auth`. Decimal string of uint64 (max 18446744073709551615). |
| `id`   | Required: `mint`, `auth`, `transfer`, `burn`. Format `txid_vout` (valid outpoint). Auto = deploy outpoint for deploy ops.                    |
| `dec`  | Optional on deploy only. String integer 0–18. Default 0. Numeric JSON numbers are **not** valid.                                             |
| `sym`  | Optional on deploy only. Display string; not unique. See [Symbol](#symbol-sym).                                                              |
| `icon` | Optional on deploy only. Outpoint pointer to an inscription or B-protocol file. See [Icon](#icon-icon).                                      |

### Validation rules

Validation is **per token id** within a transaction. Indexers admit or reject outputs; consensus miners do not enforce BSV-21 rules.

**Deploy** (`deploy+mint`, `deploy+auth`):

* Always valid as genesis (no token-input check).
* Token id := this output's outpoint.

**Mint**:

* Requires at least one valid **authority** input of the same token.
* Mint outputs create supply; they are not paid from transfer-input balances.

**Auth**:

* Requires spending a valid authority input of the same token.
* Auth inputs contribute **0** to token balance.

**Transfer and burn (balance)**:

* Let `I` = sum of amounts on valid **value** inputs of this token (prior admitted `deploy+mint`, `mint`, or `transfer` outputs — not auth, not burn).
* Let `O_t` = sum of `transfer` output amounts for this token.
* Let `O_b` = sum of `burn` output amounts for this token.
* Admit transfer and burn outputs only when `I >= O_t + O_b`.
* If `O_t + O_b > I`: those outputs are invalid and input tokens are **burned** (no admitted transfer/burn outs from that imbalance).
* If `I > O_t + O_b`: the excess is burned (implicit burn).
* Authority inputs do **not** relax transfer balance checks. Presence of auth does not allow unfunded transfers.
* Burn inputs contribute nothing to `I`.

**Display metadata:**

* `sym`, `icon`, and `dec` are set at deploy only (see [Deploy display fields](#deploy-display-fields)).
* Later operations need not repeat them; indexers attach deploy metadata when serving balances.
* Invalid or unresolvable `icon` does not affect balance or authority admission.

### Locking scripts

Any valid locking script is allowed. BSV-21 does not constrain spend conditions beyond the inscription fields and the validation rules above.

### Satoshi value (convention)

By convention in the 1Sat ecosystem, token outputs often hold **1 satoshi**. That is ecosystem practice for indexing and wallet UX, not a consensus rule of this protocol. Validators MAY apply a 1-sat policy when admitting outputs.

### Protocol identifier note

All JSON operations use `"p": "bsv-20"` for backward compatibility. Implementations MUST NOT require `"p": "bsv-21"`. The name **BSV-21** refers to this specification family (deploy-id tokens + auth), not the JSON `p` string.

## Examples

### Fixed supply lifecycle

1. **Deploy** `deploy+mint` with `amt: "10000"`, `dec: "2"` → token `abc…_0` with 10 000 base units (100.00 display).
2. **Split** — spend deploy; two `transfer` outs of 5 000 each.
3. **Pay** — spend one 5 000; `transfer` 4 900 to recipient + 100 change.

### Auth lifecycle

1. **Deploy** `deploy+auth` → token `def…_0`, authority at that outpoint.
2. **Mint** — spend auth; outputs: `mint` 1 000 000 + `auth` (continue).
3. **Distribute** — `transfer` splits of the mint output.
4. **Delegate** — spend auth → two `auth` outs (admin A, admin B).
5. **End auth** — spend an auth with no `auth` out; that authority ends. Minting stops only when the last auth is ended.

### Balance check

Valid:

```
In:  1000 + 500 transfer
Out: 800 + 600 + 100 transfer
```

Invalid (all transfer outs rejected; inputs burned):

```
In:  500
Out: 300 + 400
```

## Security considerations

* **Indexer trust** — validity is not miner-enforced; wallets rely on overlays / indexers that implement these rules.
* **Symbol collision** — `sym` is not unique; always key tokens by deploy outpoint id.
* **Auth compromise** — holder of an authority UTXO can mint unbounded supply until that auth is ended.
* **Over-transfer burn** — creating outputs that exceed inputs burns the inputs; careless tx building destroys balances.
* **Display spoofing** — `sym` is not unique; `icon` is an unauthenticated outpoint claim. Resolve the pointed inscription/B file independently if display integrity matters.

## Implementations

* [b-open-io/1sat-stack](https://github.com/b-open-io/1sat-stack)
* [b-open-io/1sat-sdk](https://github.com/b-open-io/1sat-sdk)

## References

1. [BRC-36](/outpoints/0036.md) — Format for Bitcoin Outpoints
2. [BRC-45](/tokens/0045.md) — Definition of UTXOs as Bitcoin Tokens
3. [BRC-159](/tokens/0159.md) — 1Sat Ordinals — Single-Satoshi Tokens and Origin Tracking
4. [BRC-160](/tokens/0160.md) — 1Sat Ordinals — Inscription Envelopes
5. B protocol (Bitcom `19HxigV4QyBv3tHpQVcUEQyq1pzZVdoAut`)
6. [BRC-176](/tokens/0176.md) — BSV-21 Validity Proofs


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://bsv.brc.dev/tokens/0161.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
