From 7d30ae382671b7a6fb2ac02cff2b3a835e0c5503 Mon Sep 17 00:00:00 2001 From: chungquantin <56880684+chungquantin@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:24:11 +0700 Subject: [PATCH] chore: add psp34 skeleton code --- pop-api/examples/nonfungibles/Cargo.toml | 34 +++++++ pop-api/examples/nonfungibles/lib.rs | 123 +++++++++++++++++++++++ pop-api/examples/nonfungibles/tests.rs | 0 3 files changed, 157 insertions(+) create mode 100644 pop-api/examples/nonfungibles/Cargo.toml create mode 100644 pop-api/examples/nonfungibles/lib.rs create mode 100644 pop-api/examples/nonfungibles/tests.rs diff --git a/pop-api/examples/nonfungibles/Cargo.toml b/pop-api/examples/nonfungibles/Cargo.toml new file mode 100644 index 000000000..dc8ec851b --- /dev/null +++ b/pop-api/examples/nonfungibles/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = [ "R0GUE " ] +edition = "2021" +name = "nonfungibles" +version = "0.1.0" + +[dependencies] +ink = { version = "=5.0.0", default-features = false, features = [ "ink-debug" ] } +pop-api = { path = "../../../pop-api", default-features = false, features = [ + "nonfungibles", +] } + +[dev-dependencies] +drink = { package = "pop-drink", git = "https://github.com/r0gue-io/pop-drink" } +env_logger = { version = "0.11.3" } +serde_json = "1.0.114" + +# TODO: due to compilation issues caused by `sp-runtime`, `frame-support-procedural` and `staging-xcm` this dependency +# (with specific version) has to be added. Will be tackled by #348, please ignore for now. +frame-support-procedural = { version = "=30.0.1", default-features = false } +sp-runtime = { version = "=38.0.0", default-features = false } +staging-xcm = { version = "=14.1.0", default-features = false } + +[lib] +path = "lib.rs" + +[features] +default = [ "std" ] +e2e-tests = [ ] +ink-as-dependency = [ ] +std = [ + "ink/std", + "pop-api/std", +] diff --git a/pop-api/examples/nonfungibles/lib.rs b/pop-api/examples/nonfungibles/lib.rs new file mode 100644 index 000000000..90552c013 --- /dev/null +++ b/pop-api/examples/nonfungibles/lib.rs @@ -0,0 +1,123 @@ +use ink::prelude::vec::Vec; +use pop_api::v0::nonfungibles::{ + self as api, + events::{Approval, Transfer}, + traits::{Psp34, Psp34Enumerable, Psp34Metadata}, + types::{CollectionConfig, CollectionId, ItemId}, + Psp34Error, +}; + +#[cfg(test)] +mod tests; + +#[ink::contract] +mod nonfungibles { + use super::*; + + #[ink(storage)] + pub struct NonFungible { + id: CollectionId, + owner: AccountId, + } + + impl NonFungible { + /// Instantiate the contract and create a new collection. The collection identifier will be + /// stored in contract's storage. + /// + /// # Parameters + /// * - `id` - The identifier of the collection. + /// * - `config` - The configuration of the collection. + #[ink(constructor, payable)] + pub fn new(id: CollectionId, config: CollectionConfig) -> Result { + let instance = Self { id, owner: Self::env().caller() }; + let contract_id = instance.env().account_id(); + api::create(contract_id, config).map_err(Psp34Error::from)?; + Ok(instance) + } + } + impl Psp34 for NonFungible { + /// Returns the collection `Id`. + #[ink(message)] + fn collection_id(&self) -> ItemId { + self.id + } + + // Returns the current total supply of the NFT. + #[ink(message)] + fn total_supply(&self) -> u128 { + api::total_supply(self.id).unwrap_or_default() + } + + /// Returns the amount of items the owner has within a collection. + /// + /// # Parameters + /// - `owner` - The account whose balance is being queried. + #[ink(message)] + fn balance_of(&self, owner: AccountId) -> u32 { + api::balance_of(self.id, owner).unwrap_or_default() + } + + /// Returns whether the operator is approved by the owner to withdraw `item`. If `item` is + /// `None`, it returns whether the operator is approved to withdraw all owner's items for + /// the given collection. + /// + /// # Parameters + /// * `owner` - The account that owns the item(s). + /// * `operator` - the account that is allowed to withdraw the item(s). + /// * `item` - The item. If `None`, it is regarding all owner's items in collection. + #[ink(message)] + fn allowance(&self, owner: AccountId, operator: AccountId, id: Option) -> bool { + api::allowance(self.id, id, owner, operator).unwrap_or_default() + } + + /// Transfers an owned or approved item to the specified recipient. + /// + /// # Parameters + /// * `to` - The recipient account. + /// * `item` - The item. + /// - `data` - Additional data in unspecified format. + #[ink(message)] + fn transfer( + &mut self, + to: AccountId, + id: ItemId, + _data: Vec, + ) -> Result<(), Psp34Error> { + let contract = self.env().account_id(); + api::transfer(self.id, id, to).map_err(Psp34Error::from)?; + self.env().emit_event(Transfer { from: Some(contract), to: Some(to), item: id }); + Ok(()) + } + + /// Approves operator to withdraw item(s) from the contract's account. + /// + /// # Parameters + /// * `operator` - The account that is allowed to withdraw the item. + /// * `item` - Optional item. `None` means all items owned in the specified collection. + /// * `approved` - Whether the operator is given or removed the right to withdraw the + /// item(s). + #[ink(message)] + fn approve( + &mut self, + operator: AccountId, + id: Option, + approved: bool, + ) -> Result<(), Psp34Error> { + let contract = self.env().account_id(); + api::approve(self.id, id, operator, approved).map_err(Psp34Error::from)?; + let value = self.allowance(contract, operator, id); + self.env() + .emit_event(Approval { owner: contract, operator, item: id, approved }); + Ok(()) + } + + /// Returns the owner of an item within a specified collection, if any. + /// + /// # Parameters + /// * `item` - The item. + #[ink(message)] + fn owner_of(&self, id: ItemId) -> Option { + api::owner_of(self.id, id).unwrap_or_default() + } + } +} diff --git a/pop-api/examples/nonfungibles/tests.rs b/pop-api/examples/nonfungibles/tests.rs new file mode 100644 index 000000000..e69de29bb