Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pop-api): further implementation of nfts api #21

Merged
merged 10 commits into from
Mar 7, 2024
2 changes: 2 additions & 0 deletions Cargo.lock

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

107 changes: 62 additions & 45 deletions contracts/pop-api-examples/nfts/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,80 @@ 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 {
NftsError(nfts::Error),
InvalidCollection,
ItemAlreadyExists,
NftsError(nfts::Error),
NotOwner,
}

impl From<nfts::Error> for ContractError {
fn from(value: nfts::Error) -> Self {
ContractError::NftsError(value)
}
fn from(value: nfts::Error) -> Self {
ContractError::NftsError(value)
}
}

#[ink::contract(env = pop_api::Environment)]
mod pop_api_extension_demo {
use super::ContractError;
use super::ContractError;

#[ink(storage)]
#[derive(Default)]
pub struct PopApiExtensionDemo;
#[ink(storage)]
#[derive(Default)]
pub struct PopApiExtensionDemo;

impl PopApiExtensionDemo {
#[ink(constructor, payable)]
pub fn new() -> Self {
ink::env::debug_println!("PopApiExtensionDemo::new");
Default::default()
}
impl PopApiExtensionDemo {
#[ink(constructor, payable)]
pub fn new() -> Self {
ink::env::debug_println!("Contract::new");
Default::default()
}

#[ink(message)]
pub fn mint_through_runtime(
&mut self,
collection_id: u32,
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);
#[ink(message)]
pub fn mint_through_runtime(
&mut self,
collection_id: u32,
item_id: u32,
receiver: AccountId,
) -> Result<(), ContractError> {
ink::env::debug_println!(
"Contract::mint_through_runtime: collection_id: {:?} item_id {:?} receiver: {:?}",
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:?}"
);
if let Err(pop_api::nfts::Error::NoConfig) = result {
ink::env::debug_println!(
"PopApiExtensionDemo::mint_through_runtime expected error received"
);
}
result?;
// 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);
}

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

#[cfg(test)]
mod tests {
use super::*;
// 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);
},
}

#[ink::test]
fn default_works() {
PopApiExtensionDemo::new();
}
}
ink::env::debug_println!("Contract::mint_through_runtime end");
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

#[ink::test]
fn default_works() {
PopApiExtensionDemo::new();
}
}
}
4 changes: 3 additions & 1 deletion pop-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ version = "0.0.0"
edition = "2021"

[dependencies]
enumflags2 = { version = "0.7.7" }
ink = { version = "4.3.0", 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 }
scale-info = { version = "2.6", default-features = false, features = ["derive"] }
sp-io = { version = "23.0.0", default-features = false, features = ["disable_panic_handler", "disable_oom", "disable_allocator"] }
sp-runtime = { version = "24.0", default-features = false }

Expand All @@ -22,6 +23,7 @@ crate-type = ["rlib"]
[features]
default = ["std"]
std = [
"enumflags2/std",
"ink/std",
"pop-api-primitives/std",
"scale/std",
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]);
peterwht marked this conversation as resolved.
Show resolved Hide resolved
// 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: 23 additions & 0 deletions pop-api/primitives/src/storage_keys.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
use super::*;
use scale::{Decode, Encode, MaxEncodedLen};

#[derive(Encode, Decode, Debug, MaxEncodedLen)]
pub enum RuntimeStateKeys {
Nfts(NftsKeys),
ParachainSystem(ParachainSystemKeys),
}

#[derive(Encode, Decode, Debug, MaxEncodedLen)]
pub enum ParachainSystemKeys {
LastRelayChainBlockNumber,
}

// https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/nfts/src/impl_nonfungibles.rs
#[derive(Encode, Decode, Debug, MaxEncodedLen)]
pub enum NftsKeys {
// 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>),
}
16 changes: 4 additions & 12 deletions pop-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,14 @@ pub mod v0;
use crate::PopApiError::{Balances, Nfts, UnknownStatusCode};
use ink::{prelude::vec::Vec, ChainExtensionInstance};
use primitives::storage_keys::*;
use scale;
pub use sp_runtime::{BoundedVec, MultiAddress, MultiSignature};
use v0::RuntimeCall;
pub use v0::{balances, nfts, state};
pub use v0::{balances, nfts, relay_chain_block_number, 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 = <ink::env::DefaultEnvironment as ink::env::Environment>::AccountId;
type Balance = <ink::env::DefaultEnvironment as ink::env::Environment>::Balance;
type BlockNumber = <ink::env::DefaultEnvironment as ink::env::Environment>::BlockNumber;
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
9 changes: 9 additions & 0 deletions pop-api/src/v0/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
use crate::{
primitives::storage_keys::{ParachainSystemKeys, RuntimeStateKeys},
BlockNumber, PopApiError,
};

pub mod balances;
pub mod nfts;
pub mod state;

pub fn relay_chain_block_number() -> Result<BlockNumber, PopApiError> {
state::read(RuntimeStateKeys::ParachainSystem(ParachainSystemKeys::LastRelayChainBlockNumber))
}

#[derive(scale::Encode)]
pub(crate) enum RuntimeCall {
#[codec(index = 10)]
Expand Down
Loading
Loading