GitHub Logo HIP-646: Fungible Token Metadata Field

Author May Chan
Working Group Michael Tinker, Ashe Oro, Michael Garber
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/627
Status Final
Needs Council Approval Yes
Review period ends Mon, 30 Jan 2023 07:00:00 +0000
Type Standards Track
Category Service
Created 2023-01-04
Updated 2024-05-22
Release v0.49.0

Abstract

This HIP proposes the addition of the metadata field to Fungible Tokens (FT), taking after the Non-Fungible Token (NFT) metadata field which was added in HIP-17. While HIP-17 metadata is scoped to a single NFT, here we propose adding metadata scoped to an entire token type.

Motivation

Similar to NFT’s on the network, the fungible token implementation is largely functional. There is a need for a token creator to specify additional “metadata” about the token. The data and formatting is explored in HIP-405 but there is no field suitable for storing the link to this metadata.

The most ‘logical’ field proposed to store this data is the existing ‘memo’ field, however a dedicated metadata field is more appropriate.

Rationale

The success of HIP-412 in standardizing the NFT space on Hedera demonstrates the potential of standardized metadata functionality for FT’s. Wallets, explorers and other applications can display relevant supplementary information about tokens to users in a decentralized fashion.

  • HIP-765 will add metadata for non-fungible token classes, which will introduce the same fields as this HIP.
  • HIP-657 introduces mutable metadata for NFTs. The METADATA key defined in HIP-657 will also allow updating the metadata field specified in this HIP.

User stories

As a token creator, I want a platform-standardized method to host information about my token in a decentralized fashion, allowing applications to query data such as token icon and website.

As a wallet or explorer, I want to query a mirror node to obtain the metadata for any fungible token, similar to current non-fungible token calls, to simplify calls and implementation. Mirror nodes currently return metadata for individual NFTs; but for fungible token types, we want to get token-level metadata.

As a developer, I want to store the metadata uri in a dedicated field, to avoid ambiguity of using an overloaded field such as ‘memo’.

Specification

HAPI Changes

   // Retrieves the metadata of a token
   rpc getTokenInfo (Query) returns (Response);

TokenCreateTransactionBody

  1. Add a new field to TokenCreateTransactionBody, Property metadata is updated at the token-type level for fungibles.
    message TokenCreateTransactionBody {
     ...
    
     /**
      * Metadata of the created token definition.
      */
     bytes metadata = 23;
    }
    

TokenUpdateTransactionBody

  1. Permit updates by adding a new field to TokenUpdateTransactionBody, Property metadata is updated at the token-type level for fungibles.

Updating the metadata field should require a metadataKey (ie HIP-657)

message TokenUpdateTransactionBody {
    ...
    
    /**
     * If set, the metadata of the updated token definition
     */
    google.protobuf.BytesValue metadata = 16;
}

GetTokenInfo

  1. Support getting the metadata directly from consensus nodes in the getTokenInfo response, ``` message TokenInfo { … /**
    • The token’s metadata, if any. */ bytes metadata = 27; } ```

Pricing considerations: The price for this metadata will be identical to the cost for storage of the memo.

Mirror Node Changes

Currently, only for individual NFTs does the Mirror Node REST API return the metadata field. This will be extended to an entire token type for both fungible (this HIP) and non-fungible token collections (HIP-765).

/api/v1/tokens

For the list tokens endpoint, the token level metadata field will be returned as a base64 encoded value.

{
    "links": {
        "next": null
    },
    "tokens": [
        {
            "admin_key": {
                "_type": "ED25519",
                "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
            },
            "metadata": "Ag==",
            "symbol": "fungible",
            "token_id": "0.0.1032",
            "type": "FUNGIBLE_COMMON"
        },
        {
            "admin_key": {
                "_type": "ED25519",
                "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
            },
            "metadata": "VEVTVF9tZXRhZGF0YQ==",
            "symbol": "non_fungible",
            "token_id": "0.0.1036",
            "type": "NON_FUNGIBLE_UNIQUE"
        }
    ]
}

/api/v1/tokens/{tokenId}

For a given token ID, in addition to the base64 encoded metadata field, the new metadata_key (HIP-657) will also be returned in the standard key format.

{
    "admin_key": {
        "_type": "ED25519",
        "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
    },
    "auto_renew_account": "0.0.1020",
    "auto_renew_period": 6999999,
    "created_timestamp": "1706556543.894559367",
    "custom_fees": {
        "created_timestamp": "1706556543.894559367",
        "fixed_fees": [],
        "royalty_fees": []
    },
    "decimals": "0",
    "deleted": true,
    "expiry_timestamp": 1713556542894559367,
    "fee_schedule_key": {
        "_type": "ED25519",
        "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
    },
    "freeze_default": false,
    "freeze_key": null,
    "initial_supply": "0",
    "kyc_key": null,
    "max_supply": "0",
    "memo": "Mirror Node acceptance test: 2024-01-29T19:29:03.525656Z Create token",
    "metadata": "VEVTVF9tZXRhZGF0YQ==",
    "metadata_key": {
        "_type": "ED25519",
        "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
    },
    "modified_timestamp": "1706556543.894559367",
    "name": "non_fungible_name",
    "pause_key": {
        "_type": "ED25519",
        "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
    },
    "pause_status": "UNPAUSED",
    "supply_key": {
        "_type": "ED25519",
        "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
    },
    "supply_type": "INFINITE",
    "symbol": "non_fungible",
    "token_id": "0.0.1036",
    "total_supply": "0",
    "treasury_account_id": "0.0.1020",
    "type": "NON_FUNGIBLE_UNIQUE",
    "wipe_key": {
        "_type": "ED25519",
        "key": "0aa8e21064c61eab86e2a9c164565b4e7a9a4146106e0a6cd03a8c395a110e92"
    }
}

Backwards Compatibility

This HIP adds functionality and does not affect other services.

Security Implications

There are no additional security implications for the addition of metadata to FT’s that are different from NFT metadata.

How to Teach This

The Hedera documentation should be updated to reflect the new field. Specific education on metadata contents and formatting is out of scope.

Reference Implementation

The reference implementation must be complete before any HIP is given the status of “Final”. The final implementation must include test code and documentation.

Rejected Ideas

Using the existing ‘memo’ field to store metadata was a suggestion that would not require a HIP. This was rejected by the community in favour of a clearly defined, dedicated field.

Open Issues

For completeness, it’s out-of-scope here to enhance the EVM system contracts for TokenCreate, TokenUpdate, and GetTokenInfo with metadata support; but if token metadata becomes important for ecosystem interoperability, a future HIP may be required.

References

A collections of URLs used as references through the HIP.

https://hips.hedera.com/hip/hip-17 - Non-Fungible Tokens https://hips.hedera.com/hip/hip-405 - Fungible Token Metadata JSON Schema https://hips.hedera.com/hip/hip-412 - NFT Token Metadata JSON Schema

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: