Skip to content

Commit

Permalink
feat(pop-api): continue support for nft state queries
Browse files Browse the repository at this point in the history
  • Loading branch information
evilrobot-01 committed Mar 7, 2024
1 parent 7801839 commit 101c759
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 115 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 29 additions & 12 deletions contracts/pop-api-examples/nfts/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use pop_api::nfts;
#[derive(Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum ContractError {
InvalidCollection,
ItemAlreadyExists,
NftsError(nfts::Error),
NotOwner,
}

impl From<nfts::Error> for ContractError {
Expand All @@ -25,7 +28,7 @@ mod pop_api_extension_demo {
impl PopApiExtensionDemo {
#[ink(constructor, payable)]
pub fn new() -> Self {
ink::env::debug_println!("PopApiExtensionDemo::new");
ink::env::debug_println!("Contract::new");
Default::default()
}

Expand All @@ -36,21 +39,35 @@ mod pop_api_extension_demo {
item_id: u32,
receiver: AccountId,
) -> Result<(), ContractError> {
ink::env::debug_println!("PopApiExtensionDemo::mint_through_runtime: collection_id: {:?} \nitem_id {:?} \nreceiver: {:?}, ", collection_id, item_id, receiver);

// simplified API call
let result = pop_api::nfts::mint(collection_id, item_id, receiver);
ink::env::debug_println!(
"PopApiExtensionDemo::mint_through_runtime result: {result:?}"
"Contract::mint_through_runtime: collection_id: {:?} item_id {:?} receiver: {:?}",
collection_id,
item_id,
receiver
);
if let Err(pop_api::nfts::Error::NoConfig) = result {
ink::env::debug_println!(
"PopApiExtensionDemo::mint_through_runtime expected error received"
);

// Check if item already exists (demo purposes only, unnecessary as would expect check in mint call)
if pop_api::nfts::item(collection_id, item_id)?.is_some() {
return Err(ContractError::ItemAlreadyExists);
}

// mint api
pop_api::nfts::mint(collection_id, item_id, receiver)?;
ink::env::debug_println!("Contract::mint_through_runtime: item minted successfully");

// check owner
match pop_api::nfts::owner(collection_id, item_id)? {
Some(owner) if owner == receiver => {
ink::env::debug_println!(
"Contract::mint_through_runtime success: minted item belongs to receiver"
);
},
_ => {
return Err(ContractError::NotOwner);
},
}
result?;

ink::env::debug_println!("PopApiExtensionDemo::mint_through_runtime end");
ink::env::debug_println!("Contract::mint_through_runtime end");
Ok(())
}
}
Expand Down
2 changes: 2 additions & 0 deletions pop-api/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ version = "0.0.0"
edition = "2021"

[dependencies]
bounded-collections = { version = "0.1", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }

Expand All @@ -17,6 +18,7 @@ crate-type = ["rlib"]
[features]
default = ["std"]
std = [
"bounded-collections/std",
"scale/std",
"scale-info/std",
]
15 changes: 15 additions & 0 deletions pop-api/primitives/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

pub use bounded_collections::{BoundedBTreeMap, BoundedBTreeSet, BoundedVec, ConstU32};
//use scale::{Decode, Encode, MaxEncodedLen};

pub mod storage_keys;

// /// Some way of identifying an account on the chain.
// #[derive(Encode, Decode, Debug, MaxEncodedLen)]
// pub struct AccountId([u8; 32]);
// Id used for identifying non-fungible collections.
pub type CollectionId = u32;
// Id used for identifying non-fungible items.
pub type ItemId = u32;
/// The maximum length of an attribute key.
pub type KeyLimit = ConstU32<64>;
/// The maximum approvals an item could have.
pub type ApprovalsLimit = ConstU32<20>;
23 changes: 17 additions & 6 deletions pop-api/primitives/src/storage_keys.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::*;
use scale::{Decode, Encode, MaxEncodedLen};

#[derive(Encode, Decode, Debug, MaxEncodedLen)]
Expand All @@ -14,10 +15,20 @@ pub enum ParachainSystemKeys {
// https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/nfts/src/impl_nonfungibles.rs
#[derive(Encode, Decode, Debug, MaxEncodedLen)]
pub enum NftsKeys {
Owner,
CollectionOwner,
Attribute,
CustomAttribute,
SystemAttribute,
CollectionAttribute,
// Get the details of a collection.
Collection(CollectionId),
/// Get the owner of the collection, if the collection exists.
CollectionOwner(CollectionId),
// Get the details of an item.
Item(CollectionId, ItemId),
/// Get the owner of the item, if the item exists.
Owner(CollectionId, ItemId),
/// Get the attribute value of `item` of `collection` corresponding to `key`.
Attribute(CollectionId, ItemId, BoundedVec<u8, KeyLimit>),
// /// Get the custom attribute value of `item` of `collection` corresponding to `key`.
// CustomAttribute(AccountId, CollectionId, ItemId, BoundedVec<u8, KeyLimit>),
/// Get the system attribute value of `item` of `collection` corresponding to `key`
SystemAttribute(CollectionId, Option<ItemId>, BoundedVec<u8, KeyLimit>),
/// Get the attribute value of `item` of `collection` corresponding to `key`.
CollectionAttribute(CollectionId, BoundedVec<u8, KeyLimit>),
}
7 changes: 0 additions & 7 deletions pop-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,10 @@ pub use sp_runtime::{BoundedVec, MultiAddress, MultiSignature};
use v0::RuntimeCall;
pub use v0::{balances, nfts, state};

// Id used for identifying non-fungible collections.
pub type CollectionId = u32;

// Id used for identifying non-fungible items.
pub type ItemId = u32;

type AccountId = <Environment as ink::env::Environment>::AccountId;
type Balance = <Environment as ink::env::Environment>::Balance;
type BlockNumber = <Environment as ink::env::Environment>::BlockNumber;
type StringLimit = u32;
type KeyLimit = u32;
type MaxTips = u32;

pub type Result<T> = core::result::Result<T, PopApiError>;
Expand Down
97 changes: 95 additions & 2 deletions pop-api/src/v0/nfts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::RuntimeCall;
use crate::{PopApiError::UnknownStatusCode, *};
use ink::prelude::vec::Vec;
use primitives::MultiAddress;
use primitives::{ApprovalsLimit, BoundedBTreeMap, CollectionId, ItemId, KeyLimit, MultiAddress};
use scale::Encode;
use types::*;

Expand Down Expand Up @@ -300,6 +300,66 @@ pub fn claim_swap(
}))?)
}

/// Get the owner of the item, if the item exists.
pub fn owner(collection: CollectionId, item: ItemId) -> Result<Option<AccountId>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::Owner(collection, item)))?)
}

/// Get the owner of the collection, if the collection exists.
pub fn collection_owner(collection: CollectionId) -> Result<Option<AccountId>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::CollectionOwner(collection)))?)
}

/// Get the attribute value of `item` of `collection` corresponding to `key`.
pub fn attribute(
collection: CollectionId,
item: ItemId,
key: BoundedVec<u8, KeyLimit>,
) -> Result<Option<Vec<u8>>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::Attribute(collection, item, key)))?)
}

// /// Get the custom attribute value of `item` of `collection` corresponding to `key`.
// pub fn custom_attribute(
// account: AccountId,
// collection: CollectionId,
// item: ItemId,
// key: BoundedVec<u8, KeyLimit>,
// ) -> Result<Option<Vec<u8>>> {
// Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::CustomAttribute(
// account, collection, item, key,
// )))?)
// }

/// Get the system attribute value of `item` of `collection` corresponding to `key` if
/// `item` is `Some`. Otherwise, returns the system attribute value of `collection`
/// corresponding to `key`.
pub fn system_attribute(
collection: CollectionId,
item: Option<ItemId>,
key: BoundedVec<u8, KeyLimit>,
) -> Result<Option<Vec<u8>>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::SystemAttribute(collection, item, key)))?)
}

/// Get the attribute value of `item` of `collection` corresponding to `key`.
pub fn collection_attribute(
collection: CollectionId,
key: BoundedVec<u8, KeyLimit>,
) -> Result<Option<Vec<u8>>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::CollectionAttribute(collection, key)))?)
}

/// Get the details of a collection.
pub fn collection(collection: CollectionId) -> Result<Option<CollectionDetails>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::Collection(collection)))?)
}

/// Get the details of an item.
pub fn item(collection: CollectionId, item: ItemId) -> Result<Option<ItemDetails>> {
Ok(state::read(RuntimeStateKeys::Nfts(NftsKeys::Item(collection, item)))?)
}

#[derive(Encode)]
pub(crate) enum NftCalls {
#[codec(index = 0)]
Expand Down Expand Up @@ -582,7 +642,10 @@ impl From<PopApiError> for Error {
// Local implementations of pallet-nfts types
mod types {
use super::*;
use crate::{Balance, BlockNumber, CollectionId};
use crate::{
primitives::{CollectionId, ItemId},
Balance, BlockNumber,
};
use enumflags2::{bitflags, BitFlags};
use scale::{Decode, EncodeLike, MaxEncodedLen};
use scale_info::{build::Fields, meta_type, prelude::vec, Path, Type, TypeInfo, TypeParameter};
Expand Down Expand Up @@ -611,6 +674,24 @@ mod types {
pub mint_settings: MintSettings,
}

/// Information about a collection.
#[derive(Decode)]
pub struct CollectionDetails {
/// Collection's owner.
pub owner: AccountId,
/// The total balance deposited by the owner for all the storage data associated with this
/// collection. Used by `destroy`.
pub owner_deposit: Balance,
/// The total number of outstanding items of this collection.
pub items: u32,
/// The total number of outstanding item metadata of this collection.
pub item_metadatas: u32,
/// The total number of outstanding item configs of this collection.
pub item_configs: u32,
/// The total number of attributes for this collection.
pub attributes: u32,
}

/// Wrapper type for `BitFlags<CollectionSetting>` that implements `Codec`.
pub struct CollectionSettings(pub BitFlags<CollectionSetting>);

Expand All @@ -633,6 +714,18 @@ mod types {
DepositRequired,
}

/// Information concerning the ownership of a single unique item.
#[derive(Decode)]
pub struct ItemDetails {
/// The owner of this item.
pub owner: AccountId,
/// The approved transferrer of this item, if one is set.
pub approvals: BoundedBTreeMap<AccountId, Option<BlockNumber>, ApprovalsLimit>,
/// The amount held in the pallet's default account for this item. Free-hold items will have
/// this as zero.
pub deposit: Balance,
}

/// Support for up to 64 user-enabled features on an item.
#[bitflags]
#[repr(u64)]
Expand Down
4 changes: 4 additions & 0 deletions runtime/src/assets_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ parameter_types! {

impl pallet_nfts::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
// TODO: source from primitives
type CollectionId = CollectionId;
// TODO: source from primitives
type ItemId = ItemId;
type Currency = Balances;
type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
Expand All @@ -50,8 +52,10 @@ impl pallet_nfts::Config for Runtime {
type AttributeDepositBase = NftsAttributeDepositBase;
type DepositPerByte = NftsDepositPerByte;
type StringLimit = ConstU32<256>;
// TODO: source from primitives
type KeyLimit = ConstU32<64>;
type ValueLimit = ConstU32<256>;
// TODO: source from primitives
type ApprovalsLimit = ConstU32<20>;
type ItemAttributesApprovalsLimit = ConstU32<30>;
type MaxTips = ConstU32<10>;
Expand Down
Loading

0 comments on commit 101c759

Please sign in to comment.