diff --git a/README.md b/README.md index d89151e..1a933c5 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ If you don't find what you're looking for, feel free to create an issue and prop - [SRC-2; Inline Documentation](./standards/src_2/) defines how to document your Sway files. - [SRC-3; Mint and Burn](./standards/src_3/) is used to enable mint and burn functionality for Native Assets. - [SRC-5; Ownership Standard](./standards/src_5/) is used to restrict function calls to admin users in contracts. +- [SRC-7; Arbitrary Asset Metadata Standard] is used to store metadata for [Native Assets](https://fuellabs.github.io/sway/v0.44.0/book/blockchain-development/native_assets.html). ## Using a standard diff --git a/standards/Forc.toml b/standards/Forc.toml index 0ca2b5e..fced462 100644 --- a/standards/Forc.toml +++ b/standards/Forc.toml @@ -1,2 +1,2 @@ [workspace] -members = ["src_3", "src_5", "src_20"] +members = ["src_3", "src_5", "src_7", "src_20"] diff --git a/standards/src_7/.docs/src-7-logo-dark-theme.png b/standards/src_7/.docs/src-7-logo-dark-theme.png new file mode 100644 index 0000000..b70e95c Binary files /dev/null and b/standards/src_7/.docs/src-7-logo-dark-theme.png differ diff --git a/standards/src_7/.docs/src-7-logo-light-theme.png b/standards/src_7/.docs/src-7-logo-light-theme.png new file mode 100644 index 0000000..b7b5691 Binary files /dev/null and b/standards/src_7/.docs/src-7-logo-light-theme.png differ diff --git a/standards/src_7/Forc.toml b/standards/src_7/Forc.toml new file mode 100644 index 0000000..07e2a98 --- /dev/null +++ b/standards/src_7/Forc.toml @@ -0,0 +1,5 @@ +[project] +authors = ["Fuel Labs "] +entry = "src_7.sw" +license = "Apache-2.0" +name = "src_7" diff --git a/standards/src_7/README.md b/standards/src_7/README.md new file mode 100644 index 0000000..0e74141 --- /dev/null +++ b/standards/src_7/README.md @@ -0,0 +1,73 @@ +

+ + + SRC-7 logo + +

+ +# Abstract + +The following standard attempts to define the retrieval of on-chain arbitrary metadata for any [Native Asset](https://fuellabs.github.io/sway/v0.45.0/book/blockchain-development/native_assets.html). Any contract that implements the SRC-7 standard MUST implement the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) standard. + +# Motivation + +The SRC-7 standard seeks to enable data-rich assets on the Fuel Network while maintaining compatibility between multiple assets minted by the same contract. The standard ensures type safety with the use of an `enum` and an `Option`. All metadata queries are done through a single function to facilitate cross-contract calls. + +# Prior Art + +The use of generic metadata was originally found in the Sway-Lib's [NFT Library](https://github.com/FuelLabs/sway-libs/tree/v0.12.0/libs/nft) which did not use Fuel's [Native Assets](https://fuellabs.github.io/sway/v0.45.0/book/blockchain-development/native_assets.html). This library has since been deprecated. + +A previous definition for a metadata standard was written in the original edit of the now defunct [SRC-721](https://github.com/FuelLabs/sway-standards/issues/2). This has since been replaced with the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) standard as `SubId` was introduced to enable multiple assets to be minted from a single contract. + +The standard takes inspiration from [ENS's public resolver](https://docs.ens.domains/contract-api-reference/publicresolver) with the use of a `String` as the key. This should enable human-readable keys to help minimize errors and enable the standardization of certain keys, such as "image" as opposed to an `enum` or `u64` representation of keys. + +We also take a look at existing common metadata practices such as [OpenSea's Metadata Standards](https://docs.opensea.io/docs/metadata-standards) and seek to stay backwards compatible with them while enabling more functionality. Through the combination of `String` keys and various return types, both pre-defined URIs or specific attributes may be stored and retrieved with the SRC-7 standard. + +# Specification + +## Metadata Type + +The following describes an enum that wraps various metadata types into a single return type. There SHALL be the following variants in the `Metadata` enum: + +### - `B256` + +The `B256` variant SHALL be used when the stored metadata for the corresponding `AssetId` and `Sting` key pair is of the `b256` type. + +### - `Bytes` + +The `Bytes` variant SHALL be used when the stored metadata for the corresponding `AssetId` and `String` key pair is of the `Bytes` type. The `Bytes` variant should be used when storing custom data such as but not limited to structs and enums. + +### - `Int` + +The `Int` variant SHALL be used when the stored metadata for the corresponding `AssetId` and `Sting` key pair is of the `u64` type. + +### - `String` + +The `String` variant SHALL be used when the stored metadata for the corresponding `AssetId` and `String` key pair is of the `String` type. The `String` variant MUST be used when a URI is required but MAY contain any arbitrary `String` data. + +## Require Functions + +### `fn metadata(asset: AssetId, key: String) -> Option` + +This function MUST return valid metadata for the corresponding `asset` and `key`, where the data is either a `B256`, `Bytes`, `Int`, or `String` variant. If the asset does not exist or no metadata exists, the function MUST return `None`. + +# Rationale + +The SRC-7 standard should allow for data-rich assets to interact with one another in a safe manner. + +# Backwards Compatibility + +This standard is compatible with Fuel's [Native Assets](https://fuellabs.github.io/sway/v0.45.0/book/blockchain-development/native_assets.html) and the [SRC-20](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_20) standard. It also maintains compatibility with existing standards in other ecosystems. + +# Security Considerations + +This standard does not introduce any security concerns, as it does not call external contracts, nor does it define any mutations of the contract state. + +# Example ABI + +```rust +abi SRC7Metadata { + #[storage(read)] + fn metadata(asset: AssetId, key: String) -> Option; +} +``` \ No newline at end of file diff --git a/standards/src_7/src/src_7.sw b/standards/src_7/src/src_7.sw new file mode 100644 index 0000000..bb4a473 --- /dev/null +++ b/standards/src_7/src/src_7.sw @@ -0,0 +1,64 @@ +library; + +use std::{bytes::Bytes, string::String}; + +abi SRC7 { + /// Returns metadata for the corresponding `asset` and `key`. + /// + /// # Arguments + /// + /// * `asset`: [AssetId] - The asset of which to query the metadata. + /// * `key`: [String] - The key to the specific metadata. + /// + /// # Returns + /// + /// * [Option] - `Some` metadata that corresponds to the `key` or `None`. + /// + /// # Examples + /// + /// ```sway + /// use src_7::{SRC7, Metadata}; + /// use std::string::String; + /// + /// fn foo(contract_id: ContractId, asset: AssetId) { + /// let contract_abi = abi(SRC7, contract_id); + /// let key = String::from_ascii_str("image"); + /// let data = contract_abi.metadata(asset, key); + /// assert(data.is_some()); + /// } + /// ``` + #[storage(read)] + fn metadata(asset: AssetId, key: String) -> Option; +} + +/// Universal return type for metadata. +pub enum Metadata { + // Used when the stored metadata is a `b256`. + B256: b256, + /// Used when the stored metadata is `Bytes`. + Bytes: Bytes, + /// Used when the stored metadata is a `u64`. + Int: u64, + /// Used when the stored metadata is a `String`. + String: String, +} + +impl core::ops::Eq for Metadata { + fn eq(self, other: Self) -> bool { + match (self, other) { + (Metadata::B256(bytes1), Metadata::B256(bytes2)) => { + bytes1 == bytes2 + }, + (Metadata::Bytes(bytes1), Metadata::Bytes(bytes2)) => { + bytes1 == bytes2 + }, + (Metadata::Int(int1), Metadata::Int(int2)) => { + int1 == int2 + }, + (Metadata::String(string1), Metadata::String(string2)) => { + string1 == string2 + }, + _ => false, + } + } +}