difftreelog
refactor split nonfungible into its own pallet
in: master
8 files changed
pallets/nonfungible/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/Cargo.toml
@@ -0,0 +1,37 @@
+[package]
+name = "pallet-nonfungible"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies.codec]
+default-features = false
+features = ['derive']
+package = 'parity-scale-codec'
+version = '2.0.0'
+
+[dependencies]
+frame-support = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10' }
+frame-system = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10' }
+sp-runtime = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10' }
+sp-std = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10' }
+sp-core = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.10' }
+pallet-common = { default-features = false, path = '../common' }
+nft-data-structs = { default-features = false, path = '../../primitives/nft' }
+evm-coder = { default-features = false, path = '../../crates/evm-coder' }
+pallet-evm-coder-substrate = { default-features = false, path = '../evm-coder-substrate' }
+ethereum = { default-features = false, version = "0.9.0" }
+
+[features]
+default = ["std"]
+std = [
+ "frame-support/std",
+ "frame-system/std",
+ "sp-runtime/std",
+ "sp-std/std",
+ "nft-data-structs/std",
+ "pallet-common/std",
+ "evm-coder/std",
+ "ethereum/std",
+ "pallet-evm-coder-substrate/std",
+]
+runtime-benchmarks = []
pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -0,0 +1 @@
+#![cfg(feature = "runtime-benchmarking")]
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/src/common.rs
@@ -0,0 +1,228 @@
+use core::marker::PhantomData;
+
+use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
+use nft_data_structs::TokenId;
+use pallet_common::{
+ CommonCollectionOperations, CommonWeightInfo, account::CrossAccountId, with_weight,
+};
+use sp_runtime::DispatchError;
+use sp_std::vec::Vec;
+
+use crate::{
+ AccountBalance, Allowance, Config, CreateItemData, DataKind, Error, NonfungibleHandle, Owned,
+ Owner, Pallet, SelfWeightOf, TokenData, weights::WeightInfo,
+};
+
+pub struct CommonWeights<T: Config>(PhantomData<T>);
+impl<T: Config> CommonWeightInfo for CommonWeights<T> {
+ fn create_item() -> Weight {
+ <SelfWeightOf<T>>::create_item()
+ }
+
+ fn create_multiple_items(amount: u32) -> Weight {
+ <SelfWeightOf<T>>::create_multiple_items(amount)
+ }
+
+ fn burn_item() -> Weight {
+ <SelfWeightOf<T>>::burn_item()
+ }
+
+ fn transfer() -> Weight {
+ <SelfWeightOf<T>>::transfer()
+ }
+
+ fn approve() -> Weight {
+ <SelfWeightOf<T>>::approve()
+ }
+
+ fn transfer_from() -> Weight {
+ <SelfWeightOf<T>>::transfer_from()
+ }
+
+ fn set_variable_metadata(_bytes: u32) -> Weight {
+ <SelfWeightOf<T>>::set_variable_metadata()
+ }
+}
+
+fn map_create_data<T: Config>(
+ data: nft_data_structs::CreateItemData,
+ to: &T::CrossAccountId,
+) -> Result<CreateItemData<T>, DispatchError> {
+ match data {
+ nft_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData {
+ const_data: data.const_data,
+ variable_data: data.variable_data,
+ owner: to.clone(),
+ }),
+ _ => fail!(<Error<T>>::NotNonfungibleDataUsedToMintFungibleCollectionToken),
+ }
+}
+
+impl<T: Config> CommonCollectionOperations<T> for NonfungibleHandle<T> {
+ fn create_item(
+ &self,
+ sender: T::CrossAccountId,
+ to: T::CrossAccountId,
+ data: nft_data_structs::CreateItemData,
+ ) -> DispatchResultWithPostInfo {
+ with_weight(
+ <Pallet<T>>::create_item(self, &sender, map_create_data(data, &to)?),
+ <SelfWeightOf<T>>::create_item(),
+ )
+ }
+
+ fn create_multiple_items(
+ &self,
+ sender: T::CrossAccountId,
+ to: T::CrossAccountId,
+ data: Vec<nft_data_structs::CreateItemData>,
+ ) -> DispatchResultWithPostInfo {
+ let data = data
+ .into_iter()
+ .map(|d| map_create_data::<T>(d, &to))
+ .collect::<Result<Vec<_>, DispatchError>>()?;
+
+ let amount = data.len();
+ with_weight(
+ <Pallet<T>>::create_multiple_items(self, &sender, data),
+ <SelfWeightOf<T>>::create_multiple_items(amount as u32),
+ )
+ }
+
+ fn burn_item(
+ &self,
+ sender: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> DispatchResultWithPostInfo {
+ ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+ if amount == 1 {
+ with_weight(
+ <Pallet<T>>::burn(&self, &sender, token),
+ <SelfWeightOf<T>>::burn_item(),
+ )
+ } else {
+ Ok(().into())
+ }
+ }
+
+ fn transfer(
+ &self,
+ from: T::CrossAccountId,
+ to: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> DispatchResultWithPostInfo {
+ ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+ if amount == 1 {
+ with_weight(
+ <Pallet<T>>::transfer(&self, &from, &to, token),
+ <SelfWeightOf<T>>::transfer(),
+ )
+ } else {
+ Ok(().into())
+ }
+ }
+
+ fn approve(
+ &self,
+ sender: T::CrossAccountId,
+ spender: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> DispatchResultWithPostInfo {
+ ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+
+ with_weight(
+ if amount == 1 {
+ <Pallet<T>>::set_allowance(&self, &sender, token, Some(&spender))
+ } else {
+ <Pallet<T>>::set_allowance(&self, &sender, token, None)
+ },
+ <SelfWeightOf<T>>::approve(),
+ )
+ }
+
+ fn transfer_from(
+ &self,
+ sender: T::CrossAccountId,
+ from: T::CrossAccountId,
+ to: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> DispatchResultWithPostInfo {
+ ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+
+ if amount == 1 {
+ with_weight(
+ <Pallet<T>>::transfer_from(&self, &sender, &from, &to, token),
+ <SelfWeightOf<T>>::transfer_from(),
+ )
+ } else {
+ Ok(().into())
+ }
+ }
+
+ fn set_variable_metadata(
+ &self,
+ sender: T::CrossAccountId,
+ token: TokenId,
+ data: Vec<u8>,
+ ) -> DispatchResultWithPostInfo {
+ with_weight(
+ <Pallet<T>>::set_variable_metadata(&self, &sender, token, data),
+ <SelfWeightOf<T>>::set_variable_metadata(),
+ )
+ }
+
+ fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {
+ <Owned<T>>::iter_prefix((self.id, account.as_sub()))
+ .map(|(id, _)| id)
+ .collect()
+ }
+
+ fn token_exists(&self, token: TokenId) -> bool {
+ <Pallet<T>>::token_exists(self, token)
+ }
+
+ fn token_owner(&self, token: TokenId) -> T::CrossAccountId {
+ <Owner<T>>::get((self.id, token))
+ }
+ fn const_metadata(&self, token: TokenId) -> Vec<u8> {
+ <TokenData<T>>::get((self.id, token, DataKind::Constant))
+ }
+ fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
+ <TokenData<T>>::get((self.id, token, DataKind::Variable))
+ }
+
+ fn collection_tokens(&self) -> u32 {
+ <Pallet<T>>::total_supply(self)
+ }
+
+ fn account_balance(&self, account: T::CrossAccountId) -> u32 {
+ <AccountBalance<T>>::get((self.id, account.as_sub()))
+ }
+
+ fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {
+ if <Owner<T>>::get((self.id, token)) == account {
+ 1
+ } else {
+ 0
+ }
+ }
+
+ fn allowance(
+ &self,
+ sender: T::CrossAccountId,
+ spender: T::CrossAccountId,
+ token: TokenId,
+ ) -> u128 {
+ if <Owner<T>>::get((self.id, token)) != sender {
+ 0
+ } else if <Allowance<T>>::get((self.id, token)) == Some(spender) {
+ 1
+ } else {
+ 0
+ }
+ }
+}
pallets/nonfungible/src/erc.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/src/erc.rs
@@ -0,0 +1,396 @@
+use core::{
+ char::{REPLACEMENT_CHARACTER, decode_utf16},
+ convert::TryInto,
+};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*};
+use frame_support::BoundedVec;
+use nft_data_structs::TokenId;
+use pallet_evm_coder_substrate::dispatch_to_evm;
+use sp_core::{H160, U256};
+use sp_std::{vec::Vec, vec};
+use pallet_common::{account::CrossAccountId, erc::CommonEvmHandler};
+use pallet_evm_coder_substrate::call_internal;
+use pallet_common::erc::PrecompileOutput;
+
+use crate::{
+ AccountBalance, Config, CreateItemData, DataKind, NonfungibleHandle, Owner, Pallet, TokenData,
+ TokensMinted,
+};
+
+#[derive(ToLog)]
+pub enum ERC721Events {
+ Transfer {
+ #[indexed]
+ from: address,
+ #[indexed]
+ to: address,
+ #[indexed]
+ token_id: uint256,
+ },
+ Approval {
+ #[indexed]
+ owner: address,
+ #[indexed]
+ approved: address,
+ #[indexed]
+ token_id: uint256,
+ },
+ #[allow(dead_code)]
+ ApprovalForAll {
+ #[indexed]
+ owner: address,
+ #[indexed]
+ operator: address,
+ approved: bool,
+ },
+}
+
+#[derive(ToLog)]
+pub enum ERC721MintableEvents {
+ #[allow(dead_code)]
+ MintingFinished {},
+}
+
+#[solidity_interface(name = "ERC721Metadata")]
+impl<T: Config> NonfungibleHandle<T> {
+ fn name(&self) -> Result<string> {
+ Ok(decode_utf16(self.name.iter().copied())
+ .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
+ .collect::<string>())
+ }
+ fn symbol(&self) -> Result<string> {
+ Ok(string::from_utf8_lossy(&self.token_prefix).into())
+ }
+
+ #[solidity(rename_selector = "tokenURI")]
+ fn token_uri(&self, token_id: uint256) -> Result<string> {
+ let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
+ Ok(string::from_utf8_lossy(&<TokenData<T>>::get((
+ self.id,
+ token_id,
+ DataKind::Constant,
+ )))
+ .into())
+ }
+}
+
+#[solidity_interface(name = "ERC721Enumerable")]
+impl<T: Config> NonfungibleHandle<T> {
+ fn token_by_index(&self, index: uint256) -> Result<uint256> {
+ Ok(index)
+ }
+
+ fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
+ // TODO: Not implemetable
+ Err("not implemented".into())
+ }
+
+ fn total_supply(&self) -> Result<uint256> {
+ Ok(<Pallet<T>>::total_supply(self).into())
+ }
+}
+
+#[solidity_interface(name = "ERC721", events(ERC721Events))]
+impl<T: Config> NonfungibleHandle<T> {
+ fn balance_of(&self, owner: address) -> Result<uint256> {
+ let owner = T::CrossAccountId::from_eth(owner);
+ let balance = <AccountBalance<T>>::get((self.id, owner.as_sub()));
+ Ok(balance.into())
+ }
+ fn owner_of(&self, token_id: uint256) -> Result<address> {
+ let token: TokenId = token_id.try_into()?;
+ Ok(*<Owner<T>>::get((self.id, token)).as_eth())
+ }
+ fn safe_transfer_from_with_data(
+ &mut self,
+ _from: address,
+ _to: address,
+ _token_id: uint256,
+ _data: bytes,
+ _value: value,
+ ) -> Result<void> {
+ // TODO: Not implemetable
+ Err("not implemented".into())
+ }
+ fn safe_transfer_from(
+ &mut self,
+ _from: address,
+ _to: address,
+ _token_id: uint256,
+ _value: value,
+ ) -> Result<void> {
+ // TODO: Not implemetable
+ Err("not implemented".into())
+ }
+
+ fn transfer_from(
+ &mut self,
+ caller: caller,
+ from: address,
+ to: address,
+ token_id: uint256,
+ _value: value,
+ ) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let from = T::CrossAccountId::from_eth(from);
+ let to = T::CrossAccountId::from_eth(to);
+ let token = token_id.try_into()?;
+
+ <Pallet<T>>::transfer_from(self, &caller, &from, &to, token)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn approve(
+ &mut self,
+ caller: caller,
+ approved: address,
+ token_id: uint256,
+ _value: value,
+ ) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let approved = T::CrossAccountId::from_eth(approved);
+ let token = token_id.try_into()?;
+
+ <Pallet<T>>::set_allowance(self, &caller, token, Some(&approved))
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn set_approval_for_all(
+ &mut self,
+ _caller: caller,
+ _operator: address,
+ _approved: bool,
+ ) -> Result<void> {
+ // TODO: Not implemetable
+ Err("not implemented".into())
+ }
+
+ fn get_approved(&self, _token_id: uint256) -> Result<address> {
+ // TODO: Not implemetable
+ Err("not implemented".into())
+ }
+
+ fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
+ // TODO: Not implemetable
+ Err("not implemented".into())
+ }
+}
+
+#[solidity_interface(name = "ERC721Burnable")]
+impl<T: Config> NonfungibleHandle<T> {
+ fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let token = token_id.try_into()?;
+
+ <Pallet<T>>::burn(self, &caller, token).map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+}
+
+#[solidity_interface(name = "ERC721Mintable", events(ERC721MintableEvents))]
+impl<T: Config> NonfungibleHandle<T> {
+ fn minting_finished(&self) -> Result<bool> {
+ Ok(false)
+ }
+
+ fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let token_id: u32 = token_id.try_into()?;
+ if <TokensMinted<T>>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?
+ != token_id
+ {
+ return Err("item id should be next".into());
+ }
+
+ <Pallet<T>>::create_item(
+ self,
+ &caller,
+ CreateItemData {
+ const_data: BoundedVec::default(),
+ variable_data: BoundedVec::default(),
+ owner: to,
+ },
+ )
+ .map_err(dispatch_to_evm::<T>)?;
+
+ Ok(true)
+ }
+
+ #[solidity(rename_selector = "mintWithTokenURI")]
+ fn mint_with_token_uri(
+ &mut self,
+ caller: caller,
+ to: address,
+ token_id: uint256,
+ token_uri: string,
+ ) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?;
+ if <TokensMinted<T>>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?
+ != token_id
+ {
+ return Err("item id should be next".into());
+ }
+
+ <Pallet<T>>::create_item(
+ self,
+ &caller,
+ CreateItemData {
+ const_data: Vec::<u8>::from(token_uri)
+ .try_into()
+ .map_err(|_| "token uri is too long")?,
+ variable_data: BoundedVec::default(),
+ owner: to,
+ },
+ )
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+
+ fn finish_minting(&mut self, _caller: caller) -> Result<bool> {
+ Err("not implementable".into())
+ }
+}
+
+#[solidity_interface(name = "ERC721UniqueExtensions")]
+impl<T: Config> NonfungibleHandle<T> {
+ #[solidity(rename_selector = "transfer")]
+ fn transfer_nft(
+ &mut self,
+ caller: caller,
+ to: address,
+ token_id: uint256,
+ _value: value,
+ ) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let token = token_id.try_into()?;
+
+ <Pallet<T>>::transfer(self, &caller, &to, token).map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn next_token_id(&self) -> Result<uint256> {
+ Ok(<TokensMinted<T>>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?
+ .into())
+ }
+
+ fn set_variable_metadata(
+ &mut self,
+ caller: caller,
+ token_id: uint256,
+ data: bytes,
+ ) -> Result<void> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let token = token_id.try_into()?;
+
+ <Pallet<T>>::set_variable_metadata(self, &caller, token, data)
+ .map_err(dispatch_to_evm::<T>)?;
+ Ok(())
+ }
+
+ fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {
+ let token: TokenId = token_id.try_into()?;
+
+ Ok(<TokenData<T>>::get((self.id, token, DataKind::Variable)))
+ }
+
+ fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let mut expected_index = <TokensMinted<T>>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?;
+
+ let total_tokens = token_ids.len();
+ for id in token_ids.into_iter() {
+ let id: u32 = id.try_into().map_err(|_| "token id overflow")?;
+ if id != expected_index {
+ return Err("item id should be next".into());
+ }
+ expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
+ }
+ let data = (0..total_tokens)
+ .map(|_| CreateItemData {
+ const_data: BoundedVec::default(),
+ variable_data: BoundedVec::default(),
+ owner: to.clone(),
+ })
+ .collect();
+
+ <Pallet<T>>::create_multiple_items(self, &caller, data).map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+
+ #[solidity(rename_selector = "mintBulkWithTokenURI")]
+ fn mint_bulk_with_token_uri(
+ &mut self,
+ caller: caller,
+ to: address,
+ tokens: Vec<(uint256, string)>,
+ ) -> Result<bool> {
+ let caller = T::CrossAccountId::from_eth(caller);
+ let to = T::CrossAccountId::from_eth(to);
+ let mut expected_index = <TokensMinted<T>>::get(self.id)
+ .checked_add(1)
+ .ok_or("item id overflow")?;
+
+ let mut data = Vec::with_capacity(tokens.len());
+ for (id, token_uri) in tokens {
+ let id: u32 = id.try_into().map_err(|_| "token id overflow")?;
+ if id != expected_index {
+ panic!("item id should be next ({}) but got {}", expected_index, id);
+ }
+ expected_index = expected_index.checked_add(1).ok_or("item id overflow")?;
+
+ data.push(CreateItemData {
+ const_data: Vec::<u8>::from(token_uri)
+ .try_into()
+ .map_err(|_| "token uri is too long")?,
+ variable_data: vec![].try_into().unwrap(),
+ owner: to.clone(),
+ });
+ }
+
+ <Pallet<T>>::create_multiple_items(self, &caller, data).map_err(dispatch_to_evm::<T>)?;
+ Ok(true)
+ }
+}
+
+#[solidity_interface(
+ name = "UniqueNFT",
+ is(
+ ERC721,
+ ERC721Metadata,
+ ERC721Enumerable,
+ ERC721UniqueExtensions,
+ ERC721Mintable,
+ ERC721Burnable,
+ )
+)]
+impl<T: Config> NonfungibleHandle<T> {}
+
+// Not a tests, but code generators
+generate_stubgen!(gen_impl, UniqueNFTCall, true);
+generate_stubgen!(gen_iface, UniqueNFTCall, false);
+
+pub const CODE: &[u8] = include_bytes!("./stubs/UniqueNFT.raw");
+
+impl<T: Config> CommonEvmHandler for NonfungibleHandle<T> {
+ const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");
+
+ fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
+ let result = call_internal::<UniqueNFTCall, _>(*source, &mut self, value, input);
+ self.0.recorder.evm_to_precompile_output(result)
+ }
+}
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1#![cfg_attr(not(feature = "std"), no_std)]23use erc::ERC721Events;4use frame_support::{BoundedVec, ensure};5use nft_data_structs::{6 AccessMode, CUSTOM_DATA_LIMIT, Collection, CollectionId, CustomDataLimit, TokenId,7};8use pallet_common::{9 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,10};11use sp_core::H160;12use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};13use sp_std::{vec::Vec, vec};14use core::ops::Deref;15use sp_std::collections::btree_map::BTreeMap;1617pub use pallet::*;18pub mod benchmarking;19pub mod common;20pub mod erc;21pub mod weights;2223pub struct CreateItemData<T: Config> {24 pub const_data: BoundedVec<u8, CustomDataLimit>,25 pub variable_data: BoundedVec<u8, CustomDataLimit>,26 pub owner: T::CrossAccountId,27}28pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;2930#[frame_support::pallet]31pub mod pallet {32 use frame_support::{Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};33 use sp_std::vec::Vec;34 use nft_data_structs::{CollectionId, TokenId};35 use super::weights::WeightInfo;3637 #[pallet::error]38 pub enum Error<T> {39 /// Not Nonfungible item data used to mint in Nonfungible collection.40 NotNonfungibleDataUsedToMintFungibleCollectionToken,41 /// Used amount > 1 with NFT42 NonfungibleItemsHaveNoAmount,43 }4445 #[pallet::config]46 pub trait Config: frame_system::Config + pallet_common::Config {47 type WeightInfo: WeightInfo;48 }4950 #[pallet::pallet]51 #[pallet::generate_store(pub(super) trait Store)]52 pub struct Pallet<T>(_);5354 #[pallet::storage]55 pub(super) type TokensMinted<T: Config> =56 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;57 #[pallet::storage]58 pub(super) type TokensBurnt<T: Config> =59 StorageMap<Hasher = Twox64Concat, Key = CollectionId, Value = u32, QueryKind = ValueQuery>;6061 #[derive(Encode, Decode)]62 pub enum DataKind {63 Constant,64 Variable,65 }6667 #[pallet::storage]68 pub(super) type TokenData<T: Config> = StorageNMap<69 Key = (70 Key<Twox64Concat, CollectionId>,71 Key<Twox64Concat, TokenId>,72 Key<Identity, DataKind>,73 ),74 Value = Vec<u8>,75 QueryKind = ValueQuery,76 >;7778 #[pallet::storage]79 pub(super) type Owner<T: Config> = StorageNMap<80 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),81 Value = T::CrossAccountId,82 QueryKind = ValueQuery,83 >;84 /// Used to enumerate tokens owned by account85 #[pallet::storage]86 pub(super) type Owned<T: Config> = StorageNMap<87 Key = (88 Key<Twox64Concat, CollectionId>,89 Key<Blake2_128Concat, T::AccountId>,90 Key<Twox64Concat, TokenId>,91 ),92 Value = bool,93 QueryKind = ValueQuery,94 >;9596 #[pallet::storage]97 pub(super) type AccountBalance<T: Config> = StorageNMap<98 Key = (99 Key<Twox64Concat, CollectionId>,100 Key<Blake2_128Concat, T::AccountId>,101 ),102 Value = u32,103 QueryKind = ValueQuery,104 >;105106 #[pallet::storage]107 pub(super) type Allowance<T: Config> = StorageNMap<108 Key = (Key<Twox64Concat, CollectionId>, Key<Twox64Concat, TokenId>),109 Value = T::CrossAccountId,110 QueryKind = OptionQuery,111 >;112}113114pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);115impl<T: Config> NonfungibleHandle<T> {116 pub fn cast(inner: pallet_common::CollectionHandle<T>) -> Self {117 Self(inner)118 }119 pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {120 self.0121 }122}123impl<T: Config> Deref for NonfungibleHandle<T> {124 type Target = pallet_common::CollectionHandle<T>;125126 fn deref(&self) -> &Self::Target {127 &self.0128 }129}130131impl<T: Config> Pallet<T> {132 pub fn total_supply(collection: &NonfungibleHandle<T>) -> u32 {133 <TokensMinted<T>>::get(collection.id) - <TokensBurnt<T>>::get(collection.id)134 }135 pub fn token_exists(collection: &NonfungibleHandle<T>, token: TokenId) -> bool {136 <Owner<T>>::contains_key((collection.id, token))137 }138 pub fn ensure_owner(139 collection: &NonfungibleHandle<T>,140 token: TokenId,141 sender: &T::CrossAccountId,142 ) -> DispatchResult {143 ensure!(144 &<Owner<T>>::get((collection.id, token)) == sender,145 <CommonError<T>>::NoPermission146 );147 Ok(())148 }149 pub fn item_owner(150 collection: &NonfungibleHandle<T>,151 token: TokenId,152 ) -> Result<T::CrossAccountId, DispatchError> {153 let owner = <Owner<T>>::get((collection.id, token));154 ensure!(155 owner != T::CrossAccountId::default(),156 <CommonError<T>>::TokenNotFound157 );158 Ok(owner)159 }160}161162// unchecked calls skips any permission checks163impl<T: Config> Pallet<T> {164 pub fn init_collection(data: Collection<T>) -> Result<CollectionId, DispatchError> {165 PalletCommon::init_collection(data)166 }167 pub fn destroy_collection(168 collection: NonfungibleHandle<T>,169 sender: &T::CrossAccountId,170 ) -> DispatchResult {171 let id = collection.id;172173 // =========174175 PalletCommon::destroy_collection(collection.0, sender)?;176177 <Owner<T>>::remove_prefix((id,), None);178 <Owned<T>>::remove_prefix((id,), None);179 <TokensMinted<T>>::remove(id);180 <TokensBurnt<T>>::remove(id);181 <TokenData<T>>::remove_prefix((id,), None);182 <Allowance<T>>::remove_prefix((id,), None);183 <AccountBalance<T>>::remove_prefix((id,), None);184 Ok(())185 }186187 pub fn burn(188 collection: &NonfungibleHandle<T>,189 sender: &T::CrossAccountId,190 token: TokenId,191 ) -> DispatchResult {192 let token_owner = <Pallet<T>>::item_owner(collection, token)?;193 ensure!(194 &token_owner == sender195 || (collection.limits.owner_can_transfer196 && collection.is_owner_or_admin(sender)?),197 <CommonError<T>>::NoPermission198 );199200 if collection.access == AccessMode::WhiteList {201 collection.check_whitelist(sender)?;202 }203204 let burnt = <TokensBurnt<T>>::get(collection.id)205 .checked_add(1)206 .ok_or(ArithmeticError::Overflow)?;207208 // =========209210 <Owner<T>>::remove((collection.id, token));211 <Owned<T>>::remove((collection.id, token_owner.as_sub(), token));212 <TokensBurnt<T>>::insert(collection.id, burnt);213 <TokenData<T>>::remove_prefix((collection.id, token), None);214 <Allowance<T>>::remove((collection.id, token));215216 collection.log_infallible(ERC721Events::Transfer {217 from: *token_owner.as_eth(),218 to: H160::default(),219 token_id: token.into(),220 });221 <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(222 collection.id,223 token,224 token_owner,225 1,226 ));227 return Ok(());228 }229230 pub fn transfer(231 collection: &NonfungibleHandle<T>,232 from: &T::CrossAccountId,233 to: &T::CrossAccountId,234 token: TokenId,235 ) -> DispatchResult {236 ensure!(237 collection.transfers_enabled,238 <CommonError<T>>::TransferNotAllowed239 );240241 let token_owner = <Pallet<T>>::item_owner(collection, token)?;242 ensure!(243 &token_owner == from244 || (collection.limits.owner_can_transfer && collection.is_owner_or_admin(from)?),245 <CommonError<T>>::NoPermission246 );247248 if collection.access == AccessMode::WhiteList {249 collection.check_whitelist(from)?;250 collection.check_whitelist(to)?;251 }252 <PalletCommon<T>>::ensure_correct_receiver(to)?;253254 let balance_from = <AccountBalance<T>>::get((collection.id, from.as_sub()))255 .checked_sub(1)256 .ok_or(<CommonError<T>>::TokenValueTooLow)?;257 let balance_to = if from != to {258 let balance_to = <AccountBalance<T>>::get((collection.id, to.as_sub()))259 .checked_add(1)260 .ok_or(ArithmeticError::Overflow)?;261262 ensure!(263 balance_to < collection.limits.account_token_ownership_limit(),264 <CommonError<T>>::AccountTokenLimitExceeded,265 );266267 Some(balance_to)268 } else {269 None270 };271272 collection.consume_sstores(4)?;273 collection.consume_log(3, 0)?;274275 // =========276277 if let Some(balance_to) = balance_to {278 // from != to279 if balance_from == 0 {280 <AccountBalance<T>>::remove((collection.id, from.as_sub()));281 } else {282 <AccountBalance<T>>::insert((collection.id, from.as_sub()), balance_from);283 }284 <AccountBalance<T>>::insert((collection.id, to.as_sub()), balance_to);285 <Owned<T>>::remove((collection.id, from.as_sub(), token));286 <Owned<T>>::insert((collection.id, to.as_sub(), token), true);287 }288 Self::set_allowance_unchecked(collection, from, token, None);289 <Owner<T>>::insert((collection.id, token), &to);290291 collection.log_infallible(ERC721Events::Transfer {292 from: *from.as_eth(),293 to: *to.as_eth(),294 token_id: token.into(),295 });296 <PalletCommon<T>>::deposit_event(CommonEvent::Transfer(297 collection.id,298 token,299 from.clone(),300 to.clone(),301 1,302 ));303 Ok(())304 }305306 pub fn create_multiple_items(307 collection: &NonfungibleHandle<T>,308 sender: &T::CrossAccountId,309 data: Vec<CreateItemData<T>>,310 ) -> DispatchResult {311 let unrestricted_minting = collection.is_owner_or_admin(sender)?;312 if !unrestricted_minting {313 ensure!(314 collection.mint_mode,315 <CommonError<T>>::PublicMintingNotAllowed316 );317 collection.check_whitelist(sender)?;318319 for item in data.iter() {320 collection.check_whitelist(&item.owner)?;321 }322 }323324 for data in data.iter() {325 <PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;326 if !data.const_data.is_empty() {327 collection.consume_sstore()?;328 }329 if !data.variable_data.is_empty() {330 collection.consume_sstore()?;331 }332 collection.consume_sstore()?;333 collection.consume_log(3, 0)?;334 }335336 let first_token = <TokensMinted<T>>::get(collection.id);337 let tokens_minted = first_token338 .checked_add(data.len() as u32)339 .ok_or(ArithmeticError::Overflow)?;340 ensure!(341 tokens_minted < collection.limits.token_limit,342 <CommonError<T>>::CollectionTokenLimitExceeded343 );344 collection.consume_sstore()?;345346 let mut balances = BTreeMap::new();347 for data in &data {348 let balance = balances349 .entry(data.owner.as_sub())350 .or_insert_with(|| <AccountBalance<T>>::get((collection.id, data.owner.as_sub())));351 *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?;352353 ensure!(354 *balance <= collection.limits.account_token_ownership_limit(),355 <CommonError<T>>::AccountTokenLimitExceeded,356 );357 }358 collection.consume_sstores(balances.len())?;359360 // =========361362 <TokensMinted<T>>::insert(collection.id, tokens_minted);363 for (account, balance) in balances {364 <AccountBalance<T>>::insert((collection.id, account), balance);365 }366 for (i, data) in data.into_iter().enumerate() {367 let token = first_token + i as u32;368369 if !data.const_data.is_empty() {370 <TokenData<T>>::insert((collection.id, token, DataKind::Constant), data.const_data);371 }372 if !data.variable_data.is_empty() {373 <TokenData<T>>::insert(374 (collection.id, token, DataKind::Variable),375 data.variable_data,376 );377 }378 <Owner<T>>::insert((collection.id, token), &data.owner);379 <Owned<T>>::insert((collection.id, data.owner.as_sub(), token), true);380381 collection.log_infallible(ERC721Events::Transfer {382 from: H160::default(),383 to: *data.owner.as_eth(),384 token_id: token.into(),385 });386 }387 Ok(())388 }389390 pub fn set_allowance_unchecked(391 collection: &NonfungibleHandle<T>,392 sender: &T::CrossAccountId,393 token: TokenId,394 spender: Option<&T::CrossAccountId>,395 ) {396 if let Some(spender) = spender {397 let old_spender = <Allowance<T>>::get((collection.id, token));398 <Allowance<T>>::insert((collection.id, token), spender);399 // In ERC721 there is only one possible approved user of token, so we set400 // approved user to spender401 collection.log_infallible(ERC721Events::Approval {402 owner: *sender.as_eth(),403 approved: *spender.as_eth(),404 token_id: token.into(),405 });406 // In Unique chain, any token can have any amount of approved users, so we need to407 // set allowance of old owner to 0, and allowance of new owner to 1408 if old_spender.as_ref() != Some(spender) {409 if let Some(old_owner) = old_spender {410 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(411 collection.id,412 token,413 sender.clone(),414 old_owner.clone(),415 0,416 ));417 }418 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(419 collection.id,420 token,421 sender.clone(),422 spender.clone(),423 1,424 ));425 }426 } else {427 let old_spender = <Allowance<T>>::take((collection.id, token));428 // In ERC721 there is only one possible approved user of token, so we set429 // approved user to zero address430 collection.log_infallible(ERC721Events::Approval {431 owner: *sender.as_eth(),432 approved: H160::default(),433 token_id: token.into(),434 });435 // In Unique chain, any token can have any amount of approved users, so we need to436 // set allowance of old owner to 0437 if let Some(old_spender) = old_spender {438 <PalletCommon<T>>::deposit_event(CommonEvent::Approved(439 collection.id,440 token,441 sender.clone(),442 old_spender.clone(),443 0,444 ));445 }446 }447 }448449 pub fn set_allowance(450 collection: &NonfungibleHandle<T>,451 sender: &T::CrossAccountId,452 token: TokenId,453 spender: Option<&T::CrossAccountId>,454 ) -> DispatchResult {455 if collection.access == AccessMode::WhiteList {456 collection.check_whitelist(&sender)?;457 if let Some(spender) = spender {458 collection.check_whitelist(&spender)?;459 }460 }461462 if let Some(spender) = spender {463 <PalletCommon<T>>::ensure_correct_receiver(spender)?;464 }465 let token_owner = Self::item_owner(collection, token)?;466 if &token_owner != sender {467 ensure!(468 collection.ignores_owned_amount(sender)?,469 <CommonError<T>>::CantApproveMoreThanOwned470 );471 }472473 // =========474475 Self::set_allowance_unchecked(collection, sender, token, spender);476 Ok(())477 }478479 pub fn transfer_from(480 collection: &NonfungibleHandle<T>,481 spender: &T::CrossAccountId,482 from: &T::CrossAccountId,483 to: &T::CrossAccountId,484 token: TokenId,485 ) -> DispatchResult {486 if spender == from {487 return Self::transfer(collection, from, to, token);488 }489 if collection.access == AccessMode::WhiteList {490 // `from`, `to` checked in [`transfer`]491 collection.check_whitelist(spender)?;492 }493494 if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {495 ensure!(496 collection.ignores_allowance(spender)?,497 <CommonError<T>>::TokenValueNotEnough498 );499 }500501 // =========502503 Self::transfer(collection, &from, to, token)?;504 // Allowance is reset in [`transfer`]505 Ok(())506 }507508 pub fn set_variable_metadata(509 collection: &NonfungibleHandle<T>,510 sender: &T::CrossAccountId,511 token: TokenId,512 data: Vec<u8>,513 ) -> DispatchResult {514 ensure!(515 data.len() as u32 <= CUSTOM_DATA_LIMIT,516 <CommonError<T>>::TokenVariableDataLimitExceeded517 );518 let item_owner = Self::item_owner(collection, token)?;519 collection.check_can_update_meta(sender, &item_owner)?;520521 collection.consume_sstore()?;522523 // =========524525 <TokenData<T>>::insert((collection.id, token, DataKind::Variable), data);526 Ok(())527 }528529 /// Delegated to `create_multiple_items`530 pub fn create_item(531 collection: &NonfungibleHandle<T>,532 sender: &T::CrossAccountId,533 data: CreateItemData<T>,534 ) -> DispatchResult {535 Self::create_multiple_items(collection, sender, vec![data])536 }537}pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+// Anonymous struct
+struct Tuple0 {
+ uint256 field_0;
+ string field_1;
+}
+
+// Common stubs holder
+contract Dummy {
+ uint8 dummy;
+ string stub_error = "this contract is implemented in native";
+}
+
+// Inline
+contract ERC721Events {
+ event Transfer(
+ address indexed from,
+ address indexed to,
+ uint256 indexed tokenId
+ );
+ event Approval(
+ address indexed owner,
+ address indexed approved,
+ uint256 indexed tokenId
+ );
+ event ApprovalForAll(
+ address indexed owner,
+ address indexed operator,
+ bool approved
+ );
+}
+
+// Inline
+contract ERC721MintableEvents {
+ event MintingFinished();
+}
+
+// Inline
+contract InlineNameSymbol is Dummy {
+ // Selector: name() 06fdde03
+ function name() public view returns (string memory) {
+ require(false, stub_error);
+ dummy;
+ return "";
+ }
+
+ // Selector: symbol() 95d89b41
+ function symbol() public view returns (string memory) {
+ require(false, stub_error);
+ dummy;
+ return "";
+ }
+}
+
+// Inline
+contract InlineTotalSupply is Dummy {
+ // Selector: totalSupply() 18160ddd
+ function totalSupply() public view returns (uint256) {
+ require(false, stub_error);
+ dummy;
+ return 0;
+ }
+}
+
+contract ERC165 is Dummy {
+ // Selector: supportsInterface(bytes4) 01ffc9a7
+ function supportsInterface(uint32 interfaceId) public view returns (bool) {
+ require(false, stub_error);
+ interfaceId;
+ dummy;
+ return false;
+ }
+}
+
+contract ERC721 is Dummy, ERC165, ERC721Events {
+ // Selector: balanceOf(address) 70a08231
+ function balanceOf(address owner) public view returns (uint256) {
+ require(false, stub_error);
+ owner;
+ dummy;
+ return 0;
+ }
+
+ // Selector: ownerOf(uint256) 6352211e
+ function ownerOf(uint256 tokenId) public view returns (address) {
+ require(false, stub_error);
+ tokenId;
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
+
+ // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
+ function safeTransferFromWithData(
+ address from,
+ address to,
+ uint256 tokenId,
+ bytes memory data
+ ) public {
+ require(false, stub_error);
+ from;
+ to;
+ tokenId;
+ data;
+ dummy = 0;
+ }
+
+ // Selector: safeTransferFrom(address,address,uint256) 42842e0e
+ function safeTransferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) public {
+ require(false, stub_error);
+ from;
+ to;
+ tokenId;
+ dummy = 0;
+ }
+
+ // Selector: transferFrom(address,address,uint256) 23b872dd
+ function transferFrom(
+ address from,
+ address to,
+ uint256 tokenId
+ ) public {
+ require(false, stub_error);
+ from;
+ to;
+ tokenId;
+ dummy = 0;
+ }
+
+ // Selector: approve(address,uint256) 095ea7b3
+ function approve(address approved, uint256 tokenId) public {
+ require(false, stub_error);
+ approved;
+ tokenId;
+ dummy = 0;
+ }
+
+ // Selector: setApprovalForAll(address,bool) a22cb465
+ function setApprovalForAll(address operator, bool approved) public {
+ require(false, stub_error);
+ operator;
+ approved;
+ dummy = 0;
+ }
+
+ // Selector: getApproved(uint256) 081812fc
+ function getApproved(uint256 tokenId) public view returns (address) {
+ require(false, stub_error);
+ tokenId;
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
+
+ // Selector: isApprovedForAll(address,address) e985e9c5
+ function isApprovedForAll(address owner, address operator)
+ public
+ view
+ returns (address)
+ {
+ require(false, stub_error);
+ owner;
+ operator;
+ dummy;
+ return 0x0000000000000000000000000000000000000000;
+ }
+}
+
+contract ERC721Burnable is Dummy {
+ // Selector: burn(uint256) 42966c68
+ function burn(uint256 tokenId) public {
+ require(false, stub_error);
+ tokenId;
+ dummy = 0;
+ }
+}
+
+contract ERC721Enumerable is Dummy, InlineTotalSupply {
+ // Selector: tokenByIndex(uint256) 4f6ccce7
+ function tokenByIndex(uint256 index) public view returns (uint256) {
+ require(false, stub_error);
+ index;
+ dummy;
+ return 0;
+ }
+
+ // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+ function tokenOfOwnerByIndex(address owner, uint256 index)
+ public
+ view
+ returns (uint256)
+ {
+ require(false, stub_error);
+ owner;
+ index;
+ dummy;
+ return 0;
+ }
+}
+
+contract ERC721Metadata is Dummy, InlineNameSymbol {
+ // Selector: tokenURI(uint256) c87b56dd
+ function tokenURI(uint256 tokenId) public view returns (string memory) {
+ require(false, stub_error);
+ tokenId;
+ dummy;
+ return "";
+ }
+}
+
+contract ERC721Mintable is Dummy, ERC721MintableEvents {
+ // Selector: mintingFinished() 05d2035b
+ function mintingFinished() public view returns (bool) {
+ require(false, stub_error);
+ dummy;
+ return false;
+ }
+
+ // Selector: mint(address,uint256) 40c10f19
+ function mint(address to, uint256 tokenId) public returns (bool) {
+ require(false, stub_error);
+ to;
+ tokenId;
+ dummy = 0;
+ return false;
+ }
+
+ // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
+ function mintWithTokenURI(
+ address to,
+ uint256 tokenId,
+ string memory tokenUri
+ ) public returns (bool) {
+ require(false, stub_error);
+ to;
+ tokenId;
+ tokenUri;
+ dummy = 0;
+ return false;
+ }
+
+ // Selector: finishMinting() 7d64bcb4
+ function finishMinting() public returns (bool) {
+ require(false, stub_error);
+ dummy = 0;
+ return false;
+ }
+}
+
+contract ERC721UniqueExtensions is Dummy {
+ // Selector: transfer(address,uint256) a9059cbb
+ function transfer(address to, uint256 tokenId) public {
+ require(false, stub_error);
+ to;
+ tokenId;
+ dummy = 0;
+ }
+
+ // Selector: nextTokenId() 75794a3c
+ function nextTokenId() public view returns (uint256) {
+ require(false, stub_error);
+ dummy;
+ return 0;
+ }
+
+ // Selector: setVariableMetadata(uint256,bytes) d4eac26d
+ function setVariableMetadata(uint256 tokenId, bytes memory data) public {
+ require(false, stub_error);
+ tokenId;
+ data;
+ dummy = 0;
+ }
+
+ // Selector: getVariableMetadata(uint256) e6c5ce6f
+ function getVariableMetadata(uint256 tokenId)
+ public
+ view
+ returns (bytes memory)
+ {
+ require(false, stub_error);
+ tokenId;
+ dummy;
+ return hex"";
+ }
+
+ // Selector: mintBulk(address,uint256[]) 44a9945e
+ function mintBulk(address to, uint256[] memory tokenIds)
+ public
+ returns (bool)
+ {
+ require(false, stub_error);
+ to;
+ tokenIds;
+ dummy = 0;
+ return false;
+ }
+
+ // Selector: mintBulkWithTokenURI(address,(uint256,string)[]) 36543006
+ function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+ public
+ returns (bool)
+ {
+ require(false, stub_error);
+ to;
+ tokens;
+ dummy = 0;
+ return false;
+ }
+}
+
+contract UniqueNFT is
+ Dummy,
+ ERC165,
+ ERC721,
+ ERC721Metadata,
+ ERC721Enumerable,
+ ERC721UniqueExtensions,
+ ERC721Mintable,
+ ERC721Burnable
+{}
pallets/nonfungible/src/weights.rsdiffbeforeafterboth--- /dev/null
+++ b/pallets/nonfungible/src/weights.rs
@@ -0,0 +1,37 @@
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use sp_std::marker::PhantomData;
+
+pub trait WeightInfo {
+ fn create_item() -> Weight;
+ fn create_multiple_items(b: u32) -> Weight;
+ fn burn_item() -> Weight;
+ fn transfer() -> Weight;
+ fn approve() -> Weight;
+ fn transfer_from() -> Weight;
+ fn set_variable_metadata() -> Weight;
+}
+
+pub struct SubstrateWeight<T>(PhantomData<T>);
+impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
+ fn create_item() -> Weight {0}
+ fn create_multiple_items(_b: u32) -> Weight {0}
+ fn burn_item() -> Weight {0}
+ fn transfer() -> Weight {0}
+ fn approve() -> Weight {0}
+ fn transfer_from() -> Weight {0}
+ fn set_variable_metadata() -> Weight {0}
+}
+
+impl WeightInfo for () {
+ fn create_item() -> Weight {0}
+ fn create_multiple_items(_b: u32) -> Weight {0}
+ fn burn_item() -> Weight {0}
+ fn transfer() -> Weight {0}
+ fn approve() -> Weight {0}
+ fn transfer_from() -> Weight {0}
+ fn set_variable_metadata() -> Weight {0}
+}