use near_sdk::json_types::Base64VecU8; use near_sdk::{ext_contract, near, require}; /// This spec can be treated like a version of the standard. pub const NFT_METADATA_SPEC: &str = "nft-1.0.0"; /// Metadata for the NFT contract itself. #[derive(Clone, Debug, PartialEq, Eq)] #[near(serializers=[borsh, json])] pub struct NFTContractMetadata { pub spec: String, // required, essentially a version like "nft-1.0.0" pub name: String, // required, ex. "Mosaics" pub symbol: String, // required, ex. "MOSIAC" pub icon: Option, // Data URL pub base_uri: Option, // Centralized gateway known to have reliable access to decentralized storage assets referenced by `reference` or `media` URLs pub reference: Option, // URL to a JSON file with more info pub reference_hash: Option, // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included. } #[near(serializers=[borsh, json])] #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct TokenMetadata { pub title: Option, // ex. "Arch Nemesis: Mail Carrier" or "Parcel #5055" pub description: Option, // free-form description pub media: Option, // URL to associated media, preferably to decentralized, content-addressed storage pub media_hash: Option, // Base64-encoded sha256 hash of content referenced by the `media` field. Required if `media` is included. pub copies: Option, // number of copies of this set of metadata in existence when token was minted. pub issued_at: Option, // ISO 8601 datetime when token was issued or minted pub expires_at: Option, // ISO 8601 datetime when token expires pub starts_at: Option, // ISO 8601 datetime when token starts being valid pub updated_at: Option, // ISO 8601 datetime when token was last updated pub extra: Option, // anything extra the NFT wants to store on-chain. Can be stringified JSON. pub reference: Option, // URL to an off-chain JSON file with more info. pub reference_hash: Option, // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included. } /// Offers details on the contract-level metadata. #[ext_contract(ext_nft_metadata_provider)] pub trait NonFungibleTokenMetadataProvider { fn nft_metadata(&self) -> NFTContractMetadata; } impl NFTContractMetadata { pub fn assert_valid(&self) { require!(self.spec == NFT_METADATA_SPEC, "Spec is not NFT metadata"); require!( self.reference.is_some() == self.reference_hash.is_some(), "Reference and reference hash must be present" ); if let Some(reference_hash) = &self.reference_hash { require!(reference_hash.0.len() == 32, "Hash has to be 32 bytes"); } } } impl TokenMetadata { pub fn assert_valid(&self) { require!(self.media.is_some() == self.media_hash.is_some()); if let Some(media_hash) = &self.media_hash { require!(media_hash.0.len() == 32, "Media hash has to be 32 bytes"); } require!(self.reference.is_some() == self.reference_hash.is_some()); if let Some(reference_hash) = &self.reference_hash { require!(reference_hash.0.len() == 32, "Reference hash has to be 32 bytes"); } } }