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.
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.
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.
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.
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.
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.
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.
The Metadata (byte[]) is a byte-array of variable length (metadata_size).
The metadata_sizeMAY 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 maximum byte size of an AVM Box MAX_BOX_SIZE (32768 bytes);
The maximum Application Call arguments size MAX_ARG_SIZE (2048 bytes);
The maximum number of transaction per Group MAX_GROUP_SIZE (16);
The HEADER_SIZE;
The ARC-4 method selector size ARC4_METHOD_SELECTOR_SIZE (4
bytes);
The available payload for the method arc89_create_metadata(uint64,byte,byte,uint16,byte[],pay)
(FIRST_PAYLOAD_MAX_SIZE = MAX_ARG_SIZE - (ARC4_METHOD_SELECTOR_SIZE + 8 + 1 + 1 + 2 + 2 + 0) = 2030 bytes),
which consumes an extra pay transaction in the Group (the pay transaction is
not encoded as argument bytes, hence the + 0 in the formula);
The available payload for the method arc89_extra_payload(uint64,byte[])
(EXTRA_PAYLOAD_MAX_SIZE = MAX_ARG_SIZE - (ARC4_METHOD_SELECTOR_SIZE + 8 + 2 = 2034) bytes);
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.
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.
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.).
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:
The AVM size of the log opcode MAX_LOG_SIZE (1024 bytes);
The ARC-4 return prefix (151f7c75) size ARC4_RETURN_PREFIX_SIZE
(4 bytes);
The maximum ARC-4return type encoding overhead bytes depends on the
Get Metadata interface) return type (bool,uint64,byte[]). ABI
tuple are encoded as head(...) || tail(...).
The page_sizeMUST hold the condition page_size ≤ PAGE_SIZE.
A pageMUST 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 pageMAY 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).
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:
The sign (uint8) enum:
ENUM
VALUE
DESCRIPTION
NULL
0
Null
POS
1
Positive
NEG
255
Negative
The amount (uint64) of MBR, expressed in microALGO.
The MBR Delta is calculated based on the following contextual information:
The existence of the Asset Metadata Box for the ASA and,
The relative byte sizes (delta_size) between a new Metadata (new_metadata_size)
and the existing Metadata (metadata_size, if any).
If the Asset Metadata Hash (am) field of the ASA is set (i.e., not zero), then:
It takes precedence over the hash computation, and it is copied verbatim as Metadata
Hash, and
The Asset Metadata MUST be flagged as immutable
at creation, and
The ASA Metadata Registry SHALL validate it (according to the following specification)
if the Asset Metadata is flagged as ARC-89 Native ASA and
not as ARC-3 compliant.
Refer to the Asset Metadata Hash section for details about
the Asset Metadata Hash (am) field.
Otherwise, the Metadata Hash is computed as follows:
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.
It is RECOMMENDED to use the Asset URL (au) suffix option, in this case
the partialARC-90 URI would be: algorand://<netauth>/app/<singleton_arc89_app_id>?box=#arc3
The ASA MUST comply with the ARC-3 ASA Parameters Conventions
for the Asset Metadata Hash (am) field if the Asset Metadata are set as immutable
at creation, otherwise the Asset Metadata Hash (am) field MUST NOT be set
(i.e., set to zero).
The ASA Manager Address is not set to the Zero Address.
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-3MUST NOT contain additional
elements (i.e., #arc3+89 is not allowed), see ARC-90 compliance fragment
section for details.
To get the ARC-90Asset 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):
The MainNetnetauth is empty, therefore, the partial Asset URL on MainNet 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,
resulting in the following partial Asset URL:
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 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.
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.
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, clients SHALL point to the new ARC-90
Asset Metadata URI:
By fixing a singleton application per Algorand network and using a partial ARC-90
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).
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.
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.
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.
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.
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.
The registry turns ASA metadata into on-chain first class citizens, using the full
potential of AVM opcodes (json_ref
and 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 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.
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. Clients need to acquire the Asset Metadata URI
from a distribution channel.
{"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"},
"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"},
"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"},
"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"}
"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"},
The authorization MUST be restricted to the ASA Manager Address, and
The Asset Metadata Box MUST NOTexist, 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 IdentifierMUST be set to True.
The MetadataMUST be initialized with the provided payload value
(empty is allowed).
If the creation is part of a Group, the 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 FlagsMUST be initialized with the provided
reversible_flags value (byte).
The Irreversible FlagsMUST be initialized with the provided
irreversible_flags value (byte).
If the ASA is declared as ARC-89 Native ASA, the Asset URL
(au) MUST comply with the specified Asset Metadata URI
(no #arc fragment validation enforced).
The MBR Deltaamount 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.
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 MUSTexist, 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 IdentifierMUST be set to True.
The MetadataMUST be replaced with the provided payload value
(empty is allowed).
If the replacement is part of a Group, the 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.
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 MUSTexist, 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 IdentifierMUST be set to True.
The MetadataMUST be replaced with the provided payload value
(empty is allowed).
If the creation is part of a Group, the 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 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 Deltaamount 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.
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 MUSTexist, 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_idMUST 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]
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).
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 pages 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 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.
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.
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.
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.