1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]18extern crate alloc;19use alloc::vec::Vec;2021use ink_lang as ink;22use ink_env::{Environment, DefaultEnvironment};2324pub enum NftEnvironment {}2526impl Environment for NftEnvironment {27 const MAX_EVENT_TOPICS: usize =28 <DefaultEnvironment as Environment>::MAX_EVENT_TOPICS;2930 type AccountId = <DefaultEnvironment as Environment>::AccountId;31 type Balance = <DefaultEnvironment as Environment>::Balance;32 type Hash = <DefaultEnvironment as Environment>::Hash;33 type BlockNumber = <DefaultEnvironment as Environment>::BlockNumber;34 type Timestamp = <DefaultEnvironment as Environment>::Timestamp;3536 type ChainExtension = NftChainExtension;37}383940#[derive(41 Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode,42)]43pub enum NftErrorCode {44 SomeError,45}4647impl ink_env::chain_extension::FromStatusCode for NftErrorCode {48 fn from_status_code(status_code: u32) -> Result<(), Self> {49 match status_code {50 0 => Ok(()),51 1 => Err(Self::SomeError),52 _ => panic!("encountered unknown status code"),53 }54 }55}5657#[derive(scale::Encode, scale::Decode, scale_info::TypeInfo)]58pub enum CreateItemData {59 Nft {60 const_data: Vec<u8>,61 },62 Fungible {63 value: u128,64 },65 ReFungible {66 const_data: Vec<u8>,67 pieces: u128,68 },69}7071type DefaultAccountId = <DefaultEnvironment as Environment>::AccountId;7273#[ink::chain_extension]74pub trait NftChainExtension {75 type ErrorCode = NftErrorCode;7677 78 79 #[ink(extension = 0, returns_result = false)]80 fn transfer(recipient: DefaultAccountId, collection_id: u32, token_id: u32, amount: u128);81 #[ink(extension = 1, returns_result = false)]82 fn create_item(owner: DefaultAccountId, collection_id: u32, data: CreateItemData);83 #[ink(extension = 2, returns_result = false)]84 fn create_multiple_items(owner: DefaultAccountId, collection_id: u32, data: Vec<CreateItemData>);85 #[ink(extension = 3, returns_result = false)]86 fn approve(spender: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);87 #[ink(extension = 4, returns_result = false)]88 fn transfer_from(owner: DefaultAccountId, recipient: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);89 #[ink(extension = 6, returns_result = false)]90 fn toggle_allow_list(collection_id: u32, address: DefaultAccountId, allowlisted: bool);91}9293#[ink::contract(env = crate::NftEnvironment, dynamic_storage_allocator = true)]94mod nft_transfer {95 use alloc::vec::Vec;96 97 use crate::CreateItemData;9899 #[ink(storage)]100 pub struct NftTransfer {101 }102103 impl NftTransfer {104 105 106 107 #[ink(constructor)]108 pub fn default() -> Self {109 Self {}110 }111112 113 #[ink(message)]114 pub fn transfer(&mut self, recipient: AccountId, collection_id: u32, token_id: u32, amount: u128) {115 let _ = self.env()116 .extension()117 .transfer(recipient, collection_id, token_id, amount);118 }119 #[ink(message)]120 pub fn create_item(&mut self, recipient: AccountId, collection_id: u32, data: CreateItemData) {121 let _ = self.env()122 .extension()123 .create_item(recipient, collection_id, data);124 }125 #[ink(message)]126 pub fn create_multiple_items(&mut self, owner: AccountId, collection_id: u32, data: Vec<CreateItemData>) {127 let _ = self.env()128 .extension()129 .create_multiple_items(owner, collection_id, data);130 }131 #[ink(message)]132 pub fn approve(&mut self, spender: AccountId, collection_id: u32, item_id: u32, amount: u128) {133 let _ = self.env()134 .extension()135 .approve(spender, collection_id, item_id, amount);136 }137 #[ink(message)]138 pub fn transfer_from(&mut self, owner: AccountId, recipient: AccountId, collection_id: u32, item_id: u32, amount: u128) {139 let _ = self.env()140 .extension()141 .transfer_from(owner, recipient, collection_id, item_id, amount);142 }143 #[ink(message)]144 pub fn toggle_allow_list(&mut self, collection_id: u32, address: AccountId, allowlisted: bool) {145 let _ = self.env()146 .extension()147 .toggle_allow_list(collection_id, address, allowlisted);148 }149150 }151152}