ASA Metadata Registry | Algorand Developer Portal

ASA Metadata Registry

Abstract

Section titled “Abstract”

This ARC defines the interface and the implementation of a singleton Application that provides Algorand Standard Assets metadata through the Algod API or the AVM.

Motivation

Section titled “Motivation”

Algorand Standard Assets (ASA) lack a dedicated metadata field on the Algorand ledger for storing additional asset information.

Although it’s generally not advisable to use Algorand as a distributed storage system for data that could easily reside elsewhere, the absence of a native metadata store on the ledger has led the ecosystem to adopt less-than-ideal solutions for discovering and fetching off-chain asset data, involving the usage of an Indexer or external infrastructure (such as IPFS), or hacking on the ASA RBAC roles to get asset metadata mutability.

While storing huge data, such as images, off-chain is a practical (and recommended) approach, smaller, more pertinent data should not incur the expenses, availability challenges, and latency typically associated with external infrastructure.

This ARC establishes a standardized URI within the ASA URL field to solve this simple use case: directly retrieving ASA metadata using the Algod API or the AVM.

Specification

Section titled “Specification”

The keywords “ MUST”, “ MUST NOT”, “ REQUIRED”, “ SHALL”, “ SHALL NOT”, “ SHOULD”, “ SHOULD NOT”, “ RECOMMENDED”, “ MAY”, and “ OPTIONAL” in this document are to be interpreted as described in RFC 2119.

The data types (like uint64, byte[], etc.) in this document are to be interpreted as specified in ARC-4.

Notes like this are non-normative.

ASA Metadata Registry

Section titled “ASA Metadata Registry”

The ASA Metadata Registry is an immutable singleton Application that stores mutable or immutable Asset Metadata.

The trusted deployments of ASA Metadata Registry are:

NETWORK GENESIS HASH (base64) APP ID CREATOR ADDRESS
Main Net wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8= TBD XODGWLOMKUPTGL3ZV53H3GZZWMCTJVQ5B2BZICFD3STSLA2LPSH6V6RW3I
Test Net SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI= 753324084 QYK5DXJ27Y7WIWUJMP3FFOTEU56L4KTRP4CY2GAKRXZHHKLNWV6M7JLYJM

Refer to the AppSpec section for the detailed ARC-56 Application Specification of the singleton reference implementation.

The initial Minimum Balance Requirement (MBR) for the ASA Metadata Registry Application Account SHOULD be provided before enabling the creation of any Asset Metadata.

Once deployed, the ASA Metadata Registry MUST NOT be updated.

Asset Metadata Box

Section titled “Asset Metadata Box”

The ASA Metadata, along with some ancillary information, are stored in a dedicated Box of the ASA Metadata Registry, called Asset Metadata Box.

There MUST be at most one Asset Metadata Box per ASA.

The Asset Metadata Box Name MUST be equal to the raw 8-byte big-endian encoding of the Asset ID (uint64) (ASSET_METADATA_BOX_KEY_SIZE = 8 bytes).

The Asset Metadata Box Value MUST be defined as follows:

FIELD SCOPE IN METADATA HASH TYPE BYTE OFFSET BYTE SIZE
Metadata Identifiers Header Yes byte 0 1
Reversible Flags Header Yes byte 1 1
Irreversible Flags Header Yes byte 2 1
Metadata Hash Header No (Recursive) byte[32] 3 32
Last Modified Round Header No uint64 35 8
Deprecated By Header No uint64 43 8
Metadata Body Yes byte[] 51 up to MAX_METADATA_SIZE

See the Metadata section for more details about the Metadata encoding and size limits.

Metadata Header

Section titled “Metadata Header”

The Metadata Header is a byte-array of fixed length (HEADER_SIZE), encoding ancillary attributes of the Asset Metadata.

The HEADER_SIZE (uint16) is a parameter of the ASA Metadata Registry that is equal to the sum of the Header fields byte sizes (51 bytes).

The maximum HEADER_SIZE depends on:

Therefore, HEADER_SIZE ≤ MAX_LOG_SIZE - ARC4_RETURN_PREFIX_SIZE = 1020 bytes.

Metadata Identifiers

Section titled “Metadata Identifiers”

The Metadata Identifiers (byte) are a set of boolean switches set by the ASA Metadata Registry.

The Metadata Identifiers are defined as follows:

BIT DESCRIPTION DEFAULT STATE TRANSITION
LSB Not used - -
1 Not used - -
2 Not used - -
3 Not used - -
4 Not used - -
5 Not used - -
6 Not used - -
MSB Short Metadata False Two-ways

The MSB is the leftmost bit in the byte stored in Asset Metadata Box.

The Metadata Identifiers SHALL NOT be updated if the Metadata is immutable.

Short Metadata

Section titled “Short Metadata”

The Metadata MAY be identified as short on creation or after, by setting the MSB in the Metadata Identifier to True.

The short Metadata identifier is derived by the metadata_size. It is set to True if and only if metadata_size ≤ SHORT_METADATA_SIZE, and False otherwise. Its value MAY change on update.

Clients MUST NOT assume shortness identifier persists across updates, since the Metadata size is not guaranteed to be constant (if not immutable).

If the Metadata is identified as short, clients are aware that all AVM opcodes can operate directly on the whole Metadata, example: decoding (json_ref, base64_decode), cryptography (sha256, keccak256, sha512_256, sha3_256), byte manipulations, etc.

For further details on identification rules, refer to the Metadata section.

Metadata Flags

Section titled “Metadata Flags”

The Metadata Flags ( reversible and irreversible) are two distinct sets of boolean switches set by the ASA Manager Address.

Metadata Flags can be used for bitwise operations with a bitmask.

The Metadata Flags MAY set by the ASA Manager Address on creation or later.

The Metadata Flags SHALL NOT be updated if the Metadata is immutable.

Reversible Flags

Section titled “Reversible Flags”

The Reversible Flags (byte) are defined as follows:

BIT DESCRIPTION DEFAULT SET TIME
LSB ARC-20 Smart ASA False Any
1 ARC-62 Circulating Supply False Any
2 Native Token Transfers (NTT) supported False Any
3 Custom, should be reserved for future ARCs False Any
4 Custom, should be reserved for future ARCs False Any
5 Custom, should be reserved for future ARCs False Any
6 Custom, should be reserved for future ARCs False Any
MSB Custom, should be reserved for future ARCs False Any

The MSB is the leftmost bit in the byte stored in Asset Metadata Box.

The bits 2 ... MSB are reserved for future ARCs (default False if not used).

An ASA MAY be declared to be an ARC-20 Smart ASA on creation or after, setting the LSB in the Reversible Flags to True.

If the ASA is declared to be an ARC-20 Smart ASA:

The ARC-62 ASA Circulating Supply MAY be enabled on creation or after, setting the bit 1 in the Reversible Flags to True.

If the ARC-62 support is enabled:

An ASA MAY declare to support Native Token Transfers (NTT) on creation or after, setting the 2 bit in the Reversible Flags to True.

Irreversible Flags

Section titled “Irreversible Flags”

The Irreversible Flags (byte) are defined as follows:

BIT DESCRIPTION DEFAULT SET TIME
LSB ARC-3 Compliant False At metadata creation
1 ARC-89 Native ASA False At metadata creation
2 ARC-54 Burnable ASA False Any
3 Custom, should be reserved for future ARCs False Any
4 Custom, should be reserved for future ARCs False Any
5 Custom, should be reserved for future ARCs False Any
6 Custom, should be reserved for future ARCs False Any
MSB Metadata Immutability False Any

The MSB is the leftmost bit in the byte stored in Asset Metadata Box.

The bits 3 ... 6 are reserved for future ARCs (default False if not used).

The Metadata MAY be declared as ARC-3 compliant on creation, setting the bit LSB in the Irreversible Flags to True.

The ASA MAY be declared as a native ARC-89 ASA on creation, setting the bit 1 in the Irreversible Flags to True.

The ASA MAY be declared as a burnable ARC-54 ASA on creation or after, setting the bit 2 in the Irreversible Flags to True, if it ASA has no Clawback Address.

Metadata Immutability

Section titled “Metadata Immutability”

The Metadata MAY be declared as immutable on creation or after, setting the MSB in the Irreversible Flags to True.

⚠️ WARNING: If the ASA Manager Address is set to the Zero Address, this implies that the ASA is effectively immutable, regardless of the Metadata Immutability flag (MSB) setting.

Metadata Hash

Section titled “Metadata Hash”

The Metadata Hash (byte[32]) is a 256-bit hash computed as defined in the Metadata\ Hash Computation section.

The Metadata Hash MUST be set on Asset Metadata creation.

If the Asset Metadata is not immutable, the Metadata Hash MUST be updated on any modification of either:

Last Modified Round

Section titled “Last Modified Round”

The Last Modified Round (uint64) records the block in which the Metadata Header or the Metadata was last modified (or created).

If the Asset Metadata is not immutable, the Last Modified Round MUST be updated on any modification of either:

The Last Modified Round is guaranteed to be monotonically increasing.

Deprecated By

Section titled “Deprecated By”

The Deprecated By (uint64) is the Application ID of the new ASA Metadata Registry version.

The Deprecated By field MUST be set to 0 if the ASA Metadata Registry is not deprecated.

The ASA Manager Address MAY migrate mutable metadata to a new ASA Metadata Registry version by setting the Deprecated By field to the Application ID of the new ASA Metadata Registry version.

Immutable metadata MUST NOT be migrated.

Metadata

Section titled “Metadata”

The Metadata (byte[]) is a byte-array of variable length (metadata_size).

The metadata_size MAY be 0, representing empty Metadata. In this case, the Metadata Body is the empty byte string (and total_pages = 0, see Pagination).

The Metadata Header still exists and can be retrieved by clients.

The MAX_METADATA_SIZE (uint16) is a parameter of the ASA Metadata Registry that depends on:

The MAX_METADATA_SIZE is not constrained by the first head payload for the methods arc89_replace_metadata(...) and arc89_replace_metadata_larger(...) since they are larger than the one of arc89_create_metadata(...).

Refer to the ARC-4 Interface section for details about the method signatures.

Therefore, MAX_METADATA_SIZE = FIRST_PAYLOAD_MAX_SIZE + 14 * EXTRA_PAYLOAD_MAX_SIZE = 30506 bytes.

The condition MAX_METADATA_SIZE ≤ MAX_BOX_SIZE - HEADER_SIZE MUST hold.

The metadata_size MUST hold the condition: metadata_size ≤ MAX_METADATA_SIZE.

The SHORT_METADATA_SIZE (uint16) is a parameter of the ASA Metadata Registry that is equal to the AVM Stack length (4096 bytes).

If the metadata_size ≤ SHORT_METADATA_SIZE, it MUST be declared as short.

The Metadata MUST NOT be updated if immutable.

The available payload for the method arc89_replace_metadata_slice(uint64,uint16,byte[]) is REPLACE_PAYLOAD_MAX_SIZE = MAX_ARG_SIZE - (ARC4_METHOD_SELECTOR_SIZE + 8 + 2 + 2 = 2032) bytes.

Encoding

Section titled “Encoding”

The Metadata MUST be a sequence of bytes representing a valid UTF-8 encoded JSON object, as defined in RFC\ 8259, without Byte Order Mark (BOM).

If Metadata is empty (metadata_size == 0), clients MUST treat it as an empty JSON object for parsing purposes.

If the Metadata is a valid JSON object, it SHOULD conform to the ARC-3 JSON\ Metadata File Schema. This is the RECOMMENDED schema for maximum interoperability with the ecosystem (e.g., explorers, wallets, etc.).

Pagination

Section titled “Pagination”

A Metadata Page is a byte-array of variable length (page_size) that contains a portion of (or the entire) Metadata.

The PAGE_SIZE (uint16) is a parameter of the ASA Metadata Registry that depends on:

Therefore, PAGE_SIZE = MAX_LOG_SIZE - ARC4_RETURN_PREFIX_SIZE - (1 + 8 + 2 + 2) = 1007 bytes.

The page_size MUST hold the condition page_size ≤ PAGE_SIZE.

A page MUST be identified by a 0-based index (uint8) from the head of the Metadata.

Page p covers the byte range [p*PAGE_SIZE, min((p+1)*PAGE_SIZE, metadata_size)).
The final page MAY be shorter; all intermediate pages SHOULD have page_size = PAGE_SIZE.
\

A uint8 is enough as a page index since ceil(MAX_METADATA_SIZE/PAGE_SIZE) = 31;
0 pages are allowed (i.e., empty Metadata).

Empty Metadata: when total_pages == 0, there are no Metadata Pages for hashing
purposes; however, the Get Metadata method accepts page = 0
and return an empty page (and has_next_page = False) as a convenience (any
page != 0 fails).
\

MBR Delta\


Section titled “MBR Delta”

The MBR Delta is the variation of the ASA Metadata Registry Application Account
MBR due to the creation, update, or deletion of the Asset Metadata Box.

It is a tuple of two elements, encoding:
\

Metadata Hash Computation\


Section titled “Metadata Hash Computation”

If the Asset Metadata Hash (am) field of the ASA is set (i.e., not zero), then:
\

  1. Compute the Metadata Header Hash (hh):
    \
hh = SHA-512/256("arc0089/header" || Asset ID || Metadata Identifiers || Reversible Flags || Irreversible Flags || Metadata Size)\
```\
\
1. If `total_pages > 0`, compute the Page Hashes (`ph[i]`) for each Metadata Page\
(`i = 0 ... total_pages - 1`):\
\
```\
ph[i] = SHA-512/256("arc0089/page" || Asset ID || Page Index || Page Size || Page Content)\
```\
\
1. If `total_pages > 0`, compute the Asset Metadata Hash (`am`) as:\
\
```\
am = SHA-512/256("arc0089/am" || hh || ph[0] || ph[1] || ... || ph[total_pages - 1])\
```\
\
otherwise, if `total_pages == 0`, compute the Asset Metadata Hash (`am`) as:\
\
```\
am = SHA-512/256("arc0089/am" || hh)\
```\
\
Where:\
\
- `||` denotes concatenation,\
- `Asset ID` is the 8-byte encoding of the Asset ID (`uint64`), serialized in network byte order (big-endian);\
- `Metadata Identifiers` is the 1-byte encoding of the [Metadata Identifiers](https://dev.algorand.co/arc-standards/arc-0089/#metadata-identifiers) (`byte`);\
- `Reversible Flags` is the 1-byte encoding of the [Reversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#reversible-flags) (`byte`);\
- `Irreversible Flags` is the 1-byte encoding of the [Irreversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags) (`byte`);\
- `Metadata Size` is the 2-byte encoding of the Metadata Size (`uint16`), serialized in network byte order (big-endian);\
- `Page Index` is the 1-byte encoding of the 0-based Metadata Page Index (`uint8`);\
- `Page Size` is 2-byte encoding of the i-th Page byte size (`uint16`), serialized in network byte order (big-endian);\
- `Page Content` are the _exact raw bytes_ content of the i-th Metadata Page, unpadded if `len(page) < PAGE_SIZE`;\
- `SHA-512/256` is defined in [NIST FIPS 180-4](https://doi.org/10.6028/NIST.FIPS.180-4).\
\
Hash components **MUST NOT** be reinterpreted as a signed integer, bitset string,\
or multibyte integer prior to hashing.\
\
> ⚠️ The Last Modified Round and the Deprecated By fields are **NOT** included in\
> the Metadata Hash computation.\
\
### ASA Creation\
\
[Section titled “ASA Creation”](https://dev.algorand.co/arc-standards/arc-0089/#asa-creation)\
\
Care has to be taken when creating an [ARC-89 Native ASA](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags), specifically:\
\
- The _Asset URL_ (`au`) field is defined at ASA creation time, and it is _immutable_,\
\
- The _Asset Metadata Hash_ (`am`) field is defined at ASA creation time, and it\
is _immutable_,\
\
- The ASA Manager Address **MUST NOT** be set to the Zero Address on creation.\
\
\
#### Asset URL\
\
[Section titled “Asset URL”](https://dev.algorand.co/arc-standards/arc-0089/#asset-url)\
\
The _Asset URL_ (`au`) field is used as a _partial_ URI pointing to the Asset Metadata\
on the Algorand ledger.\
\
The _Asset URL_ (`au`) **MUST** begin with the _partial_ [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) URI:\
\
`algorand://<netauth>/app/<singleton_arc89_app_id>?box=`\
\
and **MAY** declare the [ARC-90 compliance fragment](https://dev.algorand.co/arc-standards/arc-0089/arc-0090#compliance-fragment)\
at the end of the _partial_ URI:\
\
`algorand://<netauth>/app/<singleton_arc89_app_id>?box=#arc<A>+<B>+<C>...`\
\
where `<A>`, `<B>`, `<C>`, etc. are the ARC numbers of the compliance fragments.\
\
The [Native ARC-89 ASA Flag](https://dev.algorand.co/arc-standards/arc-0089/#arc-89-native-asa-creation) **MUST** be set to `True`.\
\
Clients **MUST** resolve the _partial_ Asset URL (`au`) to a _complete_ [Asset Metadata\\
URI](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri) before using it.\
\
> Refer to the [Asset Metadata URI section](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri) for details about\
> the _complete_ [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) _Asset Metadata URI_.\
\
#### Asset Metadata Hash\
\
[Section titled “Asset Metadata Hash”](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-hash)\
\
The _Asset Metadata Hash_ (`am`) field is used as hash-lock invariant on ASA creation.\
\
The ASA Creator **SHOULD** compute the _Asset Metadata Hash_ (`am`) field as specified\
by:\
\
- The [ARC-3 Parameters Convention](https://dev.algorand.co/arc-standards/arc-0003#asa-parameters-conventions), if\
the ASA is [ARC-3 compliant](https://dev.algorand.co/arc-standards/arc-0089/#arc-3-compliance),\
- Otherwise, the [Metadata Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
> Since the Metadata Identifiers are set by the ASA Metadata Registry on creation,\
> the ASA Creator needs to pre-identify the ASA based on the creation parameters,\
> specifically:\
>\
> - If the Metadata size at creation time is less than or equal to `SHORT_METADATA_SIZE`.\
\
#### [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) Compliance\
\
[Section titled “ARC-3 Compliance”](https://dev.algorand.co/arc-standards/arc-0089/#arc-3-compliance)\
\
The compliance with [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) is **OPTIONAL** but **RECOMMENDED** to maximize\
interoperability with the ecosystem.\
\
If the ASA conforms to [ARC-3](https://dev.algorand.co/arc-standards/arc-0003), then:\
\
- The ASA **MUST** comply with the [_ARC-3 ASA Parameters Conventions_](https://dev.algorand.co/arc-standards/arc-0003#asa-parameters-conventions)\
for the _Asset Name_ (`an`) and the _Asset URL_ (`au`) fields.\
  - It is **RECOMMENDED** to use the _Asset URL_ (`au`) suffix option, in this case\
    the _partial_ [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) URI would be: `algorand://<netauth>/app/<singleton_arc89_app_id>?box=#arc3`\
- The ASA **MUST** comply with the [_ARC-3 ASA Parameters Conventions_](https://dev.algorand.co/arc-standards/arc-0003#asa-parameters-conventions)\
for the _Asset Metadata Hash_ (`am`) field if the Asset Metadata are set as [_immutable_](https://dev.algorand.co/arc-standards/arc-0089/#metadata-immutability)\
at creation, otherwise the _Asset Metadata Hash_ (`am`) field **MUST NOT** be set\
(i.e., set to zero).\
\
- The Asset Metadata **MUST** comply with the [_ARC-3 JSON Metadata File Schema_](https://dev.algorand.co/arc-standards/arc-0003#json-metadata-file-schema).\
\
- The [ARC-3 Compliant Flag](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags) **MUST** be set to `True`.\
\
\
> Refer to the [Asset Metadata URI section](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri) for details about\
> the _complete_ [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) _Asset Metadata URI_.\
\
> The ASA Metadata Registry does not enforce _Asset Metadata Hash_ (`am`) validation\
> for [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) ASA.\
\
#### Creation Process\
\
[Section titled “Creation Process”](https://dev.algorand.co/arc-standards/arc-0089/#creation-process)\
\
Two **RECOMMENDED** creation processes are provided.\
\
##### ARC-89 Native ASA Creation\
\
[Section titled “ARC-89 Native ASA Creation”](https://dev.algorand.co/arc-standards/arc-0089/#arc-89-native-asa-creation)\
\
The **RECOMMENDED** creation process for an [ARC-89](https://dev.algorand.co/arc-standards/arc-0089) _native_ ASA:\
\
1. The ASA Creator Address defines the [Metadata Flags](https://dev.algorand.co/arc-standards/arc-0089/#metadata-flags) and the\
[Metadata](https://dev.algorand.co/arc-standards/arc-0089/#metadata),\
\
2. The ASA Creator Address creates an ASA as follows:\
   - The _Asset URL_ (`au`) field is set to `algorand://<netauth>/app/<singleton_arc89_app_id>?box=#arc89`,\
   - If the Asset Metadata is [_immutable_](https://dev.algorand.co/arc-standards/arc-0089/#metadata-immutability), the _Asset Metadata_\
     _Hash_ (`am`) field is computed according to the [Metadata Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation)\
     using the [Metadata Identifiers](https://dev.algorand.co/arc-standards/arc-0089/#metadata-identifiers), the defined [Metadata\\
     Flags](https://dev.algorand.co/arc-standards/arc-0089/#metadata-flags) and the Metadata (raw bytes),\
   - The ASA Manager Address is _not_ set to the Zero Address.\
3. The ASA Manager Address creates the Asset Metadata on the ASA Metadata Registry,\
using the defined Metadata Flags and Metadata.\
\
\
##### ARC-89 Native ASA Creation with ARC-3 Compliant Metadata\
\
[Section titled “ARC-89 Native ASA Creation with ARC-3 Compliant Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#arc-89-native-asa-creation-with-arc-3-compliant-metadata)\
\
The **RECOMMENDED** creation process for an [ARC-89](https://dev.algorand.co/arc-standards/arc-0089) _native_ ASA\
with [ARC-3 compliant](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags) Metadata is:\
\
1. The ASA Creator Address defines the [Metadata Flags](https://dev.algorand.co/arc-standards/arc-0089/#metadata-flags) and the\
[Metadata](https://dev.algorand.co/arc-standards/arc-0089/#metadata),\
\
2. The ASA Creator Address creates an ASA as follows:\
   - The _Asset URL_ (`au`) field is set to `algorand://<netauth>/app/<singleton_arc89_app_id>?box=#arc3`,\
   - If the Asset Metadata is [_immutable_](https://dev.algorand.co/arc-standards/arc-0089/#metadata-immutability), the _Asset Metadata_\
     _Hash_ (`am`) field is set according to the [_ARC-3 ASA Parameters Conventions_](https://dev.algorand.co/arc-standards/arc-0003#asa-parameters-conventions),\
   - The ASA Manager Address is _not_ set to the Zero Address.\
3. The ASA Manager Address creates the Asset Metadata on the ASA Metadata Registry,\
using the defined Metadata Flags and Metadata.\
\
\
If the ASA configuration (Role-Based Access Control and destroyability) needs to\
be locked (by disabling the ASA Manager Address), the Asset Metadata **MUST** be\
created first.\
\
> The compliance fragment for [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) **MUST NOT** contain additional\
> elements (i.e., `#arc3+89` is not allowed), see [ARC-90 compliance fragment](https://dev.algorand.co/arc-standards/arc-0090#compliance-fragment)\
> section for details.\
\
### Asset Metadata URI\
\
[Section titled “Asset Metadata URI”](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri)\
\
To get the [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) _Asset Metadata URI_, clients **SHALL** complete\
the _Asset URL_ with the `boxparam` filled with the Asset Metadata Box Name, equal\
to the _Asset ID_ (big-endian `uint64` encoded as `base64url`, URL-safe with padding):\
\
`algorand://<netauth>/app/<singleton_arc89_app_id>?box=<base64url_encoded_asset_id>#arc<A>+<B>+<C>...`\
\
where `<A>`, `<B>`, `<C>`, etc. are the ARC numbers of the compliance fragments as\
defined by [ARC-90](https://dev.algorand.co/arc-standards/arc-0090#compliance-fragment).\
\
If the [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) compliance fragment is used, it **MUST** be the only\
fragment as defined by [ARC-90](https://dev.algorand.co/arc-standards/arc-0090#compliance-fragment) (i.e., `#arc3` **is valid**, `#arc3+89` **is not valid**).\
\
> The **MainNet**`netauth` is empty, therefore:\
>\
> - the **Asset URL** is: `algorand://app/<singleton_arc89_app_id>?box=#arc<A>+<B>+<C>...`\
>\
> - the **Asset Metadata URI** is: `algorand://app/<singleton_arc89_app_id>?box=<base64url_encoded_asset_id>#arc<A>+<B>+<C>...`\
\
> The **TestNet** deployments uses `testnet` as `netlabel` for the `netauth` selector,\
> therefore:\
>\
> - the **Asset URL** is: `algorand://net:testnet/app/<singleton_arc89_app_id>?box=#arc<A>+<B>+<C>...`\
>\
> - the **Asset Metadata URI** is: `algorand://net:testnet/app/<singleton_arc89_app_id>?box=<base64url_encoded_asset_id>#arc<A>+<B>+<C>...`\
\
Clients **MUST** encode the Asset Metadata Box Name with URL-safe `base64url` (with\
padding) in [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) URIs, and with Standard `base64` when calling Algod API\
endpoints with `/box?name=` query parameter.\
\
> For further details on the `base64` Standard and URL-safe encodings refer to the\
> [RFC 4648 sections 4 and 5](https://www.rfc-editor.org/rfc/rfc4648.html#section-4).\
\
> The _Asset ID_ (`uint64`) used as Asset Metadata Box Name (`boxparam`) in the Asset\
> Metadata URI is encoded as `base64url` for two reasons: (1) the Box Name is assumed\
> to be raw big-endian 8-bytes encoding a `uint64` and (2) the Algod API requires\
> `/box?name=` query parameter to be Standard `base64` encoded, while the URI requires\
> the URL-safe `base64url` encoding.\
\
#### Examples\
\
[Section titled “Examples”](https://dev.algorand.co/arc-standards/arc-0089/#examples)\
\
> | Asset ID (`uint64`) | 8-byte big-endian (hex) | Algod `/box?name=` (Standard `base64`) | ARC-90 `box=` (URL-safe `base64url`) |\
> | --: | :-: | :-: | :-: |\
> | `0` | `0000000000000000` | `AAAAAAAAAAA=` | `AAAAAAAAAAA=` |\
> | `1` | `0000000000000001` | `AAAAAAAAAAE=` | `AAAAAAAAAAE=` |\
> | `2^32` | `0000000100000000` | `AAAAAQAAAAA=` | `AAAAAQAAAAA=` |\
> | `2^63−1` | `7fffffffffffffff` | `f/////////8=` | `f_________8=` |\
>\
> The _Asset Metadata URI_ for the ASA `12345` would be:\
>\
> `algorand://<netauth>/app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc89`\
>\
> - **MainNet**: `algorand://app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc89`\
> - **TestNet**: `algorand://net:testnet/app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc89`\
>\
> The _Asset Metadata URI_ for the [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) ASA\
> `12345` would be:\
>\
> `algorand://<netauth>/app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc3`\
>\
> - **MainNet**: `algorand://app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc3`\
> - **TestNet**: `algorand://net:testnet/app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc3`\
\
### Deprecation and ASA migration\
\
[Section titled “Deprecation and ASA migration”](https://dev.algorand.co/arc-standards/arc-0089/#deprecation-and-asa-migration)\
\
The ASA Metadata Registry singleton application is _immutable_.\
\
Any eventual future version **MUST** be deployed as a new Application ID.\
\
The decision to migrate existing ASA Metadata to a new version **MUST** be made\
by the ASA Manager Address, by declaring the new Application ID in the Deprecated\
By field of the Metadata Header.\
\
If the Deprecated By field is not `0`:\
\
- The ASA Manager **SHOULD** leave the [Metadata](https://dev.algorand.co/arc-standards/arc-0089/#metadata) (body) **empty** (i.e., `metadata_size = 0`),\
\
- Clients **SHALL** point to the new [ARC-90](https://dev.algorand.co/arc-standards/arc-0090) Asset Metadata URI:\
\
`algorand://<netauth>/app/<deprecated_by_app_id>?box=<base64url_encoded_asset_id>#arc<A>+<B>+<C>...`\
\
and complete it as specified in the [Asset Metadata URI section](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri).\
\
\
## Rationale\
\
[Section titled “Rationale”](https://dev.algorand.co/arc-standards/arc-0089/#rationale)\
\
This ARC standardizes an on-chain, Algod/AVM-addressable metadata source for Algorand\
Standard Assets (ASAs).\
\
The design goals are:\
\
1. Direct retrieval without Indexer or external storage for small but important metadata,\
\
2. Predictable costs and limits via a single-box layout and strict pagination caps,\
\
3. Interoperability with the existing ecosystem through conditional ARCs hooks,\
\
4. Forward compatibility with future ARCs standards, and\
\
5. Precise deprecation strategy for new ASA Metadata Registry versions.\
\
\
### ASA Metadata Registry Application + ARC-90 URI discovery\
\
[Section titled “ASA Metadata Registry Application + ARC-90 URI discovery”](https://dev.algorand.co/arc-standards/arc-0089/#asa-metadata-registry-application--arc-90-uri-discovery)\
\
By fixing a _singleton_ application per Algorand network and using a partial [ARC-90](https://dev.algorand.co/arc-standards/arc-0090)\
URI in the Asset URL (`au`) field, any client can deterministically compute the query\
parameter pointing to the Asset Metadata (`/box?name=` as big-endian _Asset ID_)\
and retrieve the metadata through (a) Algod REST API (`GetApplicationBoxByName`)\
or (b) direct AVM calls to the ASA Metadata Registry. The standard supports two different\
entrypoints for the Metadata discovery and retrieval: the _Asset ID_ (available on\
the Algorand ledger) or the _Asset Metadata URI_ (which could be distributed on the\
Web or by other external channels).\
\
> Refer to the [Usage section](https://dev.algorand.co/arc-standards/arc-0089/#usage) for details.\
\
### Metadata Header/Body split\
\
[Section titled “Metadata Header/Body split”](https://dev.algorand.co/arc-standards/arc-0089/#metadata-headerbody-split)\
\
A compact header (Identifiers, Flags, Hash, Last-Modified Round, Deprecated By) precedes\
the body (JSON). The Last-Modified Round provides a monotonic version marker so readers\
can detect mid-stream changes. The Deprecated By field allows the Asset Managers\
to migrate existing ASA Metadata to a new future version of the ASA Metadata Registry.\
\
### Identifiers vs Flags\
\
[Section titled “Identifiers vs Flags”](https://dev.algorand.co/arc-standards/arc-0089/#identifiers-vs-flags)\
\
The ASA Metadata Registry sets Identifiers (short-metadata hint) while the ASA Manager\
Address governs Flags (ARC-3, ARC-20, ARC-62, ARC-89, immutability). One-way transitions\
(e.g., immutability) are enforced on-chain. This mirrors ASA trust roles and prevents\
metadata rewrites after lock.\
\
### Pagination with hard bounds\
\
[Section titled “Pagination with hard bounds”](https://dev.algorand.co/arc-standards/arc-0089/#pagination-with-hard-bounds)\
\
Metadata pagination is provided for the AVM clients (Algod clients can read entire\
Metadata in a single request). A fixed `PAGE_SIZE` keeps each response within AVM\
limits. The registry guarantees `len(page) ≤ PAGE_SIZE` and supplies a `has_next`\
boolean. AVM clients can read paginated Metadata either _atomically_ ( **RECOMMENDED**),\
using Group Transactions of Inner Transactions, or with _sequential_ Application\
Calls. If the _sequential_ read is used, the Last-Modified Round supports streaming\
and parallel fetch with drift detection. A separate pagination head exposes total\
metadata size, page size, and total pages for preallocation and progress UIs.\
\
### Hash-lock for immutable Metadata\
\
[Section titled “Hash-lock for immutable Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#hash-lock-for-immutable-metadata)\
\
When the ASA is declared _immutable_ at creation, the Asset Metadata Hash (`am`)\
field can commit to the on-chain bytes (domain-separated SHA-512/256 over Flags and\
Metadata). This binds the ledger state to a wallet-verifiable hash without requiring\
JSON normalization.\
\
### Scope and limits\
\
[Section titled “Scope and limits”](https://dev.algorand.co/arc-standards/arc-0089/#scope-and-limits)\
\
The registry intentionally caps data to a single box (~32 KiB minus header). Large\
artifacts (images, media) remain off-chain; their URIs (e.g., `ipfs://...`, `https://...`)\
live in the JSON. This strikes a balance between availability and ledger hygiene,\
discouraging chain-as-a-drive patterns.\
\
### Operability\
\
[Section titled “Operability”](https://dev.algorand.co/arc-standards/arc-0089/#operability)\
\
Metadata deletion returns excess MBR; third-party cleanup of metadata for destroyed\
ASAs is permitted to prevent abandoned state. Network-specific singleton IDs are\
published by the ARC.\
\
### AVM Operations\
\
[Section titled “AVM Operations”](https://dev.algorand.co/arc-standards/arc-0089/#avm-operations)\
\
The registry turns ASA metadata into on-chain first class citizens, using the full\
potential of AVM opcodes ( [`json_ref`](https://specs.algorand.co/avm/avm-appendix-a#json_ref)\
and [`base64_decode`](https://specs.algorand.co/avm/avm-appendix-a#base64_decode)).\
ASA metadata on the registry can be read and written programatically on-chain, making\
them part of the AVM runtime (e.g., an Application can decide to pay a different\
amount based on some ASA metadata property).\
\
## Backwards Compatibility\
\
[Section titled “Backwards Compatibility”](https://dev.algorand.co/arc-standards/arc-0089/#backwards-compatibility)\
\
Backwards compatibility for existing ASA is possible, as long as the size of their\
metadata does not exceed `MAX_METADATA_SIZE`. Existing ASAs **SHOULD NOT** be flagged\
as an [ARC-89 native ASA](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags).\
\
The ASA Metadata Registry can be used by existing ASA as a fallback option in addition\
to the existing URIs requiring external infrastructures (e.g., Indexer, IPFS, etc.).\
\
Since the Asset URL (`au`) field is immutable, the Asset Metadata cannot be discovered\
though an ASA look-up.\
\
Existing ASAs willing to backport metadata to the ASA Metadata Registry **MUST**\
publish the [Asset Metadata URI](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri) as [ARC-2](https://dev.algorand.co/arc-standards/arc-0002) message, as follows:\
\
- The `<arc-number>` **MUST** be equal to `89`;\
- The **RECOMMENDED**`<data-format>` are [MsgPack](https://msgpack.org/)\
(`m`) or [JSON](https://www.json.org/json-en.html) (`j`);\
- The `<data>` **MUST** specify `uri` key value equal to the [Asset Metadata URI](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri).\
\
> **WARNING**: To preserve the existing ASA RBAC (e.g. Manager Address, Freeze Address,\
> etc.) it is necessary to **include all the existing role addresses** in the `AssetConfig`.\
> Not doing so would irreversibly disable the RBAC roles!\
\
Clients discover the backport [ARC-2](https://dev.algorand.co/arc-standards/arc-0002) message inspecting the ASA\
`AssetConfig` transaction history.\
\
Clients **SHOULD** optimistically check ASA metadata existence on the ASA Metadata\
Registry first, to avoid inspecting the transaction history.\
\
### Backporting Message Example - JSON without a version\
\
[Section titled “Backporting Message Example - JSON without a version”](https://dev.algorand.co/arc-standards/arc-0089/#backporting-message-example---json-without-a-version)\
\
> The [ARC-2](https://dev.algorand.co/arc-standards/arc-0002) message to backport existing [ARC-3](https://dev.algorand.co/arc-standards/arc-0003)\
> ASA `12345` metadata to the ASA Metadata Registry would be:\
>\
> ```\
> arc89:j{"uri": "algorand://<netauth>/app/<singleton_arc89_app_id>?box=AAAAAAAAMDk#arc3"}\
> ```\
\
## Reference Implementation\
\
[Section titled “Reference Implementation”](https://dev.algorand.co/arc-standards/arc-0089/#reference-implementation)\
\
### [ARC-4](https://dev.algorand.co/arc-standards/arc-0004) Interface\
\
[Section titled “ARC-4 Interface”](https://dev.algorand.co/arc-standards/arc-0089/#arc-4-interface)\
\
```\
{\
\
  "name": "ASA Metadata Registry",\
\
  "desc": "Singleton Application providing ASA metadata via Algod API and AVM",\
\
  "methods": [\
\
    {\
\
      "name": "arc89_create_metadata",\
\
      "desc": "Create Asset Metadata for an existing ASA, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to create the Asset Metadata for" },\
\
        { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
        { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags. WARNING: LSB and 1 can by set only at creation time. If the MSB is True the Asset Metadata is IMMUTABLE" },\
\
        { "type": "uint16", "name": "metadata_size", "desc": "The Metadata byte size to be created" },\
\
        { "type": "byte[]", "name": "payload", "desc": "The Metadata payload (without Header). WARNING: Payload larger than args capacity must be provided with arc89_extra_payload calls in the Group" },\
\
        { "type": "pay", "name": "mbr_delta_payment", "desc": "Payment of the MBR Delta amount (microALGO) for the Asset Metadata Box creation" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "(uint8,uint64)", "desc": "MBR Delta: sign enum, and amount (microALGO)" }\
\
    },\
\
    {\
\
      "name": "arc89_replace_metadata",\
\
      "desc": "Replace mutable Metadata with smaller or equal size payload for an existing ASA, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to replace the Asset Metadata for" },\
\
        { "type": "uint16", "name": "metadata_size", "desc": "The new Asset Metadata byte size" },\
\
        { "type": "byte[]", "name": "payload", "desc": "The Metadata payload (without Header). WARNING: Payload larger than args capacity must be provided with arc89_extra_payload calls in the Group" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "(uint8,uint64)", "desc": "MBR Delta: sign enum, and amount (microALGO)" }\
\
    },\
\
    {\
\
      "name": "arc89_replace_metadata_larger",\
\
      "desc": "Replace mutable Metadata with larger size payload for an existing ASA, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to replace the Asset Metadata for" },\
\
        { "type": "uint16", "name": "metadata_size", "desc": "The new Metadata byte size" },\
\
        { "type": "byte[]", "name": "payload", "desc": "The Metadata payload (without Header). WARNING: Payload larger than args capacity must be provided with arc89_extra_payload calls in the Group" },\
\
        { "type": "pay", "name": "mbr_delta_payment", "desc": "Payment of the MBR Delta amount (microALGO) for the larger Asset Metadata Box replace" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "(uint8,uint64)", "desc": "MBR Delta: sign enum, and amount (microALGO)" }\
\
    },\
\
    {\
\
      "name": "arc89_replace_metadata_slice",\
\
      "desc": "Replace a slice of the Asset Metadata for an ASA with a payload of the same size, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to replace the Asset Metadata slice for" },\
\
        { "type": "uint16", "name": "offset", "desc": "The 0-based byte offset within the Metadata (body) bytes" },\
\
        { "type": "byte[]", "name": "payload", "desc": "The slice payload" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "void" }\
\
    },\
\
    {\
\
      "name": "arc89_migrate_metadata",\
\
      "desc": "Migrate the Asset Metadata for an ASA to a new ASA Metadata Registry version, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to migrate the Asset Metadata for" },\
\
        { "type": "uint64", "name": "new_registry_id", "desc": "The Application ID of the new ASA Metadata Registry version" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataMigrated",\
\
          "desc": "Event emitted when Asset Metadata has been migrated to a new ASA Metadata Registry version",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "new_registry_id", "desc": "The Application ID of the new ASA Metadata Registry version" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata migration" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata migration" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "void" }\
\
    },\
\
    {\
\
      "name": "arc89_delete_metadata",\
\
      "desc": "Delete Asset Metadata for an ASA, restricted to the ASA Manager Address (if the ASA still exists)",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to delete the Asset Metadata for" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataDeleted",\
\
          "desc": "Event emitted when Asset Metadata is deleted",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the deleted Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata delete" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata deletion" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "(uint8,uint64)", "desc": "MBR Delta: sign enum, and amount (microALGO)" }\
\
    },\
\
    {\
\
      "name": "arc89_extra_payload",\
\
      "desc": "Concatenate extra payload to Asset Metadata head call methods (creation or replacement)",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to provide Metadata extra payload for" },\
\
        { "type": "byte[]", "name": "payload", "desc": "The Metadata extra payload to concatenate" }\
\
      ],\
\
      "returns": { "type": "void" }\
\
    },\
\
    {\
\
      "name": "arc89_set_reversible_flag",\
\
      "desc": "Set a reversible Asset Metadata Flag, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to set the Metadata Flag for" },\
\
        { "type": "uint8", "name": "flag", "desc": "The reversible flag index to set" },\
\
        { "type": "bool", "name": "value", "desc": "The flag value to set" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "void" }\
\
    },\
\
    {\
\
      "name": "arc89_set_irreversible_flag",\
\
      "desc": "Set an irreversible Asset Metadata Flag, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to set the Metadata Flag for" },\
\
        { "type": "uint8", "name": "flag", "desc": "The irreversible flag index to set. WARNING: must be in 2 ... 6" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "void" }\
\
    },\
\
    {\
\
      "name": "arc89_set_immutable",\
\
      "desc": "Set Asset Metadata as immutable, restricted to the ASA Manager Address",\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to set immutable Asset Metadata for" }\
\
      ],\
\
      "events": [\
\
        {\
\
          "name": "Arc89MetadataUpdated",\
\
          "desc": "Event emitted when Asset Metadata is created or updated",\
\
          "args": [\
\
            { "type": "uint64", "name": "asset_id", "desc": "The Asset ID of the created or updated Asset Metadata" },\
\
            { "type": "uint64", "name": "round", "desc": "Round of the Asset Metadata creation or update" },\
\
            { "type": "uint64", "name": "timestamp", "desc": "Timestamp of the Asset Metadata creation or update" },\
\
            { "type": "byte", "name": "reversible_flags", "desc": "The Reversible Flags" },\
\
            { "type": "byte", "name": "irreversible_flags", "desc": "The Irreversible Flags" },\
\
            { "type": "bool", "name": "is_short", "desc": "True if the Asset Metadata is identified as short" },\
\
            { "type": "byte[32]", "name": "hash", "desc": "The Metadata Hash" }\
\
          ]\
\
        }\
\
      ],\
\
      "returns": { "type": "void" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_registry_parameters",\
\
      "desc": "Return the ASA Metadata Registry parameters",\
\
      "readonly": true,\
\
      "args": [],\
\
      "returns": { "type": "(uint8,uint16,uint16,uint16,uint16,uint16,uint16,uint16,uint64,uint64)", "desc": "Tuple of (ASSET_METADATA_BOX_KEY_SIZE, HEADER_SIZE, MAX_METADATA_SIZE, SHORT_METADATA_SIZE, PAGE_SIZE, FIRST_PAYLOAD_MAX_SIZE, EXTRA_PAYLOAD_MAX_SIZE, REPLACE_PAYLOAD_MAX_SIZE, FLAT_MBR, BYTE_MBR)" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_partial_uri",\
\
      "desc": "Return the Asset Metadata ARC-90 partial URI, without compliance fragment (optional)",\
\
      "readonly": true,\
\
      "args": [],\
\
      "returns": { "type": "string", "desc": "Asset Metadata ARC-90 partial URI, without compliance fragment" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_mbr_delta",\
\
      "desc": "Return the Asset Metadata Box MBR Delta for an ASA, given a new Asset Metadata byte size. If the Asset Metadata Box does not exist, the creation MBR Delta is returned.",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to calculate the Asset Metadata MBR Delta for" },\
\
        { "type": "uint16", "name": "new_metadata_size", "desc": "The new Asset Metadata byte size" }\
\
      ],\
\
      "returns": { "type": "(uint8,uint64)", "desc": "MBR Delta: sign enum, and amount (microALGO)" }\
\
    },\
\
    {\
\
      "name": "arc89_check_metadata_exists",\
\
      "desc": "Checks whether the specified ASA exists and whether its associated Asset Metadata is available",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to check the ASA and Asset Metadata existence for" }\
\
      ],\
\
      "returns": { "type": "(bool,bool)", "desc": "Tuple of (ASA exists, Asset Metadata exists)" }\
\
    },\
\
    {\
\
      "name": "arc89_is_metadata_immutable",\
\
      "desc": "Return True if the Asset Metadata for an ASA is immutable, False otherwise",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to check the Asset Metadata immutability for" }\
\
      ],\
\
      "returns": { "type": "bool", "desc": "Asset Metadata for the ASA is immutable" }\
\
    },\
\
    {\
\
      "name": "arc89_is_metadata_short",\
\
      "desc": "Return True if Asset Metadata for an ASA is short (up to 4096 bytes), False otherwise",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to check the Asset Metadata size classification for" }\
\
      ],\
\
      "returns": { "type": "(bool,uint64)", "desc": "Tuple of (Is Short Metadata, Metadata Last Modified Round)" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_header",\
\
      "desc": "Return the Asset Metadata Header for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Asset Metadata Header for" }\
\
      ],\
\
      "returns": { "type": "(byte,byte,byte,byte[32],uint64,uint64)", "desc": "Asset Metadata Header (Identifiers, Reversible Flags, Irreversible Flags, Hash, Last Modified Round, Deprecated By)" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_pagination",\
\
      "desc": "Return the Asset Metadata pagination for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Asset Metadata pagination for" }\
\
      ],\
\
      "returns": { "type": "(uint16,uint16,uint8)", "desc": "Tuple of (total metadata byte size, PAGE_SIZE, total number of pages)" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata",\
\
      "desc": "Return paginated Asset Metadata (without Header) for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Asset Metadata for" },\
\
        { "type": "uint8", "name": "page", "desc": "The 0-based Metadata page number" }\
\
      ],\
\
      "returns": { "type": "(bool,uint64,byte[])", "desc": "Tuple of (has next page, Metadata Last Modified Round, page content)" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_slice",\
\
      "desc": "Return a slice of the Asset Metadata for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Asset Metadata slice for" },\
\
        { "type": "uint16", "name": "offset", "desc": "The 0-based byte offset within the Metadata (body) bytes" },\
\
        { "type": "uint16", "name": "size", "desc": "The slice bytes size to return" }\
\
      ],\
\
      "returns": { "type": "byte[]", "desc": "Asset Metadata slice (size limited to PAGE_SIZE)" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_header_hash",\
\
      "desc": "Return the Metadata Header Hash for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Metadata Header Hash for" }\
\
      ],\
\
      "returns": { "type": "byte[32]", "desc": "Asset Metadata Header Hash" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_page_hash",\
\
      "desc": "Return the SHA512-256 of a Metadata page for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Asset Metadata page hash for" },\
\
        { "type": "uint8", "name": "page", "desc": "The 0-based Metadata page number" }\
\
      ],\
\
      "returns": { "type": "byte[32]", "desc": "The SHA512-256 of the Metadata page" }\
\
    },\
\
    {\
\
      "name": "arc89_get_metadata_hash",\
\
      "desc": "Return the Metadata Hash for an ASA",\
\
      "readonly": true,\
\
      "args": [\
\
        { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the Metadata Hash for" }\
\
      ],\
\
      "returns": { "type": "byte[32]", "desc": "Asset Metadata Hash" }\
\
    },\
\
    {\
\
       "name": "arc89_get_metadata_string_by_key",\
\
       "desc": "Return the UTF‑8 string value for a top‑level JSON key of type JSON String from short Metadata for an ASA; errors if the key does not exist or is not a JSON String",\
\
       "readonly": true,\
\
       "args": [\
\
          { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the key value for" },\
\
          { "type": "string", "name": "key", "desc": "The top‑level JSON key whose string value to fetch" }\
\
       ],\
\
       "returns": { "type": "string", "desc": "The string value from valid UTF‑8 JSON Metadata (size limited to PAGE_SIZE)" }\
\
    },\
\
    {\
\
       "name": "arc89_get_metadata_uint64_by_key",\
\
       "desc": "Return the uint64 value for a top‑level JSON key of type JSON Uint64 from short Metadata for an ASA; errors if the key does not exist or is not a JSON Uint64",\
\
       "readonly": true,\
\
       "args": [\
\
          { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the key value for" },\
\
          { "type": "string", "name": "key", "desc": "The top‑level JSON key whose uint64 value to fetch" }\
\
       ],\
\
       "returns": { "type": "uint64", "desc": "The uint64 value from valid UTF‑8 JSON Metadata" }\
\
    },\
\
    {\
\
       "name": "arc89_get_metadata_object_by_key",\
\
       "desc": "Return the UTF-8 object value for a top‑level JSON key of type JSON Object from short Metadata for an ASA; errors if the key does not exist or is not a JSON Object",\
\
       "readonly": true,\
\
       "args": [\
\
          { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the key value for" },\
\
          { "type": "string", "name": "key", "desc": "The top‑level JSON key whose object value to fetch" }\
\
       ],\
\
       "returns": { "type": "string", "desc": "The object value from valid UTF‑8 JSON Metadata (size limited to PAGE_SIZE)" }\
\
    },\
\
    {\
\
       "name": "arc89_get_metadata_b64_bytes_by_key",\
\
       "desc": "Return the base64-decoded bytes for a top-level JSON key of type JSON String from short Metadata for an ASA; errors if the key does not exist, is not a JSON String, or is not valid base64 for the chosen encoding",\
\
       "readonly": true,\
\
       "args": [\
\
          { "type": "uint64", "name": "asset_id", "desc": "The Asset ID to get the key value for" },\
\
          { "type": "string", "name": "key", "desc": "The top-level JSON key whose base64 string value to fetch and decode" },\
\
          { "type": "uint8", "name": "b64_encoding", "desc": "base64 encoding enum: 0 = URLEncoding, 1 = StdEncoding" }\
\
       ],\
\
       "returns": { "type": "byte[]", "desc": "The base64-decoded bytes from valid UTF‑8 JSON Metadata (size limited to PAGE_SIZE)" }\
\
    }\
\
  ]\
\
}\
```\
\
The ASA Metadata Registry **MUST** validate [ARC-4](https://dev.algorand.co/arc-standards/arc-0004) method arguments\
size according to their types.\
\
> Refer to the [AppSpec section](https://dev.algorand.co/arc-standards/arc-0089/#arc-56-appspec) for the detailed [ARC-56](https://dev.algorand.co/arc-standards/arc-0056)\
> Application Specification of the singleton reference implementation.\
\
##### Create Metadata\
\
[Section titled “Create Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#create-metadata)\
\
To create the Asset Metadata:\
\
- The ASA **MUST** _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST NOT** _exist_, and\
\
\
If the provided `metadata_size > MAX_METADATA_SIZE` the creation **MUST** be rejected.\
\
If the provided `metadata_size ≤ SHORT_METADATA_SIZE`, the [Short Metadata Identifier](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata) **MUST** be set to `True`.\
\
The [Metadata](https://dev.algorand.co/arc-standards/arc-0089/#metadata) **MUST** be initialized with the provided `payload` value\
(empty is allowed).\
\
If the creation is part of a Group, the [extra payload](https://dev.algorand.co/arc-standards/arc-0089/#extra-payload) provided\
by _later_ transactions for the same `asset_id` in the same Group **MUST** be concatenated\
in order.\
\
The creation **MUST** be rejected as soon as the cumulative staged size for the same\
`asset_id` in the same Group exceeds `metadata_size`.\
\
The cumulative staged payload **MUST** be equal to the provided `metadata_size` (no\
truncation), otherwise the creation is rejected.\
\
The [Reversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#reversible-flags) **MUST** be initialized with the provided\
`reversible_flags` value (`byte`).\
\
The [Irreversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags) **MUST** be initialized with the provided\
`irreversible_flags` value (`byte`).\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be initialized according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be initialized to the current\
round.\
\
The [Deprecated By](https://dev.algorand.co/arc-standards/arc-0089/#deprecated-by) field **MUST** be initialized to `0`.\
\
If the ASA is declared as [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) compliant, the _Asset Name_ (`an`)\
or the _Asset URL_ (`au`) **MUST** comply with the [_ARC-3 ASA Parameters Conventions_](https://dev.algorand.co/arc-standards/arc-0003#asa-parameters-conventions).\
\
If the ASA is declared as [ARC-89 Native ASA](https://dev.algorand.co/arc-standards/arc-0089/#arc-89-native-asa-creation), the _Asset URL_\
(`au`) **MUST** comply with the specified [Asset Metadata URI](https://dev.algorand.co/arc-standards/arc-0089/#asset-metadata-uri)\
(no `#arc` fragment validation enforced).\
\
If the ASA is declared as [ARC-54 Burnable ASA](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags), the ASA **MUST**\
**NOT** have a Clawback Address.\
\
The [MBR Delta](https://dev.algorand.co/arc-standards/arc-0089/#mbr-delta) _amount_ of the created Asset Metadata Box **MUST** be\
provided contextually to the ASA Metadata Registry Address.\
\
An `Arc89MetadataUpdated` event **MUST** be emitted.\
\
> ⚠️ WARNING: If the MSB of the Irreversible Flags is `True` the Asset Metadata is\
> _immutable_, for further details refer to the [Irreversible Flags section](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags).\
\
##### Replace Metadata\
\
[Section titled “Replace Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#replace-metadata)\
\
To replace the Asset Metadata for an ASA with smaller or equal size Metadata:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_.\
\
\
If the provided `metadata_size > MAX_METADATA_SIZE` the update **MUST** be rejected.\
\
If the provided `metadata_size > existing_metadata_size` the update **MUST** be rejected.\
\
If the provided `metadata_size ≤ SHORT_METADATA_SIZE`, the [Short Metadata Identifier](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata) **MUST** be set to `True`.\
\
The [Metadata](https://dev.algorand.co/arc-standards/arc-0089/#metadata) **MUST** be replaced with the provided `payload` value\
(empty is allowed).\
\
If the replacement is part of a Group, the [extra payload](https://dev.algorand.co/arc-standards/arc-0089/#extra-payload) provided\
by _later_ transactions for the same `asset_id` in the same Group **MUST** be concatenated\
in order.\
\
The replacement **MUST** be rejected as soon as the cumulative staged payload for\
the same `asset_id` in the same Group exceeds `metadata_size`.\
\
The cumulative staged payload **MUST** be equal to the provided `metadata_size` (no\
truncation), otherwise the replacement is rejected.\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be updated according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be updated to the current\
round.\
\
The [MBR Delta](https://dev.algorand.co/arc-standards/arc-0089/#mbr-delta) _amount_ of the updated Asset Metadata Box **MUST** be\
managed contextually:\
\
- If _sign_ is `NULL`, no MBR management is required;\
\
- If _sign_ is `NEG`, the excess of MBR amount **MUST** be returned from the ASA\
Metadata Registry Address to the ASA Manager Address.\
\
\
An `Arc89MetadataUpdated` event **MUST** be emitted.\
\
> MBR is returned with an Inner Transaction whose fee is externally provided.\
\
##### Replace Metadata Larger\
\
[Section titled “Replace Metadata Larger”](https://dev.algorand.co/arc-standards/arc-0089/#replace-metadata-larger)\
\
To replace the Asset Metadata for an ASA with larger size Metadata:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_.\
\
\
If the provided `metadata_size > MAX_METADATA_SIZE` the update **MUST** be rejected.\
\
If the provided `metadata_size ≤ existing_metadata_size` the update **MUST** be rejected.\
\
If the provided `metadata_size ≤ SHORT_METADATA_SIZE`, the [Short Metadata Identifier](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata) **MUST** be set to `True`.\
\
The [Metadata](https://dev.algorand.co/arc-standards/arc-0089/#metadata) **MUST** be replaced with the provided `payload` value\
(empty is allowed).\
\
If the creation is part of a Group, the [extra payload](https://dev.algorand.co/arc-standards/arc-0089/#extra-payload) provided\
by _later_ transactions for the same `asset_id` in the same Group **MUST** be concatenated\
in order.\
\
The replacement **MUST** be rejected as soon as the cumulative staged payload for\
the same `asset_id` in the same Group exceeds `metadata_size`.\
\
The cumulative staged payload **MUST** be equal to the provided `metadata_size` (no\
truncation), otherwise the replacement is rejected.\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be updated according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be updated to the current\
round.\
\
The [MBR Delta](https://dev.algorand.co/arc-standards/arc-0089/#mbr-delta) _amount_ of the updated Asset Metadata Box **MUST** be\
provided contextually to the ASA Metadata Registry Address.\
\
An `Arc89MetadataUpdated` event **MUST** be emitted.\
\
##### Replace Metadata Slice\
\
[Section titled “Replace Metadata Slice”](https://dev.algorand.co/arc-standards/arc-0089/#replace-metadata-slice)\
\
To replace the Metadata slice for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_, and\
\
- The byte range specified by `offset` (`uint16`) and `payload` length **MUST NOT**\
exceed the `metadata_size`.\
\
\
The Metadata slice **MUST** be replaced with the provided `payload` value.\
\
The Metadata slice replacement **MUST** preserve the `metadata_size`.\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be updated according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be updated to the current\
round.\
\
An `Arc89MetadataUpdated` event **MUST** be emitted.\
\
> A group transaction can be used to replace a large Metadata slice atomically.\
\
##### Migrate Metadata\
\
[Section titled “Migrate Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#migrate-metadata)\
\
To migrate the Asset Metadata for an ASA to a new ASA Metadata Registry version:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_, and\
\
- The `new_registry_id` (`uint64`) **MUST** be different from the current ASA Metadata\
Registry Application ID (`uint64`).\
\
\
The [Deprecated By](https://dev.algorand.co/arc-standards/arc-0089/#deprecated-by) field **MUST** be set to the `new_registry_id`\
(`uint64`) value.\
\
An `Arc89MetadataMigrated` event **MUST** be emitted.\
\
> The migration can be performed more than once and reverted.\
\
> ⚠️ The Deprecated By field is not included in the Metadata Hash computation, and\
> does not affect the Last Modified Round.\
\
##### Delete Metadata\
\
[Section titled “Delete Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#delete-metadata)\
\
To delete the Asset Metadata for an ASA:\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- If the ASA still _exists_:\
  - The Asset Metadata **MUST NOT** be _immutable_, and\
\
  - The authorization **MUST** be restricted to the ASA Manager Address.\
\
> ⚠️ WARNING: Not even the ASA Manager Address can delete the _immutable_ Asset Metadata\
> of an _existing_ ASA, while anyone can delete Asset Metadata if the ASA has been\
> _destroyed_, regardless of being _immutable_ or not.\
\
The Asset Metadata Box **MUST** be deleted.\
\
The [MBR Delta](https://dev.algorand.co/arc-standards/arc-0089/#mbr-delta) _amount_ of the deleted Asset Metadata Box **MUST** be\
managed contextually:\
\
- If the ASA _exists_, it **MUST** be returned to the ASA Manager Address, otherwise\
\
- It **MUST** be returned to the caller.\
\
\
An `Arc89MetadataDeleted` event **MUST** be emitted.\
\
> MBR is returned with an Inner Transaction whose fee is externally provided.\
\
> ⚠️ The ASA Metadata Registry is not aware of the ASA destruction events, therefore\
> it cannot guarantee a grace period in favor of the ASA Manager Address. ASA Manager\
> Address **SHOULD** group the ASA destruction and Asset Metadata deletion transactions\
> in the same Group to avoid any race condition.\
\
##### Extra Payload\
\
[Section titled “Extra Payload”](https://dev.algorand.co/arc-standards/arc-0089/#extra-payload)\
\
To provide an extra payload to append to Asset Metadata creation or replace for an\
ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address.\
\
\
The extra payload calls **MUST** appear _after_ the corresponding header call (create\
or replace) for that same `asset_id` in the same Group (top-level or inner). Concatenation\
order is transaction-index order.\
\
All extra payload calls for a given `asset_id` **MUST** be top-level if the header\
call is top-level, or inner if the header is inner.\
\
> The Asset Metadata Box already exists since the extra payload call is always preceded\
> by a header call (create or replace).\
\
> The header call (create or replace) checks that the extra payload call is keyed\
> to the same Asset ID to manage interleaving and idempotence on the _same_ Group.\
> Interleaving on different Group levels (top-level / inner) are **not supported**.\
>\
> **Example:** Creating and updating different Assets Metadata in the same Group\
>\
> ```\
> [Tx1: Create Payload A, Extra Payload A1, Update Payload B, Extra Payload A2, Extra Payload B1]\
> ```\
>\
> Would result in the following Asset Metadata Boxes:\
>\
> - Asset ID A: `[Header A, Create Payload A || Extra Payload A1 || Extra Payload A2]`\
> - Asset ID B: `[Header B, Update Payload B || Extra Payload B1]`\
\
##### Set Reversible Flag\
\
[Section titled “Set Reversible Flag”](https://dev.algorand.co/arc-standards/arc-0089/#set-reversible-flag)\
\
To set a _reversible_ Asset Metadata Flag for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_, and\
\
- The _reversible_`flag` (`uint8`) **MUST** be in `0 ... 7`.\
\
\
The reversible `flag` **MUST** be set to the provided `value` (`bool`).\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be updated according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be updated to the current\
round.\
\
An `Arc89MetadataUpdated` event **MUST** be emitted if not idempotent.\
\
##### Set Irreversible Flag\
\
[Section titled “Set Irreversible Flag”](https://dev.algorand.co/arc-standards/arc-0089/#set-irreversible-flag)\
\
To set an _irreversible_ Asset Metadata Flag for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_, and\
\
- The _irreversible_`flag` (`uint8`) **MUST** be in `2 ... 6`.\
\
\
The irreversible `flag` **MUST** be set to `True` (idempotent).\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be updated according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be updated to the current\
round.\
\
If the ASA is declared as [ARC-54 Burnable ASA](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags), the ASA **MUST**\
**NOT** have a Clawback Address.\
\
An `Arc89MetadataUpdated` event **MUST** be emitted if not idempotent.\
\
> ⚠️ WARNING: flags 0, 1 are set only at creation time, for further details refer\
> to the [Irreversible Flags section](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags).\
\
##### Set Immutable\
\
[Section titled “Set Immutable”](https://dev.algorand.co/arc-standards/arc-0089/#set-immutable)\
\
To set the Asset Metadata as _immutable_:\
\
- The ASA **MUST** still _exist_, and\
\
- The authorization **MUST** be restricted to the ASA Manager Address, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST NOT** be _immutable_.\
\
\
The Asset Metadata _immutability_ flag in the [Irreversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags) **MUST** be set to `True`.\
\
The [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash) **MUST** be updated according to the [Metadata\\
Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) **MUST** be updated to the current\
round.\
\
An `Arc89MetadataUpdated` event **MUST** be emitted.\
\
> ⚠️ WARNING: Asset Metadata immutability cannot be revoked once set.\
\
##### Get Metadata Registry Parameters\
\
[Section titled “Get Metadata Registry Parameters”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-registry-parameters)\
\
The method **MUST** return the ASA Metadata Registry parameters as a tuple:\
\
- The firs value is the `ASSET_METADATA_BOX_KEY_SIZE` (`uint8`),\
\
- The second value is the `HEADER_SIZE` (`uint16`),\`\
\
- The third value is the `MAX_METADATA_SIZE` (`uint16`),\`\
\
- The fourth value is the `SHORT_METADATA_SIZE` (`uint16`),\`\
\
- The fifth value is the `PAGE_SIZE` (`uint16`),\
\
- The sixth value is the `FIRST_PAYLOAD_MAX_SIZE` (`uint16`),\
\
- The seventh value is the `EXTRA_PAYLOAD_MAX_SIZE` (`uint16`),\
\
- The eighth value is the `REPLACE_PAYLOAD_MAX_SIZE` (`uint16`),\
\
- The nineth value is the `FLAT_MBR` (`uint64`),\
\
- The tenth value is the `BYTE_MBR` (`uint64`).\
\
\
Clients **SHOULD** use these parameter values and avoid locally computed constants.\
\
##### Get Metadata Partial URI\
\
[Section titled “Get Metadata Partial URI”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-partial-uri)\
\
The method **MUST** return the Asset Metadata Partial URI (`string`) without the\
optional `#arc` compliance fragment:\
\
`algorand://<netauth>/app/<singleton_arc89_app_id>?box=`\
\
Clients **SHOULD** use this value as [Asset URL](https://dev.algorand.co/arc-standards/arc-0089/#asset-url) and avoid locally computed\
constants.\
\
##### Get Metadata MBR Delta\
\
[Section titled “Get Metadata MBR Delta”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-mbr-delta)\
\
To get the [MBR Delta](https://dev.algorand.co/arc-standards/arc-0089/#mbr-delta) for an ASA:\
\
The `new_metadata_size` (`uint16`) **MUST** be less than or equal to `MAX_METADATA_SIZE`.\
\
- If the Asset Metadata Box _exists_, `flat_mbr = 0` and then:\
  - If the `new_metadata_size == metadata_size`, then:\
    - The returned _sign_ **MUST** be `NULL`, and\
    - `delta_size = 0`.\
  - If the `new_metadata_size > metadata_size`, then:\
    - The returned _sign_ **MUST** be `POS`, and\
    - `delta_size = new_metadata_size - metadata_size`.\
  - If the `new_metadata_size < metadata_size`, then:\
    - The returned _sign_ **MUST** be `NEG`, and\
    - `delta_size = metadata_size - new_metadata_size`.\
- If the Asset Metadata Box _does not exist_, `flat_mbr = FLAT_MBR` and then:\
  - The returned _sign_ **MUST** be `POS`, and\
  - `delta_size = ASSET_METADATA_BOX_KEY_SIZE + HEADER_SIZE + new_metadata_size`.\
\
The returned _amount_ **MUST** be `flat_mbr + BYTE_MBR * delta_size`.\
\
> The _static_ MBR Delta calculation provided to the clients is based on:\
>\
> - `FLAT_MBR` (`uint64`), a parameter of the ASA Metadata Registry (microALGO) equal\
>   to AVM MBR for Box creation;\
>\
> - `BYTE_MBR` (`uint64`), a parameter of the ASA Metadata Registry (microALGO) equal\
>   to AVM MBR for byte used by the Box.\
\
> The _dynamic_ ( **RECOMMENDED**) MBR Delta calculation is provided to the clients\
> by simulating the create, update, or delete methods.\
\
##### Check Metadata Exists\
\
[Section titled “Check Metadata Exists”](https://dev.algorand.co/arc-standards/arc-0089/#check-metadata-exists)\
\
The method **MUST** return a pair of booleans (`(bool,bool)`):\
\
- The first value is `True` if the ASA _still exists_, `False` otherwise;\
\
- The second value is `True` if the Asset Metadata for the ASA _exists_, `False` otherwise.\
\
\
##### Is Metadata Immutable\
\
[Section titled “Is Metadata Immutable”](https://dev.algorand.co/arc-standards/arc-0089/#is-metadata-immutable)\
\
To check if the Asset Metadata is [_immutable_](https://dev.algorand.co/arc-standards/arc-0089/#metadata-immutability):\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_.\
\
\
The method **MUST** return `True` if the Asset Metadata for an ASA is _immutable_\
or the ASA Manager Address is set to the Zero Address, `False` otherwise.\
\
##### Is Metadata Short\
\
[Section titled “Is Metadata Short”](https://dev.algorand.co/arc-standards/arc-0089/#is-metadata-short)\
\
To check if the Asset Metadata is [_short_](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata):\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_.\
\
\
The method **MUST** return the value of the [Short Metadata](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata) identifier\
and the Last Modified Round (`uint64`).\
\
##### Get Metadata Header\
\
[Section titled “Get Metadata Header”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-header)\
\
To get the Asset Metadata Header for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_.\
\
\
The Metadata Header **MUST** be returned as a tuple `(byte,byte,byte,byte[32],uint64,uint64)`,\
where:\
\
- The first value (`byte`) is the [Metadata Identifiers](https://dev.algorand.co/arc-standards/arc-0089/#metadata-identifiers),\
\
- The second value (`byte`) is the [Reversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#reversible-flags),\
\
- The third value (`byte`) is the [Irreversible Flags](https://dev.algorand.co/arc-standards/arc-0089/#irreversible-flags),\
\
- The fourth value (`byte[32]`) is the [Metadata Hash](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash),\
\
- The fifth value (`uint64`) is the [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round),\
\
- The sixth value (`uint64`) is the [Deprecated By](https://dev.algorand.co/arc-standards/arc-0089/#deprecated-by) field.\
\
\
##### Get Metadata Pagination\
\
[Section titled “Get Metadata Pagination”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-pagination)\
\
To get the Asset Metadata pagination for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_.\
\
\
The pagination **MUST** be returned as a tuple `(uint16,uint16,uint8)`, where:\
\
- The first value (`uint16`) is the Metadata _total length_ (`metadata_size`, in\
bytes),\
\
- The second value (`uint16`) is the `PAGE_SIZE` (in bytes, as defined in the [Metadata\\
Pagination section](https://dev.algorand.co/arc-standards/arc-0089/#pagination)),\
\
- The third value (`uint8`) is the total number of Metadata pages (`total_pages`).\
\
\
##### Get Metadata\
\
[Section titled “Get Metadata”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata)\
\
To get the Asset Metadata for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_,\
\
\
Let `total_pages` be as returned by [Get Metadata Pagination](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-pagination).\
\
- If `total_pages > 0`, the provided 0-indexed `page` (`uint8`) **MUST** satisfy\
`page < total_pages`.\
\
- If `total_pages == 0`, the provided `page` **MUST** be `0`.\
\
\
The paginated Asset Metadata **MUST** be returned as a tuple `(bool,uint64,byte[])`,\
where:\
\
- The first value (`bool`) is a flag indicating if the Metadata _has next page_,\
\
- The second value (`uint64`) is the [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round)\
of the Metadata,\
\
- The third value (`byte[]`) is the content of Metadata page with length equal to\
`content_size` bytes. If `total_pages == 0` (i.e., `metadata_size == 0`), the implementation\
**MUST** return an empty `byte[]`. The empty value does **NOT** imply the existence\
of a Metadata Page Hash (see [Get Metadata Page Hash](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-page-hash)).\
\
\
The _has next page_ flag **MUST** be `True` if, at the time of serving the request,\
`(page + 1) * PAGE_SIZE < metadata_size`, and `False` otherwise.\
\
The _content_ byte size **MUST NOT** exceed the `PAGE_SIZE`.\
\
The implementation **MUST** ensure that `content_size ≤ PAGE_SIZE` for every response.\
\
For `page`s `p` where `(p+1)*PAGE_SIZE ≤ metadata_size` at serve time, the response\
the implementation **SHOULD** return `content_size = PAGE_SIZE`. The final page **MUST**\
return `content_size = metadata_size − PAGE_SIZE*(total_pages−1)`.\
\
> This invariant guarantees the read operation remains within protocol return-size\
> limits, enables deterministic computation of total pages and _has next page_, and\
> allows client implementations to safely preallocate buffers and parallelize fetches\
> without risk of oversized responses.\
\
It is **RECOMMENDED** to group `total_pages` reading in a single _atomic read_ using\
a Group Transaction or Inner Transactions.\
\
If the `total_pages` reading is _not atomic_, clients **MUST** verify that [Last\\
Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) remains constant across pages; if it changes,\
clients **SHOULD** re-use the `arc89_get_metadata_pagination` method and restart\
reading from page `0`. Clients **MAY** simulate the _sequential_ calls to guarantee\
atomicity under their own round expectation.\
\
> For further details refer to the [usage section](https://dev.algorand.co/arc-standards/arc-0089/#usage-mode-2-avm).\
\
##### Get Metadata Slice\
\
[Section titled “Get Metadata Slice”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-slice)\
\
To get a Metadata Slice for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The condition `size ≤ PAGE_SIZE` **MUST** hold, and\
\
- The byte range specified with `offset` (`uint16`) and `size` (`uint16`) **MUST**\
**NOT** exceed the `metadata_size`.\
\
\
The slice extracted from the Metadata **MUST** be returned.\
\
##### Get Metadata Header Hash\
\
[Section titled “Get Metadata Header Hash”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-header-hash)\
\
To get the Metadata Header Hash (`hh`) for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_.\
\
\
The Metadata Header Hash (`hh`) **MUST** be returned according to the [Metadata Hash\\
Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
##### Get Metadata Page Hash\
\
[Section titled “Get Metadata Page Hash”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-page-hash)\
\
To get the Metadata Page Hash for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
\
Let `total_pages` be as returned by [Get Metadata Pagination](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-pagination).\
\
- If `total_pages > 0`, the provided 0-indexed `page` (`uint8`) **MUST** satisfy\
`page < total_pages`.\
\
- If `total_pages == 0`, the method **MUST** fail.\
\
\
The Metadata Page Hash (`ph[page]`) **MUST** be returned according to the\
[Metadata Hash Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
The Metadata Page Hash (`ph[i]`) **MUST** be returned according to the [Metadata Hash\\
Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
##### Get Metadata Hash\
\
[Section titled “Get Metadata Hash”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-hash)\
\
To get the Metadata Hash for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_.\
\
\
The Metadata Hash (`am`) **MUST** be returned according to the [Metadata Hash\\
Computation](https://dev.algorand.co/arc-standards/arc-0089/#metadata-hash-computation).\
\
##### Get Metadata String By Key\
\
[Section titled “Get Metadata String By Key”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-string-by-key)\
\
To get a Metadata JSON String value by top-level key for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST** be [_short_](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata), and\
\
- The key’s value length **MUST NOT** exceed `PAGE_SIZE`.\
\
\
The top-level key’s value (JSON String) extracted from the JSON Metadata object **MUST**\
be returned (as `string`).\
\
> ⚠️ WARNING: This getter does not provide pagination or truncation of the returned\
> value.\
\
> ⚠️ WARNING: The following conditions cause a _runtime error_:\
>\
> - The Metadata (body) is not a valid UTF-8 encoded JSON object,\
> - The top-level key does not exist,\
> - The top-level key’s value is not a JSON String.\
\
##### Get Metadata Uint64 By Key\
\
[Section titled “Get Metadata Uint64 By Key”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-uint64-by-key)\
\
To get a Metadata uint64 value by top-level JSON key for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST** be [_short_](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata).\
\
\
The top-level key’s value (JSON Uint64) extracted from the JSON Metadata object **MUST**\
be returned (as `uint64`).\
\
> ⚠️ WARNING: The following conditions cause a _runtime error_:\
>\
> - The Metadata (body) is not a valid UTF-8 encoded JSON object,\
> - The top-level key does not exist,\
> - The top-level key’s value is not a JSON Uint64.\
\
##### Get Metadata Object By Key\
\
[Section titled “Get Metadata Object By Key”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-object-by-key)\
\
To get a Metadata object value by top-level JSON key for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST** be [_short_](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata), and\
\
- The key’s value length **MUST NOT** exceed `PAGE_SIZE`.\
\
\
The top-level key’s value (JSON Object) extracted from the JSON Metadata object **MUST**\
be returned (as `string`).\
\
> ⚠️ WARNING: This getter does not provide pagination or truncation of the returned\
> value.\
\
> ⚠️ WARNING: The following conditions cause a _runtime error_:\
>\
> - The Metadata (body) is not a valid UTF-8 encoded JSON object,\
> - The top-level key does not exist,\
> - The top-level key’s value is not a JSON Object.\
\
##### Get Metadata b64 Bytes By Key\
\
[Section titled “Get Metadata b64 Bytes By Key”](https://dev.algorand.co/arc-standards/arc-0089/#get-metadata-b64-bytes-by-key)\
\
To get a Metadata base64-decoded value by top-level JSON key for an ASA:\
\
- The ASA **MUST** still _exist_, and\
\
- The Asset Metadata Box **MUST** _exist_, and\
\
- The Asset Metadata **MUST** be [_short_](https://dev.algorand.co/arc-standards/arc-0089/#short-metadata), and\
\
- The `b64_encoding` enum (`uint8`) **MUST** be either `0` (`URLEncoding`) or `1`\
(`StdEncoding`), and\
\
- The key’s base64-decoded value length **MUST NOT** exceed `PAGE_SIZE`.\
\
\
The top-level key’s value (JSON String) extracted from the JSON Metadata object **MUST**\
be base64-decoded using the selected `b64_encoding` and returned (as `byte[]`).\
\
> ⚠️ WARNING: This getter does not provide pagination or truncation of the returned\
> value.\
\
> ⚠️ WARNING: The following conditions cause a _runtime error_:\
>\
> - The Metadata (body) is not a valid UTF-8 encoded JSON object,\
> - The top-level key does not exist,\
> - The top-level key’s value is not a JSON String,\
> - The top-level key’s value is not a valid base64-encoding string for the chosen\
>   encoding.\
\
> For further details on the base64 encodings refer to the `base64_decode` [AVM opcode specifications](https://specs.algorand.co/avm/avm-appendix-a#base64_decode).\
\
### [ARC-28](https://dev.algorand.co/arc-standards/arc-0028) Events\
\
[Section titled “ARC-28 Events”](https://dev.algorand.co/arc-standards/arc-0089/#arc-28-events)\
\
| ARC-28 EVENT SIGNATURE | 4-BYTE SELECTOR (HEX) |\
| --- | --- |\
| `Arc89MetadataUpdated(uint64,uint64,uint64,byte,byte,bool,byte[32])` | `8b035084` |\
| `Arc89MetadataMigrated(uint64,uint64,uint64,uint64)` | `c87023bf` |\
| `Arc89MetadataDeleted(uint64,uint64,uint64)` | `bc3f20d1` |\
\
### [ARC-56](https://dev.algorand.co/arc-standards/arc-0056) AppSpec\
\
[Section titled “ARC-56 AppSpec”](https://dev.algorand.co/arc-standards/arc-0089/#arc-56-appspec)\
\
The ASA Metadata Registry AppSpec is published in the reference implementation\
[repository](https://github.com/algorandfoundation/arc89/blob/main/smart_contracts/artifacts/asa_metadata_registry/AsaMetadataRegistry.arc56.json).\
\
### Usage\
\
[Section titled “Usage”](https://dev.algorand.co/arc-standards/arc-0089/#usage)\
\
The ASA Metadata Registry has two modes of operation:\
\
- **Algod API**: the _entire_ Asset Metadata is retrieved via a single request to\
the Algod REST API endpoints (or via SDK wrappers);\
\
- **AVM**: the _paginated_ Asset Metadata is retrieved via _grouped_ ( **RECOMMENDED**)\
or _sequential_ Application Calls (real or simulated) to the ASA Metadata Registry.\
\
\
#### Usage Mode 1: Algod API\
\
[Section titled “Usage Mode 1: Algod API”](https://dev.algorand.co/arc-standards/arc-0089/#usage-mode-1-algod-api)\
\
The Algod clients retrieve the Asset Metadata from two entrypoints:\
\
1. The _Asset ID_;\
\
2. The _Asset Metadata URI_.\
\
\
> A minimal [\[Python SDK](https://github.com/algorandfoundation/arc89/tree/main/src/asa_metadata_registry).\
> is provided with the reference implementation.\
\
##### Example 1: Get [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) Metadata from the Asset ID\
\
[Section titled “Example 1: Get ARC-3 Metadata from the Asset ID”](https://dev.algorand.co/arc-standards/arc-0089/#example-1-get-arc-3-metadata-from-the-asset-id)\
\
Given the _Asset ID_`12345`, the client:\
\
1. Calls the Algod API [GetAssetByID](https://dev.algorand.co/reference/rest-api/algod/#getassetbyid)\
endpoint to get the _Asset URL_ field (`url`) from the response and drops the `#arc3`\
suffix (if present), obtaining:\
\
`algorand://<netauth>/app/<singleton_arc89_app_id>?box=`;\
\
2. Encodes the _Asset ID_ as `base64url` to get the Asset Metadata Box Name (`<base64url_encoded_asset_id>`);\
\
3. Calls the Algod API [GetApplicationBoxByName](https://dev.algorand.co/reference/rest-api/algod/#getapplicationboxbyname)\
endpoint to get the content of the _Asset Metadata Box_ from the response:\
\
\
```\
curl -X GET http://localhost/v2/applications/<singleton_arc89_app_id>/box?name=<base64_encoded_asset_id> \\
\
 -H 'Accept: application/json' \\
\
 -H 'X-Algo-API-Token: API_KEY'\
```\
\
The `value` field of the response contains the Asset Metadata Box content as concatenation\
of the following fields:\
\
- Metadata Header (`byte[HEADER_SIZE]`);\
- Metadata Body (`byte[]`): [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) JSON Metadata.\
\
> Clients **MUST** strip the Metadata Header (`byte[HEADER_SIZE]`) from the Asset\
> Metadata Box value before parsing the JSON Metadata.\
\
##### Example 2: Get [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) Metadata from Asset Metadata URI\
\
[Section titled “Example 2: Get ARC-3 Metadata from Asset Metadata URI”](https://dev.algorand.co/arc-standards/arc-0089/#example-2-get-arc-3-metadata-from-asset-metadata-uri)\
\
Given the _Asset Metadata URI_`algorand://<netauth>/app/<singleton_arc89_app_id>?box=<base64url_encoded_asset_id>#arc3`,\
the client:\
\
1. Calls the Algod API [GetApplicationBoxByName](https://dev.algorand.co/reference/rest-api/algod/#getapplicationboxbyname)\
endpoint to get the content of the _Asset Metadata Box_ from the response:\
\
```\
curl -X GET http://localhost/v2/applications/<singleton_arc89_app_id>/box?name=<base64_encoded_asset_id> \\
\
 -H 'Accept: application/json' \\
\
 -H 'X-Algo-API-Token: API_KEY'\
```\
\
The `value` field of the response contains the Asset Metadata Box content as concatenation\
of the following fields:\
\
- Metadata Header (`byte[HEADER_SIZE]`);\
- Metadata Body (`byte[]`): [ARC-3](https://dev.algorand.co/arc-standards/arc-0003) JSON Metadata.\
\
> Clients **MUST** strip the Metadata Header (`byte[HEADER_SIZE]`) from the Asset\
> Metadata Box value before parsing the JSON Metadata.\
\
#### Usage Mode 2: AVM\
\
[Section titled “Usage Mode 2: AVM”](https://dev.algorand.co/arc-standards/arc-0089/#usage-mode-2-avm)\
\
The AVM clients issue Application calls (real or simulated) to the ASA Metadata Registry\
in two ways:\
\
1. ( **RECOMMENDED**) Atomically, via grouped (Top-level or Inner) Application Calls;\
\
2. Sequentially, via standalone Application Calls;\
\
\
##### Example 1: Atomic read with Top-level Group\
\
[Section titled “Example 1: Atomic read with Top-level Group”](https://dev.algorand.co/arc-standards/arc-0089/#example-1-atomic-read-with-top-level-group)\
\
Given the _Asset ID_`12345`, the client:\
\
1. Call `arc89_get_metadata_pagination` with `asset_id=12345`, ASA Metadata Registry\
returns:\
   - The total Metadata byte size (`uint16`);\
   - The `PAGE_SIZE` (`uint16`), as defined in the [Metadata Pagination section](https://dev.algorand.co/arc-standards/arc-0089/#pagination);\
   - The total Metadata pages `N` (`uint8`).\
2. Check that `N ≤ MAX_TXN_PER_GROUP`.\
\
3. Group call `N * arc89_get_metadata` with `asset_id=12345` and `page=0...N-1`\
(0-based).\
\
\
**PROS:**\
\
- Best UX, no delay, atomic fetch guarantees integrity and no data drift.\
\
**CONS:**\
\
- The fetchable `metadata_size` is capped by `MAX_TXN_PER_GROUP` capacity for a Top-level\
Group, (while Inner Groups can fetch up to `MAX_METADATA_SIZE`).\
\
##### Example 2: Sequential read, while “has next” page\
\
[Section titled “Example 2: Sequential read, while “has next” page”](https://dev.algorand.co/arc-standards/arc-0089/#example-2-sequential-read-while-has-next-page)\
\
Given the _Asset ID_`12345`, the client:\
\
1. Call `arc89_get_metadata` with `asset_id=12345` and `page=0` (0-based), ASA Metadata\
Registry returns:\
   - A _has next_ (`bool`) flag indicating if more pages exist;\
   - The [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) monotonic counter;\
   - Exactly `PAGE_SIZE` bytes of Metadata (or fewer on the last page), as defined\
     in the [Metadata Pagination section](https://dev.algorand.co/arc-standards/arc-0089/#pagination).\
2. While _has next_ page, call `arc89_get_metadata` with `asset_id=12345` and incremented\
`page`, verifying Last Modified Round is unchanged.\
\
\
**PROS:**\
\
- No arithmetic on the caller; just loop while _has next_.\
\
**CONS:**\
\
- Caller doesn’t know the total Metadata length or pages upfront.\
- Callers that want progress bars have to either read page `0` first or call the\
separate `arc89_get_metadata_pagination` method.\
\
**BEST FOR:**\
\
- Wallets and explorers that stream progressively and don’t care about total Metadata\
length until finished.\
\
##### Example 3: Sequential read, two-call pattern\
\
[Section titled “Example 3: Sequential read, two-call pattern”](https://dev.algorand.co/arc-standards/arc-0089/#example-3-sequential-read-two-call-pattern)\
\
Given the _Asset ID_`12345`, the client:\
\
1. Call `arc89_get_metadata_pagination` with `asset_id=12345`, ASA Metadata Registry\
returns:\
   - The total Metadata byte size (`uint16`);\
   - The `PAGE_SIZE` (`uint16`), as defined in the [Metadata Pagination section](https://dev.algorand.co/arc-standards/arc-0089/#pagination);\
   - The total Metadata pages `N` (`uint8`).\
2. Loop calls `arc89_get_metadata` with `asset_id=12345` and `page=0...N-1` (0-based),\
verifying [Last Modified Round](https://dev.algorand.co/arc-standards/arc-0089/#last-modified-round) is unchanged.\
\
\
**PROS:**\
\
- Changes of `PAGE_SIZE` in the future won’t break readers;\
- Improves UX (progress, preallocation).\
\
**CONS:**\
\
- Requires two round trips in the common case.\
\
**BEST FOR:**\
\
- Latency-tolerant clients and SDKs that value clarity and future-proofing.\
\
## Security Considerations\
\
[Section titled “Security Considerations”](https://dev.algorand.co/arc-standards/arc-0089/#security-considerations)\
\
The authorization to create the Asset Metadata and update and delete _mutable_ Asset\
Metadata is granted to the ASA Manager Address to preserve the ASA trust model. The\
authorization is not granted to the ASA Creator Address, since this role could be\
performed programmatically by Applications and is not supposed to be the long-lasting\
maintainer of the ASA.\
\
## Copyright\
\
[Section titled “Copyright”](https://dev.algorand.co/arc-standards/arc-0089/#copyright)\
\
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).\
\
\
\
Ask AI\
\
reCAPTCHA\
\
Recaptcha requires verification.\
\
protected by **reCAPTCHA**