#![cfg_attr(not(feature = "std"), no_std, no_main)] pub use data::{Id, PSP34Data, PSP34Event}; pub use errors::PSP34Error; pub use traits::{PSP34, PSP34Burnable, PSP34Enumerable, PSP34Metadata, PSP34Mintable}; mod data; mod errors; mod traits; mod unit_tests; mod test_utils; // An example code of a smart contract using PSP34Data struct to implement // the functionality of PSP34 fungible token. // // Any contract can be easily enriched to act as PSP34 token by: // (1) adding PSP34Data to contract storage // (2) properly initializing it // (3) defining the correct AttributeSet, Transfer and Approval events // (4) implementing PSP34 trait based on PSP34Data methods // (5) properly emitting resulting events // // Implemented the optional PSP34Mintable (6), PSP34Burnable (7), and PSP34Metadata (8) extensions // and included unit tests (8). #[cfg(feature = "contract")] #[ink::contract] pub mod token { use ink::prelude::string::ToString; use ink::prelude::vec::Vec; use crate::{Id, PSP34, PSP34Data, PSP34Error, PSP34Event}; use crate::data::Data; #[ink(storage)] pub struct Token { pub data: PSP34Data, } impl Token { #[ink(constructor)] pub fn new() -> Self { Self { data: PSP34Data::new(), } } // A helper function translating a vector of PSP34Events into the proper // ink event types (defined internally in this contract) and emitting them. // (5) fn emit_events(&self, events: ink::prelude::vec::Vec) { for event in events { match event { PSP34Event::Approval { owner, operator, id, approved, } => self.env().emit_event(Approval { owner, operator, id, approved, }), PSP34Event::Transfer { from, to, id } => { self.env().emit_event(Transfer { from, to, id }) } PSP34Event::AttributeSet { id, key, data } => { self.env().emit_event(AttributeSet { id, key, data }) } } } } } // (3) #[ink(event)] pub struct Approval { #[ink(topic)] owner: AccountId, #[ink(topic)] operator: AccountId, #[ink(topic)] id: Option, approved: bool, } // (3) #[ink(event)] pub struct Transfer { #[ink(topic)] from: Option, #[ink(topic)] to: Option, #[ink(topic)] id: Id, } // (3) #[ink(event)] pub struct AttributeSet { id: Id, key: Vec, data: Vec, } // (4) impl PSP34 for Token { #[ink(message)] fn collection_id(&self) -> Id { self.data.collection_id(self.env().account_id()) } #[ink(message)] fn total_supply(&self) -> u128 { self.data.total_supply() } #[ink(message)] fn balance_of(&self, owner: AccountId) -> u32 { self.data.balance_of(owner) } #[ink(message)] fn allowance(&self, owner: AccountId, operator: AccountId, id: Option) -> bool { self.data.allowance(owner, operator, id.as_ref()) } #[ink(message)] fn transfer( &mut self, to: AccountId, id: Id, data: ink::prelude::vec::Vec, ) -> Result<(), PSP34Error> { let events = self.data.transfer(self.env().caller(), to, id, data)?; self.emit_events(events); Ok(()) } #[ink(message)] fn approve( &mut self, operator: AccountId, id: Option, approved: bool, ) -> Result<(), PSP34Error> { let events = self .data .approve(self.env().caller(), operator, id, approved)?; self.emit_events(events); Ok(()) } #[ink(message)] fn owner_of(&self, id: Id) -> Option { self.data.owner_of(&id) } } }