# Protocol Specification

Ordinals-compatible, built on Bitcoin SV

```
Protocol:          1Sat Ordinals
Status:            DRAFT
Documentation:     https://docs.1satordinals.com
```

### Overview

1SatOrdinals in an implementation of Ordinals running on the BSV blockchain.

See the [Ordinals Docs](https://docs.ordinals.com/) for more information on Ordinals and ordinal theory.

This inscription script represents an inscription on an ordinal. The output value is 1 satoshi.

```bash
OP_FALSE OP_IF 6f7264 OP_1 <content-type> OP_0 <data> OP_ENDIF
```

A locking script (typically P2PKH) is then prepended/appended to the inscription script, optionally separated by OP\_CODE\_SEPERATOR.

```bash
<locking script> <inscription script>
OR
<inscription script> <locking script>
OR
<inscription script> OP_CODE_SEPERATOR <locking script>
```

### Creating an Inscription

Creating an inscription requires a single transaction. To summarize the transaction template:

```bash
Input  #1 - Any valid utxo
Output #1 - Inscription w/ Locking Script (1 Satoshi)
Output #2 - Change
```

The output with this script should lock exactly 1 Sat.

#### `ord` Envelope

Inscribe a data file by filling in the two inscription fields, `data` and `content-type`.

```bash
OP_FALSE OP_IF "ord" OP_1 <content-type> OP_0 <data> OP_ENDIF 
```

#### Locking Script

Typically, a P2PKH script is used to lock the ordinal. Simply send the 1 sat output to a new destination to transfer it. From here on, `1SAT_P2PKH` refers to a standard p2pkh output with a single sat value, but keep in mind, any locking script can be used.

```bash
OP_DUP OP_HASH160 <pubkeyhash> OP_EQUALVERIFY OP_CHECKSIG
```

### Transfers

To transfer ownership, simply send the 1sat output to the intended recipient as you normally would with any utxo while maintaining ordinality of the satoshi being transferred. (i.e. the `n`th satoshi input to the transaction is transferred to the `n`th satoshi output of the transaction)

```
i1 - 1sat_p2pkh
i2 - funding utxo
o1 - 1sat_p2pkh
o2 - change
```

You can also append to the inscriptions on an ordinal by inscribing the same sat again.

```
i1 - previously inscribed ordinal
i2 - funding utxo
o1 - second inscription w/ 1sat_p2pkh
o2 - change
```

### Examples

In this example, we inscribe a 3d model (GLTF binary) and tag it with a geolocation:

Mint & Inscribe: (1SAT\_P2PKH + inscription)

```
https://whatsonchain.com/tx/10f4465cd18c39fbc7aa4089268e57fc719bf19c8c24f2e09156f4a89a2809d6
```

Transfer:

```
https://whatsonchain.com/tx/61fd6e240610a9e9e071c34fc87569ef871760ea1492fe1225d668de4d76407e
```

## Ordinals vs 1SatOrdinals

The BSV blockchain is unique among blockchains which support ordinals, in that BSV supports single satoshi outputs. This allows us to take some short-cuts in indexing efficiently. We call this `origin`-based indexing.

Since ordinals are a unique serial number for each satoshi, an `origin` can be defined as the first outpoint where a satoshi exists alone, in a one satoshi output. Each subsequent spend of that satoshi can be crawled back to the first ancestor where an output contains more than one satoshi.

We define an 1SatOrdinal as a chain of single satoshi output spends. Each owner transfers 1sat by creating transaction that has single satoshi output in a position determined by ordinals theory. Payee can verify these transfers math to verify the chain of ownership.

If a satoshi is subsequently packaged up in an output of more than one satoshi, the origin is no longer carried forward and the token can be considered burned. If the satoshi is later spent into another one satoshi output, a new origin will be created. Both of these origins would be the same ordinal, but are distinct tokens in 1SatOrdinals.

1SatOrdinals uses the same [inscription rules](https://docs.ordinals.com/inscriptions.html) as the founding implementation on BTC, with the following caveats/clarifications:

### Inscribing in Outputs

Due to the use of Tap Root in BTC, inscriptions are exposed in the input scripts. On BSV, they are written in outputs. Due to this difference, Inscription IDs in 1SatOrdinals are stated in relation to the output of a transaction, and take the form of `<txid hex>_<vout>`.

Only the first valid inscription envelope produces a 1SatOrdinal. Any subsequent inscriptions MUST be ignored.

### 1 Satoshi Outputs

1SatOrinals requires inscrptions to be made on a single satoshi output.

### PUSH DATA

On BSV, push data are NOT limited to 520 bytes and values should NOT be concatenated across multiple data pushes.

### Valid Inscriptions

An inscription is considered valid if an `ord` envelope is present inline in an output script on a 1 satoshi output.

### ord Envelope Format

```
OP_FALSE OP_IF 6f7264
    <field1> <value1>
    ...
    <fieldN> <valueN>
    OP_0 <content> 
OP_ENDIF
```

* `field` and `value` MUST alway appear as pairs
* `field` MUST be a single PUSH\_DATA or `OP_1`-`OP_16`
* `value` MUST be a single PUSH\_DATA, `OP_0`, or `OP_1`-`OP_16`

See the [Ordinals Docs](https://docs.ordinals.com/inscriptions.html) for more information on Ordinals fields.

### Field Aliases

Due to ambiguity of documentation and implementations of Bitcoin ASM, `OP_1`-`OP_16` are treated as alieses of the corisponding push values of `OP_DATA_1` followed by the value 1-16

### Repeated Fields

Parsing considerations for handling if a field is repeated is not defined in the Ordinals Spec. 1SatOrdinals treats repeated fields such that later values will overwrite previous values.

### Origin

1SatOrdinals is a superset of the Ordinals Protocol and is 100% backward compatible.

We take a different approach to indexing due to the expanded capacity of the BSV blockchain. `origin` indexing is built on the idea that it ultimately doesn't matter WHICH specific ordinal is being transferred across the blockchain, as long as it can be easily determined that multiple transactions are referencing the SAME ordinal.

`origin`s are tracked within the 1SatOrdinals indexer only as 1-satoshi outputs. If you inscribe on more than 1 satoshi, that the inscription is not a valid 1SatOrdinal.

### Resources

* [Discord](https://discord.gg/XUfss6StD8)
* [BTC Ordinals Specification](https://docs.ordinals.com/)


# Introduction

<figure><img src="/files/YLBUq0EgbFBud8KHchPp" alt=""><figcaption></figcaption></figure>

There are some significant differences between BTC, where ordinals originated, and Bitcoin SV. Most notably, BSV does not have taproot or segregated witness, which Ordinals protocol leverages to inscribe data on BTC.

Since data limits are much higher on Bitcoin SV, we can encode ordinals directly to output scripts, following the same pushdata scheme, and creating an inscribed ordinal in a single stage compared to the two-step commit + reveal process on BTC.

### 1Sat Protocol

Ordinals are based on a numbering scheme that targets a specific satoshi. In practice, a range of Satoshis is used to satisfy dust limits. Since Bitcoin SV has no dust limit, we can simplify further by inscribing a single satoshi. The protocol name highlights this capability, and we focus on 1 satoshi outputs in these documents. It's important to note, we can easily add support for additional sats in a compatible way.

### Interoperability

The spirit of the original Ordinals protocol is alive and well here. Ordinal numbers, inscription numbers, and data formats are identical. We're hoping that a common protocol makes it easy for others to experience the value BSV can add to these ideas, and build cool stuff leveraging the interoperability along the way.


# Terms

#### Inscription ID

An outpoint representing a particular inscription, comprised of a transaction ID and output index with the following formatting: `` `txid_vout` ``

#### Inscription Number

This is an auto-incrementing id given to each inscription as they appear in mined blocks, starting with inscription #0. Because inscription numbers are dependent on the order of transactions in a block, inscription numbers are not assigned until a transaction is confirmed. This also makes inscription number sensitive to reorgs.

#### Origin

This is like a "low resolution" ordinal number. It represents the last time a particular ordinal became a 1 satoshi output. Since utxos can be split and joined over time, an ordinal can have more than one origin. This is a 1Sat protocol specific concept, not present in the original ordinals protocol.

#### Ordinal Number

An ordinal is an identifier given to a specific satoshi. It is given when the sat comes into existence during a coinbase transaction. To learn more about this concept read the original "ordinal theory" documentation.


# Resolving Ordinals

To resolve ordinal numbers for unspent outputs an indexer is required. This diagram shows the process of resolving an ordinal number.

![Ordinals Indexing](https://github.com/BitcoinSchema/1sat-ordinals/blob/main/Ordinals_Indexer.jpg?raw=true)

## Current implementation

Production indexing and HTTP resolution for this ecosystem are provided by [**1sat-stack**](https://github.com/b-open-io/1sat-stack) (see [Libraries](/libraries)). Content and transfer-chain resolution over HTTP are described in [**OrdFS**](/content-and-resolution/ordfs).

## Historical reference implementations

{% hint style="info" %}
**Deprecated for new work.** The following repositories are early indexers/servers. Prefer **1sat-stack**.
{% endhint %}

{% embed url="<https://github.com/shruggr/1sat-server>" %}

{% embed url="<https://github.com/shruggr/1sat-indexer>" %}


# Rare Sats

You can choose which Satoshi to inscribe by creating a transaction with two change outputs.

```
i1 - any utxo
o1 - change1 (n sats)
o2 - 1SAT_P2PKH + inscription (1 sat)
o3 - change2 (remaining sats)
```

## Bounties

Coming soon...


# Test Vectors

Transaction examples you can use for testing

### Basic Image Inscription

image/png inscription

```
fc2d9e145000154873cfd304bbadf450816a084cdd7725da8c614de55e0b8702
```

image/jpeg inscription

```
655729f0d35b1cc586dd9500ef22784b23e8d9e6775522b47caf401c3bb88e68
```

image/png inscription

```
e749a32652a69601ee407ccda605d4eb19d93bddf5b355e1b1cae383bc26a81e
```

image/jpeg inscription

```
392840d529f1cf1b4afc37f04f93a68b5ae6c1b2ff66a2a3440e0435e7ee6e6f
```

### Image + Metadata Inscription

First test inscription w metadata:

```typescript
10f4465cd18c39fbc7aa4089268e57fc719bf19c8c24f2e09156f4a89a2809d6
```

Transfer:

```
61fd6e240610a9e9e071c34fc87569ef871760ea1492fe1225d668de4d76407e
```

Re-Inscription by 2nd key:

```typescript
662104c5bb6a9e912f260795f5d770e670f0a966bc6fd89fe8c0e88fc78e8378
```

Re-Inscription with original key:

```
// TODO
```

## Large 3D Model

```
281484f9ba41f5dd10dac0b6445b10ba8a49c4fc71247a8a40a03691194324e5
```

## Collection - 2 Image Inscriptions

```
9e4f93b535a8ab811ddd21f72abd337515cc0f42a110bcb0a51510c909bab57d
```

## Audio Inscription

Transfer

```
52214a6db95aff19826b507587ded5e65d5944ebf074448002af4f967766aa0b
```

## Partially Signed Bitcoin Transaction

Off-chain bid rawTx

```
0100000004d14b5f9fec20643a72bd8d1317ca54f3d76b9449d81e33fc0c384f3dd8841041000000006a473044022009c1f0de5fd2e61abbfc9c9cabacb74246e85d836a4ac8e0af97cd40cbb18426022032ed88b3b47dc9692869eb17bf73ceb2d042fc0fff5568cec8bb57727c6a6fa1432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009fffffffffd14b5f9fec20643a72bd8d1317ca54f3d76b9449d81e33fc0c384f3dd8841041010000006a473044022071a59693505b1655bfeb3f1ecd179d88ff6c9553d5064714bc1992e51bf39d430220515f22b9ee0f79e82c2f3d35cb48c0206f3577be89c252f4a95082bb0c48bd6d432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009fffffffff84a5788927871968b32bb2c8af735fd76e1b34d295339427046475c356787de1510000000000000000534664a3793ac49f90a353af74d976d314e5fea0067d2d9fa9da4b11446d13fc000000006b483045022100d5a5ddcc624df31bfb16c2b4016866f9f20500c9b0c04d4fefe403ec8d32ba99022076a2e7db5d298922a4959ff8825f287437e0164ce3f0a8ec7db68de47a665a4a432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009fffffffff0428000000000000001976a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac01000000000000001976a914bed1a83a3fd87aeaa222a7a6540f8df644f508fb88ac00e1f505000000001976a91402d1e3d3567a88e0cfd13f57167238c4eb7c813888acd16b0000000000001976a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac00000000
```

On-chain finalization txid

```
fcc55cd1a4275e5750070381028d3e3edf99b238bdc56199ff8bdc17dfb599d1
```


# BSV-21

Extensible fungible token specification for Bitcoin SV

## Overview

BSV-21 is a fungible token standard for Bitcoin SV that uses ordinal inscriptions to create, mint, and transfer tokens. Tokens are identified by their genesis transaction output (`<txid>_<vout>`) and exist as UTXOs on the Bitcoin SV blockchain.

The protocol supports two token models:

* **Fixed Supply**: Entire token supply created in a single deployment transaction
* **Auth Tokens**: Auth-based system allowing ongoing token creation

## Core Concepts

### Token Identification

Tokens are identified by the outpoint of their deployment transaction in the format `<txid>_<vout>`. This unique identifier remains constant throughout the token's lifecycle.

### UTXO Model

BSV-21 tokens exist in UTXOs, identical to native Bitcoin. This enables:

* Parallel transaction processing
* Natural splitting and combining of token amounts
* Standard Bitcoin script locking mechanisms
* Direct integration with Bitcoin's security model

### Content Type

All BSV-21 operations use the content type `application/bsv-20` for ordinal inscriptions.

### JSON Field Handling

BSV-21 inscriptions may contain additional JSON fields beyond those specified in this standard. Implementations must ignore unrecognized fields - only the fields defined in this specification affect token behavior.

## Fixed Supply Tokens

### Deploy+Mint Operation

Creates a token with a fixed, immutable supply. The entire token supply is minted in a single transaction output.

**Fields:**

| Field  | Required | Description                                                     |
| ------ | -------- | --------------------------------------------------------------- |
| `p`    | Yes      | Protocol identifier: `bsv-20`                                   |
| `op`   | Yes      | Operation: `deploy+mint`                                        |
| `amt`  | Yes      | Total token supply (max: 2^64-1)                                |
| `sym`  | No       | Token symbol (not enforced unique)                              |
| `icon` | No       | Icon reference (inscription origin or B protocol file outpoint) |
| `dec`  | No       | Decimal precision (default: 0, max: 18)                         |

**Example:**

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

The token ID will be set to the outpoint where this inscription is created (e.g., `3b31...e000_0`).

## Auth Tokens

Auth tokens enable controlled, ongoing minting through auth UTXOs that grant minting capability.

### Deploy+Auth Operation

Creates a token with no initial supply and generates an authority UTXO that can be spent to mint new tokens.

**Fields:**

| Field  | Required | Description                                                       |
| ------ | -------- | ----------------------------------------------------------------- |
| `p`    | Yes      | Protocol identifier: `bsv-20`                                     |
| `op`   | Yes      | Operation: `deploy+auth`                                          |
| `sym`  | No       | Token symbol (not enforced unique)                                |
| `icon` | No       | Icon reference (inscription origin or B protocol file outpoint)   |
| `dec`  | No       | Decimal precision (default: 0, max: 18)                           |
| `amt`  | No       | **Must not be present** - auth outputs carry authority, not value |

**Example:**

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

### Mint Operation

Creates new token supply by spending an auth UTXO. Any number of mint outputs can be created from a single auth input.

**Fields:**

| Field | Required | Description                                      |
| ----- | -------- | ------------------------------------------------ |
| `p`   | Yes      | Protocol identifier: `bsv-20`                    |
| `op`  | Yes      | Operation: `mint`                                |
| `id`  | Yes      | Token ID (`<txid>_<vout>` of deploy+auth output) |
| `amt` | Yes      | Amount of tokens to mint                         |

**Example:**

```json
{
  "p": "bsv-20",
  "op": "mint",
  "id": "3b31...e000_0",
  "amt": "1000000"
}
```

**Transaction Structure:**

```
Inputs:
  - Auth UTXO (from deploy+auth or previous auth output)

Outputs:
  - Mint inscription (creates 1,000,000 new tokens)
  - Auth inscription (continues minting capability)
```

### Auth Operation

Manages auth UTXOs by creating new auth outputs. Auth can be split, combined, or transferred to delegate minting authority.

**Fields:**

| Field | Required | Description                                                       |
| ----- | -------- | ----------------------------------------------------------------- |
| `p`   | Yes      | Protocol identifier: `bsv-20`                                     |
| `op`  | Yes      | Operation: `auth`                                                 |
| `id`  | Yes      | Token ID (`<txid>_<vout>` of deploy+auth output)                  |
| `amt` | No       | **Must not be present** - auth outputs carry authority, not value |

**Example:**

```json
{
  "p": "bsv-20",
  "op": "auth",
  "id": "3b31...e000_0"
}
```

**Auth Capabilities:**

* **Split**: One auth input → multiple auth outputs (delegate authority)
* **Combine**: Multiple auth inputs → one auth output (consolidate authority)
* **Transfer**: Spend auth to new locking script (transfer authority)
* **Burn**: Spend auth without creating new auth output (destroys that auth output; minting for the token ends once no auth outputs remain)

## Token Transfers

Tokens are transferred by spending token UTXOs and creating new token outputs, identical to spending native Bitcoin.

### Transfer Operation

**Fields:**

| Field | Required | Description                                     |
| ----- | -------- | ----------------------------------------------- |
| `p`   | Yes      | Protocol identifier: `bsv-20`                   |
| `op`  | Yes      | Operation: `transfer`                           |
| `id`  | Yes      | Token ID (`<txid>_<vout>` of deployment output) |
| `amt` | Yes      | Amount of tokens in this output                 |

**Example:**

```json
{
  "p": "bsv-20",
  "op": "transfer",
  "id": "3b31...e000_0",
  "amt": "5000"
}
```

### Transfer Validation Rules

**Token Conservation:**

* Total output tokens ≤ Total input tokens
* If outputs exceed inputs: transaction invalid, tokens burned
* If outputs < inputs: excess tokens burned

**Example Transaction:**

```
Inputs:
  - Transfer UTXO: 1,000 tokens
  - Transfer UTXO: 500 tokens

Outputs:
  - Transfer: 800 tokens (to recipient A)
  - Transfer: 600 tokens (to recipient B)
  - Transfer: 100 tokens (change to sender)

Total In: 1,500 tokens
Total Out: 1,500 tokens
Status: Valid
```

**Invalid Example:**

```
Inputs:
  - Transfer UTXO: 500 tokens

Outputs:
  - Transfer: 300 tokens
  - Transfer: 400 tokens

Total In: 500 tokens
Total Out: 700 tokens
Status: Invalid - All tokens burned
```

## Burning Tokens

Tokens are explicitly and permanently removed from circulating supply with the `burn` operation.

### Burn Operation

**Fields:**

| Field | Required | Description                                     |
| ----- | -------- | ----------------------------------------------- |
| `p`   | Yes      | Protocol identifier: `bsv-20`                   |
| `op`  | Yes      | Operation: `burn`                               |
| `id`  | Yes      | Token ID (`<txid>_<vout>` of deployment output) |
| `amt` | Yes      | Amount of tokens to burn                        |

**Example:**

```json
{
  "p": "bsv-20",
  "op": "burn",
  "id": "3b31...e000_0",
  "amt": "1000"
}
```

Burn outputs are recorded so that circulating supply can be computed (mints − burns), but they carry no spendable token value. Spending a burn output later has no effect on token validation.

## Validation Rules

### Operation-Specific Rules

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

* Automatically valid - no input validation required
* Token ID is set to the deployment output's outpoint
* Creates token genesis

**Mint Operations:**

* Requires at least one auth input to be valid
* Minted tokens are created, not transferred from inputs
* Any number of mint outputs can be created from a single auth input

**Auth Operations:**

* Requires valid auth input spending
* Auth inputs do not contribute to token balance
* Can create multiple auth outputs from single auth input

**Transfer Operations:**

* Requires token conservation: `total_input_tokens ≥ total_output_tokens` (transfer and burn outputs combined)
* Auth inputs do not affect transfer validation
* Presence of auth does not bypass balance requirements

**Burn Operations:**

* Validated together with transfers: transfer and burn outputs are admitted only when token inputs cover the combined amount
* Burn outputs carry no spendable token value
* Burn inputs contribute nothing to balance validation

### Field Validation

**Amount Field (`amt`):**

* Required: `deploy+mint`, `mint`, `transfer`, `burn`
* Prohibited: `deploy+auth`, `auth`
* Format: String representation of uint64 (max: 18,446,744,073,709,551,615)

**Token ID Field (`id`):**

* Required: `mint`, `auth`, `transfer`, `burn`
* Format: `<txid>_<vout>` where txid is 64 hex characters
* Must reference valid deployment output
* Auto-set for deploy operations

**Decimals Field (`dec`):**

* Optional: `deploy+mint`, `deploy+auth`
* Range: 0-18
* Default: 0
* Format: String representation of an integer (numeric JSON values are not recognized)
* Determines token divisibility

## Locking Scripts

BSV-21 tokens support any valid Bitcoin locking script, including P2PKH, multisig, custom smart contracts, and complex spending conditions. Tokens can be locked using the same mechanisms available to native Bitcoin satoshis.

## Token Metadata

Token metadata (`sym`, `icon`, `dec`) is set during deployment and inherited by all subsequent operations.

The `icon` field references an image by its outpoint in `<txid>_<vout>` format, pointing to either an inscription containing an image or a B protocol file upload.

**Deployment:** Sets metadata

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

**Transfer:** Metadata auto-populated from deployment

```json
{
  "p": "bsv-20",
  "op": "transfer",
  "id": "3b31...e000_0",
  "amt": "100"
}
```

The transfer inherits `sym: "GOLD"`, `dec: 8`, `icon: "abc..."` from the deployment.

## Protocol Identifier

All BSV-21 operations use `"p": "bsv-20"` as the protocol identifier for backward compatibility with existing infrastructure.

## Transaction Examples

### Complete Fixed Supply Token Lifecycle

**1. Deploy Token**

```json
{
  "p": "bsv-20",
  "op": "deploy+mint",
  "amt": "10000",
  "sym": "FIXED",
  "dec": "2"
}
```

Creates token `abc...123_0` with 10,000 tokens (100.00 with 2 decimals)

**2. Split Tokens**

```
Input: Deploy output (10,000 tokens)
Outputs:
  - Transfer: 5,000 tokens
  - Transfer: 5,000 tokens
```

**3. Transfer to User**

```
Input: Transfer UTXO (5,000 tokens)
Outputs:
  - Transfer: 4,900 tokens (to user)
  - Transfer: 100 tokens (change)
```

### Complete Auth Token Lifecycle

**1. Deploy with Auth**

```json
{
  "p": "bsv-20",
  "op": "deploy+auth",
  "sym": "STABLE",
  "dec": "6"
}
```

Creates token `def...456_0` with auth capability

**2. Initial Mint**

```
Input: Auth UTXO (from deploy+auth)
Outputs:
  - Mint: 1,000,000 tokens
  - Auth: Continue minting capability
```

**3. Distribute Minted Tokens**

```
Input: Mint output (1,000,000 tokens)
Outputs:
  - Transfer: 500,000 tokens (to user A)
  - Transfer: 500,000 tokens (to user B)
```

**4. Additional Mint**

```
Input: Auth UTXO (from previous auth output)
Outputs:
  - Mint: 500,000 tokens
  - Auth: Continue minting capability
```

**5. Delegate Minting Authority**

```
Input: Auth UTXO
Outputs:
  - Auth: Locked to admin A
  - Auth: Locked to admin B
```

**6. Burn Auth**

```
Input: Auth UTXO
Outputs:
  - (No auth outputs created)
```

This auth output is destroyed. Any other auth outputs for the token keep their minting capability; minting is permanently disabled for the token only when the last auth output is spent without a replacement.

## Summary

BSV-21 provides two complementary token models on Bitcoin SV:

**Fixed Supply Tokens** offer simplicity and immutability - the entire supply is created at deployment and cannot be changed.

**Auth Tokens** offer flexibility - auth UTXOs enable controlled, ongoing minting with delegatable authority.

Both models leverage Bitcoin's UTXO architecture for parallel processing, standard script locking, and native security guarantees.


# Shrug ¯\\\_(ツ)\_/¯

Script-native fungible token protocol for Bitcoin SV

{% hint style="warning" %}
¯\\\_(ツ)\_/¯ is experimental and the specification may still change. For production tokens, use [BSV-21](/fungible-tokens/bsv-21).
{% endhint %}

## Overview

Shrug is a fungible token protocol for Bitcoin SV where the token data lives directly in the locking script as plain data pushes. Every token output starts with a short, fixed prefix — the shrug tag, a token id, and an amount — followed by an ordinary locking script.

Shrug is an evolution of [BSV-21](/fungible-tokens/bsv-21) and follows the same general rules. If you know BSV-21, the mapping is summarized in the comparison below; if you don't, this page stands on its own.

## Why not BSV-21?

BSV-21 has wide adoption and works well when wallets and indexers are the only software handling tokens. Its weak spot is Bitcoin script. Token data is a JSON document inside an inscription envelope, and script cannot work with that easily:

* A contract that creates a token output must build JSON in script: assemble the inscription envelope, quote the fields, and convert amounts from numbers into ASCII decimal strings.
* A contract that checks a token output does the same in reverse — hunting for fields inside a text document instead of reading bytes at known positions.
* Token ids are hex text in the opposite byte order from the outpoints script sees in sighash preimages, so even comparing an id means converting and reversing first.

Shrug puts the same data where script can use it. The amount is a script number, so arithmetic opcodes use the pushed value as-is. The token id is the same 36 bytes as a preimage outpoint, so comparing them is one equality check. Building a new token output is concatenating a few pushes. Everything else about the token model stays as BSV-21 defined it.

## Wire Format

```
<push "¯\_(ツ)_/¯"> <push token id | OP_0> OP_2DROP <push amount | OP_0> OP_DROP <owner locking script>
```

| Element      | Encoding                                                                                    |
| ------------ | ------------------------------------------------------------------------------------------- |
| Tag          | Push of the 13-byte UTF-8 string `¯\_(ツ)_/¯` (hex `c2af5c5f28e38384295f2fc2af`)             |
| Token id     | Push of a 36-byte outpoint (32-byte txid + 4-byte little-endian vout), or `OP_0` on deploys |
| `OP_2DROP`   | Drops the tag and id from the stack                                                         |
| Amount       | Push of the amount as a script number, or `OP_0` for zero                                   |
| `OP_DROP`    | Drops the amount                                                                            |
| Owner script | Any locking script — P2PKH, multisig, a custom contract                                     |

The prefix pushes three values and drops all three, so the owner script runs exactly as it would on its own.

## Token Identity

A token is identified by the outpoint of the output that created it — its deploy output — written as 36 bytes: the txid followed by the output index. A deploy output leaves the id field empty (`OP_0`); its own outpoint becomes the token id. Every later output for that token carries the id.

This is the same 36-byte outpoint encoding that appears inside sighash preimages, so a covenant can compare a token id against a spent outpoint byte for byte.

## Operations

The two prefix fields say everything about what an output does:

| Token id | Amount | Meaning                                                      |
| -------- | ------ | ------------------------------------------------------------ |
| Empty    | > 0    | Deploy a token; the fixed supply is held in this output      |
| Empty    | 0      | Deploy a token; this output is the initial minting authority |
| Present  | 0      | Minting authority                                            |
| Present  | > 0    | Token value                                                  |

Tokens are burned by spending them without creating matching outputs.

## Amounts

Amounts are script numbers — the same little-endian format Bitcoin's arithmetic opcodes work with, so `OP_BIN2NUM` or `OP_ADD` can use the pushed value as-is. They must be minimally encoded and non-negative, and there is no upper limit: script numbers have no fixed width. An amount of zero marks the output as a minting authority rather than a token value.

Since amounts have no width limit, software that adds them up must use arithmetic that cannot overflow.

## Satoshi Value

By convention, token outputs hold exactly 1 satoshi, and that is the recommended default. Wallets and indexers across the 1Sat ecosystem are built around single-satoshi outputs, and a deploy output carrying an inscription needs one identifiable satoshi for the inscription to bind to.

This is a convention, not a strict protocol rule. Validation reads only the script, so a token output may hold any number of satoshis, and the token and the satoshis travel together when the output is spent. Carrying additional value is an advanced option: it can have legal and regulatory implications depending on how a token is structured. Policy may dictate validation be limited to single satoshi outputs only.

## Metadata

Display information — symbol, icon, and decimal precision — lives in its own document: a CBOR inscription on the deploy output with content type `application/shrug+cbor`.

The document is an open key/value map. The deployer may include any data they like; these keys have defined meanings:

| Key    | CBOR type              | Description                                                                   |
| ------ | ---------------------- | ----------------------------------------------------------------------------- |
| `sym`  | text string            | Token symbol. Uniqueness is not enforced                                      |
| `icon` | byte string (36 bytes) | Outpoint of an inscription or B protocol file — same encoding as the token id |
| `dec`  | unsigned integer       | Decimal precision 0-18, default 0                                             |

Diagnostic notation example:

```
{"sym": "GOLD", "icon": h'11…01000000', "dec": 8}
```

The document is encoded deterministically (RFC 8949 §4.2) — the same fields always produce the same bytes, so it can be hashed or signed reliably. Keys are text strings; readers use the keys they understand. The spec may define more keys over time. All fields are optional, and so is the document itself. Indexers read the metadata once from the deploy output and apply it to the whole token.

## Composition

The prefix makes no claims about the rest of the script, so it stacks with other script-level protocols by simple concatenation. In particular, a standard 1Sat inscription envelope can sit between the prefix and the owner script:

```
<shrug prefix> <inscription envelope> <owner locking script>
```

A shrug decoder reads the prefix and hands the rest to the inscription decoder. By convention, content and metadata go on the deploy output; transfer outputs carry just the prefix.

### Non-Fungible Ordinals

A deploy with a supply of 1, carrying an inscription, is a non-fungible token — and still a completely normal 1Sat ordinal. What the prefix adds is the token's origin, right in the locking script:

* Normally, finding an ordinal's origin means walking the spend chain backwards to its genesis. With the prefix, every output states its origin, and shrug validation proves the claim one transaction at a time — each output is only valid if it spends a valid input of the same token — so no walk is ever needed.
* An indexer can choose to track only shrug-prefixed ordinals and skip origin crawling entirely.
* Indexers that only understand inscriptions see a normal ordinal and ignore the prefix. Nothing about the output is invalidated for them.

The same origin data serves three audiences: shrug indexers verify it, anyone reading the raw script can use it as a hint, and inscription-only indexers never see it.

## Validation Rules

**Deploys** (empty id) are always valid. The output's own outpoint becomes the token id.

**Authority outputs** (id present, amount 0) are valid only when the transaction spends a valid authority output of the same token. A deploy with amount 0 is the token's first authority. Authority can be:

* Split — one authority input, many authority outputs
* Combined — many in, one out
* Passed to a new owner
* Ended — spend it without creating a replacement; that authority is destroyed. Minting for the token as a whole ends only when its last authority is spent this way

Spending an authority adds nothing to token balance.

**Value outputs** (id present, amount > 0):

* If the transaction spends a valid authority for the token, its value outputs are valid without needing input balance. This is how new tokens are minted.
* Otherwise, the transaction's value outputs must be covered by its valid value inputs — all of them or none of them, per token.
* If outputs exceed inputs with no authority present, the outputs are invalid and the input tokens are burned.
* If inputs exceed outputs, the difference is burned.

Because minting and transferring look the same on-chain, individual outputs are not labeled one or the other. Circulating supply is the net value created in authority-backed transactions, minus everything burned.

## Comparison with BSV-21

Shrug follows the BSV-21 token model — outpoint identity, UTXO balances, authority-gated minting, balance-checked transfers — re-encoded for script:

|                                 | BSV-21                                  | Shrug                                                   |
| ------------------------------- | --------------------------------------- | ------------------------------------------------------- |
| Encoding                        | JSON inscription (`application/bsv-20`) | Binary script prefix                                    |
| Token id                        | `<txid>_<vout>` string                  | 36-byte binary outpoint                                 |
| Operations                      | Explicit `op` field (6 ops)             | Implied by field presence                               |
| Explicit burn                   | Yes                                     | No (implicit only)                                      |
| Metadata (`sym`, `icon`, `dec`) | Optional at deploy                      | Inscription on deploy output (`application/shrug+cbor`) |
| Amount                          | String uint64 in JSON                   | Script number, no width limit                           |
| Script access to token data     | Requires envelope/JSON parsing          | Fixed-position pushes                                   |
| Validation model                | Auth-gated minting + balance checks     | Same                                                    |

## Examples

### Output Scripts

Deploy a token with a fixed supply of 21,000,000, owned by a P2PKH address:

```
"¯\_(ツ)_/¯" OP_0 OP_2DROP 21000000 OP_DROP
OP_DUP OP_HASH160 <pubkeyhash> OP_EQUALVERIFY OP_CHECKSIG
```

Deploy an authority-based token (no initial supply):

```
"¯\_(ツ)_/¯" OP_0 OP_2DROP OP_0 OP_DROP
OP_DUP OP_HASH160 <pubkeyhash> OP_EQUALVERIFY OP_CHECKSIG
```

A value output for an existing token:

```
"¯\_(ツ)_/¯" <36-byte token id> OP_2DROP 5000 OP_DROP <owner script>
```

An authority output for an existing token:

```
"¯\_(ツ)_/¯" <36-byte token id> OP_2DROP OP_0 OP_DROP <owner script>
```

### Fixed Supply Lifecycle

**1. Deploy**

```
Outputs:
  - Deploy: 10,000 tokens (the token id is this output's outpoint)
```

**2. Split the supply**

```
Input:  deploy output (10,000 tokens)

Outputs:
  - Value: 5,000 tokens
  - Value: 5,000 tokens
```

**3. Transfer to a user**

```
Input:  value output (5,000 tokens)

Outputs:
  - Value: 4,900 tokens (recipient)
  - Value: 100 tokens (change)
```

### Authority Lifecycle

**1. Deploy with authority**

```
Outputs:
  - Authority: amount 0 (the token id is this output's outpoint)
```

**2. Mint the first supply**

```
Input:  genesis authority

Outputs:
  - Value: 1,000,000 tokens (newly created — an authority input is present)
  - Authority: amount 0 (keeps minting open)
```

**3. Distribute**

```
Input:  value output (1,000,000 tokens)

Outputs:
  - Value: 500,000 tokens (user A)
  - Value: 500,000 tokens (user B)
```

**4. Mint again later**

```
Input:  authority from step 2

Outputs:
  - Value: 500,000 tokens
  - Authority: amount 0
```

**5. Delegate authority**

```
Input:  authority

Outputs:
  - Authority: amount 0 (admin A)
  - Authority: amount 0 (admin B)
```

**6. End an authority**

```
Input:  authority

Outputs:
  - (no authority output)
```

This authority is destroyed. Any other authorities for the token keep working; minting is closed for the whole token only when its last authority is spent without a replacement.

### Balance Validation

A valid transfer — outputs covered by inputs:

```
Inputs:
  - Value: 1,000 tokens
  - Value: 500 tokens

Outputs:
  - Value: 800 tokens (recipient A)
  - Value: 600 tokens (recipient B)
  - Value: 100 tokens (change)

Total in: 1,500. Total out: 1,500. Valid.
```

An invalid transfer — outputs exceed inputs with no authority present:

```
Inputs:
  - Value: 500 tokens

Outputs:
  - Value: 300 tokens
  - Value: 400 tokens

Total in: 500. Total out: 700. All outputs invalid; the 500 input tokens are burned.
```

An implicit burn — inputs exceed outputs:

```
Inputs:
  - Value: 1,000 tokens

Outputs:
  - Value: 250 tokens

750 tokens are burned.
```

### Non-Fungible Ordinal

Deploy a supply of 1 with content, on a 1-satoshi output:

```
Outputs:
  - Deploy: 1 token
    script: <shrug prefix> <inscription envelope (image)> <owner P2PKH>
```

Transfer it — the origin travels in the script:

```
Input:  the token (1)

Outputs:
  - Value: 1 token
    script: <shrug prefix with token id> <new owner P2PKH>
```


# BSV-20 (deprecated)

"first-is-first" style fungible token specification

{% hint style="warning" %}
BSV-20 is deprecated. There is no reference implementation for BSV-20. Use [BSV-21](/fungible-tokens/bsv-21) for new tokens.
{% endhint %}

`First is fist` deployment and minting allows for a single use-case where a token is publicly mintable, by anyone, outside of the control of any token issuer.

## Abstract

This proposal introduces a fungible token standard based off of the BRC20[1](/#footnote-1) standard on BTC introduced by Domo [here](https://domo-2.gitbook.io/brc-20-experiment/) but customized to work on BSV (Bitcoin Satoshi Vision). In order to avoid confusion with the BRC-20 standard on BTC, we are calling this standard BSV-20.

## Motivation

The purpose of this proposal is to provide a standard that offers the same functionality that BRC20-BTC offers that works on BSV instead of BTC. A guiding motivation behind this standard proposal is to try and keep the standard as simple as possible.

## Specification

This specification is meant be as similar to the BTC BRC20 standard so it also follows the `first is first` approach. In order to deploy or mint a token, the process is almost identical to the protocol on BTC: you would create a transaction output with the data fields below and transaction are indexed on a 'first is first' approach with duplicates or overflows being invalid and ignored. The main difference between bsv-20 (this protocol) and bsv-20 protocol (on BTC) is:

* A content type of `application/bsv-20` is used in place of `text/plain`. This change means a bsv-20 indexer does not need to parse every text inscription to test for embedded JSON content (and failing most of the time) in order to determine if an inscription is BSV-20 related.

### Deploy

#### Notes

* The first deployment of a ticker is the only one that has claim to the ticker. Tickers are not case sensitive (DOGE = doge)
* If two events occur in the same block, prioritization is assigned via order they were confirmed in the block. (first to last)
* The first mint to exceed the maximum supply will receive the fraction that is valid. (ex. 21,000,000 maximum supply, 20,999,242 circulating supply, and 1000 mint inscription = 758 balance state applied)
* Number of decimals cannot exceed 18 (default)
* Maximum supply cannot exceed uint64\_max

In order to deploy an BSV-20 token, you must make sure that that token ticker has not already been deployed and then create a TXO with the following data present in the script. It does not matter whether this UTXO is spendable or not.

| Key  | Required? | Description                                                                                                  |
| ---- | --------- | ------------------------------------------------------------------------------------------------------------ |
| p    | Yes       | Protocol: `bsv-20`                                                                                           |
| op   | Yes       | Operation: `deploy`                                                                                          |
| tick | Yes       | Ticker: 4 letter identifier of the bsv-20                                                                    |
| max  | Yes       | Max supply: set max supply of the bsv-20                                                                     |
| lim  | No        | Mint limit: If letting users mint to themselves, limit per ordinal. If ommitted or 0, mint amt us unlimited. |
| dec  | No        | Decimals: set decimal precision, default to 0                                                                |

#### Example

To deploy the `ordi` token, you would create an inscription with the following json (with `ContentType: application/bsv-20`):

```json
{ 
  "p": "bsv-20",
  "op": "deploy",
  "tick": "ordi",
  "max": "21000000",
  "lim": "1000"
}
```

### Mint

In order to mint tokens of a specific BSV-20 token, you must make sure that that token ticker has already been deployed and then create a UTXO with 1 satoshi value as well as with the following data present in the script. This UTXO should be spendable in order for you to be able to transfer these minted tokens.

| Key  | Required? | Description                                                                                        |
| ---- | --------- | -------------------------------------------------------------------------------------------------- |
| p    | Yes       | Protocol: `bsv-20`                                                                                 |
| op   | Yes       | Operation: `mint`                                                                                  |
| tick | Yes       | Ticker: 4 letter identifier of the bsv-20                                                          |
| amt  | Yes       | Amount to mint: States the amount of the bsv-20 to mint. Has to be less than "lim" above if stated |

#### Example

To mint `ordi` tokens, you would create an inscription with the following json (with `ContentType: application/bsv-20`):

```json
{ 
  "p": "bsv-20",
  "op": "mint",
  "tick": "ordi",
  "amt": "1000"
}
```

### Transfer

Tokens in BSV-20 are held in UTXOs, similar to native bitcoins. This is different from BRC20, which holds balance in an account model. In order to transfer tokens, you spend that specific UTXO and create new outputs the same way you spend regular Satoshis, but the output(s) must contain `transfer` inscriptions.

If more tokens are transferred in the output(s) than are available in the input(s) then the transaction is considered invalid and the tokens are burned. If less tokens are created in the outputs than are available in the intput(s), the unallocated tokens are burned.

Using the same procedure as regular Satoshi transfers allows us to benefit from the parallelisation Bitcoin benefits from, where you can split a specific UTXO with a large amount into smaller UTXOs and spend those in parallel (the same way you could exchange a $100 bill into $1 bills and spend those in parallel) with no sequential bottlenecks that something like ERC20 (Ethereum) suffers from.

| Key  | Required? | Description                                  |
| ---- | --------- | -------------------------------------------- |
| p    | Yes       | Protocol: `bsv-20`                           |
| op   | Yes       | Operation: `transfer`                        |
| tick | Yes       | Ticker: 4 letter identifier of the bsv-20    |
| amt  | Yes       | Amount of tokens transferred in this output. |

#### Example

To transfer the `ordi` tokens that you minted as shown above, you would create a transaction spending the minting UTXO (providing the signature and public key normally to spend the P2PKH script) with an output (or many) with similar scripts with the following json (with `ContentType: application/bsv-20`), as shown below:

To mint `ordi` tokens, you would create an inscription with the following json:

```json
{ 
  "p": "bsv-20",
  "op": "transfer",
  "tick": "ordi",
  "amt": "1000"
}
```

| Inputs                                              | Outputs                                                                 |
| --------------------------------------------------- | ----------------------------------------------------------------------- |
| Signature Public\_key (spending mint of 1000 ordis) | inscription(`{"p":"bsv-20","op":"transfer","tick":"ordi","amt":"100"}`) |
|                                                     | inscription(`{"p":"bsv-20","op":"transfer","tick":"ordi","amt":"500"}`) |
|                                                     | inscription(`{"p":"bsv-20","op":"transfer","tick":"ordi","amt":"400"}`) |

## Grandfathering in older inscriptions

There are several inscriptions on the blockchain prior to the release of this spec that use `text/plain` as the content type instead of `application/bsv-20`. We will continue to index these up to block height `793000`. Starting with this block, BSV-20 inscriptions must have a content type of `application/bsv-20` to be considered valid by indexers.

## Implied Transfers Deprecated

V1 of this spec, supported functionality of `implied` transfers. An `implied` transfer was achieved by transferring a `mint` or `transfer` inscription without the creation of a new `transfer` inscription. This functionality was put in place to support users who transferred their inscriptions before there were any publicly accessible tools to create `transfer` inscriptions, and was always a temporary solution. This functionality will be discontinued at block height 807000.

## References

* 1: [BRC20 on BTC](https://domo-2.gitbook.io/brc-20-experiment/)


# Introduction

Names on Bitcoin — what OpNS is and how the pieces around it fit together

An OpNS name — `alice`, `pizza`, `node-7` — is a single satoshi on the Bitcoin SV blockchain. You claim one by doing a bit of computational work, and it's then yours the way a coin is yours: hold it, send it, sell it. Attach an identity to it and people can pay you at that name like an email address.

Nobody registers it for you, and there's nothing to renew.

## What it is

Names are mined one character at a time. Each character is a transaction carrying a proof of work — a few million hash attempts, seconds on an ordinary computer. Mining `alice` along an untouched path takes five transactions, and you keep `a`, `al`, `ali`, and `alic` as well.

The rules live in the transaction, not in a service checking submissions. An invalid mint isn't rejected by a gatekeeper; it can't confirm. Each character can be claimed only once from a given prefix, so a name can be minted once and never again.

After the mint, the mining rules are done with it. The name is an ordinary 1Sat ordinal that transfers and sells like any other, and it never expires.

## Why it works

Nothing about a name is stored off-chain. The proof of work, the character claimed, and the name itself are all in the transaction that mints it — so anyone can rebuild the entire namespace by starting at the genesis output in block 806214 and following the spends.

That costs one transaction per character, which for a namespace in real use is millions of small transactions. OpNS treats that as an ordinary thing to ask of Bitcoin, and that's what keeps the state on-chain rather than in somebody's database.

Nobody rebuilds from genesis per lookup, though. An **overlay** is a node that tracks just the OpNS slice of the chain and syncs it with other overlays. It's a cache, not an authority: if one disappears its peers hold the same set, and if one answers wrongly the chain says so.

## The network

| Piece              | What it does                                                                   |
| ------------------ | ------------------------------------------------------------------------------ |
| **Overlay**        | Which names are taken, where each was minted, which prefixes are still minable |
| **Paymail host**   | Where to send money for `alice` — reads the identity bound to the name         |
| **Delivery**       | Tells the recipient's wallet that a payment arrived                            |
| **Wallets & apps** | Search, mine, hold, transfer, sell                                             |

None of them holds a name; that sits in the owner's wallet. Any of them can be swapped for another, because the name and its identity are both on-chain.

## What this is for

A handle people can pay, with each payment going to a fresh output so nothing is reused. An asset you can sell without anyone's approval. An identity key anchored to a name, so the name can verify a signature and not just receive money.

## Protocol

How names are mined and proven unique → [OpNS](/name-service/opns)

How a name becomes payable → [Payments](/name-service/payments)


# OpNS

Low-difficulty proof-of-work name service for Bitcoin SV

## Overview

OpNS is a name service for Bitcoin SV. Names are claimed permissionlessly by low-difficulty proof of work — enough cost to deter spam, not a serious mining race — with no registrar, no auction, and no renewal. Each name can exist exactly once. A claimed name is an ordinary 1Sat ordinal inscription, so holding, transferring, and selling a name works like any other ordinal.

Uniqueness is enforced on-chain by a stateful covenant. Contract UTXOs form a trie — the *mine tree* — where each live UTXO represents a name prefix. Spending a node extends its prefix by one character, and the spend is only valid with a proof-of-work solution. Every spend emits the newly formed name as an inscription.

## Protocol Constants

| Constant         | Value                                                                |
| ---------------- | -------------------------------------------------------------------- |
| Genesis outpoint | `58b7558ea379f24266c7e2f5fe321992ad9a724fd7a87423ba412677179ccb25_0` |
| Difficulty       | 22 bits                                                              |
| Character set    | `a-z`, `0-9`, `-`                                                    |
| Content type     | `application/op-ns`                                                  |
| Protocol marker  | `1opNSUJVbBc2Vf8LFNSoywGGK4jMcGVrC`                                  |

The genesis output (block 806214) holds the root contract instance — the empty prefix from which all names descend. Difficulty and an optional TLD suffix were fixed at deployment; the mainnet deployment uses 22 bits and no TLD. The original contract source is at [github.com/shruggr/opns](https://github.com/shruggr/opns) for reference and for validating the deployed bytecode.

## The Mine Tree

Each node in the tree carries four state variables:

| Field     | Size     | Description                                                                                                |
| --------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `genesis` | 36 bytes | Outpoint of the deployment output (txid + little-endian vout). Identifies the lineage                      |
| `claimed` | variable | Little-endian bitmask; bit *n* set means the character with ASCII code *n* has been claimed from this node |
| `domain`  | variable | The name prefix this node represents                                                                       |
| `pow`     | 32 bytes | The previous proof-of-work solution hash; seed for the next solution                                       |

A freshly spawned node has `claimed = 0x00` and `domain` equal to its full prefix. The root node's domain is the empty string.

## The Mint Operation

Nodes are not owned. The contract has a single public method, `mint`, with no signature check — anyone who produces a valid proof of work may spend a node. The contract enforces everything:

**Character validation.** The character must be in the allowed set (`a-z`, `0-9`, `-`), and its bit must not already be set in `claimed`. Each character can be claimed from a given node exactly once — and since every name is exactly one path through the tree, each name can only ever be minted once.

**Proof of work.** The solution is a nonce such that:

```
hash256(pow ‖ char ‖ nonce)
```

has its top 22 bits zero when the hash is read **byte-reversed** (leading zero bits of that view) — about 4.2 million attempts (2²²) on average. `pow` is the spent node's 32-byte seed, `char` the single character byte, `nonce` miner-chosen. The winning hash becomes the `pow` seed of both resulting nodes, so solutions chain: future work cannot be precomputed.

**Output structure.** The contract verifies `hashOutputs` against exactly this layout (extending prefix `app` with `l`):

```
Inputs:
  0: node "app" (1 sat)
  1+: funding inputs (unconstrained)

Outputs:
  0: node "app" restated — 'l' marked claimed, new pow seed (1 sat)
  1: node "appl" — new child, nothing claimed (1 sat)
  2: name inscription "appl", locked to the miner's chosen script (1 sat)
  3+: change and other outputs (unconstrained)
```

Output 0 keeps the prefix alive so its remaining characters stay minable. Output 1 opens the next level of the tree. Output 2 is the name itself.

The unlocking script pushes five values: the character, the nonce, the owner locking script for output 2, the concatenated raw bytes of any outputs past index 2, and the sighash preimage (`SIGHASH_ALL | ANYONECANPAY | FORKID`), which the contract uses for output introspection.

**Mining races.** Every spend consumes the node and recreates it at a new outpoint with a new seed. Two miners working from the same node — even on different characters — are racing for one UTXO: only one spend confirms, and the loser's solution is worthless because the seed changed. Mining from any given node is inherently serialized.

## Name Inscriptions

Output 2 is a standard 1Sat ordinal inscription, built by the contract:

```
<owner locking script>
OP_FALSE OP_IF
  "ord"
  OP_1 "application/op-ns"
  OP_0 <name>
OP_ENDIF
OP_RETURN
  "1opNSUJVbBc2Vf8LFNSoywGGK4jMcGVrC"
  <36-byte genesis outpoint>
```

The content type is `application/op-ns` and the content is the full name. The `OP_RETURN` carries the protocol marker and the genesis outpoint so indexers can recognize a claimed OpNS name and its lineage without decoding the mine tree — though the claim still requires verification (see [Validation Rules](#validation-rules)).

Every character mint emits an inscription: mining `appl` when only `ap` existed also mints `app` along the way. Each intermediate name goes to whatever lock the miner supplied for that step.

## Ownership and Transfer

The contract's involvement ends when the inscription is created. The name ordinal is an ordinary spendable output: transfers, sales (e.g. [Ordinal Lock](/ordinal-lock)), and custom locking scripts all work exactly as for any other 1Sat ordinal. The current owner of a name is the current holder of its ordinal, resolved by standard ordinal tracking from the name's origin. Names never expire.

## Identity Binding

By application convention, a name can be bound to an identity key and used as a paymail handle. This is not part of the contract protocol — the holder re-locks the name ordinal with a signed PushDrop script carrying the identity key. See [Payments](/name-service/payments).

## Validation Rules

**Mints are valid by construction.** The script enforces proof of work, the character set, the claimed bitmask, and the exact output structure. An invalid mint cannot be confirmed, so any observed spend of a genuine node is a valid mint.

**Lineage must be verified.** Anything in a script can be forged — a fake node or an inscription carrying the genesis outpoint in its `OP_RETURN` proves nothing by itself. A name is genuine only if its mint traces back through node spends to the genesis outpoint. Indexers must follow the tree from genesis rather than pattern-match scripts.

**Names are unique.** Each character is claimable once per node, each name is one path through the tree, so a genuine name has exactly one origin.

**Transfers need no OpNS validation.** Once minted, a name ordinal follows ordinary ordinal rules; only the mint itself is protocol-governed.

## Resolution

An OpNS indexer starts at the genesis outpoint and follows spends of node outputs (outputs 0 and 1 of each mint), producing two kinds of records:

* **Prefix nodes** — the live UTXO for each prefix, where mining continues
* **Name origins** — the inscription outpoint where each name was minted

Availability follows from the tree: a name is taken if a node with that exact domain exists (it was spawned when the name was minted). If not, the longest mined prefix is the node to mine from — the remaining characters each take one mint transaction.

The hosted overlay at `api.1sat.app` exposes this index:

| Endpoint                      | Returns                                                                                     |
| ----------------------------- | ------------------------------------------------------------------------------------------- |
| `GET /1sat/opns/origin/:name` | The origin outpoint of a claimed name                                                       |
| `GET /1sat/opns/mine/:name`   | Nothing if the name is taken; otherwise the longest mined prefix and its live node outpoint |
| `POST /1sat/opns/origins`     | For a JSON array of outpoints, which are genuine OpNS origins                               |

Ownership and metadata lookups from an origin use standard ordinal resolution; content and accumulated MAP are available through [OrdFS](/content-and-resolution/ordfs).

## Mining a Name

Mining `ab` from an empty tree takes two transactions.

**1. Mine `a` from the root**

```
Input:  root node "" (seed S0)

Outputs:
  0: node "" — 'a' claimed, seed S1
  1: node "a" — nothing claimed, seed S1
  2: inscription "a" → miner's lock
```

The miner found a nonce where `hash256(S0 ‖ 'a' ‖ nonce)` meets difficulty (22 leading zero bits of the byte-reversed hash); that hash is `S1`.

**2. Mine `b` from node `a`**

```
Input:  node "a" (seed S1)

Outputs:
  0: node "a" — 'b' claimed, seed S2
  1: node "ab" — nothing claimed, seed S2
  2: inscription "ab" → miner's lock
```

The names `a` and `ab` now exist, each as a 1-sat ordinal. The root can still mint `b` through `z`, node `a` can still mint every character except `b`, and node `ab` is open for a third character. No transaction can ever mint `a` or `ab` again.

## Summary

OpNS names are mined, not registered. A covenant trie makes each name mintable exactly once, proof of work is the only cost of claiming one, and the result is a plain 1Sat ordinal that transfers and trades like any other. The contract enforces the entire mint; indexers only need to follow the tree from genesis to know every name, its origin, and what remains available.

## Reference implementations

* **TypeScript template** — `@1sat/templates` `OpNS` (`lock`, `decode`, `unlock`, `buildInscription`, `claimBit`, `testSolution`)
* **Go template / overlay** — `1sat-stack` `pkg/template/opns` and `pkg/opns` (mine-tree index and HTTP API above)

Identity binding and paymail are application conventions; see [Payments](/name-service/payments). The wider network around names: [Introduction](/name-service/ecosystem).


# Payments

Sending payments to OpNS names

OpNS names double as payment handles. A name is addressed as standard paymail — `<name>@<domain>` — where the alias is the name itself and the domain is any host serving the paymail capabilities described here. Because ownership and the identity binding both live on-chain, every resolver reads the same state: `alice@1sat.name` and `alice@example.com` pay the same owner.

To receive payments at a name, the holder publishes an identity binding on the name itself. Claiming the name (see [OpNS](/name-service/opns)) and publishing the binding are separate steps.

## Binding (signed PushDrop)

A name is bound by spending its ordinal into a **signed PushDrop lock** that carries the identity key. The binding is the locking script of the current name UTXO — not metadata riding alongside it — so the live UTXO always states its own binding.

| PushDrop parameter | Value                                                        |
| ------------------ | ------------------------------------------------------------ |
| Protocol           | `[0, 'p 1sat']`                                              |
| Counterparty       | `anyone`                                                     |
| Key ID             | `opns:{txid}_{vout}` of the input spent to create the output |
| Fields             | `[identity public key, display name?, avatar outpoint?]`     |
| Field signature    | yes, same derivation                                         |

Field 0 is the 33-byte compressed identity public key. Fields 1 and 2 are optional presentation values, described below. The field signature is the last field and covers everything before it, so the profile is signed by the same key that binds the name.

The bind is self-certifying: the lock key is derived from the identity key itself (`anyone`-side derivation over the protocol and key ID), and the field is signed under the same derivation. Only the holder of the identity key can produce a valid binding for it, and anyone can verify one offline from the script alone — no server, no metadata history.

**The binding lives and dies with the UTXO.** Transferring, listing, or burning the name spends the PushDrop output and re-locks the ordinal as a plain output — the binding is gone. A new owner who wants payments publishes their own binding after acquiring the name. Deregistering spends the name back to an ordinary P2PKH, removing the binding without moving ownership.

### Profile fields

Two optional fields follow the identity key. Both are **presentation only** — the OpNS name is the unique, owned value, and a display name is neither owned nor unique. Anything rendering these must keep the name primary.

| Field | Encoding                                                   | Meaning                                                             |
| ----- | ---------------------------------------------------------- | ------------------------------------------------------------------- |
| 1     | UTF-8                                                      | Display name                                                        |
| 2     | 36 bytes — 32-byte txid (little-endian) + 4-byte vout (LE) | Outpoint of the avatar image: an inscription or a B protocol output |

The avatar is an **outpoint, not a URL** — the image is on chain, so resolving it depends on no DNS name and no hosting provider. The outpoint names the output holding the image directly.

Field 1 is an empty push when only an avatar is set; a trailing unset field is omitted entirely.

Editing a profile is republishing: there is no separate edit operation. Both fields are cleared along with the binding when the name is transferred, listed, or deregistered.

### Wallet actions (`@1sat/actions`)

| Action           | Role                                                                                                                                     |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `registerOpns`   | Publish the binding — re-lock the name with a signed PushDrop carrying the wallet identity key, plus optional `profileName` and `avatar` |
| `deregisterOpns` | Remove the binding — spend back to plain P2PKH                                                                                           |
| `sendOpns`       | Transfer the name ordinal (unlocks a bound name; binding does not carry)                                                                 |
| `sellOpns`       | List the name for sale (ordlock)                                                                                                         |
| `listOpns`       | List OpNS names in the wallet                                                                                                            |

## Resolution

A paymail server answers "where do I pay `alice`?" as follows:

1. **Origin** — look up the name's origin outpoint in the OpNS overlay.
2. **Current state** — from that origin, resolve the ordinal's latest outpoint and load its locking script.
3. **Binding** — decode the PushDrop, take the identity key from the first field, re-derive the lock key from it, and verify both the lock and the field signature. Any profile fields come from the same decode.

**No binding, no payment.** An unbound name (plain lock, or failed verification) is not payable. Resolvers do not fall back to the name ordinal's current locking script or its holder address — only a valid identity binding yields a destination.

## How the paymail server works

1. **Discovery** — `.well-known/bsvalias` advertises the capabilities below.
2. **PKI** — `GET /id/:paymail` returns the bound **identity public key**.
3. **Payment destination** — `POST /p2p-payment-destination/:paymail` with the amount:
   * Resolve and verify the binding.
   * Derive a one-shot P2PKH with BRC-29 (server **anyone** key vs recipient identity key, random derivation prefix and suffix); store pending with script, amount, prefix, suffix, and identity under a `reference`.
   * Return `reference` and the output script to the payer.
4. **Receive** — payer posts the signed payment to `receive-beef` (or `receive-transaction`) with that `reference`:
   * Server verifies the transaction against the pending destination.
   * Broadcasts the transaction.
   * Posts a remittance to the recipient's messagebox (`payment_inbox`, addressed by identity public key) so the wallet can internalize: BEEF, output index, derivation prefix/suffix, sender identity key, satoshis, and alias.
5. **Wallet** — the owner's wallet lists `payment_inbox`, internalizes with the derivation remittance, and acknowledges the message.

## Paymail Capabilities

Servers expose the standard bsvalias surface, discovered via `.well-known/bsvalias`:

| Capability     | Endpoint                            | Purpose                                         |
| -------------- | ----------------------------------- | ----------------------------------------------- |
| `pki`          | `/id/:paymail`                      | The identity key bound to the name              |
| `f12f968c92d6` | `/public-profile/:paymail`          | Display name and avatar, read from the binding  |
| `2a40af698840` | `/p2p-payment-destination/:paymail` | Payment outputs for a requested amount          |
| `5c55a7fdb7bb` | `/receive-beef/:paymail`            | Deliver the signed payment as BEEF              |
| `5f1323cddf31` | `/receive-transaction/:paymail`     | Deliver the signed payment as a raw transaction |

## Notes

* The binding is the current UTXO's locking script: spending the name removes it, so a bound name is always bound by its current holder — stale bindings from prior owners cannot linger.
* Every destination is a one-shot BRC-29 derivation: no address reuse, and payments are internalized through the wallet inbox rather than sitting at a static address.
* Bindings verify offline from the script alone; resolvers need the OpNS index only to find the name's latest outpoint.
* `public-profile` returns the display name when one is published and the OpNS name otherwise, and serves the avatar as a content URL on the same ORDFS host the resolver reads from.
* Claiming a name does not make it payable. The holder must publish a binding (`registerOpns`) before paymail destinations work.
* Overlays and payment hosts are open infrastructure; see [Introduction](/name-service/ecosystem).


# OrdFS

Resolve ordinal content and metadata over HTTP

OrdFS is an HTTP gateway for 1Sat ordinals: it turns on-chain inscription state into ordinary web resources. Apps load inscription bytes, walk transfer history, and read accumulated MAP metadata without reimplementing ordinal crawls.

It does not mint or transfer ordinals. It **reads** content and chain state that already exist on Bitcoin.

## What you can do with it

* **Serve content** — fetch inscription (or B-protocol) bytes by outpoint with the right `Content-Type` (images, video, HTML, JSON, …).
* **Follow the ordinal** — resolve origin, a specific sequence, or the current tip of the transfer chain.
* **Read application state** — merge MAP fields written along that chain (collections, custom keys).
* **Host small apps** — [directories](/content-and-resolution/directories) (`ord-fs/json`), path traversal, SPA-style fallback to `index.html`.
* **Stream large media** — [streams](/content-and-resolution/streams) with HTTP Range when content is chunked on-chain.
* **Shared payloads** — a directory whose default entry is `"."` pointing at a source inscription (see [Directories](/content-and-resolution/directories#default-entry-empty-path)).

Services built on names use the same model: look up a name’s **origin**, then use OrdFS to resolve its current tip (see [Payments](/name-service/payments)).

## How resolution works

An **outpoint** (`txid_vout`) names a transaction output. OrdFS loads that output, extracts content when present, and can walk the ordinal’s spend chain.

| Concept       | Meaning                                                                  |
| ------------- | ------------------------------------------------------------------------ |
| **Origin**    | First 1-sat inscription outpoint in the ordinal lineage                  |
| **seq**       | Position along the transfer chain (see below)                            |
| **Content**   | Inscription envelope, or B-protocol data when no inscription type is set |
| **MAP merge** | All MAP entries up through the target sequence; later keys win           |

### Sequence (`seq`)

Appended to the pointer as `{outpoint}:{seq}` (e.g. `…_0:-1`).

| seq         | Behavior                                              |
| ----------- | ----------------------------------------------------- |
| *(omitted)* | Content at that outpoint only — no chain crawl        |
| `-2`        | Content at the **origin**                             |
| `0`, `1`, … | Content as of that absolute sequence (ownership step) |
| `-1`        | **Tip** — current end of the transfer chain           |

Ownership transfers and content reinscriptions are tracked separately. Requesting a sequence returns the **latest content at or before** that step, so a pure transfer does not clear prior inscription bytes.

### MAP

MAP (`1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5`) on outputs along the chain is merged chronologically. That is how mutable application fields — collection membership, display metadata, custom keys — stay attached to an ordinal across transfers without changing the inscription body.

## Scope of a deployment

An OrdFS instance is backed by a **transaction store and spend index** — typically the same graph an overlay has admitted, not necessarily the full blockchain.

It does not need a complete global history to be useful. If a request needs an ancestor, spend, or outpoint **outside** what that instance has, OrdFS responds with **404**. That is normal for a bounded deployment, not a protocol failure.

## HTTP surface

**Content** is mounted at the host root. Other OrdFS routes sit under `/1sat/ordfs`. Paths use outpoint form `txid_vout`.

| Use           | Method / path shape                                  |
| ------------- | ---------------------------------------------------- |
| Content       | `GET /content/{outpoint}[:seq][/filepath]`           |
| Metadata      | `GET /1sat/ordfs/metadata/{outpoint}[:seq]`          |
| Bulk metadata | `POST /1sat/ordfs/metadata` with a list of outpoints |
| Stream        | `GET /1sat/ordfs/stream/{outpoint}`                  |
| Preview       | `GET` / `POST` `/1sat/ordfs/preview…`                |

Useful response headers when present: `X-Outpoint`, `X-Origin`, `X-Ord-Seq`, `X-Map`, `X-Parent`. Fixed-sequence content can be cached as immutable; tip (`seq=-1`) is not.

On `/content/`, OrdFS may apply layout-specific rules after loading the inscription:

| Layout    | Spec                                               | Behavior summary                                                       |
| --------- | -------------------------------------------------- | ---------------------------------------------------------------------- |
| Directory | [Directories](/content-and-resolution/directories) | Path walk under `ord-fs/json`; empty path uses `"."` then `index.html` |
| Stream    | [Streams](/content-and-resolution/streams)         | Full assembly on `/1sat/ordfs/stream/…`, not on `/content/`            |

## Names and payments

[OpNS](/name-service/opns) defines how names are mined and where each name’s **origin** is. OrdFS resolves **forward** from that origin to the current tip. [Payments](/name-service/payments) composes the two: origin from OpNS, identity key from the tip’s locking script (a signed PushDrop bind).

## See also

* [Directories](/content-and-resolution/directories) — `ord-fs/json` file trees
* [Streams](/content-and-resolution/streams) — multi-inscription media
* [Metadata](/adding-metadata) — MAP and schema types on ordinals
* [HTML inscriptions](/html-ordinals) — content that often loads via OrdFS URLs


# Directories

Host file trees with ord-fs/json directory inscriptions

An inscription with content type **`ord-fs/json`** is a **directory**. Its body is a JSON object: keys are **single path segment** names, values are **pointers** to other inscriptions (files or nested directories).

**Keys must not contain `/`.** Each directory is one depth only — a flat map of name → pointer. Multi-level URLs (`…/lib/util.js`) come from **recursive** resolution: an entry whose content type is also `ord-fs/json` is another single-level directory, not a key with slashes.

Served by [OrdFS](/content-and-resolution/ordfs) under `/content/{outpoint}/…`.

```json
{
  ".": "_0",
  "index.html": "_1",
  "style.css": "_2",
  "lib": "aa11bb22…ff_0",
  "readme.md": "ord://cc33dd…_0"
}
```

### Default entry (empty path)

`GET /content/{dirOutpoint}` with no filepath (and without `?raw`) picks a **default** map key:

| Priority | Key          | Empty-path behavior                                                                                               |
| -------- | ------------ | ----------------------------------------------------------------------------------------------------------------- |
| 1        | `.`          | Serve that pointer **in place** (no redirect). Prefer this for a type-neutral root payload (e.g. a shared image). |
| 2        | `index.html` | **Redirect** to `{path}/index.html`. Prefer this for sites / SPAs.                                                |

`.` wins when both keys exist. Explicit paths such as `/content/{dir}/style.css` are unchanged.

**SPA fallback** (missing last path segment only) still tries `index.html` only — not `.`.

Minimal default-only map:

```json
{ ".": "aa11bb22…ff_0" }
```

```
GET /content/{dirOutpoint}       →  bytes of the pointed-to inscription
GET /content/{dirOutpoint}?raw   →  directory JSON (ord-fs/json)
GET /content/{dirOutpoint}/.     →  same as default when `.` is the map key (optional explicit segment)
```

## Deploying a directory

1. Inscribe each file (and any nested directory inscriptions) as its own 1-sat output.
2. Inscribe the directory itself with:
   * Content type: `ord-fs/json`
   * Body: JSON map as above
3. Prefer putting **siblings in the same transaction** and pointing at them with relative vouts (`_1`, `_2`, …) so one mint tx holds the tree root and leaves. Absolute outpoints work when children live in other txs.
4. Serve via content URL. The directory outpoint is the site root:

```
GET /content/{dirTxid}_{dirVout}/
GET /content/{dirTxid}_{dirVout}/style.css
GET /content/{dirTxid}_{dirVout}/lib/util.js
```

Every pointed-to outpoint must exist in **this OrdFS instance’s** transaction store (same [scope rules](/content-and-resolution/ordfs#scope-of-a-deployment) as other content). Missing children 404.

## Pointer forms

| Pointer                    | Meaning                                                                             |
| -------------------------- | ----------------------------------------------------------------------------------- |
| `_N`                       | Output index `N` in the **same transaction** as the directory inscription (sibling) |
| `txid_vout` or `txid.vout` | Absolute outpoint                                                                   |
| `txid` (64 hex)            | Treated as that transaction’s first resolvable content output                       |
| `ord://…`                  | Same as the forms above with an optional `ord://` prefix (stripped)                 |

## Recursive resolution

`GET /content/{pointer}[:seq]/filepath}` drives directory walk:

1. Load the root pointer. If content type is not `ord-fs/json`, serve the bytes as a normal file.
2. If it **is** a directory and **filepath is empty**:
   * With **`?raw`**: return the directory JSON (`Content-Type: ord-fs/json`).
   * Else if map has **`.`**: load that pointer and serve it (in place).
   * Else if map has **`index.html`**: **redirect** to `{path}/index.html`.
   * Else: not found.
3. Split filepath on `/` into segments. For each segment, in order:
   * Look up the name in the **current** directory map.
   * **SPA fallback:** if the name is missing and this is the **last** segment only, use `index.html` if present (not `.`).
   * Load that entry’s pointer (same pointer rules).
   * If there are **more** segments and the loaded content is again `ord-fs/json`, **recurse** into that subdirectory with the remaining path.
   * If this is the last segment (or the entry is not a directory), **serve that content**.
4. Nesting is capped at **8** directory levels (`directory nesting too deep` if exceeded).

Example: `/content/{root}/lib/util.js` where `root` is `ord-fs/json` with `"lib" → subdirOutpoint`, and that subdir is `ord-fs/json` with `"util.js" → fileOutpoint`, loads the file through two map lookups.

Intermediate segments that are not directories (or missing keys mid-path without SPA fallback) fail with not found / bad request as appropriate.

## Practical notes

* Use **`"."`** as the default entry for a single non-HTML payload (or any root you want at `/content/{outpoint}` without a filename).
* Include **`index.html`** for web roots and SPAs that rely on redirect and last-segment fallback.
* Nested apps: put another `ord-fs/json` inscription behind a key (e.g. `"docs"`) and link to `/content/{root}/docs/…`.
* Relative `_N` pointers only work when the directory’s own outpoint is known (normal content serving).

## See also

* [OrdFS](/content-and-resolution/ordfs) — gateway resolution, seq, MAP, HTTP routes
* [Streams](/content-and-resolution/streams) — large files split across a transfer chain


# Streams

Large files split across an ordinal transfer chain

Large payloads can be split across **multiple inscriptions on one ordinal transfer chain**, then reassembled by OrdFS.

## On-chain layout

1. **Chunk 0 (start of stream):** the payload’s actual content type (e.g. `video/mp4`, `application/octet-stream`). Conventionally mark it as streamable, e.g. `video/mp4; stream=ordfs` (parameter on the type string). Body is the first slice of bytes.
2. **Further chunks:** each successive **spend** of the ordinal carries the next slice with content type exactly **`ordfs/stream`**.
3. Chain ends when a spend has no further content, spend is missing, or a later output’s type is **not** `ordfs/stream` (after the first chunk).

All chunks must be in the instance’s BEEF/spends graph so the stream walk can follow the ordinal. Same [scope rules](/content-and-resolution/ordfs#scope-of-a-deployment) as other OrdFS loads.

## Serving

```
GET /1sat/ordfs/stream/{outpoint}
```

OrdFS:

1. Resolves origin / chain from the starting outpoint.
2. Walks spends forward, concatenating content bodies in order.
3. Sets `Content-Type` from the **first** chunk’s type (so clients see `video/mp4`, not `ordfs/stream`).
4. Supports **HTTP Range** (`Range: bytes=start-end`) for seek and progressive download; only the relevant portions of chunks are written.

Example:

```bash
curl -H "Range: bytes=0-1023" "https://{host}/1sat/ordfs/stream/{txid}_{vout}"
```

`GET /content/{outpoint}` on a stream origin returns only that outpoint’s inscription (typically chunk 0), not the assembled stream. Use the stream route for full media.

## Deploying a stream

1. Split the file into chunks sized for your inscription limits (1 MiB bodies are a practical default).
2. Mint chunk 0 as a 1-sat inscription with the public content type (and optional `stream=ordfs` parameter).
3. Transfer/reinscribe the same ordinal for each subsequent chunk with type `ordfs/stream` and the next bytes (order is spend order).
4. Point clients at `/1sat/ordfs/stream/{firstChunkOutpoint}` (or an outpoint mid-chain if you only need a suffix — walk starts from the requested outpoint).

If a middle chunk is missing from the store, the stream stops or errors when that spend cannot be loaded.

## Reference mint (`@1sat/actions`)

The TypeScript SDK’s `inscribe` action can build this layout:

* `stream: true` — multi-tx stream with **1 MiB** chunk bodies
* `streamChunkSize: N` — multi-tx stream with custom body size

Omit both for a single-transaction inscription. Stream outputs are tagged with `sha256:<content-hash>` and `stream-i:<index>`. See [Libraries](/libraries) and [1sat-sdk](https://github.com/b-open-io/1sat-sdk).

## See also

* [OrdFS](/content-and-resolution/ordfs) — gateway resolution, seq, MAP, HTTP routes
* [Directories](/content-and-resolution/directories) — multi-file sites via `ord-fs/json`


# Libraries & software

This site is the **protocol** specification for 1Sat Ordinals. Application code and hosted services live in separate repositories.

## Current

### 1sat-sdk

TypeScript monorepo for building on 1Sat Ordinals: wallets, actions (inscribe, transfer, list, tokens, OpNS bindings), HTTP clients, script templates, CLI, and browser connect.

|                |                                                                        |
| -------------- | ---------------------------------------------------------------------- |
| **Repository** | [github.com/b-open-io/1sat-sdk](https://github.com/b-open-io/1sat-sdk) |
| **npm scope**  | [`@1sat/*`](https://www.npmjs.com/org/1sat)                            |

Common packages (install what you need):

| Package                                                            | Role                                        |
| ------------------------------------------------------------------ | ------------------------------------------- |
| [`@1sat/cli`](https://www.npmjs.com/package/@1sat/cli)             | CLI (`bunx @1sat/cli`)                      |
| [`@1sat/actions`](https://www.npmjs.com/package/@1sat/actions)     | High-level wallet actions                   |
| [`@1sat/wallet`](https://www.npmjs.com/package/@1sat/wallet)       | BRC-100 wallet engine                       |
| [`@1sat/client`](https://www.npmjs.com/package/@1sat/client)       | HTTP client for hosted APIs                 |
| [`@1sat/templates`](https://www.npmjs.com/package/@1sat/templates) | Script templates (OpNS, BSV-21, OrdLock, …) |
| [`@1sat/connect`](https://www.npmjs.com/package/@1sat/connect)     | Browser wallet popup protocol               |
| [`@1sat/react`](https://www.npmjs.com/package/@1sat/react)         | React hooks                                 |

Underlying crypto and transaction types typically come from [`@bsv/sdk`](https://www.npmjs.com/package/@bsv/sdk).

See the SDK repository README for setup, skills, and examples. This docs site does **not** fully specify the SDK API surface.

### 1sat-stack

Go server that hosts the live 1Sat stack: transaction/BEEF storage, ordinal resolution ([OrdFS](/content-and-resolution/ordfs)), OpNS overlay, paymail, marketplace (OrdLock), owner sync, and related HTTP APIs. Modules can be embedded, remote, or disabled per deployment.

|                           |                                                                            |
| ------------------------- | -------------------------------------------------------------------------- |
| **Repository**            | [github.com/b-open-io/1sat-stack](https://github.com/b-open-io/1sat-stack) |
| **Public host (example)** | `https://api.1sat.app`                                                     |

Capability mounts commonly sit under `/1sat/…` (e.g. `/1sat/opns`, `/1sat/ordfs`). Content is at root **`/content/…`**. Exact routes depend on configuration; use the deployment’s OpenAPI/swagger where enabled.

App clients usually talk to a stack host via `@1sat/client` rather than reimplementing endpoints.

***

## Historical / deprecated

The following libraries and servers predate the current SDK and stack. They remain useful for archaeology and old integrations but are **not** the recommended path for new work.

### Javascript

#### js-1sat-ord (deprecated)

Legacy JS library. Docs site: [js.1satordinals.com](https://js.1satordinals.com/). Repo: [bitcoinschema/js-1sat-ord](https://github.com/bitcoinschema/js-1sat-ord). Prefer **1sat-sdk** (`@1sat/*`).

#### bmapjs

Transaction parser with 1Sat inscription and metadata support: [rohenaz/bmap](https://github.com/rohenaz/bmap) (`npm i bmapjs`). Still useful for BMAP-shaped parsing; not a full 1Sat app stack.

### Go

#### go-1sat-ord (deprecated)

Legacy Go helpers for creating 1Sat transactions: [bitcoinschema/go-1sat-ord](https://github.com/bitcoinschema/go-1sat-ord). Prefer **1sat-stack** templates/packages and **1sat-sdk** for app-level flows.

#### go-bmap

Transaction parser with 1Sat inscription and metadata support: [bitcoinschema/go-bmap](https://github.com/bitcoinschema/go-bmap).


# Public APIs (historical)

{% hint style="warning" %}
**Historical.** This page documents the older **1sat-server** HTTP API (GorillaPool / `ordinals.gorillapool.io`). New integrations should use a **1sat-stack** deployment (example host: `https://api.1sat.app`) and the TypeScript client in [1sat-sdk](/libraries) (`@1sat/client`). See [Libraries](/libraries) for current software.
{% endhint %}

## Current platform (summary)

| Surface                                     | Where                                                                                        |
| ------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Stack (OpNS, OrdFS, owner, market, beef, …) | [1sat-stack](https://github.com/b-open-io/1sat-stack) — typically `/1sat/…` and `/content/…` |
| Content & ordinal resolution                | [OrdFS](/content-and-resolution/ordfs)                                                       |
| Names                                       | [OpNS](/name-service/opns)                                                                   |
| App SDK                                     | [1sat-sdk](https://github.com/b-open-io/1sat-sdk) / [Libraries](/libraries)                  |

***

## Legacy: 1sat-server (deprecated for new work)

GorillaPool maintained a public `1sat-server`. Basic usage is below. See the auto-generated [swagger documentation](https://ordinals.gorillapool.io/api/docs/) for a complete API reference.

The API is also [available on Github](https://github.com/shruggr/1sat-server).

### Other APIs

* There is also basic support from [#whats-on-chain](#whats-on-chain "mention")
* The [#bmap-api](#bmap-api "mention") can be used to resolve inscriptions with support for several other data protocols.

## 1SAT Server Endpoints

### Get Files, Inscriptions

```
METHOD: GET
```

Get inscription file for a given origin.

```
https://ordinals.gorillapool.io/api/files/inscriptions/:origin
```

Sample response

<figure><img src="/files/AzUroHCHxv0ri8R9Is4w" alt=""><figcaption></figcaption></figure>

### Get Inscriptions

```
Method: GET
```

Get inscription data for a given origin.

```
https://ordinals.gorillapool.io/api/inscriptions/origin/:origin
```

Get inscriptions for a given txid.

```
https://ordinals.gorillapool.io/api/inscriptions/txid/:txid
```

Sample response

```json
[
    {
      // inscription number
      "id": 165, 
      // transaction id
      "txid": "e17d7856c375640427943395d2341b6ed75f73afc8b22bb3681987278978a584",
      // output index
      "vout": 1,
      // file info
      "file": {
        "hash": "3dbe16ec7625e0d8a02ceaa5b2b03bc412c06186d03fbd69090c162469cf0292",
        "size": 2592,
        "type": "image/png"
      },
      // 1sat output origin
      "origin": "e17d7856c375640427943395d2341b6ed75f73afc8b22bb3681987278978a584_1",
      // ordinal number
      "ordinal": 0,
      // block height
      "height": 783968,
      // block index
      "idx": 756,
      // hash of locking script preceding inscription
      "lock": "5d5c07f532ae28f90263209aeba5417366569c60947b74b363ce55c5d57d253d"
    }
]
```

### Get Ordinal Utxos

```
Method: GET
```

Get unspent utxos with ordinal locks matching a given address.

```
https://ordinals.gorillapool.io/api/utxos/address/:address
```

Sample response

{% code overflow="wrap" %}

```json
[
    {
      "txid": "5af82e9c72688270afc9c70a3f523560600d1aa2c39eab74756d11243f4752ba",
      "vout": 0,
      "satoshis": 1,
      "lock": "b0a542a4a4707f7b5b48f4c7a45e12bee4f9481a5ad3db250dfd3730f5ff4225",
      "origin": "5af82e9c72688270afc9c70a3f523560600d1aa2c39eab74756d11243f4752ba_0",
      "ordinal": 0
    },
    {
      "txid": "7ecb6b642cf7e44cf757562fe88f8c51f0bb844e41c6c844eca2b13af8c49ca0",
      "vout": 0,
      "satoshis": 1,
      "lock": "b0a542a4a4707f7b5b48f4c7a45e12bee4f9481a5ad3db250dfd3730f5ff4225",
      "origin": "7ecb6b642cf7e44cf757562fe88f8c51f0bb844e41c6c844eca2b13af8c49ca0_0",
      "ordinal": 0
    }
]
```

{% endcode %}

You can also get inscriptions for UTXOs in a single request

```
https://ordinals.gorillapool.io/api/utxos/address/:address/inscriptions
```

## Get Lock Utxos

```
Method: GET
```

Get unspent outputs for a given "lock", which is the scripthash of the locking script up to the point of an inscription.

```
https://ordinals.gorillapool.io/api/utxos/lock/:lock
```

Returns UTXOs:

```json
[{
    "txid": string,
    "vout": number,
    "satoshis": number,
    "lock": string,
    "spend": string,
    "origin": string,
    "ordinal": number,
}]
```

## Address Events - SSE

SSE endpoints are available for real-time mempool tx notifications. Watch multiple addresses or locking script hashes simultaneously, and get notified when a transaction occurs matching. Add query param `address` for each address you want to monitor, and `lock` for each script hash.

You will receive both new Inscription UTXOs AND spends from the same messages. If the `spend` field is not `null`, that means you have received a spend, and you should remove the UTXO identified by `txid`:`vout` from your UTXO set.

If the spend field is `null`, then this is a new Inscription in your wallet.

{% code overflow="wrap" %}

```javascript
https://ordinals.gorillapool.io/api/subscribe?address=:address1&address=:address2&lock=:lock1&...
```

{% endcode %}

Listening for ordinal address activity:

```tsx
const API_HOST = "https://ordinals.gorillapool.io/api/"
const s = new EventSource(`${API_HOST}subscribe?address=${ordAddress}`);

s.onmessage = (e) => {
    console.log({ message: e })
}
// s.onopen
// s.onerror
```

## What's On Chain

WhatsOnChain.com also provides 1Sat Ordinals support by tagging the inscriptions and providing a plugin for rendering ordinals by txid and output index as follows:

{% code overflow="wrap" %}

```
https://plugins.whatsonchain.com/api/plugin/main/:txid/:vout
```

{% endcode %}

## BMAP API

Get a BMAP Transaction object as a formatted JSON string

```
https://b.map.sv/tx/:txid
```

or non-formatted bmap

```
https://b.map.sv/tx/:txid/bmap
```

raw transaction hex

```
https://b.map.sv/tx/:txid/raw
```

or BOB format

```
https://b.map.sv/tx/:txid/bob
```


# Text Inscriptions

A substandard has emerged for recording other protocols as text files, using the inscription as an envelope. This is done by creating an inscription with `text/plain;charset=utf-8` in the `content-type` field along with a JSON payload for the data:

```json
{ "p": "brc-20", "op": "mint", "tick": "meme", "amt": "1" }
```

Two such early protocols are sns and brc-20. Since 1Sat Inscriptions follow the same data protocol, text-based inscription sub-protocols are instantly portable to BSV.


# Reference Inscriptions

Inscribe references to content by URI

You can inscribe references to on-chain content using the text/uri-list content type defined here:\
<https://www.rfc-editor.org/rfc/rfc2483#section-5>

### Examples

```
# This is a comment
https://mydomain.com/something.pdf
```

In this example we reference a JSON inscription. The file extension is useful for hinting before the content has been loaded, allowing clients to make UI decisions sooner (like choosing the correct component to render the content).

Using [OrdFS](/content-and-resolution/ordfs)-compatible content routes, you can reference on-chain files by relative path:

```
# This is an image inscription
/content/<outpoint | contentHash>.png
```

See [OrdFS](/content-and-resolution/ordfs), [Directories](/content-and-resolution/directories), and [Streams](/content-and-resolution/streams) for resolution rules. Gateways such as [ordfs.network](https://ordfs.network) expose a compatible `/content/` path.

### Multiple Files

You can also reference many files in a single text/uri-list inscription:

```
/content/<outpoint1>.html
/content/<outpoint2>.js
/content/<outpoint3>.webp
/content/<outpoint4>.css
```

In this example we can make the contents of a webpage and all of its dependencies available as a single package.


# HTML Inscriptions

### Inscribing Web Pages

To inscribe a webpage, simply use the html content type when inscribing.

```bash
1SAT_P2PKH OP_IF "ord" OP_1 "text/html;charset=utf8" OP_0 <html_data> OP_ENDIF
```


# HTML References

Using ord:// and sat:// URL protocol handlers to reference inscriptions.

### /content - dynamic content resolution

HTML inscriptions can reference relative file paths to `/content/<outpoint>` to automatically have the content detected and returned as a file. How that resolution works is specified in [OrdFS](/content-and-resolution/ordfs). Public gateways such as [ordfs.network](https://ordfs.network) implement a compatible content path.

### ord:// - On-Chain Inscription References

You can embed references to other inscriptions inside the on-chain HTML or markdown. You can address.

An ordinal number is the precise satoshi identifier.

`Inscription ID` is the transaction id, and output index of a specific inscription, formatted as: `txid_vout`

### Original inscription by Ordinal Number

In a text/html inscription:

```html
<img src="ord://ordinalNumber" />
```

In a text/markdown inscription:

```markdown
[My Ordinal!]("ord://ordinalNumber")
```

### Specific inscription by Inscription ID

In a text/html inscription:

```html
<img src="ord://inscriptionID" />
```

In a text/markdown inscription:

```md
[My Ordinal!]("ord://inscriptionID")
```

## #latest - Dynamic Inscription References

Use the `#latest` fragment to return the latest inscription for a given ordinal number, or inscription ID.

### Latest inscription by Ordinal Number

In a text/html inscription:

```html
<img src="ord://ordinalNumber#latest" />
```

In a text/markdown inscription:

```markdown
[My Ordinal!]("ord://ordinalNumber#latest")
```

### Latest inscription by Inscription ID

In a text/html inscription:

```html
<img src="ord://inscriptionID#latest" />
```

In a text/markdown inscription:

```md
[My Ordinal!]("ord://inscriptionID#latest")
```

## URL Resolution

| URL                        | resolves to          |
| -------------------------- | -------------------- |
| ord://ordinalNumber        | original inscription |
| ord://inscriptionID        | specific inscription |
| ord://ordinalNumber#latest | latest inscription   |
| ord://inscriptionID#latest | latest inscription   |


# Metadata

Metadata is located after the `OP_RETURN` opcode in the output script of an inscription, and does not interefere with the [inscription protocol](/).

```
1SAT_P2PKH INSCRIPTION OP_RETURN METADATA
```

You can use metadata to add context to ordinals. For example, you can tag an ordinal with collection data, geohashes, external file references, etc. Metadata is written using "Magic Attribute Protocol" which has a prefix of `1PuQa7K62MiKCtssSLKy1kh56WWU7MtUR5`.

(TODO: Find better example using more typical case)

{% code overflow="wrap" %}

```
OP_DUP OP_HASH160 <PUBKEY> OP_EQUALVERIFY OP_CHECKSIG OP_FALSE OP_IF 6f7264 OP_1 <content-type> OP_0 <data> OP_ENDIF OP_RETURN 3150755161374b36324d694b43747373534c4b79316b683536575755374d74555235 534554 617070 6f72642d64656d6f 74797065 706f7374 636f6e74657874 67656f68617368 67656f68617368 6468786e643170776e
```

{% endcode %}

{% hint style="info" %}
Notice we do not use OP\_FALSE OP\_RETURN. This is important as omitting OP\_FALSE allows us to spend the output.
{% endhint %}

In the above example, we geotag an ordinal with a location using Magic Attribute Protocol.

## Schema Types

To help standardize consumption of this data, we define schema types to establish common field names to be shared cross platforms. While schema type cover a broad range of use cases, this document refers the Ordinals schema type `ord` .

## Other Metadata

BSV has several protocols for tagging on-chain data that pre-date Ordinals. 1Sat Ordinals can be extended using many existing protocols during inscription, or even to tag the sat as it is spent. This enables things like minting files > 10MB, attaching metadata to inscriptions, creating collections, and signing with identity keys.

```
NOTE: Enriching an ordinal with OP_RETURN is completely optional.
```

You can still add metadata from other schema types besides "ord" if you prefer. You can find a list of different schema typesa at <https://bitcoinschema.org>.

{% code overflow="wrap" %}

```bash
1SAT_P2PKH <INSCRIPTION> OP_RETURN <B fields...> | MAP SET app <platform_name> type "post" context "geohash" geohash "dhmgdqvr7"
```

{% endcode %}

Similarly, you can attach an ordinal to a particular url:

{% code overflow="wrap" %}

```bash
1SAT_P2PKH <INSCRIPTION> OP_RETURN <B fields...> | MAP SET app <platform_name> type "post" context "url" url "https://google.com"
```

{% endcode %}


# Ord Schema Type

## The "ord" schema type

The base schema type for ordinals metadata is `ord`. This base type can be extended with the `subType` property so that wallets and markets will understand how to interpret and display metadata.

\
While subtypes can be created at will, a list of common subTypes is maintained at <https://bitcoinschema.org>.

## Required Fields:

`app` - The name of the app that originally produced the ordinal

`type` - This should always be "ord". This helps indexers find the metadata based on type.

`name` - Name description of the ordinal.

## 1Sat Ordinals - Metadata Proposal

The following outlines a standard set of metadata properties that should be utilized by creators and implemented by developers when adding metadata to 1Sat Ordinals. Adhering to these specifications when creating and displaying content across applications will make for a better and more cohesive cross-platform user experience.

### Top-Level Metadata

Added to the inscription output using MAP protocol in OP\_RETURN.

Please note that the MAP protocol expects all data types for the value in the key value pair to be of type `string`.

<table><thead><tr><th width="243">Description</th><th width="124">Required</th><th width="177">Type</th><th>Example</th></tr></thead><tbody><tr><td><code>app</code><br><br>The name of the app that originally produced the ordinal</td><td>Y</td><td>string</td><td>handcash</td></tr><tr><td><code>type</code><br><br>The type of MAP data. For this spec we use <code>ord</code></td><td>Y</td><td>string</td><td>ord</td></tr><tr><td><code>name</code><br><br>Name of the ordinal</td><td>Y</td><td>string</td><td>Joe Racoon</td></tr><tr><td><code>subType</code><br><br>The subType</td><td>N</td><td>string</td><td>collectionItem, collection, website</td></tr><tr><td><code>subTypeData</code><br><br>A stringified version of the data required by the specific subType specified. See subType documentation.</td><td>N<br>SubType: Y<br></td><td>stringified JSON</td><td>{ file: ..., fileType: ... }</td></tr><tr><td><code>royalties</code><br><br>Where creator royalties should be sent</td><td>N</td><td>stringified JSON array of <code>royalty</code></td><td>see definition below</td></tr><tr><td><code>previewUrl</code></td><td>N</td><td>string URL</td><td>http://so.me/prev.png<br>b://&#x3C;txid><em>&#x3C;idx></em><br><em>c://&#x3C;contentH</em>ash></td></tr><tr><td><code>...</code><br><br>You can add additional fields with MAP as needed.</td><td>N</td><td>any</td><td>see <a href="/pages/AgZYtAIrYGuzipjEGlFV#other-metadata">metadata examples</a></td></tr></tbody></table>

## Royalties

Royalties should be applied when a sale of an item occurs. The definition of `royalty` within the `royalties` array:

<table><thead><tr><th width="166">Name</th><th width="300">Description</th><th width="104">Required</th><th>Type</th></tr></thead><tbody><tr><td>type</td><td>Currently supports paymail and any valid script/address/paymail</td><td>Y</td><td><code>PaymentType</code></td></tr><tr><td>destination</td><td>The destination of the payment (the receivers address/paymail)</td><td>Y</td><td>string</td></tr><tr><td>percentage</td><td>The royalty percentage (3% would be <code>0.03</code>)</td><td>Y</td><td>string</td></tr></tbody></table>

## Payment Type

The type definition for `PaymentType`:

```
type PaymentType = 'paymail' | 'address' | 'script';
```

## Transaction Structure

This pseudo-script creates an ordinal with metadata called "The Awesome Ordinal" with only the minimum required fields, and adds a signature via AIP so the issuer can be verified.

Output 1:

{% code overflow="wrap" %}

```
1SAT_P2PKH <INSCRIPTION> OP_RETURN MAP SET app <mint_platform> type ord name "The Awesome Ordinal" | AIP <address> "BITCOIN_ECDSA" <signature> [-1]
```

{% endcode %}

### Example `ord`type

<pre class="language-json"><code class="lang-json">{
<strong>    "app": "take_it",
</strong>    "type": "ord",
    "name": "Awesome ordinal",
    "royalties": [
        {"type": "paymail", "destination": "jdoe@handcash.io", "percentage": "0.03"}, 
        {"type": "address", "destination": "1MvYhFajARJ82sbgxuAXziq1FmgSY1XQwD", "percentage": "0.025"}
    ]
}
</code></pre>


# Collection SubType

A special subType to describe a collection of ordinals

The collection subType is an ordinal including an on-chain record describing a collection. Member ordinals reference the collection subType by `txid_vout` using the `collectionId` field.

A collection inscription should be created first before any ordinals that reference it. If you do not record the collection inscription before the member ordinals, they will not be considered valid members of the collection.

The collection record should be signed with AIP using a key that matches the signature on member ordinals.

## subType data

Since a collection is an ordinal, all top level required fields are still required. When defining a collection there will be no `collectionId` present in top level metadata.

<table><thead><tr><th width="178">Name</th><th width="188">Description</th><th width="67">Req.</th><th width="115">Type</th><th>Example</th></tr></thead><tbody><tr><td>description</td><td>A brief description of the collection.</td><td>Y</td><td>string</td><td></td></tr><tr><td>quantity</td><td>Number in collection</td><td>N</td><td>string</td><td></td></tr><tr><td>rarityLabels</td><td>valid rarity labels &#x26; occurrences</td><td>N</td><td>stringified JSON</td><td>see example below</td></tr><tr><td>traits</td><td>list of valid traits objects</td><td>N</td><td>stringified JSON Array</td><td>see example below</td></tr></tbody></table>

## Collection Inscription

The collection subType is also an ordinal whos inscription should be of type `image/*`

While other content types will be considered valid, it it strongly recommended to use an image type to ensure apps can reliably display a collection preview.

## Example Rarity

To be considered valid by the indexer, accumulated rarity occurrences must equal 100.

```json
{
  "common": "3.00",
  "rare": "97.00"
}
```

## Example Traits

To be considered valid by the indexer, each occurancePercentage array must sum to 100.

{% code overflow="wrap" %}

```json
{
  "background": {
    "values": [
      "night time",
      "day time"
    ],
    "occurancePercentages": [
      "95.00",
      "5.00"
    ]
  },
  "lips": {
    "values": [
      "red",
      "blue"
    ],
    "occurancePercentages": [
      "90.00",
      "10.00"
    ]
  }
}
```

{% endcode %}

## Signatures

Signatures are applied the same way as [top level rules](#signatures). This allows collections to be verified.

## Transaction Structure

This pseudo-script screates a collection called "The Awesome Collection" with only the minimum required fields, and adds a signature via AIP so the issuer can be verified.

Output 1:

{% code overflow="wrap" %}

```
1SAT_P2PKH <INSCRIPTION> OP_RETURN MAP SET app <mint_platform> type ord subType collection name "The Awesome Collection"  description "57 wonderul things" | AIP <address> "BITCOIN_ECDSA" <signature> [-1]
```

{% endcode %}


# CollectionItem SubType

When the top level type is `collectionItem` the `subTypeData` is defined here.

### subTypeData data

The following properties define the `subTypeData` object and should be used if your `collectionItem` ordinal has additional information that should be associated with it. A `collectionId` at the top level is required for `collectionItem` ordinals. Since a collection is an ordinal, all top level required fields are still required as well.

<table><thead><tr><th>Name &#x26; Description</th><th width="118">Required</th><th>Type</th><th>Example</th></tr></thead><tbody><tr><td><code>collectionId</code><br><br>A unique identifier, txid_vout of the collection subType.</td><td>Y</td><td><code>txid_vout</code></td><td>TODO: use a good example <code>aaff22a9568dacfa6b90d64e31218b89bb5ef1ab3995e17540870fbf46bb990b_0</code><br><br>or for self: <code>_0</code></td></tr><tr><td><code>mintNumber</code><br><br>An integer, position the ordinal exists at within the collection</td><td>N</td><td>int</td><td>3</td></tr><tr><td><code>rank</code><br><br>A integer starting at 1 where 1 is the most 'rare'</td><td>N</td><td>int</td><td>10</td></tr><tr><td><code>rarityLabel</code><br><br>The overall rarity label for this ordinal</td><td>N</td><td>string enum based on <code>subTypeData</code></td><td>"legendary"</td></tr><tr><td><code>traits</code><br><br>Array of traits that describe the ordinal</td><td>N</td><td>traits as defined by collection <code>subTypeData</code></td><td>see examples below</td></tr><tr><td><code>attachments</code></td><td>N</td><td><code>Attachment[]</code></td><td>https://...<br>b://...<br>c://...</td></tr></tbody></table>

## Trait

The definition of `trait` within the `traits` array:

<table><thead><tr><th width="197">Name</th><th width="317">Description</th><th width="106">Required</th><th>Type</th></tr></thead><tbody><tr><td>name</td><td>The name of the trait</td><td>Y</td><td>string</td></tr><tr><td>value</td><td>The value of the trait</td><td>Y</td><td>string</td></tr><tr><td>rarityLabel</td><td>A rarity label to associate with the trait</td><td>N</td><td>RarityLabel</td></tr><tr><td>occurrencePercent</td><td>The percentage which this trait occurs within this collection</td><td>N</td><td>string</td></tr></tbody></table>

## Attachment

| Name         | Description                        | Required | Type   |
| ------------ | ---------------------------------- | -------- | ------ |
| name         | The name of the attachment         | Y        | string |
| description  | The description of the attachment  | N        | string |
| content-type | The content-type of the attachment | Y        | string |
| url          | The url of the attachment          | Y        | string |

## Transaction Structure

This pseudo-script creates an ordinal with metadata called "The Awesome Ordinal" with only the minimum required fields, and adds a signature via AIP so the issuer can be verified.

Output 1:

{% code overflow="wrap" %}

```
1SAT_P2PKH <INSCRIPTION> OP_RETURN MAP SET app <mint_platform> type ord name "The Awesome Ordinal" | AIP <address> "BITCOIN_ECDSA" <signature> [-1]
```

{% endcode %}

### Example `ord` type data

```json
{
 "name": "Pepe with Fire",
 "previewUrl": "https://somepreview.com/image.png",
 "royalties": [
    {"type": "paymail", "destination": "jdoe@handcash.io", "percentage": "0.03"}, 
    {"type": "address", "destination": "1MvYhFajARJ82sbgxuAXziq1FmgSY1XQwD", "percentage": "0.025"}
  ]
}
```


# Signing

It is possible to sign ordinals to link an identity to the creation of the inscription. Separating identity signatures from funding signatures is more flexible. This is useful for verified minting. Signatures use [Author Identity Protocol](https://github.com/attilaaf/AUTHOR_IDENTITY_PROTOCOL) which has a Bitcom prefix of `15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva`.

Since AIP was designed to sign OP\_RETURN based protocols, we need to use a special indices selector to sign the entire transaction, including the ordinal data. To do this, pass `[-1]` in the indices field to indicate the entire output script is being signed.

The collection subType leverages this protocol to enable verified collection.

### User Signatures

To sign when inscribing:

```bash
1SAT_P2PKH <INSCRIPTION> OP_RETURN <AIP> <signing_address> "BITCOIN_ECDSA" <sig> -1
```

### Platform Signatures

You can not only use AIP signatures to prove a particular identity created an inscription, but you can sign once more to prove that a particular platform was used to create the transaction as well.

```bash
1SAT_P2PKH <INSCRIPTION> OP_RETURN AIP <user_address> <user_sig> -1 | AIP <platform_address> <platform_sig> -1
```

## Validating Collections


# Location Tagging

Create an Ordinal with initial location:

```
1SAT_P2PKH <INSCRIPTION> OP_RETURN MAP app <appname> type "token" context geohash geohash <geohash> | AIP <sig...>
```

Move the location by spending the ordinal with a MAP geohash of the new location. Updates can be checked by an indexer, the signature validated it came from the inscriber, and surface the new location to the user along with an update history. See the signing section for more information on signing Ordinals.

```
i1 - 1 sat o1 from inscription tx
o1 - 1SAT_P2PKH OP_RETURN MAP geohash <geohash> | AIP <sig...>
```

Complex example: To inscribe a video that exists across multiple transactions and place it on a specific geohash with identity signature

```
tx1 - o1 - 1SAT_P2PKH OP_RETURN BCAT tx2 tx3 tx4... | MAP SET context geohash geohash <geohash> | AIP <sig...> -1

tx2 - o1 - BCAT_PART <tx2_data>
```


# Bitcoin Schema

Open Social Integration

Bitcoin Schema is a set of pre-defined data schemas that form overlay networks on Bitcoin. Bitcoin Schema uses a combination of data protocols to form the building blocks of new networks, such as "BSocial" - an open, interoperable social media network.

For example, you can create an Ordinal that is also a BSocial post, make a comment with B protocol, and use MAP to assign the "post" type to the transaction. The pseudoscript would look like this:

```bash
1SAT_P2PKH INSCRIPTION OP_RETURN B_POST_TEXT "|" MAP SET app <appName> type "post"
```

When broadcasted, apps that support BSocial will see the post and display the commend and inscription.

### More Information

To learn more about using common metadata structures, and how to use them to create interoperable Bitcoin apps, check out [BitcoinSchema.org](https://bitcoinschema.org).


# Handling Large Files

If you were to inscribe files larger than 10MB (at the time of writing this) the transaction would generally not be accepted by miners. To work around this, a large data file can be spread across multiple transactions. We can achieve this using the BCAT protocol. BCAT lists, in order, the transaction ids required to assemble the data file. It is a Bitcom protocol that uses the prefix "15DHFxWZJT58f9nhyGnsRBqrgwK4W6h4Up". You can find more information about BCAT protocol [here](https://bcat.bico.media/).

While you cannot add the bcat data directly into the inscription fields (since ordinals protocol does not support concatenating external transactions), you can inscribe a thumbnail as the ordinal image, and attach the video using BCAT in OP\_RETURN as follows.

TODO: Update with info from collection definition inscription (same structure)

```bash
1SAT_P2PKH <INSCRIPTION> OP_RETURN <BCAT fields...> tx2 tx3 tx4...
```


# Ordinal Lock

{% embed url="<https://github.com/shruggr/ordinal-lock>" %}

{% code overflow="wrap" %}

```
WARNING: This is currently experimental, and not sufficiently tested. 
Use at your own risk.
```

{% endcode %}

You can lock an ordinal, creating an on-chain public listing for sale. If the listing value is transferred to the specified address, the ordinal is released to the destination given by the buyer. The listing can be canceled.

Below is the sCrypt contract. Provide a payment output, and a sellec pubkey and compile the contract.

```js
import {
    assert,
    ByteString,
    hash160,
    hash256,
    method,
    prop,
    PubKey,
    PubKeyHash,
    SmartContract,
    Sig,
    SigHash,
} from 'scrypt-ts'

export class OrdinalLock extends SmartContract {
    @prop()
    seller: PubKeyHash

    @prop()
    payOutput: ByteString

    constructor(seller: PubKeyHash, payOutput: ByteString) {
        super(...arguments)

        this.seller = seller;
        this.payOutput = payOutput;
    }

    @method(SigHash.ANYONECANPAY_ALL)
    public purchase(destOutput: ByteString, trailingOutputs: ByteString) {
        assert(hash256(destOutput + this.payOutput + trailingOutputs) == this.ctx.hashOutputs)
    }

    @method()
    public cancel(sig: Sig, pubkey: PubKey) {
        assert(this.seller == hash160(pubkey), 'bad seller')
        assert(this.checkSig(sig, pubkey), 'signature check failed')
    }
}
```

`destOutput` is the destination output for the utxo which is locked.

Once the script is compiled, use it to mint and list an ordinal in a single 1 sat output:

```bash
1Sat_ORDINAL_LOCK <INSCRIPTION>
```


# Managing Unspent Outputs

Compatible wallets should be aware that single satoshi outputs may have inscriptions and avoid spending them until it is known whether an ordinal is inscribed with the help of an indexer. To isolate ordinals and prevent accidental loss, separate keys should be used for payments and ordinals.


# Partially Signed Transactions

## Listing an Ordinal for Sale

You can create a PSBT to list a specific ordinal that you own for sale at a specific price where someone else can trustlessly complete the partially signed transaction with their inputs to pay the lsited amount as well as their output script which the ordinal will be sent to. Code to do this can be found here: <https://github.com/libsv/go-bt/blob/master/ord/listing.go>

This can allow for a Dutch auction where the seller can start at a price and keep decreasing until someone takes the offer.

To list an ordinal for sale, you just create a new Bitcoin transaction with 1 input (your ordinal utxo) and 1 output (where you want your payment to go with the listing amount) and sign with `SIGHASH_SIGNLE | SIGHASHANYONECANPAY` (using forkID). Here is an example:

```json
{
    "hex": "01000000016aced9aba38603b99a6660aaeed4119ced36540ed9e165c16ae41a36b17f028f000000006b4830450221008f321ff2fd9ae676203aae97c0f041ca0a4a99fd80d34efffa7406b65654e06002207ee3b7d45ec247cf83311dfe7984fa1cea830ca5abb438d9cba4534b52fc9fb3c32103b5a2ed046a33eeb504cbdd0aab9737f61a1b48178b284f40ae32b5efb71b89d4ffffffff01f4010000000000001976a9147921b5e173f5f664f566a9cd9514a1d0d85a76b688ac00000000",
    "txid": "a0574646e4fe5a42ae5a2f1ab6e77e1167e9107329f07dc19f816c8f50b32c8e",
    "hash": "a0574646e4fe5a42ae5a2f1ab6e77e1167e9107329f07dc19f816c8f50b32c8e",
    "size": 192,
    "version": 1,
    "locktime": 0,
    "vin": [
        {
            "n": 0,
            "txid": "8f027fb1361ae46ac165e1d90e5436ed9c11d4eeaa60669ab90386a3abd9ce6a",
            "vout": 0,
            "scriptSig": {
                "asm": "30450221008f321ff2fd9ae676203aae97c0f041ca0a4a99fd80d34efffa7406b65654e06002207ee3b7d45ec247cf83311dfe7984fa1cea830ca5abb438d9cba4534b52fc9fb3c3 03b5a2ed046a33eeb504cbdd0aab9737f61a1b48178b284f40ae32b5efb71b89d4",
                "hex": "4830450221008f321ff2fd9ae676203aae97c0f041ca0a4a99fd80d34efffa7406b65654e06002207ee3b7d45ec247cf83311dfe7984fa1cea830ca5abb438d9cba4534b52fc9fb3c32103b5a2ed046a33eeb504cbdd0aab9737f61a1b48178b284f40ae32b5efb71b89d4",
                "isTruncated": false
            },
            "sequence": 4294967295,
            "voutDetails": {
                "value": 1e-8,
                "n": 0,
                "scriptPubKey": {
                    "asm": "OP_DUP OP_HASH160 c25e9a2b70ec83d7b4fbd0f36f00a86723a48e6b OP_EQUALVERIFY OP_CHECKSIG OP_FALSE OP_IF 6f7264 OP_TRUE 746578742f706c61696e3b636861727365743d7574662d38 OP_FALSE 48656c6c6f2c20776f726c6421 OP_ENDIF",
                    "hex": "76a914c25e9a2b70ec83d7b4fbd0f36f00a86723a48e6b88ac0063036f72645118746578742f706c61696e3b636861727365743d7574662d38000d48656c6c6f2c20776f726c642168",
                    "type": "nonstandard",
                    "isTruncated": false
                },
                "scripthash": "0a45a232478e6e97f88487433fdb762eca3d8346174ec925f3d6d898e9764afc"
            }
        }
    ],
    "vout": [
        {
            "value": 0.000005,
            "n": 0,
            "scriptPubKey": {
                "asm": "OP_DUP OP_HASH160 7921b5e173f5f664f566a9cd9514a1d0d85a76b6 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a9147921b5e173f5f664f566a9cd9514a1d0d85a76b688ac",
                "reqSigs": 1,
                "type": "pubkeyhash",
                "addresses": [
                    "1C3V9TTJefP8Hft96sVf54mQyDJh8Ze4w4"
                ],
                "isTruncated": false
            },
            "scripthash": "80bd9afab38010571221a07495ba4601d052e8f5170c7fe9b076c5709f551a3a"
        }
    ],
    "vincount": 1,
    "voutcount": 1,
    "vinvalue": 1e-8,
    "voutvalue": 0.000005,
    "isUnknown": true
}
```

To accept the offer, you need to create a new tx, add 2 dummy inputs, the input from the PSBT above, then your input(s) to pay for the tx. Then 1 dummy output equal to the first 2 dummy input amounts (so those sats just passthrough), then your output for where to receive the ordinal, then the output from the PSBT above, then your change output(s), and then an optional platform fee. Then sign the rest of the inputs regularly (`SIGHASH_ALL`).

## Making a bid for an Ordinal

You can create a PSBT to bid at a specific price for a specific ordinal that someone else owns where they can accept the bid truslessly by completing the partially signed transaction. Code to do this can be found here: <https://github.com/libsv/go-bt/blob/master/ord/bidding.go>

To bid at a price for a specific ordinal, you just create a new Bitcoin transaction (similar to the one above) but backwards. You add 2 dummy inputs, then the ordinal input, then your input(s); 1 dummy output (equal to the amount of the 2 dummy inputs), then your receive output, then dummy seller receive output, then change and platform fees. Then you sign all inputs except for the ordinal input (at index #2) with `SIGHASH_SIGNLE` (using forkID). Here is an example:

```json
{
    "hex": "0100000004d14b5f9fec20643a72bd8d1317ca54f3d76b9449d81e33fc0c384f3dd8841041000000006b483045022100f00de4c6d96351533d0ff8a3ed76d58843fbc164bff6a6710d5e7e8a87951c8b022011602fcb89acb69077e71ca2d0319d44e990335c4c34f8a5515c5b1c08e700ce432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009fffffffffd14b5f9fec20643a72bd8d1317ca54f3d76b9449d81e33fc0c384f3dd8841041010000006a473044022030c089ca2cd6318870cc14a71980ec25a3d871143b4bd62a0d50487f5397fb20022030a7e280bc8793eeabffd864b3255ed998809bcecdc823b4beeb52081ad80d90432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009fffffffff84a5788927871968b32bb2c8af735fd76e1b34d295339427046475c356787de151000000000000000056c4df06a8bfba996380e4c4fd5739ae086e5f28eb38b40c8140a739dc5a814d000000006a4730440220432e2480e39396f561e232d6b02193eae75370102c681739fca2701eb3177e1d0220294364dd611f3ff65332538309e9d5759831c2a21df3fb5b393d8532048583f5432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009fffffffff0428000000000000001976a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac01000000000000001976a9140f83a353705d800d13146bf4ad90510cc057a8d588acfa000000000000001976a91402d1e3d3567a88e0cfd13f57167238c4eb7c813888ace1dff505000000001976a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac00000000",
    "txid": "c0a49982d08ed064c6822a27afc35c5c5910d001209ecc3f4868abbf43a9c1eb",
    "hash": "c0a49982d08ed064c6822a27afc35c5c5910d001209ecc3f4868abbf43a9c1eb",
    "size": 629,
    "version": 1,
    "locktime": 0,
    "vin": [
        {
            "n": 0,
            "txid": "411084d83d4f380cfc331ed849946bd7f354ca17138dbd723a6420ec9f5f4bd1",
            "vout": 0,
            "scriptSig": {
                "asm": "3045022100f00de4c6d96351533d0ff8a3ed76d58843fbc164bff6a6710d5e7e8a87951c8b022011602fcb89acb69077e71ca2d0319d44e990335c4c34f8a5515c5b1c08e700ce43 02c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009f",
                "hex": "483045022100f00de4c6d96351533d0ff8a3ed76d58843fbc164bff6a6710d5e7e8a87951c8b022011602fcb89acb69077e71ca2d0319d44e990335c4c34f8a5515c5b1c08e700ce432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009f",
                "isTruncated": false
            },
            "sequence": 4294967295,
            "voutDetails": {
                "value": 2e-7,
                "n": 0,
                "scriptPubKey": {
                    "asm": "OP_DUP OP_HASH160 5bd9baf4dc6270bad6e4152363bbeca2f5abc7c4 OP_EQUALVERIFY OP_CHECKSIG",
                    "hex": "76a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac",
                    "reqSigs": 1,
                    "type": "pubkeyhash",
                    "addresses": [
                        "19NfKd8aTwvb5ngfP29RxgfQzZt8KAYtQo"
                    ],
                    "isTruncated": false
                },
                "scripthash": "0fcf4d75e02c6256453412ed2bcf5a34f5ce03fe58967a2241cfe341c269fb57"
            }
        },
        {
            "n": 1,
            "txid": "411084d83d4f380cfc331ed849946bd7f354ca17138dbd723a6420ec9f5f4bd1",
            "vout": 1,
            "scriptSig": {
                "asm": "3044022030c089ca2cd6318870cc14a71980ec25a3d871143b4bd62a0d50487f5397fb20022030a7e280bc8793eeabffd864b3255ed998809bcecdc823b4beeb52081ad80d9043 02c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009f",
                "hex": "473044022030c089ca2cd6318870cc14a71980ec25a3d871143b4bd62a0d50487f5397fb20022030a7e280bc8793eeabffd864b3255ed998809bcecdc823b4beeb52081ad80d90432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009f",
                "isTruncated": false
            },
            "sequence": 4294967295,
            "voutDetails": {
                "value": 2e-7,
                "n": 1,
                "scriptPubKey": {
                    "asm": "OP_DUP OP_HASH160 5bd9baf4dc6270bad6e4152363bbeca2f5abc7c4 OP_EQUALVERIFY OP_CHECKSIG",
                    "hex": "76a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac",
                    "reqSigs": 1,
                    "type": "pubkeyhash",
                    "addresses": [
                        "19NfKd8aTwvb5ngfP29RxgfQzZt8KAYtQo"
                    ],
                    "isTruncated": false
                },
                "scripthash": "0fcf4d75e02c6256453412ed2bcf5a34f5ce03fe58967a2241cfe341c269fb57"
            }
        },
        {
            "n": 2,
            "txid": "e17d7856c375640427943395d2341b6ed75f73afc8b22bb3681987278978a584",
            "vout": 81,
            "scriptSig": {
                "asm": "",
                "hex": "",
                "isTruncated": false
            },
            "sequence": 0,
            "voutDetails": {
                "value": 1e-8,
                "n": 81,
                "scriptPubKey": {
                    "asm": "OP_DUP OP_HASH160 239d4c856f5bf3913a9bd27bb12763810fa89632 OP_EQUALVERIFY OP_CHECKSIG OP_FALSE OP_IF 6f7264 OP_TRUE 696d6167652f706e67 OP_FALSE 89504e470d0a1a0a0000000d49484452000001000000016008060000005486a73c00000006624b474400ff00ff00ffa0bda793000009b849444154789cedddd98f5e7501c6f16967da4e0b651784b014b008c85648a1405490a56aa2185903171ac38d01c1a86c0a0a189145b9c1c41bb8b086444924a261772111b114486823680003b2d336050bed4c3bf34efd231e9297e6f97cee1fce7be6ed7c3937bf332323000000000000000000000000000000c047cdac617f80bd76db6d5bb27f67c386a1df4362e18205d1fdbfbf79f350ef7fb79d768a3eff868d1bb7ebef6fc7f0fbfb60c8dfdfec615e1c182e0180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600502c3e8b9c9ee73fe9a8a3a2eb3fb1664db44fdf27b0c72ebb44f7bfe4904f26f391175e7d35da6f9a9c88f6a71e7b5cb45ff5fcf3d1febf6fbf157d7ffbedb557f4fd2d3be288643ef2f8ead5d1feadf5eba3fbf70400c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040b1a1ff6df643f63f203a8f7df6a9a746d75ff1e003d17e7ceedc683f31b925da5f7cd659d17e7a3088f6f73ef6d768bf79227b1fc1f8bc79d1fe9ccf9d16ed573c707fb47f7deddaa1fe0e7a0280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0587c16f9d0458ba2f3fcdff8d297a3ebdf79dfefa37d7a9effb2f32e88f66fac5b1bed7f159e471f9d9dfd3fe0e2b3be12ed27b664ef43b8fba107a3fdfc79e3d1fec2e5cba3fd5d7fb82fdabff8da6bd1efb02700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a8da5ff817fbff24a741ef9378f3c1cbd4fe085575f8dae7ff4e2c5d1f5f7dc6dd7643e3232125d7e64febc79d17e41781e7e301844fbdd77de39daa7e7f9d7bcf462f4ef67febcb9d117989ee74f790280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0d850cf227f18961e7e78741efbb2f3ce8fae3f3696bd5261d3e689687fd8810746fbd7de793bda2fde6fbf68ffdefb1f44fb9d17ee18ed2fb9f5d668ffe473ffdcae7f873c0140310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600506cbb3ecbfc615876c411d1fb046666a2f9c89cf07d02dfb9f0c2687fc8fe0744fbcb7e7e5bb4df3a3515edb39ffec8c8136bd654ff0e780280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a058f559e80fc329c71d171d49bfe7273745d7ffea555746fb05e3e3d1fed7d7df18edcfbff6fbd1feb1679ef16f38e009008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a098004031018062433f4b7df2d14747e7e9ffbe7af5d0ef2171c6f1c747f7ffe8aa5543bdffe5cb4e8c3effc32bffb15d7f7fcb972d0bef7fe550efdf1300141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c5c6d2ffc0e74fccce83ffe27b5744d7ffe62d370ff53cfd694b9746d75f71fd0dc97ce4a21f5e175d7f7a7a105dff964b2f8df653d353d1e7ffcbd34f47dfdfe94bb3f731dcf6adcb93f9c8f460105dffcf4f3d15ddbf2700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008ac5ef03d83c3919ed376eda14ed67cf1e8df69f59b2243a8f7df70d3f8eaeffb15d7789f673c6b2af7034fcf91db8cf3ed1fe9e9b7e1aedcfbefaaaec7d0883ec7d08471e7c70b4df3a351ded539e00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a09001413002816bf0f60c1bcf1687fe4c19f88f663a3d979f6db2fff76b4bfe847d745fbd1d95983efb9e9e668ffdefb1ba3fdb9d75c1dedb74c4d45fb3ffeecf6687fc1b53f88f66fae5f17edc7e7ce8df6294f00504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900149b35ec0f70fad2e3a3bfeffea7a75645f7f0e9638e89aeffb7679f1deacff094638f8b3eff6066105d7fd8f7bf7cd9b2e8fe1f5eb932fafc679e704274fd479e7c72a83f3f4f00504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141bfafb00daa5ef23b8e3bb5744d75ffbeebbd1fec6bbee8cf68faf1eeefb04da790280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a098b3d8a1f43cff355ffb7a74fd83f7dd37dacfcccc44fb77366c88f657fee28e68bfeab9e7fc1b0e780280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0d8d8b03fc0f66ecbd454b47f73fdfa68bf70c10ed17efdffde8bf6fbeeb967b41f0c06d19e8c2700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008ad5ff6df5a5871dbe2dd94f4e6d8dae3f672c7b25c396add9f5c7e7ce8bf6dbb6453fbe9189ad5ba2fd9cd1d168bfe6a597aa7f073c0140310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600502c3b8cfe1170e8a245d181f4f3cf3823bafe1bebd645fb5d162e8cf6bf7df491683f353d15edcf3f3dfbf94d86ef33d875a79da2fd8a07ee8ffefd3cfbc20bdbf5fb043c0140310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600506cec808fef1d9d879e1e4c471f60fef878b4ffec9225d17ef3e464b49f9aceee7fc503f747fb2f9c7852b49f3396bd12e297f7fe2eda7ff1a493a37dfafd2d3f6159b4dfb86953f4fb336734fbf94f6cc9eedf1300141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c5665d72ceb9d179e697df7c33fa0073e7cc89f6839941b49f98dc12ed17edbd77b47f68e5ca68bf797222dacf9a95fd79fb996dd13f9f91338f3f21da2f08df27f19f375e8ff6a3b347a3fda70e3a28daffeb9597a3bd2700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008acd5abcdffed181eeb9e1df979f19c9ce93bffeceda689fbe4f6087f9f3a3fdb6f03cfddebbef11eda706d3d1fead75eba3fdccb699689fbe4f62eb7476ffc72c5e1ced531b376d8af69e00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a090014130028f67f41969ba56c7ec1440000000049454e44ae426082 OP_ENDIF OP_RETURN 3150755161374b36324d694b43747373534c4b79316b683536575755374d74555235 534554 74797065 6f7264 636f6c6c656374696f6e 734d6f6e 617070 74616c656f6673687561 6d6f6e54797065 726f626f74 617564696f 623a2f2f35363636636634343235306234333838316433313233366336616265623936616134633762666466663737613033396462353665643239363339306430373638 7374617473 7b22737472656e677468223a352c22766974616c697479223a342c226167696c697479223a332c22696e74656c6c6967656e6365223a362c226c75636b223a342c22737069726974223a387d 67756964 65613365393162302d633662362d313165642d393436332d353932336262613136366666",
                    "hex": "76a914239d4c856f5bf3913a9bd27bb12763810fa8963288ac0063036f72645109696d6167652f706e67004d030a89504e470d0a1a0a0000000d49484452000001000000016008060000005486a73c00000006624b474400ff00ff00ffa0bda793000009b849444154789cedddd98f5e7501c6f16967da4e0b651784b014b008c85648a1405490a56aa2185903171ac38d01c1a86c0a0a189145b9c1c41bb8b086444924a261772111b114486823680003b2d336050bed4c3bf34efd231e9297e6f97cee1fce7be6ed7c3937bf332323000000000000000000000000000000c047cdac617f80bd76db6d5bb27f67c386a1df4362e18205d1fdbfbf79f350ef7fb79d768a3eff868d1bb7ebef6fc7f0fbfb60c8dfdfec615e1c182e0180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600502c3e8b9c9ee73fe9a8a3a2eb3fb1664db44fdf27b0c72ebb44f7bfe4904f26f391175e7d35da6f9a9c88f6a71e7b5cb45ff5fcf3d1febf6fbf157d7ffbedb557f4fd2d3be288643ef2f8ead5d1feadf5eba3fbf70400c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040b1a1ff6df643f63f203a8f7df6a9a746d75ff1e003d17e7ceedc683f31b925da5f7cd659d17e7a3088f6f73ef6d768bf79227b1fc1f8bc79d1fe9ccf9d16ed573c707fb47f7deddaa1fe0e7a0280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0587c16f9d0458ba2f3fcdff8d297a3ebdf79dfefa37d7a9effb2f32e88f66fac5b1bed7f159e471f9d9dfd3fe0e2b3be12ed27b664ef43b8fba107a3fdfc79e3d1fec2e5cba3fd5d7fb82fdabff8da6bd1efb02700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a8da5ff817fbff24a741ef9378f3c1cbd4fe085575f8dae7ff4e2c5d1f5f7dc6dd7643e3232125d7e64febc79d17e41781e7e301844fbdd77de39daa7e7f9d7bcf462f4ef67febcb9d117989ee74f790280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0d850cf227f18961e7e78741efbb2f3ce8fae3f3696bd5261d3e689687fd8810746fbd7de793bda2fde6fbf68ffdefb1f44fb9d17ee18ed2fb9f5d668ffe473ffdcae7f873c0140310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600506cbb3ecbfc615876c411d1fb046666a2f9c89cf07d02dfb9f0c2687fc8fe0744fbcb7e7e5bb4df3a3515edb39ffec8c8136bd654ff0e780280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a058f559e80fc329c71d171d49bfe7273745d7ffea555746fb05e3e3d1fed7d7df18edcfbff6fbd1feb1679ef16f38e009008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a098004031018062433f4b7df2d14747e7e9ffbe7af5d0ef2171c6f1c747f7ffe8aa5543bdffe5cb4e8c3effc32bffb15d7f7fcb972d0bef7fe550efdf1300141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c5c6d2ffc0e74fccce83ffe27b5744d7ffe62d370ff53cfd694b9746d75f71fd0dc97ce4a21f5e175d7f7a7a105dff964b2f8df653d353d1e7ffcbd34f47dfdfe94bb3f731dcf6adcb93f9c8f460105dffcf4f3d15ddbf2700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008ac5ef03d83c3919ed376eda14ed67cf1e8df69f59b2243a8f7df70d3f8eaeffb15d7789f673c6b2af7034fcf91db8cf3ed1fe9e9b7e1aedcfbefaaaec7d0883ec7d08471e7c70b4df3a351ded539e00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a09001413002816bf0f60c1bcf1687fe4c19f88f663a3d979f6db2fff76b4bfe847d745fbd1d95983efb9e9e668ffdefb1ba3fdb9d75c1dedb74c4d45fb3ffeecf6687fc1b53f88f66fae5f17edc7e7ce8df6294f00504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900149b35ec0f70fad2e3a3bfeffea7a75645f7f0e9638e89aeffb7679f1deacff094638f8b3eff6066105d7fd8f7bf7cd9b2e8fe1f5eb932fafc679e704274fd479e7c72a83f3f4f00504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141bfafb00daa5ef23b8e3bb5744d75ffbeebbd1fec6bbee8cf68faf1eeefb04da790280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a098b3d8a1f43cff355ffb7a74fd83f7dd37dacfcccc44fb77366c88f657fee28e68bfeab9e7fc1b0e780280620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0d8d8b03fc0f66ecbd454b47f73fdfa68bf70c10ed17efdffde8bf6fbeeb967b41f0c06d19e8c2700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008ad5ff6df5a5871dbe2dd94f4e6d8dae3f672c7b25c396add9f5c7e7ce8bf6dbb6453fbe9189ad5ba2fd9cd1d168bfe6a597aa7f073c0140310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600502c3b8cfe1170e8a245d181f4f3cf3823bafe1bebd645fb5d162e8cf6bf7df491683f353d15edcf3f3dfbf94d86ef33d875a79da2fd8a07ee8ffefd3cfbc20bdbf5fb043c0140310180620200c504008a0900141300282600504c00a0980040310180620200c504008a0900141300282600506cec808fef1d9d879e1e4c471f60fef878b4ffec9225d17ef3e464b49f9aceee7fc503f747fb2f9c7852b49f3396bd12e297f7fe2eda7ff1a493a37dfafd2d3f6159b4dfb86953f4fb336734fbf94f6cc9eedf1300141300282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c5665d72ceb9d179e697df7c33fa0073e7cc89f6839941b49f98dc12ed17edbd77b47f68e5ca68bf797222dacf9a95fd79fb996dd13f9f91338f3f21da2f08df27f19f375e8ff6a3b347a3fda70e3a28daffeb9597a3bd2700282600504c00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008acd5abcdffed181eeb9e1df979f19c9ce93bffeceda689fbe4f6087f9f3a3fdb6f03cfddebbef11eda706d3d1fead75eba3fdccb699689fbe4f62eb7476ffc72c5e1ced531b376d8af69e00a0980040310180620200c504008a0900141300282600504c00a0980040310180620200c504008a090014130028f67f41969ba56c7ec1440000000049454e44ae426082686a223150755161374b36324d694b43747373534c4b79316b683536575755374d74555235035345540474797065036f72640a636f6c6c656374696f6e04734d6f6e036170700a74616c656f6673687561076d6f6e5479706505726f626f7405617564696f44623a2f2f353636366366343432353062343338383164333132333663366162656239366161346337626664666637376130333964623536656432393633393064303736380573746174734c4c7b22737472656e677468223a352c22766974616c697479223a342c226167696c697479223a332c22696e74656c6c6967656e6365223a362c226c75636b223a342c22737069726974223a387d04677569642465613365393162302d633662362d313165642d393436332d353932336262613136366666",
                    "type": "nonstandard",
                    "isTruncated": false
                },
                "scripthash": "8fd47ee61222d2a37f3732754a3a7fb07caf813bfb618365404c638b5004bb03"
            }
        },
        {
            "n": 3,
            "txid": "4d815adc39a740810cb438eb285f6e08ae3957fdc4e4806399babfa806dfc456",
            "vout": 0,
            "scriptSig": {
                "asm": "30440220432e2480e39396f561e232d6b02193eae75370102c681739fca2701eb3177e1d0220294364dd611f3ff65332538309e9d5759831c2a21df3fb5b393d8532048583f543 02c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009f",
                "hex": "4730440220432e2480e39396f561e232d6b02193eae75370102c681739fca2701eb3177e1d0220294364dd611f3ff65332538309e9d5759831c2a21df3fb5b393d8532048583f5432102c0d6375542a242e0e14f9d405e182a1f3602369a1651e57dcfd20f7edd39009f",
                "isTruncated": false
            },
            "sequence": 4294967295,
            "voutDetails": {
                "value": 1,
                "n": 0,
                "scriptPubKey": {
                    "asm": "OP_DUP OP_HASH160 5bd9baf4dc6270bad6e4152363bbeca2f5abc7c4 OP_EQUALVERIFY OP_CHECKSIG",
                    "hex": "76a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac",
                    "reqSigs": 1,
                    "type": "pubkeyhash",
                    "addresses": [
                        "19NfKd8aTwvb5ngfP29RxgfQzZt8KAYtQo"
                    ],
                    "isTruncated": false
                },
                "scripthash": "0fcf4d75e02c6256453412ed2bcf5a34f5ce03fe58967a2241cfe341c269fb57"
            }
        }
    ],
    "vout": [
        {
            "value": 4e-7,
            "n": 0,
            "scriptPubKey": {
                "asm": "OP_DUP OP_HASH160 5bd9baf4dc6270bad6e4152363bbeca2f5abc7c4 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac",
                "reqSigs": 1,
                "type": "pubkeyhash",
                "addresses": [
                    "19NfKd8aTwvb5ngfP29RxgfQzZt8KAYtQo"
                ],
                "isTruncated": false
            },
            "scripthash": "0fcf4d75e02c6256453412ed2bcf5a34f5ce03fe58967a2241cfe341c269fb57"
        },
        {
            "value": 1e-8,
            "n": 1,
            "scriptPubKey": {
                "asm": "OP_DUP OP_HASH160 0f83a353705d800d13146bf4ad90510cc057a8d5 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a9140f83a353705d800d13146bf4ad90510cc057a8d588ac",
                "reqSigs": 1,
                "type": "pubkeyhash",
                "addresses": [
                    "12R2qFEoUtWwwVecgrkxwMZNnMq6GB8pQW"
                ],
                "isTruncated": false
            },
            "scripthash": "d1bfc516c16ca37cf1d40c91b9e901ddfe2da400ede23b3ddb06da1eebc03feb"
        },
        {
            "value": 0.0000025,
            "n": 2,
            "scriptPubKey": {
                "asm": "OP_DUP OP_HASH160 02d1e3d3567a88e0cfd13f57167238c4eb7c8138 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a91402d1e3d3567a88e0cfd13f57167238c4eb7c813888ac",
                "reqSigs": 1,
                "type": "pubkeyhash",
                "addresses": [
                    "1FunnyJoke111111111111111112AVXh5"
                ],
                "isTruncated": false
            },
            "scripthash": "2dbf8c03f51117c6f34a1803ff569b4a446bb4464b13c06e8f939b42d336ef82"
        },
        {
            "value": 0.99999713,
            "n": 3,
            "scriptPubKey": {
                "asm": "OP_DUP OP_HASH160 5bd9baf4dc6270bad6e4152363bbeca2f5abc7c4 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a9145bd9baf4dc6270bad6e4152363bbeca2f5abc7c488ac",
                "reqSigs": 1,
                "type": "pubkeyhash",
                "addresses": [
                    "19NfKd8aTwvb5ngfP29RxgfQzZt8KAYtQo"
                ],
                "isTruncated": false
            },
            "scripthash": "0fcf4d75e02c6256453412ed2bcf5a34f5ce03fe58967a2241cfe341c269fb57"
        }
    ],
    "vincount": 4,
    "voutcount": 4,
    "vinvalue": 1.00000041,
    "voutvalue": 1.00000004,
    "isUnknown": true
}
```

To accept the bid, you need to replace the dummy script in output at index #2 with the script that you want the money to go to and then sign the ordinal input regularly (`SIGHASH_ALL`).

### &#x20;Example diagram from [Magic Eden OSS docs](https://github.com/magiceden-oss/msigner/blob/main/docs/psbt.excalidraw.png):

<figure><img src="/files/ts7Z9MQEeWtS8VebCOcs" alt=""><figcaption></figcaption></figure>


# Common Questions

## Can this be combined with other Bitcoin scripts?

Yes. It is possible to use any Bitcoin locking script you prefer when sending a 1Sat Ordinal. The ordinal number is calculated based on its exact lineage, meaning the script can be changed without impacting the Ordinal number. You can also use custom scripts while inscribing new Ordinals.

## Why not use a smart contract that does X?

This protocol is intended to adhere to the original Ordinals protocol as closely as possible within reason and with some minor exceptions. This would be too far a departure for this from the precedent set on BTC for this project.

## Can 1Sat Ordinals be merged?

Not via script or by protocol but this can be accomplished at the application layer. The user sends the tokens to be merged to an API and which redeems them and issues the new "merged" Ordinal. This keeps typical token usage simple and easy to manage. This strategy can be used for "breeding" games, or anything that might require two or more Ordinals become one.

## Why not use Run?

Run is no longer in development, and has some unique challenges. Problems building the Run-Sdk with webpack and the requirement for a JS-based environment has created a demand for alternatives.

## Why not use Stas?

Stas scripts are larger than ordinals. Both systems ultimately require some level of indexer-based validation, and both can use OP\_RETURN based token data. Stas protocol has licensing requirements for minting. This was something some would prefer to avoid.


# Fair Launch

No pre-mine, equal opportunity distribution

## Genesis Coinbase

Inscription numbers will begin 218 blocks after a block is mined with a specific coinbase string.

The coinbase string that begins the countdown will be:

```
1SAT ORDINALS IN 218 BLOCKS - docs.1satordinals.com
```

When 218 blocks have been mined after this block, The inscriptions inside the 218th subsequent block, not including the block with the coinbase string, will contain the first numbered inscriptions, starting from 0.

## First Block

{% code overflow="wrap" %}

```
The starting block was mined by GorillaPool at block height 783750, making the first live block 783,968.
```

{% endcode %}


