--- a/Cargo.lock +++ b/Cargo.lock @@ -6338,6 +6338,7 @@ "pallet-nonfungible", "pallet-structure", "parity-scale-codec 3.1.2", + "rmrk-traits", "scale-info", "sp-core", "sp-runtime", @@ -6357,6 +6358,7 @@ "pallet-nonfungible", "pallet-rmrk-core", "parity-scale-codec 3.1.2", + "rmrk-traits", "scale-info", "sp-core", "sp-runtime", @@ -8999,15 +9001,24 @@ version = "0.0.1" dependencies = [ "parity-scale-codec 2.3.1", + "rmrk-traits", "serde", "sp-api", "sp-core", "sp-runtime", "sp-std", - "up-data-structs", ] [[package]] +name = "rmrk-traits" +version = "0.1.0" +dependencies = [ + "parity-scale-codec 3.1.2", + "scale-info", + "serde", +] + +[[package]] name = "rocksdb" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -12723,6 +12734,7 @@ "frame-system", "pallet-evm", "parity-scale-codec 3.1.2", + "rmrk-traits", "scale-info", "serde", "sp-core", --- a/pallets/proxy-rmrk-core/Cargo.toml +++ b/pallets/proxy-rmrk-core/Cargo.toml @@ -22,6 +22,7 @@ up-data-structs = { default-features = false, path = '../../primitives/data-structs' } pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.22" } frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" } +rmrk-traits = { default-features = false, path = "../../primitives/rmrk-traits" } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } derivative = { version = "2.2.0", features = ["use_core"] } @@ -33,6 +34,7 @@ "sp-runtime/std", "sp-std/std", "up-data-structs/std", + "rmrk-traits/std", "pallet-common/std", "pallet-nonfungible/std", "pallet-structure/std", --- a/pallets/proxy-rmrk-core/src/lib.rs +++ b/pallets/proxy-rmrk-core/src/lib.rs @@ -289,7 +289,7 @@ let sender = T::CrossAccountId::from_sub(sender); let cross_owner = T::CrossAccountId::from_sub(owner.clone()); - let royalty_info = royalty_amount.map(|amount| rmrk::RoyaltyInfo { + let royalty_info = royalty_amount.map(|amount| rmrk_traits::RoyaltyInfo { recipient: recipient.unwrap_or_else(|| owner.clone()), amount, }); --- a/pallets/proxy-rmrk-equip/Cargo.toml +++ b/pallets/proxy-rmrk-equip/Cargo.toml @@ -21,6 +21,7 @@ up-data-structs = { default-features = false, path = '../../primitives/data-structs' } pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.22" } frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.22" } +rmrk-traits = { default-features = false, path = "../../primitives/rmrk-traits" } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } pallet-rmrk-core = { default-features = false, path = "../proxy-rmrk-core" } @@ -32,6 +33,7 @@ "sp-runtime/std", "sp-std/std", "up-data-structs/std", + "rmrk-traits/std", "pallet-common/std", "pallet-nonfungible/std", "pallet-rmrk-core/std", --- a/primitives/data-structs/Cargo.toml +++ b/primitives/data-structs/Cargo.toml @@ -26,6 +26,7 @@ derivative = { version = "2.2.0", features = ["use_core"] } struct-versioning = { path = "../../crates/struct-versioning" } pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.22" } +rmrk-traits = { default-features = false, path = "../rmrk-traits" } [features] default = ["std"] @@ -39,7 +40,8 @@ "sp-core/std", "sp-std/std", "pallet-evm/std", + "rmrk-traits/std", ] serde1 = ["serde/alloc"] limit-testing = [] -runtime-benchmarks = [] \ No newline at end of file +runtime-benchmarks = [] --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -36,14 +36,12 @@ use derivative::Derivative; use scale_info::TypeInfo; -pub mod rmrk; - // RMRK -use rmrk::{ +use rmrk_traits::{ CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty, ResourceTypes, BasicResource, ComposableResource, SlotResource, }; -pub use rmrk::{ +pub use rmrk_traits::{ primitives::{ CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId, PartId as RmrkPartId, ResourceId as RmrkResourceId, --- a/primitives/data-structs/src/rmrk.rs +++ /dev/null @@ -1,435 +0,0 @@ -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::Serialize; - -use primitives::*; - -pub mod primitives { - pub type CollectionId = u32; - pub type ResourceId = u32; - pub type NftId = u32; - pub type BaseId = u32; - pub type SlotId = u32; - pub type PartId = u32; - pub type ZIndex = u32; -} - -#[cfg(feature = "std")] -mod serialize { - use core::convert::AsRef; - use serde::ser::{self, Serialize}; - - pub mod vec { - use super::*; - - pub fn serialize(value: &C, serializer: D) -> Result - where - D: ser::Serializer, - V: Serialize, - C: AsRef<[V]>, - { - value.as_ref().serialize(serializer) - } - } - - pub mod opt_vec { - use super::*; - - pub fn serialize(value: &Option, serializer: D) -> Result - where - D: ser::Serializer, - V: Serialize, - C: AsRef<[V]>, - { - match value { - Some(value) => super::vec::serialize(value, serializer), - None => serializer.serialize_none(), - } - } - } -} - -/// Collection info. -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - AccountId: Serialize, - BoundedString: AsRef<[u8]>, - BoundedSymbol: AsRef<[u8]> - "#) -)] -pub struct CollectionInfo { - /// Current bidder and bid price. - pub issuer: AccountId, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub metadata: BoundedString, - pub max: Option, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub symbol: BoundedSymbol, - pub nfts_count: u32, -} - -#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -pub enum AccountIdOrCollectionNftTuple { - AccountId(AccountId), - CollectionAndNftTuple(CollectionId, NftId), -} - -/// Royalty information (recipient and amount) -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -pub struct RoyaltyInfo { - /// Recipient (AccountId) of the royalty - pub recipient: AccountId, - /// Amount (Permill) of the royalty - pub amount: RoyaltyAmount, -} - -/// Nft info. -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - AccountId: Serialize, - RoyaltyAmount: Serialize, - BoundedString: AsRef<[u8]> - "#) -)] -pub struct NftInfo { - /// The owner of the NFT, can be either an Account or a tuple (CollectionId, NftId) - pub owner: AccountIdOrCollectionNftTuple, - /// Royalty (optional) - pub royalty: Option>, - - /// Arbitrary data about an instance, e.g. IPFS hash - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub metadata: BoundedString, - - /// Equipped state - pub equipped: bool, - /// Pending state (if sent to NFT) - pub pending: bool, -} - -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct NftChild { - pub collection_id: CollectionId, - pub nft_id: NftId, -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, PartialEq, TypeInfo)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedKey: AsRef<[u8]>, - BoundedValue: AsRef<[u8]> - "#) -)] -pub struct PropertyInfo { - /// Key of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub key: BoundedKey, - - /// Value of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub value: BoundedValue, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct BasicResource { - /// If the resource is Media, the base property is absent. Media src should be a URI like an - /// IPFS hash. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub src: Option, - - /// Reference to IPFS location of metadata - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub metadata: Option, - - /// Optional location or identier of license - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub license: Option, - - /// If the resource has the thumb property, this will be a URI to a thumbnail of the given - /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is - /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns - /// another bird, showing the full render of one bird inside the other's inventory might be a - /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an - /// image that is lighter and faster to load but representative of this resource. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub thumb: Option, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedParts: AsRef<[PartId]> - "#) -)] -pub struct ComposableResource { - /// If a resource is composed, it will have an array of parts that compose it - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub parts: BoundedParts, - - /// A Base is uniquely identified by the combination of the word `base`, its minting block - /// number, and user provided symbol during Base creation, glued by dashes `-`, e.g. - /// base-4477293-kanaria_superbird. - pub base: BaseId, - - /// If the resource is Media, the base property is absent. Media src should be a URI like an - /// IPFS hash. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub src: Option, - - /// Reference to IPFS location of metadata - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub metadata: Option, - - /// If the resource has the slot property, it was designed to fit into a specific Base's slot. - /// The baseslot will be composed of two dot-delimited values, like so: - /// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is - /// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird - - /// Optional location or identier of license - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub license: Option, - - /// If the resource has the thumb property, this will be a URI to a thumbnail of the given - /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is - /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns - /// another bird, showing the full render of one bird inside the other's inventory might be a - /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an - /// image that is lighter and faster to load but representative of this resource. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub thumb: Option, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct SlotResource { - /// A Base is uniquely identified by the combination of the word `base`, its minting block - /// number, and user provided symbol during Base creation, glued by dashes `-`, e.g. - /// base-4477293-kanaria_superbird. - pub base: BaseId, - - /// If the resource is Media, the base property is absent. Media src should be a URI like an - /// IPFS hash. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub src: Option, - - /// Reference to IPFS location of metadata - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub metadata: Option, - - /// If the resource has the slot property, it was designed to fit into a specific Base's slot. - /// The baseslot will be composed of two dot-delimited values, like so: - /// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is - /// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird - pub slot: SlotId, - - /// The license field, if present, should contain a link to a license (IPFS or static HTTP - /// url), or an identifier, like RMRK_nocopy or ipfs://ipfs/someHashOfLicense. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub license: Option, - - /// If the resource has the thumb property, this will be a URI to a thumbnail of the given - /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is - /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns - /// another bird, showing the full render of one bird inside the other's inventory might be a - /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an - /// image that is lighter and faster to load but representative of this resource. - #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] - pub thumb: Option, -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedParts: AsRef<[PartId]> - "#) -)] -pub enum ResourceTypes { - Basic(BasicResource), - Composable(ComposableResource), - Slot(SlotResource), -} - -#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr(feature = "std", derive(Serialize))] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedParts: AsRef<[PartId]> - "#) -)] -pub struct ResourceInfo { - /// id is a 5-character string of reasonable uniqueness. - /// The combination of base ID and resource id should be unique across the entire RMRK - /// ecosystem which - //#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub id: ResourceId, - - /// Resource - pub resource: ResourceTypes, - - /// If resource is sent to non-rootowned NFT, pending will be false and need to be accepted - pub pending: bool, - - /// If resource removal request is sent by non-rootowned NFT, pending will be true and need to be accepted - pub pending_removal: bool, -} - -#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - AccountId: Serialize, - BoundedString: AsRef<[u8]> - "#) -)] -pub struct BaseInfo { - /// Original creator of the Base - pub issuer: AccountId, - - /// Specifies how an NFT should be rendered, ie "svg" - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub base_type: BoundedString, - - /// User provided symbol during Base creation - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub symbol: BoundedString, -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct FixedPart { - pub id: PartId, - pub z: ZIndex, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub src: BoundedString, -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = "BoundedCollectionList: AsRef<[CollectionId]>") -)] -pub enum EquippableList { - All, - Empty, - Custom(#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] BoundedCollectionList), -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedCollectionList: AsRef<[CollectionId]> - "#) -)] -pub struct SlotPart { - pub id: PartId, - pub equippable: EquippableList, - - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub src: BoundedString, - - pub z: ZIndex, -} - -#[cfg_attr(feature = "std", derive(Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - BoundedCollectionList: AsRef<[CollectionId]> - "#) -)] -pub enum PartType { - FixedPart(FixedPart), - SlotPart(SlotPart), -} - -impl PartType { - pub fn id(&self) -> PartId { - match self { - Self::FixedPart(part) => part.id, - Self::SlotPart(part) => part.id, - } - } - - pub fn src(&self) -> &BoundedString { - match self { - Self::FixedPart(part) => &part.src, - Self::SlotPart(part) => &part.src, - } - } - - pub fn z_index(&self) -> ZIndex { - match self { - Self::FixedPart(part) => part.z, - Self::SlotPart(part) => part.z, - } - } -} - -#[cfg_attr(feature = "std", derive(Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] -#[cfg_attr( - feature = "std", - serde(bound = r#" - BoundedString: AsRef<[u8]>, - PropertyList: AsRef<[ThemeProperty]>, - "#) -)] -pub struct Theme { - /// Name of the theme - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub name: BoundedString, - - /// Theme properties - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub properties: PropertyList, - /// Inheritability - pub inherit: bool, -} - -#[cfg_attr(feature = "std", derive(Eq, Serialize))] -#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] -#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] -pub struct ThemeProperty { - /// Key of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub key: BoundedString, - - /// Value of the property - #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] - pub value: BoundedString, -} --- a/primitives/rmrk-rpc/Cargo.toml +++ b/primitives/rmrk-rpc/Cargo.toml @@ -11,7 +11,7 @@ sp-api = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.22' } sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate', branch = 'polkadot-v0.9.22' } serde = { version = "1.0.130", default-features = false, features = ["derive"] } -up-data-structs = { default-features = false, path = '../data-structs' } +rmrk-traits = { default-features = false, path = "../rmrk-traits" } [features] default = ["std"] @@ -22,5 +22,5 @@ "sp-api/std", "sp-runtime/std", "serde/std", - "up-data-structs/std", + "rmrk-traits/std", ] --- a/primitives/rmrk-rpc/src/lib.rs +++ b/primitives/rmrk-rpc/src/lib.rs @@ -3,7 +3,7 @@ use sp_api::{Encode, Decode}; use sp_std::vec::Vec; use sp_runtime::DispatchError; -use up_data_structs::rmrk::{primitives::*, NftChild}; +use rmrk_traits::{primitives::*, NftChild}; pub type Result = core::result::Result; --- /dev/null +++ b/primitives/rmrk-traits/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "rmrk-traits" +authors = ["Unique Network "] +description = "RMRK proxy data structs definitions" +edition = "2021" +license = 'GPLv3' +homepage = "https://unique.network" +repository = 'https://github.com/UniqueNetwork/unique-chain' +version = '0.1.0' + +[dependencies] +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = ["derive"] } +serde = { version = "1.0.130", features = ["derive"], default-features = false, optional = true } + +[features] +default = ["std"] +std = [ + "serde1", + "serde/std", + "codec/std", +] +serde1 = ["serde/alloc"] --- /dev/null +++ b/primitives/rmrk-traits/src/base.rs @@ -0,0 +1,30 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + AccountId: Serialize, + BoundedString: AsRef<[u8]> + "#) +)] +pub struct BaseInfo { + /// Original creator of the Base + pub issuer: AccountId, + + /// Specifies how an NFT should be rendered, ie "svg" + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub base_type: BoundedString, + + /// User provided symbol during Base creation + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub symbol: BoundedString, +} --- /dev/null +++ b/primitives/rmrk-traits/src/collection.rs @@ -0,0 +1,31 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + AccountId: Serialize, + BoundedString: AsRef<[u8]>, + BoundedSymbol: AsRef<[u8]> + "#) +)] +pub struct CollectionInfo { + /// Current bidder and bid price. + pub issuer: AccountId, + + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub metadata: BoundedString, + pub max: Option, + + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub symbol: BoundedSymbol, + pub nfts_count: u32, +} --- /dev/null +++ b/primitives/rmrk-traits/src/lib.rs @@ -0,0 +1,31 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod base; +pub mod collection; +pub mod nft; +pub mod part; +pub mod property; +pub mod resource; +pub mod theme; + +#[cfg(feature = "std")] +mod serialize; + +pub use base::BaseInfo; +pub use part::{EquippableList, FixedPart, PartType, SlotPart}; +pub use theme::{Theme, ThemeProperty}; +pub use collection::CollectionInfo; +pub use nft::{AccountIdOrCollectionNftTuple, NftInfo, RoyaltyInfo, NftChild}; +pub use property::PropertyInfo; +pub use resource::{ + BasicResource, ComposableResource, ResourceInfo, ResourceTypes, SlotResource, +}; +pub mod primitives { + pub type CollectionId = u32; + pub type ResourceId = u32; + pub type NftId = u32; + pub type BaseId = u32; + pub type SlotId = u32; + pub type PartId = u32; + pub type ZIndex = u32; +} --- /dev/null +++ b/primitives/rmrk-traits/src/nft.rs @@ -0,0 +1,61 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +use crate::primitives::*; + +#[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize))] +pub enum AccountIdOrCollectionNftTuple { + AccountId(AccountId), + CollectionAndNftTuple(CollectionId, NftId), +} + +/// Royalty information (recipient and amount) +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +pub struct RoyaltyInfo { + /// Recipient (AccountId) of the royalty + pub recipient: AccountId, + /// Amount (Permill) of the royalty + pub amount: RoyaltyAmount, +} + +/// Nft info. +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + AccountId: Serialize, + RoyaltyAmount: Serialize, + BoundedString: AsRef<[u8]> + "#) +)] +pub struct NftInfo { + /// The owner of the NFT, can be either an Account or a tuple (CollectionId, NftId) + pub owner: AccountIdOrCollectionNftTuple, + /// Royalty (optional) + pub royalty: Option>, + + /// Arbitrary data about an instance, e.g. IPFS hash + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub metadata: BoundedString, + + /// Equipped state + pub equipped: bool, + /// Pending state (if sent to NFT) + pub pending: bool, +} + +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Serialize))] +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct NftChild { + pub collection_id: CollectionId, + pub nft_id: NftId, +} --- /dev/null +++ b/primitives/rmrk-traits/src/part.rs @@ -0,0 +1,89 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +use crate::primitives::*; + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] +#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] +pub struct FixedPart { + pub id: PartId, + pub z: ZIndex, + + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub src: BoundedString, +} + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] +#[cfg_attr( + feature = "std", + serde(bound = "BoundedCollectionList: AsRef<[CollectionId]>") +)] +pub enum EquippableList { + All, + Empty, + Custom(#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] BoundedCollectionList), +} + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedString: AsRef<[u8]>, + BoundedCollectionList: AsRef<[CollectionId]> + "#) +)] +pub struct SlotPart { + pub id: PartId, + pub equippable: EquippableList, + + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub src: BoundedString, + + pub z: ZIndex, +} + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, Eq, MaxEncodedLen)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedString: AsRef<[u8]>, + BoundedCollectionList: AsRef<[CollectionId]> + "#) +)] +pub enum PartType { + FixedPart(FixedPart), + SlotPart(SlotPart), +} + +impl PartType { + pub fn id(&self) -> PartId { + match self { + Self::FixedPart(part) => part.id, + Self::SlotPart(part) => part.id, + } + } + + pub fn src(&self) -> &BoundedString { + match self { + Self::FixedPart(part) => &part.src, + Self::SlotPart(part) => &part.src, + } + } + + pub fn z_index(&self) -> ZIndex { + match self { + Self::FixedPart(part) => part.z, + Self::SlotPart(part) => part.z, + } + } +} --- /dev/null +++ b/primitives/rmrk-traits/src/property.rs @@ -0,0 +1,27 @@ +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Encode, Decode, PartialEq, TypeInfo)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedKey: AsRef<[u8]>, + BoundedValue: AsRef<[u8]> + "#) +)] +pub struct PropertyInfo { + /// Key of the property + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub key: BoundedKey, + + /// Value of the property + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub value: BoundedValue, +} --- /dev/null +++ b/primitives/rmrk-traits/src/resource.rs @@ -0,0 +1,164 @@ +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +use crate::primitives::*; + +#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] +pub struct BasicResource { + /// If the resource is Media, the base property is absent. Media src should be a URI like an + /// IPFS hash. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub src: Option, + + /// Reference to IPFS location of metadata + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub metadata: Option, + + /// Optional location or identier of license + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub license: Option, + + /// If the resource has the thumb property, this will be a URI to a thumbnail of the given + /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is + /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns + /// another bird, showing the full render of one bird inside the other's inventory might be a + /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an + /// image that is lighter and faster to load but representative of this resource. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub thumb: Option, +} + +#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedString: AsRef<[u8]>, + BoundedParts: AsRef<[PartId]> + "#) +)] +pub struct ComposableResource { + /// If a resource is composed, it will have an array of parts that compose it + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub parts: BoundedParts, + + /// A Base is uniquely identified by the combination of the word `base`, its minting block + /// number, and user provided symbol during Base creation, glued by dashes `-`, e.g. + /// base-4477293-kanaria_superbird. + pub base: BaseId, + + /// If the resource is Media, the base property is absent. Media src should be a URI like an + /// IPFS hash. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub src: Option, + + /// Reference to IPFS location of metadata + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub metadata: Option, + + /// If the resource has the slot property, it was designed to fit into a specific Base's slot. + /// The baseslot will be composed of two dot-delimited values, like so: + /// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is + /// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird + + /// Optional location or identier of license + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub license: Option, + + /// If the resource has the thumb property, this will be a URI to a thumbnail of the given + /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is + /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns + /// another bird, showing the full render of one bird inside the other's inventory might be a + /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an + /// image that is lighter and faster to load but representative of this resource. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub thumb: Option, +} + +#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] +pub struct SlotResource { + /// A Base is uniquely identified by the combination of the word `base`, its minting block + /// number, and user provided symbol during Base creation, glued by dashes `-`, e.g. + /// base-4477293-kanaria_superbird. + pub base: BaseId, + + /// If the resource is Media, the base property is absent. Media src should be a URI like an + /// IPFS hash. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub src: Option, + + /// Reference to IPFS location of metadata + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub metadata: Option, + + /// If the resource has the slot property, it was designed to fit into a specific Base's slot. + /// The baseslot will be composed of two dot-delimited values, like so: + /// "base-4477293-kanaria_superbird.machine_gun_scope". This means: "This resource is + /// compatible with the machine_gun_scope slot of base base-4477293-kanaria_superbird + pub slot: SlotId, + + /// The license field, if present, should contain a link to a license (IPFS or static HTTP + /// url), or an identifier, like RMRK_nocopy or ipfs://ipfs/someHashOfLicense. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub license: Option, + + /// If the resource has the thumb property, this will be a URI to a thumbnail of the given + /// resource. For example, if we have a composable NFT like a Kanaria bird, the resource is + /// complex and too detailed to show in a search-results page or a list. Also, if a bird owns + /// another bird, showing the full render of one bird inside the other's inventory might be a + /// bit of a strain on the browser. For this reason, the thumb value can contain a URI to an + /// image that is lighter and faster to load but representative of this resource. + #[cfg_attr(feature = "std", serde(with = "serialize::opt_vec"))] + pub thumb: Option, +} + +#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedString: AsRef<[u8]>, + BoundedParts: AsRef<[PartId]> + "#) +)] +pub enum ResourceTypes { + Basic(BasicResource), + Composable(ComposableResource), + Slot(SlotResource), +} + +#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedString: AsRef<[u8]>, + BoundedParts: AsRef<[PartId]> + "#) +)] +pub struct ResourceInfo { + /// id is a 5-character string of reasonable uniqueness. + /// The combination of base ID and resource id should be unique across the entire RMRK + /// ecosystem which + //#[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub id: ResourceId, + + /// Resource + pub resource: ResourceTypes, + + /// If resource is sent to non-rootowned NFT, pending will be false and need to be accepted + pub pending: bool, + + /// If resource removal request is sent by non-rootowned NFT, pending will be true and need to be accepted + pub pending_removal: bool, +} --- /dev/null +++ b/primitives/rmrk-traits/src/serialize.rs @@ -0,0 +1,31 @@ +use core::convert::AsRef; +use serde::ser::{self, Serialize}; + +pub mod vec { + use super::*; + + pub fn serialize(value: &C, serializer: D) -> Result + where + D: ser::Serializer, + V: Serialize, + C: AsRef<[V]>, + { + value.as_ref().serialize(serializer) + } +} + +pub mod opt_vec { + use super::*; + + pub fn serialize(value: &Option, serializer: D) -> Result + where + D: ser::Serializer, + V: Serialize, + C: AsRef<[V]>, + { + match value { + Some(value) => super::vec::serialize(value, serializer), + None => serializer.serialize_none(), + } + } +} --- /dev/null +++ b/primitives/rmrk-traits/src/theme.rs @@ -0,0 +1,42 @@ +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::Serialize; + +#[cfg(feature = "std")] +use crate::serialize; + +#[cfg_attr(feature = "std", derive(Eq, Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] +#[cfg_attr( + feature = "std", + serde(bound = r#" + BoundedString: AsRef<[u8]>, + PropertyList: AsRef<[ThemeProperty]>, + "#) +)] +pub struct Theme { + /// Name of the theme + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub name: BoundedString, + + /// Theme properties + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub properties: PropertyList, + /// Inheritability + pub inherit: bool, +} + +#[cfg_attr(feature = "std", derive(Eq, Serialize))] +#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] +#[cfg_attr(feature = "std", serde(bound = "BoundedString: AsRef<[u8]>"))] +pub struct ThemeProperty { + /// Key of the property + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub key: BoundedString, + + /// Value of the property + #[cfg_attr(feature = "std", serde(with = "serialize::vec"))] + pub value: BoundedString, +}