Skip to main content

Specification

    Title: Token Primitives for Bitcoin Cash
Type: Standards
Layer: Consensus
Maintainer: Jason Dreyzehner
Status: Final
Initial Publication Date: 2022-02-22
Final Revision Date: 2023-5-20
Version: 2.2.2
Table of Contents

Summary

This proposal enables two new primitives on Bitcoin Cash: fungible tokens and non-fungible tokens.

Terms

A token is an asset – distinct from the Bitcoin Cash currency – that can be created and transferred on the Bitcoin Cash network.

Non-Fungible tokens (NFTs) are a token type in which individual units cannot be merged or divided – each NFT contains a commitment, a short byte string attested to by the issuer of the NFT.

Fungible tokens are a token type in which individual units are undifferentiated – groups of fungible tokens can be freely divided and merged without tracking the identity of individual tokens (much like the Bitcoin Cash currency).

Deployment

Deployment of this specification is proposed for the May 2023 upgrade.

  • Activation is proposed for 1668513600 MTP, (2022-11-15T12:00:00.000Z) on chipnet.
  • Activation is proposed for 1684152000 MTP, (2023-05-15T12:00:00.000Z) on the BCH network (mainnet), testnet3, testnet4, and scalenet.

Motivation

Bitcoin Cash contracts lack primitives for issuing messages that can be verified by other contracts, preventing the development of decentralized application ecosystems on Bitcoin Cash.

Contract-Issued Commitments

In the context of the Bitcoin Cash virtual machine (VM), a commitment can be defined as an irrevocable message that was provably issued by a particular entity. Two forms of commitments are currently available to Bitcoin Cash contracts:

  • Transaction signatures – a commitment made by a private key attesting to the signing serialization of a transaction.
  • Data signatures – a commitment made by a private key attesting to the hash of an arbitrary message (introduced in 2018 by OP_CHECKDATASIG).

Each of these commitment types require the presence of a trusted private key. Because contracts cannot themselves hold a private key, any use case that requires a contract to issue a verifiable message must necessarily rely on trusted entities to provide signatures1. This limitation prevents Bitcoin Cash contracts from offering or using decentralized oracles – multiparty consensus systems that produce verifiable messages upon which other contracts can act.

By providing a commitment primitive that can be used directly by contracts, the Bitcoin Cash contract system can support advanced, decentralized applications without increasing transaction or block validation costs.

Notes
  1. Signature aggregation schemes can enable contracts to issue some commitments with reduced trust (e.g. by requiring a quorum of always-online entities to join a multiparty signing process), but these schemes typically require active coordination, carefully-designed participation incentives, fallback strategies, and other significant fixed costs (e.g. always-online servers). In practice, few such systems are able to maintain sufficient traction to continue functioning, and notably, forcing a contract to rely on these systems is arbitrary and wasteful (in terms of network bandwidth and validation costs) when their purpose is simply to attest to a result already produced by that contract.

Byte-String Commitments

The most general type of contract-issued commitment is a simple string of bytes. This type can be used to commit to any type of contract state: certifications of ownership, authorizations, credit, debt, contract-internal time or epoch, vote counts, receipts (e.g. to support refunds or future redemption), etc. Identities may commit to state within a hash structure (e.g. a merkle tree), or – to reduce transaction sizes – as a raw byte string (e.g. public keys, static numbers, boolean values).

In this proposal, byte-string commitments are called non-fungible tokens.

Numeric Commitments

The Bitcoin Cash virtual machine (VM) supports two primary data types in VM bytecode evaluation: byte strings and numbers. Given the existence of a primitive allowing contracts to commit to byte strings, another commitment primitive can be inferred: numeric commitments.

Numeric commitments are a specialization of byte-string commitments – they are commitments with numeric values which can be divided and merged in the same way as the Bitcoin Cash currency. With numeric commitments, contracts can efficiently represent fractional parts of abstract concepts – shares, pegged assets, bonds, loans, options, tickets, loyalty points, voting outcomes, etc.

While many use cases for numeric commitments can be emulated with only byte-string commitments, a numeric primitive enables many contracts to reduce or offload state management altogether (e.g. shareholder voting), simplifying contract audits and reducing transaction sizes.

In this proposal, numeric commitments are called fungible tokens.

Benefits

By enabling token primitives on Bitcoin Cash, this proposal offers several benefits.

Cross-Contract Interfaces

Using non-fungible tokens (NFTs), contracts can create messages that can be read by other contracts. These messages are impersonation-proof: other contracts can safely read and act on the commitment, certain that it was produced by the claimed contract.

With contract interoperability, behavior can be broken into clusters of smaller, coordinating contracts, reducing transaction sizes. This interoperability further enables covenants to communicate over public interfaces, allowing diverse ecosystems of compatible covenants to work together, even when developed and deployed separately.

Critically, this cross-contract interaction can be achieved within the "stateless" transaction model employed by Bitcoin Cash, rather than coordinating via shared global state. This allows Bitcoin Cash to support comparable contract functionality while retaining its >1000x efficiency advantage in transaction and block validation.

Decentralized Applications

Beyond enabling covenants to interoperate with other covenants, these token primitives allow for byte-efficient representations of complex internal state – supporting advanced, decentralized applications on Bitcoin Cash.

Non-fungible tokens are critical for coordinating activity trustlessly between multiple covenants, enabling covenant-tracking tokens, depository child covenants, multithreaded covenants, and other constructions in which a particular covenant instance must be authenticated.

Fungible tokens are valuable for covenants to represent on-chain assets – e.g. voting shares, utility tokens, collateralized loans, prediction market options, etc. – and implement complex coordination tasks – e.g. liquidity-pooling, auctions, voting, sidechain withdrawals, spin-offs, mergers, and more.

Universal Token Primitives

By exposing basic, consensus-validated token primitives, this proposal supports the development of higher-level, interoperable token standards (e.g. SLP). Token primitives can be held by any contract, wallets can easily verify the authenticity of a token or group of tokens, and tokens cannot be inadvertently destroyed by wallet software that does not support tokens.

Technical Summary

  1. A token category can include both non-fungible and fungible tokens, and every category is represented by a 32-byte category identifier – the transaction ID of the outpoint spent to create the category.
    1. All fungible tokens for a category must be created when the token category is created, ensuring the total supply within a category remains below the maximum VM number.
    2. Non-fungible tokens may be created either at category creation or in later transactions that spend tokens with minting or mutable capabilities for that category.
  2. Transaction outputs are extended to support four new token fields; every output can include one non-fungible token and any amount of fungible tokens from a single token category.
  3. Token inspection opcodes allow contracts to operate on tokens, enabling cross-contract interfaces and decentralized applications.

Transaction Output Data Model

This proposal extends the data model of transaction outputs to add four new token fields: token category, non-fungible token capability, non-fungible token commitment, and fungible token amount.

Existing FieldsDescription
ValueThe value of the output in satoshis, the smallest unit of bitcoin cash. (A.K.A. vout)
Locking BytecodeThe VM bytecode used to encumber this transaction output. (A.K.A. scriptPubKey)
Token Fields(New, optional fields added by this proposal:)
Category IDThe 32-byte ID of the token category to which the token(s) in this output belong. This field is omitted if no tokens are present.
CapabilityThe capability of the NFT held in this output: none, mutable, or minting. This field is omitted if no NFT is present.
CommitmentThe commitment contents of the NFT held in this output (0 to 40 bytes). This field is omitted if no NFT is present.
AmountThe number of fungible tokens held in this output (an integer between 1 and 9223372036854775807). This field is omitted if no fungible tokens are present.
Transaction Output JSON Format

The following snippet demonstrates a JSON representation of a transaction output using TypeScript types.

A new, optional token property is added, and the existing lockingBytecode and valueSatoshis properties are unmodified.

Note, this type is used by the test vectors.

/**
* Data type representing a Transaction Output.
*/
type Output = {
/**
* The bytecode used to encumber this transaction output. To spend the output,
* unlocking bytecode must be included in a transaction input that – when
* evaluated before the locking bytecode – completes in a valid state.
*
* A.K.A. `scriptPubKey` or "locking script"
*/
lockingBytecode: Uint8Array;

/**
* The CashToken contents of this output. This property is only defined if the
* output contains one or more tokens.
*/
token?: {
/**
* The number of fungible tokens held in this output.
*
* Because `Number.MAX_SAFE_INTEGER` (`9007199254740991`) is less than the
* maximum token amount (`9223372036854775807`), this value is encoded as
* a `bigint`. (Note, because standard JSON does not support `bigint`, this
* value must be converted to and from a `string` to pass over the network.)
*/
amount: bigint;
/**
* The 32-byte token category ID to which the token(s) in this output belong
* in big-endian byte order. This is the byte order typically seen in block
* explorers and user interfaces (as opposed to little-endian byte order,
* which is used in standard P2P network messages).
*/
category: Uint8Array;
/**
* If present, the non-fungible token (NFT) held by this output. If the
* output does not include a non-fungible token, `undefined`.
*/
nft?: {
/**
* The capability of this non-fungible token.
*/
capability: 'none' | 'mutable' | 'minting';

/**
* The commitment contents included in the non-fungible token held in
* this output.
*/
commitment: Uint8Array;
};
};

/**
* The value of the output in satoshis, the smallest unit of bitcoin cash.
*/
valueSatoshis: number;
};

Technical Specification

Subsections

Token primitives are defined, token encoding and activation are specified, and six new token inspection opcodes are introduced. Transaction validation and transaction signing serialization is modified to support tokens, SIGHASH_UTXOS is specified, BIP69 sorting is extended to support tokens, and CashAddress types with token support are defined.

Token Categories

Every token belongs to a token category specified via an immutable, 32-byte Token Category ID assigned in the category's genesis transaction – the transaction in which the token category is initially created.

Every token category ID is a transaction ID: the ID must be selected from the inputs of its genesis transaction, and only token genesis inputs – inputs which spend output 0 of their parent transaction – are eligible (i.e. outpoint transaction hashes of inputs with an outpoint index of 0). As such, implementations can locate the genesis transaction of any category by identifying the transaction that spent the 0th output of the transaction referenced by the category ID. (See Use of Transaction IDs as Token Category IDs.)

Note that because every transaction has at least one output, every transaction ID can later become a token category ID.

CashToken Creation Figure 1. Two new token categories are created by transaction c3a601.... The first category (`b201a0...`) is created by spending the 0th output of transaction `b201a0...`; for this category, a supply of `150` fungible tokens are created across two outputs (`100` and `50`). The second category (a1efcd...) is created by spending the 0th output of transaction a1efcd...; for this category, a supply of 100 fungible tokens are created across two outputs (20 and 80), and two NFTs are created (each with a commitment of 0x010203).

Token Types

Two token types are introduced: fungible tokens and non-fungible tokens. Fungible tokens have only one property: a 32-byte category. Non-fungible tokens have three properties: a 32-byte category, a 0 to 40 byte commitment, and a capability of minting, mutable, or none.

Token Behavior

Token behavior is enforced by the token validation algorithm. This algorithm has the following effects:

Universal Token Behavior

  1. A single transaction can create multiple new token categories, and each category can contain both fungible and non-fungible tokens.
  2. Tokens can be implicitly destroyed by omission from a transaction's outputs.
  3. Each transaction output can contain zero or one non-fungible token and any amount of fungible tokens, but all tokens in an output must share the same token category.

Non-Fungible Token Behavior

  1. A transaction output can contain zero or one non-fungible token.
  2. Non-fungible tokens (NFTs) of a particular category are created either in the category's genesis transaction or by later transactions that spend minting or mutable tokens of the same category.
  3. It is possible for multiple NFTs of the same category to carry the same commitment. (Though uniqueness can be enforced by covenants.)
  4. Minting tokens (NFTs with the minting capability) allow the spending transaction to create any number of new NFTs of the same category, each with any commitment and (optionally) the minting or mutable capability.
  5. Each Mutable token (NFTs with the mutable capability) allows the spending transaction to create one NFT of the same category, with any commitment and (optionally) the mutable capability.
  6. Immutable tokens (NFTs without a capability) cannot have their commitment modified when spent.

Fungible Token Behavior

  1. A transaction output can contain any amount of fungible tokens from a single category.
  2. All fungible tokens of a category are created in that category's genesis transaction; their combined amount may not exceed 9223372036854775807.
  3. A transaction can spend fungible tokens from any number of UTXOs to any number of outputs, so long as the sum of output amounts do not exceed the sum of input amounts (for each token category).

Note that fungible tokens behave independently from non-fungible tokens: non-fungible tokens are never counted in the amount, and the existence of minting or mutable NFTs in a transaction's inputs do not allow for new fungible tokens to be created.

Token Encoding

Tokens are encoded in outputs using a token prefix, a data structure that can encode a token category, zero or one non-fungible token (NFT), and an amount of fungible tokens (FTs).

For backwards-compatibility with existing transaction decoding implementations, a transaction output's token prefix (if present) is encoded before index 0 of its locking bytecode, and the CompactSize length preceding the two fields is increased to cover both fields (such that the length could be renamed token_prefix_and_locking_bytecode_length). The token prefix is not part of the locking bytecode and must not be included in bytecode evaluation. To illustrate, after deployment, the serialized output format becomes:

<satoshi_value> <token_prefix_and_locking_bytecode_length> [PREFIX_TOKEN <token_data>] <locking_bytecode>

Token Prefix

PREFIX_TOKEN is defined at codepoint 0xef (239) and indicates the presence of a token prefix:

PREFIX_TOKEN <category_id> <token_bitfield> [nft_commitment_length nft_commitment] [ft_amount]
  1. <category_id> – After the PREFIX_TOKEN byte, a 32-byte Token Category ID is required, encoded in OP_HASH256 byte order1.
  2. <token_bitfield> - A bitfield encoding two 4-bit fields is required:
    1. prefix_structure (token_bitfield & 0xf0) - 4 bitflags, defined at the higher half of the bitfield, indicating the structure of the token prefix:
      1. 0x80 (0b10000000) - RESERVED_BIT, must be unset.
      2. 0x40 (0b01000000) - HAS_COMMITMENT_LENGTH, the prefix encodes a commitment length and commitment.
      3. 0x20 (0b00100000) - HAS_NFT, the prefix encodes a non-fungible token.
      4. 0x10 (0b00010000) - HAS_AMOUNT, the prefix encodes an amount of fungible tokens.
    2. nft_capability (token_bitfield & 0x0f) – A 4-bit value, defined at the lower half of the bitfield, indicating the non-fungible token capability, if present.
      1. If not HAS_NFT: must be 0x00.
      2. If HAS_NFT:
        1. 0x00 – No capability – the encoded non-fungible token is an immutable token.
        2. 0x01 – The mutable capability – the encoded non-fungible token is a mutable token.
        3. 0x02 – The minting capability – the encoded non-fungible token is a minting token.
        4. Values greater than 0x02 are reserved and must not be used.
  3. If HAS_COMMITMENT_LENGTH:
    1. commitment_length – A commitment length is required (minimally-encoded in CompactSize format2) with a minimum value of 1 (0x01).
    2. commitment – The non-fungible token's commitment byte string of commitment_length is required.
  4. If HAS_AMOUNT:
    1. ft_amount – An amount of fungible tokens is required (minimally-encoded in CompactSize format2) with a minimum value of 1 (0x01) and a maximum value equal to the maximum VM number, 9223372036854775807 (0xffffffffffffff7f).
Notes
  1. This is the byte order produced/required by all BCH VM operations which employ SHA-256 (including OP_SHA256 and OP_HASH256), the byte order used for outpoint transaction hashes in the P2P transaction format, and the byte order produced by most SHA-256 libraries. For reference, the genesis block header in this byte order is little-endian – 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 – and can be produced by this script: <0x0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c> OP_HASH256. (Note, this is the opposite byte order as is commonly used in user interfaces like block explorers.)
  2. The CompactSize Format is a variable-length, little-endian, positive integer format used to indicate the length of the following byte array in Bitcoin Cash P2P protocol message formats (present since the protocol's publication in 2008). The format historically allowed some values to be encoded in multiple ways; token prefixes must always use minimally-encoded/canonically-encoded CompactSizes, e.g. the value 1 must be encoded as 0x01 rather than 0xfd0100, 0xfe0100000, or 0xff010000000000000.

Token Prefix Validation

  1. By consensus, commitment_length is limited to 40 (0x28), but future upgrades may increase this limit. Implementers are advised to ensure that values between 253 (0xfdfd00) and 65535 (0xfdffff) can be parsed. (See Non-Fungible Token Commitment Length.)
  2. A token prefix encoding no tokens (both HAS_NFT and HAS_AMOUNT are unset) is invalid.
  3. A token prefix encoding HAS_COMMITMENT_LENGTH without HAS_NFT is invalid.
  4. A token prefix where HAS_NFT is unset must encode nft_capability of 0x00.

Token Prefix Standardness

Implementations must recognize otherwise-standard outputs with token prefixes as standard.

Token Prefix Encoding Test Vectors

The following test vectors demonstrate valid, reserved, and invalid token prefix encodings. The token category ID is 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb and commitments use repetitions of 0xcc.

For the complete set of test vectors, see Test Vectors.

Valid Token Prefix Encodings

DescriptionEncoded (Hex)
no NFT; 1 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1001
no NFT; 252 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fc
no NFT; 253 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fdfd00
no NFT; 9223372036854775807 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10ffffffffffffffff7f
0-byte immutable NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb20
0-byte immutable NFT; 1 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb3001
0-byte immutable NFT; 253 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30fdfd00
0-byte immutable NFT; 9223372036854775807 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30ffffffffffffffff7f
1-byte immutable NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6001cc
1-byte immutable NFT; 252 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfc
2-byte immutable NFT; 253 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7002ccccfdfd00
10-byte immutable NFT; 65535 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb700accccccccccccccccccccfdffff
40-byte immutable NFT; 65536 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7028ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100
0-byte, mutable NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb21
0-byte, mutable NFT; 4294967295 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb31feffffffff
1-byte, mutable NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6101cc
1-byte, mutable NFT; 4294967296 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7101ccff0000000001000000
2-byte, mutable NFT; 9223372036854775807 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7102ccccffffffffffffffff7f
10-byte, mutable NFT; 1 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb710acccccccccccccccccccc01
40-byte, mutable NFT; 252 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7128ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfc
0-byte, minting NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb22
0-byte, minting NFT; 253 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb32fdfd00
1-byte, minting NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6201cc
1-byte, minting NFT; 65535 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7201ccfdffff
2-byte, minting NFT; 65536 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7202ccccfe00000100
10-byte, minting NFT; 4294967297 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb720accccccccccccccccccccff0100000001000000
40-byte, minting NFT; 9223372036854775807 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7228ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccffffffffffffffff7f
Reserved Token Prefix Encodings

These encodings are valid but disabled due to excessive commitment_lengths. Transactions attempting to create outputs with these token prefixes are currently rejected by consensus, but future upgrades may increase the maximum valid commitment_length.

DescriptionEncoded (Hex)
41-byte immutable NFT; 65536 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7029ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfe00000100
41-byte, mutable NFT; 252 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7129ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfc
41-byte, minting NFT; 9223372036854775807 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7229ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccffffffffffffffff7f
253-byte, immutable NFT; 0 fungibleefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb60fdfd00cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

Invalid Token Prefix Encodings

ReasonEncoded (Hex)
Token prefix must encode at least one tokenefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb00
Token prefix must encode at least one token (0 fungible)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1000
Token prefix requires a token category IDef
Token category IDs must be 32 bytesefbbbbbbbb1001
Missing token bitfieldefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Token bitfield sets reserved bitefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb9001
Unknown capability (0-byte NFT, capability 3)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb23
Has commitment length without NFT (1 fungible)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb5001
Prefix encodes a capability without an NFTefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1101
Commitment length must be specified (immutable token)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb60
Commitment length must be specified (mutable token)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb61
Commitment length must be specified (minting token)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb62
Commitment length must be minimally-encodedefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb60fd0100cc
If specified, commitment length must be greater than 0efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6000
Not enough bytes remaining in locking bytecode to satisfy commitment length (0/1 bytes)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6001
Not enough bytes remaining in locking bytecode to satisfy commitment length (mutable token, 0/1 bytes)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6101
Not enough bytes remaining in locking bytecode to satisfy commitment length (mutable token, 1/2 bytes)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6102cc
Not enough bytes remaining in locking bytecode to satisfy commitment length (minting token, 1/2 bytes)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb6202cc
Not enough bytes remaining in locking bytecode to satisfy token amount (no NFT, 1-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10
Not enough bytes remaining in locking bytecode to satisfy token amount (no NFT, 2-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fd00
Not enough bytes remaining in locking bytecode to satisfy token amount (no NFT, 4-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fe000000
Not enough bytes remaining in locking bytecode to satisfy token amount (no NFT, 8-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10ff00000000000000
Not enough bytes remaining in locking bytecode to satisfy token amount (immutable NFT, 1-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001cc
Not enough bytes remaining in locking bytecode to satisfy token amount (immutable NFT, 2-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfd00
Not enough bytes remaining in locking bytecode to satisfy token amount (immutable NFT, 4-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccfe000000
Not enough bytes remaining in locking bytecode to satisfy token amount (immutable NFT, 8-byte amount)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb7001ccff00000000000000
Token amount must be specifiedefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30
If specified, token amount must be greater than 0 (no NFT)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1000
If specified, token amount must be greater than 0 (0-byte NFT)efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb3000
Token amount must be minimally-encodedefbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb10fd0100
Token amount (9223372036854775808) may not exceed 9223372036854775807efbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb30ff0000000000000080

Token Encoding Activation

Pre-activation token-forgery outputs (PATFOs) are transaction outputs mined in blocks prior to activation of this specification where locking bytecode index 0 is set to the PREFIX_TOKEN codepoint.

Prior to activation, PATFOs remain nonstandard but do not invalidate the transaction by consensus. Because they can still be mined in valid blocks, PATFOs can be used to prepare outputs that, after activation of this specification, could encode tokens for which Token-Aware Transaction Validation was not enforced (producing token categories that do not map to a confirmed transaction hash or have a fungible token supply exceeding the maximum amount).

Note, even properly-encoded token outputs included in transactions mined prior to activation are considered PATFOs, regardless of whether or not the transaction would pass token-aware transaction validation after activation. Due to the possibility of a chain re-organization impacting the precise activation time, token issuers are advised to wait until activation is confirmed to a depth of at least 11 blocks before broadcasting critical transactions involving tokens.

PATFOs are provably unspendable1; all software implementing this specification should immediately mark PATFOs as unspendable and/or logically treat them as such for the purposes of spending.

By consensus, PATFOs mined in blocks prior to the activation of Token-Aware Transaction Validation must remain unspendable after activation. (Please note: the presence of PATFOs does not render a transaction invalid; until activation, valid blocks may contain PATFOs.)

After activation, any transaction creating an invalid token prefix2 is itself invalid, and all transactions must pass Token-Aware Transaction Validation.

Notes
  1. For pre-activation token-forgery outputs (PATFOs), this has been the case for even longer than OP_RETURN outputs: PATFOs have been provably unspendable since the Bitcoin Cash protocol's publication in 2008.
  2. That is, any transaction output where locking bytecode index 0 is set to the PREFIX_TOKEN codepoint, but a valid token prefix cannot be parsed.

Token-Aware Transaction Validation

For any transaction to be valid, the token validation algorithm must succeed.

Token Validation Algorithm

Given the following definitions:

  1. Reducing the set of UTXOs spent by the transaction:
    1. A key-value map of Available_Sums_By_Category (mapping category IDs to positive, 64-bit integers) is created by summing the input amount of each token category.
    2. A key-value map of Available_Mutable_Tokens_By_Category (mapping category IDs to positive integers) is created by summing the count of input mutable tokens for each category.
    3. A list of Genesis_Categories is created including the outpoint transaction hash of each input with an outpoint index of 0 (i.e. the spent UTXO was the 0th output in its transaction).
    4. A de-duplicated list of Input_Minting_Categories is created including the category ID of each input minting token.
    5. A list of Available_Minting_Categories is the combination of Genesis_Categories and Input_Minting_Categories.
    6. A list of all Available_Immutable_Tokens (including duplicates) is created including each NFT which does not have a minting or mutable capability.
  2. Reducing the set of outputs created by the transaction:
    1. A key-value map of Output_Sums_By_Category (mapping category IDs to positive, 64-bit integers) is created by summing the output amount of each token category.
    2. A key-value map of Output_Mutable_Tokens_By_Category (mapping category IDs to positive integers) is created by summing the count of output mutable tokens for each category.
    3. A de-duplicated list of Output_Minting_Categories is created including the category ID of each output minting token.
    4. A list of all Output_Immutable_Tokens (including duplicates) is created including each NFT which does not have a minting or mutable capability.

Perform the following validations:

  1. Each category in Output_Minting_Categories must exist in Available_Minting_Categories.
  2. Each category in Output_Sums_By_Category must either:
    1. Have an equal or greater sum in Available_Sums_By_Category, or
    2. Exist in Genesis_Categories and have an output sum no greater than 9223372036854775807 (the maximum VM number).
  3. For each category in Output_Mutable_Tokens_By_Category, if the token's category ID exists in Available_Minting_Categories, skip this (valid) category. Else:
    1. Deduct the sum in Output_Mutable_Tokens_By_Category from the sum available in Available_Mutable_Tokens_By_Category. If the value falls below 0, fail validation.
  4. For each token in Output_Immutable_Tokens, if the token's category ID exists in Available_Minting_Categories, skip this (valid) token. Else:
    1. If an equivalent token exists in Available_Immutable_Tokens (comparing both category ID and commitment), remove it and continue to the next token. Else:
      1. Deduct 1 from the sum available for the token's category in Available_Mutable_Tokens_By_Category. If no mutable tokens are available to downgrade, fail validation.

Note: because coinbase transactions have only one input with an outpoint index of 4294967295, coinbase transactions can never include a token prefix in any output.

See Implementations for examples of this algorithm in multiple programming languages.

Token Inspection Operations

The following 6 operations pop the top item from the stack as an index (VM Number) and push a single result to the stack. If the consumed value is not a valid, minimally-encoded index for the operation, an error is produced.

NameCodepointDescription
OP_UTXOTOKENCATEGORY0xce (206)Pop the top item from the stack as an input index (VM Number). If the Unspent Transaction Output (UTXO) spent by that input includes no tokens, push a 0 (VM Number) to the stack. If the UTXO does not include a non-fungible token with a capability, push the UTXO's token category, otherwise, push the concatenation of the token category and capability, where the mutable capability is represented by 1 (VM Number) and the minting capability is represented by 2 (VM Number).
OP_UTXOTOKENCOMMITMENT0xcf (207)Pop the top item from the stack as an input index (VM Number). Push the token commitment of the Unspent Transaction Output (UTXO) spent by that input to the stack. If the UTXO does not include a non-fungible token, or if it includes a non-fungible token with a zero-length commitment, push a 0 (VM Number).
OP_UTXOTOKENAMOUNT0xd0 (208)Pop the top item from the stack as an input index (VM Number). Push the fungible token amount of the Unspent Transaction Output (UTXO) spent by that input to the stack as a VM Number. If the UTXO includes no fungible tokens, push a 0 (VM Number).
OP_OUTPUTTOKENCATEGORY0xd1 (209)Pop the top item from the stack as an output index (VM Number). If the output at that index includes no tokens, push a 0 (VM Number) to the stack. If the output does not include a non-fungible token with a capability, push the output's token category, otherwise, push the concatenation of the token category and capability, where the mutable capability is represented by 1 (VM Number) and the minting capability is represented by 2 (VM Number).
OP_OUTPUTTOKENCOMMITMENT0xd2 (210)Pop the top item from the stack as an output index (VM Number). Push the token commitment of the output at that index to the stack. If the output does not include a non-fungible token, or if it includes a non-fungible token with a zero-length commitment, push a 0 (VM Number).
OP_OUTPUTTOKENAMOUNT0xd3 (211)Pop the top item from the stack as an output index (VM Number). Push the fungible token amount of the output at that index to the stack as a VM Number. If the output includes no fungible tokens, push a 0 (VM Number).
Token Inspection Operation Test Vectors

The following test vectors demonstrate the expected result of each token inspection operation for a particular output. The token category ID is 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb and commitments use repetitions of 0xcc.

For the complete set of test vectors, see Test Vectors.

DescriptionOP_UTXOTOKENCATEGORY/OP_OUTPUTTOKENCATEGORY (Hex)OP_UTXOTOKENCOMMITMENT/OP_OUTPUTTOKENCOMMITMENT (Hex)OP_UTXOTOKENAMOUNT/OP_OUTPUTTOKENAMOUNT (Hex)
no NFT; 0 fungible(empty item)(empty item)(empty item)
no NFT; 1 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)01
no NFT; 252 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)fc
no NFT; 253 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)fd00
no NFT; 9223372036854775807 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)ffffffffffffff7f
0-byte immutable NFT; 0 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)(empty item)
0-byte immutable NFT; 1 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)01
0-byte immutable NFT; 253 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)fd00
0-byte immutable NFT; 9223372036854775807 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(empty item)ffffffffffffff7f
1-byte immutable NFT; 252 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccfc
2-byte immutable NFT; 253 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccfd00
10-byte immutable NFT; 65535 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccffff
40-byte immutable NFT; 65536 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc00000100
0-byte, mutable NFT; 0 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01(empty item)(empty item)
0-byte, mutable NFT; 4294967295 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01(empty item)ffffffff
1-byte, mutable NFT; 4294967296 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01cc0000000001000000
2-byte, mutable NFT; 9223372036854775807 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01ccccffffffffffffff7f
10-byte, mutable NFT; 1 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01cccccccccccccccccccc01
40-byte, mutable NFT; 252 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb01ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfc
0-byte, minting NFT; 0 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb02(empty item)(empty item)
0-byte, minting NFT; 253 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb02(empty item)fd00
1-byte, minting NFT; 65535 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb02ccffff
2-byte, minting NFT; 65536 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb02cccc00000100
10-byte, minting NFT; 4294967297 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb02cccccccccccccccccccc0100000001000000
40-byte, minting NFT; 9223372036854775807 fungiblebbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb02ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccffffffffffffff7f

Existing Introspection Operations

Note, this specification has no impact on the behavior of OP_UTXOBYTECODE, OP_ACTIVEBYTECODE, or OP_OUTPUTBYTECODE. Each operation continues to return only the contents of the respective bytecode, excluding both the CompactSize-encoded "token_prefix_and_locking_bytecode_length" and the token prefix (if present).

Interpretation of Signature Preimage Inspection

It is possible to design contracts which inefficiently inspect the encoding of tokens using signature preimage inspection – inspecting the contents of a preimage for which a signature passes both OP_CHECKSIG(VERIFY) and OP_CHECKDATASIG(VERIFY).

This specification interprets all signature preimage inspection of tokens as intentional: these constructions are designed to succeed or fail based on the encoding of the signature preimage, and they can be used (by design) to test for 1) the availability of some types of proposed-but-not-activated upgrades, and/or 2) a contracts' presence on a fork of Bitcoin Cash. This notice codifies a network policy: the possible existence of these contracts will not preclude future upgrades from adding additional output prefix or transaction formats. (The security of a contract is the responsibility of the entity locking funds in that contract; funds can always be locked in insecure contracts, e.g. OP_DROP OP_1.)

Contract authors are advised to use Token Inspection Operations for all constructions intended to inspect the actual properties of tokens within a transaction.

Signing Serialization of Tokens

The signing serialization algorithm (A.K.A SIGHASH algorithm) is enhanced to support tokens: when evaluating a UTXO that includes tokens, the full, encoded token prefix (including PREFIX_TOKEN) must be included immediately before the coveredBytecode (A.K.A. scriptCode). Note: this behavior applies for all signing serialization types in the evaluation; it does not require a signing serialization type/flag.

SIGHASH_UTXOS

A new signing serialization type, SIGHASH_UTXOS, is defined at 0x20 (32/0b100000). When SIGHASH_UTXOS is enabled, hashUtxos is inserted in the signing serialization algorithm immediately following hashPrevouts. hashUtxos is a 32-byte double SHA256 of the serialization of all UTXOs spent by the transaction's inputs, concatenated in input order, excluding output count. (Note: this serialization is equivalent to the segment of a P2P transaction message beginning after output count and ending before locktime if the UTXOs were serialized in order as the transaction's outputs.)

The SIGHASH_UTXOS and SIGHASH_ANYONECANPAY types must not be used together; if a signature in which both flags are enabled is encountered during VM evaluation, an error is emitted (evaluation fails).

The SIGHASH_UTXOS type must be used with the SIGHASH_FORKID type; if a signature is encountered during VM evaluation with the SIGHASH_UTXOS flag and without the SIGHASH_FORKID flag, an error is emitted (evaluation fails).

For security, wallets should enable SIGHASH_UTXOS when participating in multi-entity transactions. This includes both 1) transactions where signatures are collected from multiple keys and assembled into a single transaction, and 2) transactions involving contracts that can be influenced by multiple entities (e.g. covenants). (See Recommendation of SIGHASH_UTXOS for Multi-Entity Transactions.)

Double Spend Proof Support

Transactions employing SIGHASH_UTXOS and transactions spending outputs containing tokens are not protected by either of the beta specifications for Double Spend Proofs (DSP). Support for these features are left to future proposals.

CashAddress Token Support

Two new CashAddress types are specified to indicate support for accepting tokens:

Type BitsMeaning
2 (0b0010)Token-Aware P2PKH
3 (0b0011)Token-Aware P2SH

Token-aware wallet software – wallet software which supports management of tokens – may use these CashAddress version byte values to signal token support.

Token-aware wallet software must refuse to send tokens to addresses without explicit token support i.e. P2PKH CashAddresses (type bits: 0b0000), P2SH CashAddresses (type bits: 0b0001), and legacy Base58 addresses.

Token-Aware CashAddress Test Vectors

Test vectors for the CashAddress format have been standardized and widely used since 2017, including test vectors for not-yet-defined type values.

While this specification simply uses the available type values, to assist implementers, the below test vectors have been added to the existing CashAddress test vectors in test-vectors/cashaddr.json. (For details, see Test Vectors.)

Token-Aware CashAddresses

CashAddressType BitsSize BitsPayload (Hex)
bitcoincash:qr7fzmep8g7h7ymfxy74lgc0v950j3r2959lhtxxsl0 (P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
bitcoincash:zr7fzmep8g7h7ymfxy74lgc0v950j3r295z4y4gq0v2 (Token-Aware P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
bchtest:qr7fzmep8g7h7ymfxy74lgc0v950j3r295pdnvy3hr0 (P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
bchtest:zr7fzmep8g7h7ymfxy74lgc0v950j3r295x8qj2hgs2 (Token-Aware P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
bchreg:qr7fzmep8g7h7ymfxy74lgc0v950j3r295m39d8z590 (P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
bchreg:zr7fzmep8g7h7ymfxy74lgc0v950j3r295umknfytk2 (Token-Aware P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
prefix:qr7fzmep8g7h7ymfxy74lgc0v950j3r295fu6e430r0 (P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
prefix:zr7fzmep8g7h7ymfxy74lgc0v950j3r295wkf8mhss2 (Token-Aware P2PKH)0 (20 bytes)fc916f213a3d7f1369313d5fa30f6168f9446a2d
bitcoincash:qpagr634w55t4wp56ftxx53xukhqgl24yse53qxdge0 (P2PKH)0 (20 bytes)7a81ea357528bab834d256635226e5ae047d5524
bitcoincash:zpagr634w55t4wp56ftxx53xukhqgl24ys77z7gth22 (Token-Aware P2PKH)0 (20 bytes)7a81ea357528bab834d256635226e5ae047d5524
bitcoincash:qq9l9e2dgkx0hp43qm3c3h252e9euugrfc6vlt3r9e0 (P2PKH)0 (20 bytes)0bf2e54d458cfb86b106e388dd54564b9e71034e
bitcoincash:zq9l9e2dgkx0hp43qm3c3h252e9euugrfcaxv4l9622 (Token-Aware P2PKH)0 (20 bytes)0bf2e54d458cfb86b106e388dd54564b9e71034e
bitcoincash:qre24q38ghy6k3pegpyvtxahu8q8hqmxmqqn28z85p0 (P2PKH)0 (20 bytes)f2aa822745c9ab44394048c59bb7e1c07b8366d8
bitcoincash:zre24q38ghy6k3pegpyvtxahu8q8hqmxmq8eeevptj2 (Token-Aware P2PKH)0 (20 bytes)f2aa822745c9ab44394048c59bb7e1c07b8366d8
bitcoincash:qz7xc0vl85nck65ffrsx5wvewjznp9lflgktxc58780 (P2PKH)0 (20 bytes)bc6c3d9f3d278b6a8948e06a399974853097e9fa
bitcoincash:zz7xc0vl85nck65ffrsx5wvewjznp9lflg3p4x6pp52 (Token-Aware P2PKH)0 (20 bytes)bc6c3d9f3d278b6a8948e06a399974853097e9fa
bitcoincash:ppawqn2h74a4t50phuza84kdp3794pq3ccvm92p8sh1 (P2SH)0 (20 bytes)7ae04d57f57b55d1e1bf05d3d6cd0c7c5a8411c6
bitcoincash:rpawqn2h74a4t50phuza84kdp3794pq3cct3k50p0y3 (Token-Aware P2SH)0 (20 bytes)7ae04d57f57b55d1e1bf05d3d6cd0c7c5a8411c6
bitcoincash:pqv53dwyatxse2xh7nnlqhyr6ryjgfdtagkd4vc3881 (P2SH)0 (20 bytes)1948b5c4eacd0ca8d7f4e7f05c83d0c92425abea
bitcoincash:rqv53dwyatxse2xh7nnlqhyr6ryjgfdtag38xjkhc53 (Token-Aware P2SH)0 (20 bytes)1948b5c4eacd0ca8d7f4e7f05c83d0c92425abea
bitcoincash:prseh0a4aejjcewhc665wjqhppgwrz2lw5txgn666a1 (P2SH)0 (20 bytes)e19bbfb5ee652c65d7c6b54748170850e1895f75
bitcoincash:rrseh0a4aejjcewhc665wjqhppgwrz2lw5vvmd5u9w3 (Token-Aware P2SH)0 (20 bytes)e19bbfb5ee652c65d7c6b54748170850e1895f75
bitcoincash:pzltaslh7xnrsxeqm7qtvh0v53n3gfk0v5wwf6d7j41 (P2SH)0 (20 bytes)bebec3f7f1a6381b20df80b65deca4671426cf65
bitcoincash:rzltaslh7xnrsxeqm7qtvh0v53n3gfk0v5fy6yrcdx3 (Token-Aware P2SH)0 (20 bytes)bebec3f7f1a6381b20df80b65deca4671426cf65
bitcoincash:pvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqpkp7fqn01 (P2SH)3 (32 bytes)0000000000000000000000000000123456789000000000000000000000000000
bitcoincash:rvqqqqqqqqqqqqqqqqqqqqqqzg69v7ysqqqqqqqqqqqqqqqqqqqqqn9alsp2y3 (Token-Aware P2SH)3 (32 bytes)0000000000000000000000000000123456789000000000000000000000000000
bitcoincash:pdzyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3jh2p5nn1 (P2SH)3 (32 bytes)4444444444444444444444444444444444444444444444444444444444444444
bitcoincash:rdzyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygrpttc42c3 (Token-Aware P2SH)3 (32 bytes)4444444444444444444444444444444444444444444444444444444444444444
bitcoincash:pwyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsh3sujgcr1 (P2SH)3 (32 bytes)8888888888888888888888888888888888888888888888888888888888888888
bitcoincash:rwyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9zvatfpg3 (Token-Aware P2SH)3 (32 bytes)8888888888888888888888888888888888888888888888888888888888888888
bitcoincash:p0xvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvcm6gz4t771 (P2SH)3 (32 bytes)cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
bitcoincash:r0xvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvenxvcff5rv2843 (Token-Aware P2SH)3 (32 bytes)cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
bitcoincash:p0llllllllllllllllllllllllllllllllllllllllllllllllll7x3vthu351 (P2SH)3 (32 bytes)ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
bitcoincash:r0llllllllllllllllllllllllllllllllllllllllllllllllll75zs2wagl3 (Token-Aware P2SH)3 (32 bytes)ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

Token-Aware BIP69 Sorting Algorithm

The BIP69 transaction output sorting algorithm is extended to support the sorting of outputs by token information.

As with the existing algorithm, the additional fields are ordered for sorting efficiency:

  1. Output value – ascending
  2. locking bytecode – sorted lexicographically1, ascending (e.g. 0x51 < 0x5161)
  3. token information: (no tokens < has tokens)
    1. amount – ascending (e.g. 0 < 1)
    2. HAS_NFTfalse < true
      1. capability – ascending; none < mutable < minting
      2. commitment – sorted lexicographically, ascending, short-to-long; e.g. zero-length < 0x00 < 0x01 < 0x0100)
    3. category – sorted lexicographically, ascending, where bytes are in little-endian order (matching the order used in encoded transactions)

Notes

  1. For clarity, lexicographically-sorted fields must be compared byte-by-byte from start to end. Where one item is a prefix of another item, the shorter item is considered the "lower" value. E.g. the following values are sorted lexicographically in ascending order: 0x00, 0x0011, 0x11, 0x1100.

Fungible Token Supply Definitions

Several measurements of fungible token supply are standardized for wider ecosystem compatibility. (See Specification of Token Supply Definitions.)

By design, Genesis Supply, Reserved Supply, Circulating Supply, and Total Supply of any fungible token category will not exceed 9223372036854775807 (the maximum VM number).

Genesis Supply

A token category's genesis supply is an immutable, easily-computed, maximum possible supply, known since the token category's genesis transaction. It overestimates total supply if any amount of tokens have been destroyed since the genesis transaction.

The genesis supply of a fungible token category can be computed by parsing the outputs of the category's genesis transaction and summing the amount of fungible tokens matching the category's ID.

Total Supply

A token category's total supply is the sum – at a particular moment in time – of tokens which are either in circulation or may enter circulation in the future. A token category's total supply is always less than or equal to its genesis supply.

The total supply of a fungible token category can be computed by retrieving all UTXOs which contain token prefixes matching the category ID, removing provably-destroyed outputs (spent to OP_RETURN outputs), and summing the remaining amounts.

Software implementations should emphasize total supply in user interfaces for token categories which do not meet the requirements for emphasizing circulating supply.

Reserved Supply

A token category's reserved supply or unissued supply is the sum – at a particular moment in time – of tokens held in reserve by the issuing entity. This is the portion of the supply which the issuer represents as "not in circulation".

The reserved supply of a fungible token category can be computed by retrieving all UTXOs which contain token prefixes matching the category ID, removing provably-destroyed outputs (spent to OP_RETURN outputs), and summing the amounts held in prefixes which have either the minting or mutable capability.

Circulating Supply

A token category's circulating supply is the sum – at a particular moment in time – of tokens not held in reserve by the issuing entity. This is the portion of the supply which the issuer represents as "in circulation".

The circulating supply of a fungible token category can be computed by subtracting the reserved supply from the total supply.

Software implementations might choose to emphasize circulating supply (rather than total supply) in user interfaces for token categories which:

  • are issued by an entity trusted by the user, or
  • are issued by a covenant (of a construction known to the verifier) for which token issuance is limited (via a strategy trusted by the user).

Usage Examples

Rationale

Prior Art & Alternatives

Test Vectors

Sets of cross-implementation test vectors are provided in the test-vectors directory. Each set is described below.

Token-Aware CashAddress Test Vectors

cashaddr.json includes an updated set of test vectors including tests for token-aware CashAddresses.

Test vectors for the CashAddress format have been standardized and widely used since 2017, including test vectors for not-yet-defined type values.

While this specification simply uses the available type values, to assist implementers, several additional test vectors have been added to the existing CashAddress test vectors in test-vectors/cashaddr.json.

Token Encoding Test Vectors

A complete set of test vectors that validate token encoding can be found in test-vectors/token-prefix-valid.json and test-vectors/token-prefix-invalid.json, respectively.

Transaction Validation Test Vectors

The test-vectors/vmb_tests directory contains sets of transaction test vectors that validate all technical elements of this proposal.

To maximize portability between implementations, these test vectors use Libauth's full-transaction testing strategy. Test vectors are sorted into files based on their expected behavior:

Each test vector is an array including:

  1. A short, unique identifier for the test (based on the hash of the test contents)
  2. A string describing the purpose/behavior of the test
  3. The unlocking script under test (disassembled, i.e. human-readable)
  4. The locking script under test (disassembled)
  5. The full, encoded test transaction
  6. An encoded list of unspent transaction outputs (UTXOs) with which to verify the test transaction (ordered to match the input order of the test transaction)

Only array items 5 and 6 are strictly necessary; items 1 through 4 are purely informational, and may be useful in debugging and cross-implementation communication.

To use these test vectors, implementations should decode the transaction under test (5) and its UTXOs (6), then validate the transaction using all of the implementation's transaction validation infrastructure initialized in the expected standard/nonstandard mode(s). See Implementations for examples.

Implementations

Please see the following implementations for additional examples and test vectors:

Stakeholder Responses & Statements

Stakeholder Responses & Statements

Feedback & Reviews

Acknowledgements

Thank you to the following contributors for reviewing and contributing improvements to this proposal, providing feedback, and promoting consensus among stakeholders: Calin Culianu, bitcoincashautist, imaginary_username, Joshua Green, Andrew Groot, Tom Zander, Andrew #128, Mathieu Geukens, Richard Brady, Marty Alcala, John Nieri, Jonathan Silverblood, Benjamin Scherrey, Rosco Kalis, Deyan Dimitrov, Jonas Lundqvist, Joemar Taganna, Rucknium.

Changelog

This section summarizes the evolution of this document.

  • v2.2.2 – 2022-5-20
    • Mention unissued supply as an alternative term for reserved supply
    • Mark CHIP as final
  • v2.2.1 – 2022-11-15 (7552da2d)
  • v2.2.0 – 2022-9-30 (e02012a2)
    • Compress token encoding using bitfield (#33)
    • Encode mutable capability as 0x01 and minting capability as 0x02
    • Revert to limiting commitment_length to 40 bytes by consensus (#23)
    • Revert PREFIX_TOKEN to a unique codepoint (0xef) (#41)
    • Modify OP_*TOKENCOMMITMENT to push 0 for zero-length commitments (#25)
    • Extend BIP69 sorting algorithm to support tokens (#60)
    • Specify activation times
    • Expand test vectors
    • Note non-support of beta specs for double spend proofs
    • Improve rationale
  • v2.1.0 – 2022-6-30 (f8b500a0)
    • Expand motivation, benefits, rationale, prior art & alternatives
    • Simplify token encoding, update test vectors
    • Set PREFIX_TOKEN to 0xd0 and limit commitment_length using standardness
    • Specify handling of pre-activation token-forgery outputs
    • Specify token-aware signing serialization algorithm and SIGHASH_UTXOS (#22)
  • v2.0.1 – 2022-2-25 (fcb110c3)
    • Expand rationale
    • Note impossibility of valid token outputs in coinbase transactions
  • v2.0.0 – 2022-2-22 (879c55ed)
    • Initial publication (versioning begins at v2 to differentiate from CashTokens v1)

This document is placed in the public domain.