Operation Specifications
This section details the structure and rules for the core BRC-20 operations encoded in the OP_RETURN payload.
Deploy
The deploy
operation registers a new BRC-20 token and sets its initial parameters.
{"p":"brc-20","op":"deploy","tick":"OPQT","m":"21000000","l":"1000"}
p
: protocol identifier (MUST be "brc-20").op
: operation type (MUST bedeploy
).tick
: unique ticker symbol (MUST be a string of at least 4 characters. The maximum length is constrained by the overall 80-byte OP_RETURN size limit for the entire JSON payload).m
: maximum total supply for the token (MUST be a string representing an integer ≤ 2⁶⁴–1).l
: limit on the amount of tokens that can be minted or transferred in a single operation (OPTIONAL string representing an integer). If present,mint
andtransfer
amounts cannot exceed this limit.
Indexer Validation:
A deploy
operation using this OP_RETURN extension is only valid if the specified tick
(as an exact string) has not already been validly deployed by any prior valid deploy transaction seen on-chain. This includes deploys made using the original Ordinals-based BRC-20 standard (which only supports 4-character tickers) and other deploys using this OP_RETURN method (which support tickers >= 4 characters). This creates a shared global ticker namespace. Indexers MUST enforce this uniqueness by prioritizing the first valid deploy transaction seen on-chain for any given unique ticker string, regardless of the method used. Subsequent deploys for the same ticker string are invalid and MUST be ignored by indexers.
Calculating Maximum Ticker Length
All BRC-20 deploy payloads must fit within the 80-byte OP_RETURN limit on Bitcoin.
A valid minified JSON deploy
payload with "m"
(max supply) and "l"
(limit per mint) looks like this:
{"p":"brc-20","op":"deploy","tick":"<TICKER>","m":"<MAX_SUPPLY>","l":"<LIMIT>"}
Fixed Overhead
Everything except <TICKER>
, <MAX_SUPPLY>
, <LIMIT>
, and their quotes:
Component | Bytes |
---|---|
{"p":"brc-20"} | 13 |
,"op":"deploy" | 15 |
,"tick":"" | 10 |
,"m":"" | 8 |
,"l":"" | 8 |
Total overhead | 54 bytes |
The quotes around the values are included in the fixed overhead for empty strings (""
).
Available Bytes for Data
80 (OP_RETURN limit) − 54 (fixed overhead) = 26 bytes remaining
You must divide the 26 bytes between:
<TICKER>
(token ticker)<MAX_SUPPLY>
(value for "m")<LIMIT>
(value for "l")
Examples
Example 1 — 21,000,000 tokens, mint limit = 1000
"m":"21000000"
→ 8 bytes"l":"1000"
→ 4 bytes- Remaining for ticker:
26 − 8 − 4 = 14 bytes
{"p":"brc-20","op":"deploy","tick":"ABCDEFGHIJKLMN","m":"21000000","l":"1000"}
✅ Valid — 14-character ticker fits in 80 bytes.
Example 2 — 1,000,000,000 tokens, mint limit = 10000
"m":"1000000000"
→ 10 bytes"l":"10000"
→ 5 bytes- Remaining for ticker:
26 − 10 − 5 = 11 bytes
{"p":"brc-20","op":"deploy","tick":"ABCDEFGHIJK","m":"1000000000","l":"10000"}
✅ Valid — 11-character ticker fits.
Example Raw Transaction (Illustrative):
# This is a conceptual example. Actual data string would be the hex of the minified JSON. # 'data' field value must be the hex of the OP_RETURN script (e.g., 6a...<hex_payload>) bitcoin-cli createrawtransaction '[{"txid":"<UTXO_providing_BTC>","vout":0}]' '{"data":"6a4c...<hex_of_minified_deploy_json>","1DeployAddr":0.00000546,"1ChangeAddr":0.00999}'
Developers and users should always verify the transaction structure and the OP_RETURN payload content and size using tools like decoderawtransaction
before signing and broadcasting. Be mindful that longer tickers consume more bytes, potentially impacting the ability to include other data fields within the 80-byte limit.
Mint
The mint
operation creates new units of a deployed BRC-20 token.
{"p":"brc-20","op":"mint","tick":"OPQT","amt":"500"}
p
:brc-20
.op
:mint
.tick
: the ticker symbol of the token being minted. MUST correspond to a validly deployed token (either via Ordinals or a valid OP_RETURN deploy). The ticker string MUST exactly match the deployed ticker.amt
: the amount of tokens to mint in this operation (MUST be a string representing an integer). This amount MUST be less than or equal to thel
limit specified in the token's deploy operation, ifl
was defined. The total minted supply (sum of all valid mints) plus thisamt
MUST NOT exceed the token's maximum supplym
.
A mint
operation is valid only if the tick
corresponds to a valid deploy, the amt
respects the l
limit (if set), and the operation does not cause the total minted supply to exceed the m
limit. The minted tokens are allocated to the standard outputs based on the Proportional Distribution rule.
Simple Mint (Tokens allocated to one address)
# The output amount (e.g., 0.00000546 BTC) satisfies dust limit. # The indexer allocates the token amount based on the OP_RETURN data to the recipient of this output. bitcoin-cli createrawtransaction \ '[{"txid":"<UTXO_providing_BTC>","vout":1}]' \ '{"data":"6a3b...<hex_of_minified_mint_json>","destAddr":0.00000546,"changeAddr":0.00999}'
Transfer
The transfer
operation moves existing units of a BRC-20 token from one holder to another.
{"p":"brc-20","op":"transfer","tick":"OPQT","amt":"250"}
p
:brc-20
.op
:transfer
.tick
: the ticker symbol of the token being transferred. MUST correspond to a validly deployed token. The ticker string MUST exactly match the deployed ticker.amt
: the amount of tokens to transfer in this operation (MUST be a string representing an integer).
A transfer
operation is valid only if the tick
corresponds to a valid deploy, AND the sender (identified by the input UTXO(s) being spent) has an available balance (as tracked by the indexer) greater than or equal to the amt
specified in the OP_RETURN. If l
was defined in the deploy, the amt
MUST also be less than or equal to l
. The transferred tokens are allocated to the standard outputs based on the Proportional Distribution rule.
Simple Transfer (Tokens allocated to one receiver)
# The input UTXO(s) must be recognized by the indexer as holding the sender's balance. # The output amounts (e.g., 0.00000546 BTC) satisfy dust limit. # The indexer allocates the token amount based on the OP_RETURN data to the recipient of receiverAddr. bitcoin-cli createrawtransaction \ '[{"txid":"<UTXO_carrying_sender_balance>","vout":0}]' \ '{"data":"6a3f...<hex_of_minified_transfer_json>","senderAddr":0.00000546,"receiverAddr":0.00000546,"changeAddr":0.00998}'
Note: Indexer policy determines how tokens are distributed among sender and receiver outputs based on satoshi values and intent.