difftreelog
refactor Remove variable data from tokens
in: master
23 files changed
client/rpc/src/lib.rsdiffbeforeafterboth71 token: TokenId,71 token: TokenId,72 at: Option<BlockHash>,72 at: Option<BlockHash>,73 ) -> Result<Vec<u8>>;73 ) -> Result<Vec<u8>>;74 #[rpc(name = "unique_variableMetadata")]75 fn variable_metadata(76 &self,77 collection: CollectionId,78 token: TokenId,79 at: Option<BlockHash>,80 ) -> Result<Vec<u8>>;817482 #[rpc(name = "unique_collectionProperties")]75 #[rpc(name = "unique_collectionProperties")]83 fn collection_properties(76 fn collection_properties(279 );272 );280 pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);273 pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);281 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);274 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);282 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);283275284 pass_method!(collection_properties(276 pass_method!(collection_properties(285 collection: CollectionId,277 collection: CollectionId,pallets/common/src/lib.rsdiffbeforeafterboth33 MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId,33 MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId,34 CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT,34 CollectionStats, MAX_TOKEN_OWNERSHIP, CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT,35 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT,35 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT,36 CUSTOM_DATA_LIMIT, CollectionLimits, CustomDataLimit, CreateCollectionData, SponsorshipState,36 CUSTOM_DATA_LIMIT, CollectionLimits, CreateCollectionData, SponsorshipState,37 CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,37 CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,38 PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission,38 PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission,39 PropertiesError, PropertyKeyPermission, TokenData, TrySet,39 PropertiesError, PropertyKeyPermission, TokenData, TrySet,312 CollectionTokenPrefixLimitExceeded,312 CollectionTokenPrefixLimitExceeded,313 /// Total collections bound exceeded.313 /// Total collections bound exceeded.314 TotalCollectionsLimitExceeded,314 TotalCollectionsLimitExceeded,315 /// variable_data exceeded data limit.316 TokenVariableDataLimitExceeded,317 /// Exceeded max admin count315 /// Exceeded max admin count318 CollectionAdminCountExceeded,316 CollectionAdminCountExceeded,319 /// Collection limit bounds per collection exceeded317 /// Collection limit bounds per collection exceeded1073 fn approve() -> Weight;1071 fn approve() -> Weight;1074 fn transfer_from() -> Weight;1072 fn transfer_from() -> Weight;1075 fn burn_from() -> Weight;1073 fn burn_from() -> Weight;1076 fn set_variable_metadata(bytes: u32) -> Weight;1077}1074}107810751079pub trait CommonCollectionOperations<T: Config> {1076pub trait CommonCollectionOperations<T: Config> {1163 nesting_budget: &dyn Budget,1160 nesting_budget: &dyn Budget,1164 ) -> DispatchResultWithPostInfo;1161 ) -> DispatchResultWithPostInfo;11651166 fn set_variable_metadata(1167 &self,1168 sender: T::CrossAccountId,1169 token: TokenId,1170 data: BoundedVec<u8, CustomDataLimit>,1171 ) -> DispatchResultWithPostInfo;117211621173 fn check_nesting(1163 fn check_nesting(1174 &self,1164 &self,118511751186 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1176 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1187 fn const_metadata(&self, token: TokenId) -> Vec<u8>;1177 fn const_metadata(&self, token: TokenId) -> Vec<u8>;1188 fn variable_metadata(&self, token: TokenId) -> Vec<u8>;1189 fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property>;1178 fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property>;1190 /// Amount of unique collection tokens1179 /// Amount of unique collection tokens1191 fn total_supply(&self) -> u32;1180 fn total_supply(&self) -> u32;pallets/fungible/src/common.rsdiffbeforeafterboth161617use core::marker::PhantomData;17use core::marker::PhantomData;181819use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};20use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget};20use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget};21use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};21use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};22use sp_runtime::ArithmeticError;22use sp_runtime::ArithmeticError;23use sp_std::{vec::Vec, vec};23use sp_std::{vec::Vec, vec};24use up_data_structs::{CustomDataLimit, Property, PropertyKey, PropertyKeyPermission};24use up_data_structs::{Property, PropertyKey, PropertyKeyPermission};252526use crate::{26use crate::{27 Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,27 Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,86 <SelfWeightOf<T>>::burn_from()86 <SelfWeightOf<T>>::burn_from()87 }87 }8889 fn set_variable_metadata(_bytes: u32) -> Weight {90 // Error91 092 }93}88}948995impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {90impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {287 fail!(<Error<T>>::SettingPropertiesNotAllowed)282 fail!(<Error<T>>::SettingPropertiesNotAllowed)288 }283 }289290 fn set_variable_metadata(291 &self,292 _sender: T::CrossAccountId,293 _token: TokenId,294 _data: BoundedVec<u8, CustomDataLimit>,295 ) -> DispatchResultWithPostInfo {296 fail!(<Error<T>>::FungibleItemsDontHaveData)297 }298284299 fn check_nesting(285 fn check_nesting(300 &self,286 &self,332 fn const_metadata(&self, _token: TokenId) -> Vec<u8> {318 fn const_metadata(&self, _token: TokenId) -> Vec<u8> {333 Vec::new()319 Vec::new()334 }320 }335 fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {336 Vec::new()337 }338321339 fn token_properties(&self, _token_id: TokenId, _keys: Vec<PropertyKey>) -> Vec<Property> {322 fn token_properties(&self, _token_id: TokenId, _keys: Vec<PropertyKey>) -> Vec<Property> {340 Vec::new()323 Vec::new()pallets/nonfungible/Cargo.tomldiffbeforeafterboth27scale-info = { version = "2.0.1", default-features = false, features = [27scale-info = { version = "2.0.1", default-features = false, features = [28 "derive",28 "derive",29] }29] }30struct-versioning = { path = "../../crates/struct-versioning" }303131[features]32[features]32default = ["std"]33default = ["std"]pallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth282829fn create_max_item_data<T: Config>(owner: T::CrossAccountId) -> CreateItemData<T> {29fn create_max_item_data<T: Config>(owner: T::CrossAccountId) -> CreateItemData<T> {30 let const_data = create_data::<CUSTOM_DATA_LIMIT>();30 let const_data = create_data::<CUSTOM_DATA_LIMIT>();31 let variable_data = create_data::<CUSTOM_DATA_LIMIT>();32 CreateItemData::<T> {31 CreateItemData::<T> {33 const_data,32 const_data,34 variable_data,35 owner,33 owner,36 }34 }37}35}126 <Pallet<T>>::set_allowance(&collection, &sender, item, Some(&burner))?;124 <Pallet<T>>::set_allowance(&collection, &sender, item, Some(&burner))?;127 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, &Unlimited)?}125 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, &Unlimited)?}128129 set_variable_metadata {130 let b in 0..CUSTOM_DATA_LIMIT;131 bench_init!{132 owner: sub; collection: collection(owner);133 owner: cross_from_sub; sender: cross_sub;134 };135 let item = create_max_item(&collection, &owner, sender.clone())?;136 let data = create_var_data(b).try_into().unwrap();137 }: {<Pallet<T>>::set_variable_metadata(&collection, &sender, item, data)?}138}126}139127pallets/nonfungible/src/common.rsdiffbeforeafterboth161617use core::marker::PhantomData;17use core::marker::PhantomData;181819use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};20use up_data_structs::{20use up_data_structs::{21 TokenId, CustomDataLimit, CreateItemExData, CollectionId, budget::Budget, Property,21 TokenId, CreateItemExData, CollectionId, budget::Budget, Property,22 PropertyKey, PropertyKeyPermission,22 PropertyKey, PropertyKeyPermission,23};23};24use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};24use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};87 <SelfWeightOf<T>>::burn_from()87 <SelfWeightOf<T>>::burn_from()88 }88 }8990 fn set_variable_metadata(bytes: u32) -> Weight {91 <SelfWeightOf<T>>::set_variable_metadata(bytes)92 }93}89}949095fn map_create_data<T: Config>(91fn map_create_data<T: Config>(99 match data {95 match data {100 up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {96 up_data_structs::CreateItemData::NFT(data) => Ok(CreateItemData::<T> {101 const_data: data.const_data,97 const_data: data.const_data,102 variable_data: data.variable_data,103 properties: data.properties,98 properties: data.properties,104 owner: to.clone(),99 owner: to.clone(),105 }),100 }),327 }322 }328 }323 }329330 fn set_variable_metadata(331 &self,332 sender: T::CrossAccountId,333 token: TokenId,334 data: BoundedVec<u8, CustomDataLimit>,335 ) -> DispatchResultWithPostInfo {336 let len = data.len();337 with_weight(338 <Pallet<T>>::set_variable_metadata(self, &sender, token, data),339 <CommonWeights<T>>::set_variable_metadata(len as u32),340 )341 }342324343 fn check_nesting(325 fn check_nesting(344 &self,326 &self,379 .unwrap_or_default()361 .unwrap_or_default()380 .into_inner()362 .into_inner()381 }363 }382 fn variable_metadata(&self, token: TokenId) -> Vec<u8> {383 <TokenData<T>>::get((self.id, token))384 .map(|t| t.variable_data)385 .unwrap_or_default()386 .into_inner()387 }388364389 fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property> {365 fn token_properties(&self, token_id: TokenId, keys: Vec<PropertyKey>) -> Vec<Property> {390 let properties = <Pallet<T>>::token_properties((self.id, token_id));366 let properties = <Pallet<T>>::token_properties((self.id, token_id));pallets/nonfungible/src/erc.rsdiffbeforeafterboth24use up_data_structs::{TokenId, SchemaVersion};24use up_data_structs::{TokenId, SchemaVersion};25use pallet_evm_coder_substrate::dispatch_to_evm;25use pallet_evm_coder_substrate::dispatch_to_evm;26use sp_core::{H160, U256};26use sp_core::{H160, U256};27use sp_std::{vec::Vec, vec};27use sp_std::vec::Vec;28use pallet_common::{28use pallet_common::{29 erc::{CommonEvmHandler, PrecompileResult, CollectionPropertiesCall},29 erc::{CommonEvmHandler, PrecompileResult, CollectionPropertiesCall},30 CollectionHandle,30 CollectionHandle,274 &caller,274 &caller,275 CreateItemData::<T> {275 CreateItemData::<T> {276 const_data: BoundedVec::default(),276 const_data: BoundedVec::default(),277 variable_data: BoundedVec::default(),278 properties: BoundedVec::default(),277 properties: BoundedVec::default(),279 owner: to,278 owner: to,280 },279 },322 const_data: Vec::<u8>::from(token_uri)321 const_data: Vec::<u8>::from(token_uri)323 .try_into()322 .try_into()324 .map_err(|_| "token uri is too long")?,323 .map_err(|_| "token uri is too long")?,325 variable_data: BoundedVec::default(),326 properties: BoundedVec::default(),324 properties: BoundedVec::default(),327 owner: to,325 owner: to,328 },326 },387 .into())385 .into())388 }386 }389390 #[weight(<SelfWeightOf<T>>::set_variable_metadata(data.len() as u32))]391 fn set_variable_metadata(392 &mut self,393 caller: caller,394 token_id: uint256,395 data: bytes,396 ) -> Result<void> {397 let caller = T::CrossAccountId::from_eth(caller);398 let token = token_id.try_into()?;399400 <Pallet<T>>::set_variable_metadata(401 self,402 &caller,403 token,404 data.try_into()405 .map_err(|_| "metadata size exceeded limit")?,406 )407 .map_err(dispatch_to_evm::<T>)?;408 Ok(())409 }410411 fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {412 self.consume_store_reads(1)?;413 let token: TokenId = token_id.try_into()?;414415 Ok(<TokenData<T>>::get((self.id, token))416 .ok_or("token not found")?417 .variable_data418 .into_inner())419 }420387421 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]388 #[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]422 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {389 fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {440 let data = (0..total_tokens)407 let data = (0..total_tokens)441 .map(|_| CreateItemData::<T> {408 .map(|_| CreateItemData::<T> {442 const_data: BoundedVec::default(),409 const_data: BoundedVec::default(),443 variable_data: BoundedVec::default(),444 properties: BoundedVec::default(),410 properties: BoundedVec::default(),445 owner: to.clone(),411 owner: to.clone(),446 })412 })484 const_data: Vec::<u8>::from(token_uri)450 const_data: Vec::<u8>::from(token_uri)485 .try_into()451 .try_into()486 .map_err(|_| "token uri is too long")?,452 .map_err(|_| "token uri is too long")?,487 variable_data: vec![].try_into().unwrap(),488 properties: BoundedVec::default(),453 properties: BoundedVec::default(),489 owner: to.clone(),454 owner: to.clone(),490 });455 });pallets/nonfungible/src/lib.rsdiffbeforeafterboth49pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;49pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;50pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;50pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;515152#[struct_versioning::versioned(version = 2, upper)]52#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]53#[derive(Encode, Decode, TypeInfo, MaxEncodedLen)]53pub struct ItemData<CrossAccountId> {54pub struct ItemData<CrossAccountId> {54 pub const_data: BoundedVec<u8, CustomDataLimit>,55 pub const_data: BoundedVec<u8, CustomDataLimit>,5657 #[version(..2)]55 pub variable_data: BoundedVec<u8, CustomDataLimit>,58 pub variable_data: BoundedVec<u8, CustomDataLimit>,5956 pub owner: CrossAccountId,60 pub owner: CrossAccountId,57}61}586259#[frame_support::pallet]63#[frame_support::pallet]60pub mod pallet {64pub mod pallet {61 use super::*;65 use super::*;62 use frame_support::{Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};66 use frame_support::{Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};67 use frame_system::pallet_prelude::*;63 use up_data_structs::{CollectionId, TokenId};68 use up_data_structs::{CollectionId, TokenId};64 use super::weights::WeightInfo;69 use super::weights::WeightInfo;657078 type WeightInfo: WeightInfo;83 type WeightInfo: WeightInfo;79 }84 }8586 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);808781 #[pallet::pallet]88 #[pallet::pallet]89 #[pallet::storage_version(STORAGE_VERSION)]82 #[pallet::generate_store(pub(super) trait Store)]90 #[pallet::generate_store(pub(super) trait Store)]83 pub struct Pallet<T>(_);91 pub struct Pallet<T>(_);8492134 QueryKind = OptionQuery,142 QueryKind = OptionQuery,135 >;143 >;144145 #[pallet::hooks]146 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {147 fn on_runtime_upgrade() -> Weight {148 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {149 <TokenData<T>>::translate_values::<ItemDataVersion1<T::CrossAccountId>, _>(|v| {150 Some(<ItemDataVersion2<T::CrossAccountId>>::from(v))151 })152 }153154 0155 }156 }136}157}137158138pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);159pub struct NonfungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);577 (collection.id, token),598 (collection.id, token),578 ItemData {599 ItemData {579 const_data: data.const_data,600 const_data: data.const_data,580 variable_data: data.variable_data,581 owner: data.owner.clone(),601 owner: data.owner.clone(),582 },602 },583 );603 );775 Self::burn(collection, from, token)795 Self::burn(collection, from, token)776 }796 }777778 pub fn set_variable_metadata(779 collection: &NonfungibleHandle<T>,780 sender: &T::CrossAccountId,781 token: TokenId,782 data: BoundedVec<u8, CustomDataLimit>,783 ) -> DispatchResult {784 let token_data =785 <TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;786 collection.check_can_update_meta(sender, &token_data.owner)?;787788 // =========789790 <TokenData<T>>::insert(791 (collection.id, token),792 ItemData {793 variable_data: data,794 ..token_data795 },796 );797 Ok(())798 }799797800 pub fn check_nesting(798 pub fn check_nesting(801 handle: &NonfungibleHandle<T>,799 handle: &NonfungibleHandle<T>,pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth61 }61 }62}62}6364// Selector: 56fd500b65contract CollectionProperties is Dummy, ERC165 {66 // Selector: setProperty(string,string) 62d9491f67 function setProperty(string memory key, string memory value) public {68 require(false, stub_error);69 key;70 value;71 dummy = 0;72 }7374 // Selector: deleteProperty(string) 3424191475 function deleteProperty(string memory key) public {76 require(false, stub_error);77 key;78 dummy = 0;79 }80}638164// Selector: 5880016182// Selector: 5880016165contract ERC721 is Dummy, ERC165, ERC721Events {83contract ERC721 is Dummy, ERC165, ERC721Events {276 }294 }277}295}278296279// Selector: e562194d297// Selector: d74d154f280contract ERC721UniqueExtensions is Dummy, ERC165 {298contract ERC721UniqueExtensions is Dummy, ERC165 {281 // Selector: transfer(address,uint256) a9059cbb299 // Selector: transfer(address,uint256) a9059cbb282 function transfer(address to, uint256 tokenId) public {300 function transfer(address to, uint256 tokenId) public {301 return 0;319 return 0;302 }320 }303304 // Selector: setVariableMetadata(uint256,bytes) d4eac26d305 function setVariableMetadata(uint256 tokenId, bytes memory data) public {306 require(false, stub_error);307 tokenId;308 data;309 dummy = 0;310 }311312 // Selector: getVariableMetadata(uint256) e6c5ce6f313 function getVariableMetadata(uint256 tokenId)314 public315 view316 returns (bytes memory)317 {318 require(false, stub_error);319 tokenId;320 dummy;321 return hex"";322 }323321324 // Selector: mintBulk(address,uint256[]) 44a9945e322 // Selector: mintBulk(address,uint256[]) 44a9945e325 function mintBulk(address to, uint256[] memory tokenIds)323 function mintBulk(address to, uint256[] memory tokenIds)354 ERC721Enumerable,352 ERC721Enumerable,355 ERC721UniqueExtensions,353 ERC721UniqueExtensions,356 ERC721Mintable,354 ERC721Mintable,357 ERC721Burnable355 ERC721Burnable,356 CollectionProperties358{}357{}359358pallets/nonfungible/src/weights.rsdiffbeforeafterboth45 fn approve() -> Weight;45 fn approve() -> Weight;46 fn transfer_from() -> Weight;46 fn transfer_from() -> Weight;47 fn burn_from() -> Weight;47 fn burn_from() -> Weight;48 fn set_variable_metadata(b: u32, ) -> Weight;49}48}504951/// Weights for pallet_nonfungible using the Substrate node and recommended hardware.50/// Weights for pallet_nonfungible using the Substrate node and recommended hardware.156 .saturating_add(T::DbWeight::get().reads(4 as Weight))155 .saturating_add(T::DbWeight::get().reads(4 as Weight))157 .saturating_add(T::DbWeight::get().writes(5 as Weight))156 .saturating_add(T::DbWeight::get().writes(5 as Weight))158 }157 }159 // Storage: Nonfungible TokenData (r:1 w:1)160 fn set_variable_metadata(_b: u32, ) -> Weight {161 (7_700_000 as Weight)162 .saturating_add(T::DbWeight::get().reads(1 as Weight))163 .saturating_add(T::DbWeight::get().writes(1 as Weight))164 }165}158}166159167// For backwards compatibility and tests160// For backwards compatibility and tests271 .saturating_add(RocksDbWeight::get().reads(4 as Weight))264 .saturating_add(RocksDbWeight::get().reads(4 as Weight))272 .saturating_add(RocksDbWeight::get().writes(5 as Weight))265 .saturating_add(RocksDbWeight::get().writes(5 as Weight))273 }266 }274 // Storage: Nonfungible TokenData (r:1 w:1)275 fn set_variable_metadata(_b: u32, ) -> Weight {276 (7_700_000 as Weight)277 .saturating_add(RocksDbWeight::get().reads(1 as Weight))278 .saturating_add(RocksDbWeight::get().writes(1 as Weight))279 }280}267}281268pallets/refungible/Cargo.tomldiffbeforeafterboth24scale-info = { version = "2.0.1", default-features = false, features = [24scale-info = { version = "2.0.1", default-features = false, features = [25 "derive",25 "derive",26] }26] }27struct-versioning = { path = "../../crates/struct-versioning" }272828[features]29[features]29default = ["std"]30default = ["std"]pallets/refungible/src/benchmarking.rsdiffbeforeafterboth31 users: impl IntoIterator<Item = (CrossAccountId, u128)>,31 users: impl IntoIterator<Item = (CrossAccountId, u128)>,32) -> CreateRefungibleExData<CrossAccountId> {32) -> CreateRefungibleExData<CrossAccountId> {33 let const_data = create_data::<CUSTOM_DATA_LIMIT>();33 let const_data = create_data::<CUSTOM_DATA_LIMIT>();34 let variable_data = create_data::<CUSTOM_DATA_LIMIT>();35 CreateRefungibleExData {34 CreateRefungibleExData {36 const_data,35 const_data,37 variable_data,38 users: users36 users: users39 .into_iter()37 .into_iter()40 .collect::<BTreeMap<_, _>>()38 .collect::<BTreeMap<_, _>>()204 <Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;202 <Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;205 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}203 }: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200, &Unlimited)?}206207 set_variable_metadata {208 let b in 0..CUSTOM_DATA_LIMIT;209 bench_init!{210 owner: sub; collection: collection(owner);211 sender: cross_from_sub(owner);212 };213 let item = create_max_item(&collection, &sender, [(sender.clone(), 200)])?;214 let data = create_var_data(b).try_into().unwrap();215 }: {<Pallet<T>>::set_variable_metadata(&collection, &sender, item, data)?}216}204}217205pallets/refungible/src/common.rsdiffbeforeafterboth17use core::marker::PhantomData;17use core::marker::PhantomData;181819use sp_std::collections::btree_map::BTreeMap;19use sp_std::collections::btree_map::BTreeMap;20use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight, BoundedVec};20use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight};21use up_data_structs::{21use up_data_structs::{22 CollectionId, TokenId, CustomDataLimit, CreateItemExData, CreateRefungibleExData,22 CollectionId, TokenId, CreateItemExData, CreateRefungibleExData,23 budget::Budget, Property, PropertyKey, PropertyKeyPermission,23 budget::Budget, Property, PropertyKey, PropertyKeyPermission,24};24};25use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};25use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight};112 <SelfWeightOf<T>>::burn_from()112 <SelfWeightOf<T>>::burn_from()113 }113 }114115 fn set_variable_metadata(bytes: u32) -> Weight {116 <SelfWeightOf<T>>::set_variable_metadata(bytes)117 }118}114}119115120fn map_create_data<T: Config>(116fn map_create_data<T: Config>(124 match data {120 match data {125 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateRefungibleExData {121 up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateRefungibleExData {126 const_data: data.const_data,122 const_data: data.const_data,127 variable_data: data.variable_data,128 users: {123 users: {129 let mut out = BTreeMap::new();124 let mut out = BTreeMap::new();130 out.insert(to.clone(), data.pieces);125 out.insert(to.clone(), data.pieces);306 fail!(<Error<T>>::SettingPropertiesNotAllowed)301 fail!(<Error<T>>::SettingPropertiesNotAllowed)307 }302 }308309 fn set_variable_metadata(310 &self,311 sender: T::CrossAccountId,312 token: TokenId,313 data: BoundedVec<u8, CustomDataLimit>,314 ) -> DispatchResultWithPostInfo {315 let len = data.len();316 with_weight(317 <Pallet<T>>::set_variable_metadata(self, &sender, token, data),318 <CommonWeights<T>>::set_variable_metadata(len as u32),319 )320 }321303322 fn check_nesting(304 fn check_nesting(323 &self,305 &self,357 .const_data339 .const_data358 .into_inner()340 .into_inner()359 }341 }360 fn variable_metadata(&self, token: TokenId) -> Vec<u8> {361 <TokenData<T>>::get((self.id, token))362 .variable_data363 .into_inner()364 }365342366 fn token_properties(&self, _token_id: TokenId, _keys: Vec<PropertyKey>) -> Vec<Property> {343 fn token_properties(&self, _token_id: TokenId, _keys: Vec<PropertyKey>) -> Vec<Property> {367 Vec::new()344 Vec::new()pallets/refungible/src/lib.rsdiffbeforeafterboth41pub mod weights;41pub mod weights;42pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;42pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;434344#[struct_versioning::versioned(version = 2, upper)]44#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]45#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)]45pub struct ItemData {46pub struct ItemData {46 pub const_data: BoundedVec<u8, CustomDataLimit>,47 pub const_data: BoundedVec<u8, CustomDataLimit>,4849 #[version(..2)]47 pub variable_data: BoundedVec<u8, CustomDataLimit>,50 pub variable_data: BoundedVec<u8, CustomDataLimit>,48}51}495250#[frame_support::pallet]53#[frame_support::pallet]51pub mod pallet {54pub mod pallet {52 use super::*;55 use super::*;53 use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key};56 use frame_support::{Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};57 use frame_system::pallet_prelude::*;54 use up_data_structs::{CollectionId, TokenId};58 use up_data_structs::{CollectionId, TokenId};55 use super::weights::WeightInfo;59 use super::weights::WeightInfo;566073 type WeightInfo: WeightInfo;77 type WeightInfo: WeightInfo;74 }78 }7980 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);758176 #[pallet::pallet]82 #[pallet::pallet]83 #[pallet::storage_version(STORAGE_VERSION)]77 #[pallet::generate_store(pub(super) trait Store)]84 #[pallet::generate_store(pub(super) trait Store)]78 pub struct Pallet<T>(_);85 pub struct Pallet<T>(_);7986147 QueryKind = ValueQuery,154 QueryKind = ValueQuery,148 >;155 >;156157 #[pallet::hooks]158 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {159 fn on_runtime_upgrade() -> Weight {160 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {161 <TokenData<T>>::translate_values::<ItemDataVersion1, _>(|v| {162 Some(<ItemDataVersion2>::from(v))163 })164 }165166 0167 }168 }149}169}150170151pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);171pub struct RefungibleHandle<T: Config>(pallet_common::CollectionHandle<T>);494 (collection.id, token_id),514 (collection.id, token_id),495 ItemData {515 ItemData {496 const_data: token.const_data,516 const_data: token.const_data,497 variable_data: token.variable_data,498 },517 },499 );518 );500 for (user, amount) in token.users.into_iter() {519 for (user, amount) in token.users.into_iter() {646 Ok(())665 Ok(())647 }666 }648649 pub fn set_variable_metadata(650 collection: &RefungibleHandle<T>,651 sender: &T::CrossAccountId,652 token: TokenId,653 data: BoundedVec<u8, CustomDataLimit>,654 ) -> DispatchResult {655 collection.check_can_update_meta(656 sender,657 &T::CrossAccountId::from_sub(collection.owner.clone()),658 )?;659660 let token_data = <TokenData<T>>::get((collection.id, token));661662 // =========663664 <TokenData<T>>::insert(665 (collection.id, token),666 ItemData {667 variable_data: data,668 ..token_data669 },670 );671 Ok(())672 }673667674 /// Delegated to `create_multiple_items`668 /// Delegated to `create_multiple_items`675 pub fn create_item(669 pub fn create_item(pallets/refungible/src/weights.rsdiffbeforeafterboth53 fn transfer_from_removing() -> Weight;53 fn transfer_from_removing() -> Weight;54 fn transfer_from_creating_removing() -> Weight;54 fn transfer_from_creating_removing() -> Weight;55 fn burn_from() -> Weight;55 fn burn_from() -> Weight;56 fn set_variable_metadata(b: u32, ) -> Weight;57}56}585759/// Weights for pallet_refungible using the Substrate node and recommended hardware.58/// Weights for pallet_refungible using the Substrate node and recommended hardware.243 .saturating_add(T::DbWeight::get().reads(5 as Weight))242 .saturating_add(T::DbWeight::get().reads(5 as Weight))244 .saturating_add(T::DbWeight::get().writes(7 as Weight))243 .saturating_add(T::DbWeight::get().writes(7 as Weight))245 }244 }246 // Storage: Refungible TokenData (r:1 w:1)247 fn set_variable_metadata(_b: u32, ) -> Weight {248 (7_364_000 as Weight)249 .saturating_add(T::DbWeight::get().reads(1 as Weight))250 .saturating_add(T::DbWeight::get().writes(1 as Weight))251 }252}245}253246254// For backwards compatibility and tests247// For backwards compatibility and tests437 .saturating_add(RocksDbWeight::get().reads(5 as Weight))430 .saturating_add(RocksDbWeight::get().reads(5 as Weight))438 .saturating_add(RocksDbWeight::get().writes(7 as Weight))431 .saturating_add(RocksDbWeight::get().writes(7 as Weight))439 }432 }440 // Storage: Refungible TokenData (r:1 w:1)441 fn set_variable_metadata(_b: u32, ) -> Weight {442 (7_364_000 as Weight)443 .saturating_add(RocksDbWeight::get().reads(1 as Weight))444 .saturating_add(RocksDbWeight::get().writes(1 as Weight))445 }446}433}447434pallets/unique/src/lib.rsdiffbeforeafterboth38 CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,38 CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,39 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,39 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,40 AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,40 AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,41 SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData, CustomDataLimit,41 SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData,42 CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,42 CreateItemExData, budget, CollectionField, Property, PropertyKey, PropertyKeyPermission,43};43};44use pallet_evm::account::CrossAccountId;44use pallet_evm::account::CrossAccountId;238 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;238 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;239 //#endregion239 //#endregion240240241 /// Variable metadata sponsoring242 /// Collection id (controlled?2), token id (controlled?2)243 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;244 /// Approval sponsoring241 /// Approval sponsoring245 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;242 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;246 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;243 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;333 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);330 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);334 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);331 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);335332336 <VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);337 <NftApproveBasket<T>>::remove_prefix(collection_id, None);333 <NftApproveBasket<T>>::remove_prefix(collection_id, None);338 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);334 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);339 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);335 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);931 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))927 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))932 }928 }933934 /// Set off-chain data schema.935 ///936 /// # Permissions937 ///938 /// * Collection Owner939 /// * Collection Admin940 ///941 /// # Arguments942 ///943 /// * collection_id.944 ///945 /// * schema: String representing the offchain data schema.946 #[weight = T::CommonWeightInfo::set_variable_metadata(data.len() as u32)]947 #[transactional]948 pub fn set_variable_meta_data (949 origin,950 collection_id: CollectionId,951 item_id: TokenId,952 data: BoundedVec<u8, CustomDataLimit>,953 ) -> DispatchResultWithPostInfo {954 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);955956 dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))957 }958929959 /// Set meta_update_permission value for particular collection930 /// Set meta_update_permission value for particular collection960 ///931 ///primitives/data-structs/src/lib.rsdiffbeforeafterboth364pub type CollectionPropertiesVec =364pub type CollectionPropertiesVec =365 BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;365 BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;366367#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]368#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]369pub struct NftItemType<AccountId> {370 pub owner: AccountId,371 pub const_data: Vec<u8>,372 pub variable_data: Vec<u8>,373}374375#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]376#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]377pub struct FungibleItemType {378 pub value: u128,379}380381#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]382#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]383pub struct ReFungibleItemType<AccountId> {384 pub owner: Vec<Ownership<AccountId>>,385 pub const_data: Vec<u8>,386 pub variable_data: Vec<u8>,387}388366389/// All fields are wrapped in `Option`s, where None means chain default367/// All fields are wrapped in `Option`s, where None means chain default390#[struct_versioning::versioned(version = 2, upper)]368#[struct_versioning::versioned(version = 2, upper)]394 pub account_token_ownership_limit: Option<u32>,372 pub account_token_ownership_limit: Option<u32>,395 pub sponsored_data_size: Option<u32>,373 pub sponsored_data_size: Option<u32>,374375 /// FIXME should we delete this or repurpose it?396 /// None - setVariableMetadata is not sponsored376 /// None - setVariableMetadata is not sponsored397 /// Some(v) - setVariableMetadata is sponsored377 /// Some(v) - setVariableMetadata is sponsored398 /// if there is v block between txs378 /// if there is v block between txs490 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]470 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]491 #[derivative(Debug(format_with = "bounded::vec_debug"))]471 #[derivative(Debug(format_with = "bounded::vec_debug"))]492 pub const_data: BoundedVec<u8, CustomDataLimit>,472 pub const_data: BoundedVec<u8, CustomDataLimit>,493 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]494 #[derivative(Debug(format_with = "bounded::vec_debug"))]495 pub variable_data: BoundedVec<u8, CustomDataLimit>,496473497 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]474 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]498 #[derivative(Debug(format_with = "bounded::vec_debug"))]475 #[derivative(Debug(format_with = "bounded::vec_debug"))]512 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]489 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]513 #[derivative(Debug(format_with = "bounded::vec_debug"))]490 #[derivative(Debug(format_with = "bounded::vec_debug"))]514 pub const_data: BoundedVec<u8, CustomDataLimit>,491 pub const_data: BoundedVec<u8, CustomDataLimit>,515 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]516 #[derivative(Debug(format_with = "bounded::vec_debug"))]517 pub variable_data: BoundedVec<u8, CustomDataLimit>,518 pub pieces: u128,492 pub pieces: u128,519}493}520494545pub struct CreateNftExData<CrossAccountId> {519pub struct CreateNftExData<CrossAccountId> {546 #[derivative(Debug(format_with = "bounded::vec_debug"))]520 #[derivative(Debug(format_with = "bounded::vec_debug"))]547 pub const_data: BoundedVec<u8, CustomDataLimit>,521 pub const_data: BoundedVec<u8, CustomDataLimit>,548 #[derivative(Debug(format_with = "bounded::vec_debug"))]549 pub variable_data: BoundedVec<u8, CustomDataLimit>,550 #[derivative(Debug(format_with = "bounded::vec_debug"))]522 #[derivative(Debug(format_with = "bounded::vec_debug"))]551 pub properties: CollectionPropertiesVec,523 pub properties: CollectionPropertiesVec,552 pub owner: CrossAccountId,524 pub owner: CrossAccountId,557pub struct CreateRefungibleExData<CrossAccountId> {529pub struct CreateRefungibleExData<CrossAccountId> {558 #[derivative(Debug(format_with = "bounded::vec_debug"))]530 #[derivative(Debug(format_with = "bounded::vec_debug"))]559 pub const_data: BoundedVec<u8, CustomDataLimit>,531 pub const_data: BoundedVec<u8, CustomDataLimit>,560 #[derivative(Debug(format_with = "bounded::vec_debug"))]561 pub variable_data: BoundedVec<u8, CustomDataLimit>,562 #[derivative(Debug(format_with = "bounded::map_debug"))]532 #[derivative(Debug(format_with = "bounded::map_debug"))]563 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,533 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,564}534}586impl CreateItemData {556impl CreateItemData {587 pub fn data_size(&self) -> usize {557 pub fn data_size(&self) -> usize {588 match self {558 match self {589 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),559 CreateItemData::NFT(data) => data.const_data.len(),590 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),560 CreateItemData::ReFungible(data) => data.const_data.len(),591 _ => 0,561 _ => 0,592 }562 }593 }563 }primitives/rpc/src/lib.rsdiffbeforeafterboth42 fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;42 fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;43 fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;43 fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;44 fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;44 fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;45 fn variable_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>>;464547 fn collection_properties(collection: CollectionId, properties: Vec<Vec<u8>>) -> Result<Vec<Property>>;46 fn collection_properties(collection: CollectionId, properties: Vec<Vec<u8>>) -> Result<Vec<Property>>;4847runtime/common/src/runtime_apis.rsdiffbeforeafterboth32 fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {32 fn const_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {33 dispatch_unique_runtime!(collection.const_metadata(token))33 dispatch_unique_runtime!(collection.const_metadata(token))34 }34 }35 fn variable_metadata(collection: CollectionId, token: TokenId) -> Result<Vec<u8>, DispatchError> {36 dispatch_unique_runtime!(collection.variable_metadata(token))37 }383539 fn collection_properties(36 fn collection_properties(40 collection: CollectionId,37 collection: CollectionId,runtime/common/src/sponsoring.rsdiffbeforeafterboth21 storage::{StorageMap, StorageDoubleMap, StorageNMap},21 storage::{StorageMap, StorageDoubleMap, StorageNMap},22};22};23use up_data_structs::{23use up_data_structs::{24 CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MetaUpdatePermission,24 CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,25 NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode,25 NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode,26 CreateItemData,26 CreateItemData,27};27};30use pallet_evm::account::CrossAccountId;30use pallet_evm::account::CrossAccountId;31use pallet_unique::{31use pallet_unique::{32 Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,32 Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,33 NftApproveBasket, VariableMetaDataBasket, CreateItemBasket, ReFungibleTransferBasket,33 NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket,34 FungibleTransferBasket, NftTransferBasket,34 FungibleTransferBasket, NftTransferBasket,35};35};36use pallet_fungible::Config as FungibleConfig;36use pallet_fungible::Config as FungibleConfig;140 Some(())140 Some(())141}141}142143pub fn withdraw_set_variable_meta_data<T: Config>(144 who: &T::CrossAccountId,145 collection: &CollectionHandle<T>,146 item_id: &TokenId,147 data: &[u8],148) -> Option<()> {149 // TODO: make it work for admins150 if collection.meta_update_permission != MetaUpdatePermission::ItemOwner {151 return None;152 }153 // preliminary sponsoring correctness check154 match collection.mode {155 CollectionMode::NFT => {156 let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;157 if !owner.conv_eq(who) {158 return None;159 }160 }161 CollectionMode::Fungible(_) => {162 if item_id != &TokenId::default() {163 return None;164 }165 if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {166 return None;167 }168 }169 CollectionMode::ReFungible => {170 if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {171 return None;172 }173 }174 }175176 // Can't sponsor fungible collection, this tx will be rejected177 // as invalid178 if matches!(collection.mode, CollectionMode::Fungible(_)) {179 return None;180 }181 if data.len() > collection.limits.sponsored_data_size() as usize {182 return None;183 }184185 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;186 let limit = collection.limits.sponsored_data_rate_limit()?;187188 if let Some(last_tx_block) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {189 let timeout = last_tx_block + limit.into();190 if block_number < timeout {191 return None;192 }193 }194195 <VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);196197 Some(())198}199142200pub fn withdraw_approve<T: Config>(143pub fn withdraw_approve<T: Config>(201 collection: &CollectionHandle<T>,144 collection: &CollectionHandle<T>,291 let (sponsor, collection) = load(*collection_id)?;234 let (sponsor, collection) = load(*collection_id)?;292 withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)235 withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)293 }236 }294 UniqueCall::set_variable_meta_data {295 collection_id,296 item_id,297 data,298 } => {299 let (sponsor, collection) = load(*collection_id)?;300 withdraw_set_variable_meta_data::<T>(301 &T::CrossAccountId::from_sub(who.clone()),302 &collection,303 item_id,304 data,305 )306 .map(|()| sponsor)307 }308 _ => None,237 _ => None,309 }238 }310 }239 }runtime/common/src/weights.rsdiffbeforeafterboth86 dispatch_weight::<T>() + max_weight_of!(transfer_from())86 dispatch_weight::<T>() + max_weight_of!(transfer_from())87 }87 }8889 fn set_variable_metadata(bytes: u32) -> Weight {90 dispatch_weight::<T>() + max_weight_of!(set_variable_metadata(bytes))91 }928893 fn burn_from() -> Weight {89 fn burn_from() -> Weight {94 dispatch_weight::<T>() + max_weight_of!(burn_from())90 dispatch_weight::<T>() + max_weight_of!(burn_from())runtime/tests/src/tests.rsdiffbeforeafterboth47fn default_nft_data() -> CreateNftData {47fn default_nft_data() -> CreateNftData {48 CreateNftData {48 CreateNftData {49 const_data: vec![1, 2, 3].try_into().unwrap(),49 const_data: vec![1, 2, 3].try_into().unwrap(),50 variable_data: vec![3, 2, 1].try_into().unwrap(),51 }50 }52}51}535258fn default_re_fungible_data() -> CreateReFungibleData {57fn default_re_fungible_data() -> CreateReFungibleData {59 CreateReFungibleData {58 CreateReFungibleData {60 const_data: vec![1, 2, 3].try_into().unwrap(),59 const_data: vec![1, 2, 3].try_into().unwrap(),61 variable_data: vec![3, 2, 1].try_into().unwrap(),62 pieces: 1023,60 pieces: 1023,63 }61 }64}62}215213216 let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();214 let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();217 assert_eq!(item.const_data, data.const_data.into_inner());215 assert_eq!(item.const_data, data.const_data.into_inner());218 assert_eq!(item.variable_data, data.variable_data.into_inner());219 });216 });220}217}221218247 ))244 ))248 .unwrap();245 .unwrap();249 assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());246 assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());250 assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());251 }247 }252 });248 });253}249}263 let balance =259 let balance =264 <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));260 <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));265 assert_eq!(item.const_data, data.const_data.into_inner());261 assert_eq!(item.const_data, data.const_data.into_inner());266 assert_eq!(item.variable_data, data.variable_data.into_inner());267 assert_eq!(balance, 1023);262 assert_eq!(balance, 1023);268 });263 });269}264}299 let balance =294 let balance =300 <pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));295 <pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));301 assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());296 assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());302 assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());303 assert_eq!(balance, 1023);297 assert_eq!(balance, 1023);304 }298 }305 });299 });413 create_test_item(collection_id, &data.clone().into());407 create_test_item(collection_id, &data.clone().into());414 let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));408 let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));415 assert_eq!(item.const_data, data.const_data.into_inner());409 assert_eq!(item.const_data, data.const_data.into_inner());416 assert_eq!(item.variable_data, data.variable_data.into_inner());417 assert_eq!(410 assert_eq!(418 <pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),411 <pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),419 1412 12426 });2419 });2427}2420}24282429#[test]2430fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {2431 new_test_ext().execute_with(|| {2432 let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));24332434 let origin1 = Origin::signed(1);24352436 let data = default_nft_data();2437 create_test_item(CollectionId(1), &data.into());24382439 let variable_data = b"test data".to_vec();2440 assert_ok!(Unique::set_variable_meta_data(2441 origin1,2442 collection_id,2443 TokenId(1),2444 variable_data.clone().try_into().unwrap()2445 ));24462447 assert_eq!(2448 <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2449 .unwrap()2450 .variable_data,2451 variable_data2452 );2453 });2454}24552456#[test]2457fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {2458 new_test_ext().execute_with(|| {2459 let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));24602461 let origin1 = Origin::signed(1);24622463 let data = default_re_fungible_data();2464 create_test_item(collection_id, &data.into());24652466 let variable_data = b"test data".to_vec();2467 assert_ok!(Unique::set_variable_meta_data(2468 origin1,2469 collection_id,2470 TokenId(1),2471 variable_data.clone().try_into().unwrap()2472 ));24732474 assert_eq!(2475 <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,2476 variable_data2477 );2478 });2479}24802481#[test]2482fn set_variable_meta_data_on_fungible_token_fails() {2483 new_test_ext().execute_with(|| {2484 let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));24852486 let origin1 = Origin::signed(1);24872488 let data = default_fungible_data();2489 create_test_item(collection_id, &data.into());24902491 let variable_data = b"test data".to_vec();2492 assert_noop!(2493 Unique::set_variable_meta_data(2494 origin1,2495 collection_id,2496 TokenId(0),2497 variable_data.try_into().unwrap()2498 )2499 .map_err(|e| e.error),2500 <pallet_fungible::Error<Test>>::FungibleItemsDontHaveData2501 );2502 });2503}25042505#[test]2506fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {2507 new_test_ext().execute_with(|| {2508 //default_limits();25092510 let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));25112512 let origin1 = Origin::signed(1);25132514 let data = default_nft_data();2515 create_test_item(collection_id, &data.into());25162517 assert_ok!(Unique::set_meta_update_permission_flag(2518 origin1.clone(),2519 collection_id,2520 MetaUpdatePermission::ItemOwner,2521 ));25222523 let variable_data = b"ten chars.".to_vec();2524 assert_ok!(Unique::set_variable_meta_data(2525 origin1,2526 collection_id,2527 TokenId(1),2528 variable_data.clone().try_into().unwrap()2529 ));25302531 assert_eq!(2532 <pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))2533 .unwrap()2534 .variable_data,2535 variable_data2536 );2537 });2538}253924212540#[test]2422#[test]2541fn collection_transfer_flag_works() {2423fn collection_transfer_flag_works() {2589 });2471 });2590}2472}25912592#[test]2593fn set_variable_meta_data_on_nft_with_admin_flag() {2594 new_test_ext().execute_with(|| {2595 // default_limits();25962597 let collection_id =2598 create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));25992600 let origin1 = Origin::signed(1);2601 let origin2 = Origin::signed(2);26022603 assert_ok!(Unique::set_mint_permission(2604 origin2.clone(),2605 collection_id,2606 true2607 ));2608 assert_ok!(Unique::add_to_allow_list(2609 origin2.clone(),2610 collection_id,2611 account(1)2612 ));26132614 assert_ok!(Unique::add_collection_admin(2615 origin2.clone(),2616 collection_id,2617 account(1)2618 ));26192620 let data = default_nft_data();2621 create_test_item(collection_id, &data.into());26222623 assert_ok!(Unique::set_meta_update_permission_flag(2624 origin2.clone(),2625 collection_id,2626 MetaUpdatePermission::Admin,2627 ));26282629 let variable_data = b"test.".to_vec();2630 assert_ok!(Unique::set_variable_meta_data(2631 origin1,2632 collection_id,2633 TokenId(1),2634 variable_data.clone().try_into().unwrap()2635 ));26362637 assert_eq!(2638 <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2639 .unwrap()2640 .variable_data,2641 variable_data2642 );2643 });2644}26452646#[test]2647fn set_variable_meta_data_on_nft_with_admin_flag_neg() {2648 new_test_ext().execute_with(|| {2649 // default_limits();26502651 let collection_id =2652 create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));26532654 let origin1 = Origin::signed(1);2655 let origin2 = Origin::signed(2);26562657 assert_ok!(Unique::set_mint_permission(2658 origin2.clone(),2659 collection_id,2660 true2661 ));2662 assert_ok!(Unique::add_to_allow_list(2663 origin2.clone(),2664 collection_id,2665 account(1)2666 ));26672668 let data = default_nft_data();2669 create_test_item(collection_id, &data.into());26702671 assert_ok!(Unique::set_meta_update_permission_flag(2672 origin2.clone(),2673 collection_id,2674 MetaUpdatePermission::Admin,2675 ));26762677 let variable_data = b"test.".to_vec();2678 assert_noop!(2679 Unique::set_variable_meta_data(2680 origin1,2681 collection_id,2682 TokenId(1),2683 variable_data.try_into().unwrap()2684 )2685 .map_err(|e| e.error),2686 CommonError::<Test>::NoPermission2687 );2688 });2689}269024732691#[test]2474#[test]2692fn set_variable_meta_flag_after_freeze() {2475fn set_variable_meta_flag_after_freeze() {2714 });2497 });2715}2498}27162717#[test]2718fn set_variable_meta_data_on_nft_with_none_flag_neg() {2719 new_test_ext().execute_with(|| {2720 // default_limits();27212722 let collection_id =2723 create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));2724 let origin1 = Origin::signed(1);27252726 let data = default_nft_data();2727 create_test_item(collection_id, &data.into());27282729 assert_ok!(Unique::set_meta_update_permission_flag(2730 origin1.clone(),2731 collection_id,2732 MetaUpdatePermission::None,2733 ));27342735 let variable_data = b"test.".to_vec();2736 assert_noop!(2737 Unique::set_variable_meta_data(2738 origin1.clone(),2739 collection_id,2740 TokenId(1),2741 variable_data.try_into().unwrap()2742 )2743 .map_err(|e| e.error),2744 CommonError::<Test>::NoPermission2745 );2746 });2747}274824992749#[test]2500#[test]2750fn collection_transfer_flag_works_neg() {2501fn collection_transfer_flag_works_neg() {smart_contracs/transfer/lib.rsdiffbeforeafterboth58pub enum CreateItemData {58pub enum CreateItemData {59 Nft {59 Nft {60 const_data: Vec<u8>,60 const_data: Vec<u8>,61 variable_data: Vec<u8>,62 },61 },63 Fungible {62 Fungible {64 value: u128,63 value: u128,65 },64 },66 ReFungible {65 ReFungible {67 const_data: Vec<u8>,66 const_data: Vec<u8>,68 variable_data: Vec<u8>,69 pieces: u128,67 pieces: u128,70 },68 },71}69}88 fn approve(spender: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);86 fn approve(spender: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);89 #[ink(extension = 4, returns_result = false)]87 #[ink(extension = 4, returns_result = false)]90 fn transfer_from(owner: DefaultAccountId, recipient: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);88 fn transfer_from(owner: DefaultAccountId, recipient: DefaultAccountId, collection_id: u32, item_id: u32, amount: u128);91 #[ink(extension = 5, returns_result = false)]92 fn set_variable_meta_data(collection_id: u32, item_id: u32, data: Vec<u8>);93 #[ink(extension = 6, returns_result = false)]89 #[ink(extension = 6, returns_result = false)]94 fn toggle_allow_list(collection_id: u32, address: DefaultAccountId, allowlisted: bool);90 fn toggle_allow_list(collection_id: u32, address: DefaultAccountId, allowlisted: bool);95}91}144 .extension()140 .extension()145 .transfer_from(owner, recipient, collection_id, item_id, amount);141 .transfer_from(owner, recipient, collection_id, item_id, amount);146 }142 }147 #[ink(message)]148 pub fn set_variable_meta_data(&mut self, collection_id: u32, item_id: u32, data: Vec<u8>) {149 let _ = self.env()150 .extension()151 .set_variable_meta_data(collection_id, item_id, data);152 }153 #[ink(message)]143 #[ink(message)]154 pub fn toggle_allow_list(&mut self, collection_id: u32, address: AccountId, allowlisted: bool) {144 pub fn toggle_allow_list(&mut self, collection_id: u32, address: AccountId, allowlisted: bool) {155 let _ = self.env()145 let _ = self.env()