difftreelog
Merge branch 'develop' into tests/eth-helpers
in: master
59 files changed
Cargo.lockdiffbeforeafterboth2274 "hash256-std-hasher",2274 "hash256-std-hasher",2275 "rlp",2275 "rlp",2276 "rlp-derive",2276 "rlp-derive",2277 "sha3",2277 "sha3 0.10.6",2278 "triehash",2278 "triehash",2279]2279]228022802292 "rlp",2292 "rlp",2293 "scale-info",2293 "scale-info",2294 "serde",2294 "serde",2295 "sha3",2295 "sha3 0.10.6",2296 "triehash",2296 "triehash",2297]2297]229822982350 "rlp",2350 "rlp",2351 "scale-info",2351 "scale-info",2352 "serde",2352 "serde",2353 "sha3",2353 "sha3 0.10.6",2354]2354]235523552356[[package]]2356[[package]]2380 "hex",2380 "hex",2381 "proc-macro2",2381 "proc-macro2",2382 "quote",2382 "quote",2383 "sha3",2383 "sha3 0.10.6",2384 "syn",2384 "syn",2385]2385]238623862415 "environmental",2415 "environmental",2416 "evm-core",2416 "evm-core",2417 "primitive-types 0.12.1",2417 "primitive-types 0.12.1",2418 "sha3",2418 "sha3 0.10.6",2419]2419]242024202421[[package]]2421[[package]]4958 "digest 0.10.6",4958 "digest 0.10.6",4959 "multihash-derive",4959 "multihash-derive",4960 "sha2 0.10.6",4960 "sha2 0.10.6",4961 "sha3",4961 "sha3 0.10.6",4962 "unsigned-varint",4962 "unsigned-varint",4963]4963]496449645280 "cumulus-primitives-utility",5280 "cumulus-primitives-utility",5281 "derivative",5281 "derivative",5282 "evm-coder",5282 "evm-coder",5283 "fp-evm",5283 "fp-evm-mapping",5284 "fp-evm-mapping",5284 "fp-rpc",5285 "fp-rpc",5285 "fp-self-contained",5286 "fp-self-contained",5294 "impl-trait-for-tuples",5295 "impl-trait-for-tuples",5295 "log",5296 "log",5296 "logtest",5297 "logtest",5298 "num_enum",5297 "orml-tokens",5299 "orml-tokens",5298 "orml-traits",5300 "orml-traits",5299 "orml-vesting",5301 "orml-vesting",5309 "pallet-evm-coder-substrate",5311 "pallet-evm-coder-substrate",5310 "pallet-evm-contract-helpers",5312 "pallet-evm-contract-helpers",5311 "pallet-evm-migration",5313 "pallet-evm-migration",5314 "pallet-evm-precompile-simple",5312 "pallet-evm-transaction-payment",5315 "pallet-evm-transaction-payment",5313 "pallet-foreign-assets",5316 "pallet-foreign-assets",5314 "pallet-fungible",5317 "pallet-fungible",5333 "parachain-info",5336 "parachain-info",5334 "parity-scale-codec 3.2.1",5337 "parity-scale-codec 3.2.1",5335 "polkadot-parachain",5338 "polkadot-parachain",5339 "precompile-utils-macro",5336 "rmrk-rpc",5340 "rmrk-rpc",5337 "scale-info",5341 "scale-info",5338 "serde",5342 "serde",6004 "sp-std",6008 "sp-std",6005]6009]60106011[[package]]6012name = "pallet-evm-precompile-simple"6013version = "2.0.0-dev"6014source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.33#c37ced433a29baad45899d6ab364fe437f97570e"6015dependencies = [6016 "fp-evm",6017 "ripemd",6018 "sp-io",6019]600660206007[[package]]6021[[package]]6008name = "pallet-evm-transaction-payment"6022name = "pallet-evm-transaction-payment"632863426329[[package]]6343[[package]]6330name = "pallet-nonfungible"6344name = "pallet-nonfungible"6331version = "0.1.9"6345version = "0.1.11"6332dependencies = [6346dependencies = [6333 "ethereum 0.14.0",6347 "ethereum 0.14.0",6334 "evm-coder",6348 "evm-coder",648765016488[[package]]6502[[package]]6489name = "pallet-refungible"6503name = "pallet-refungible"6490version = "0.2.8"6504version = "0.2.10"6491dependencies = [6505dependencies = [6492 "derivative",6506 "derivative",6493 "ethereum 0.14.0",6507 "ethereum 0.14.0",8594source = "registry+https://github.com/rust-lang/crates.io-index"8608source = "registry+https://github.com/rust-lang/crates.io-index"8595checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"8609checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"86108611[[package]]8612name = "precompile-utils-macro"8613version = "0.1.0"8614dependencies = [8615 "num_enum",8616 "proc-macro2",8617 "quote",8618 "sha3 0.8.2",8619 "syn",8620]859686218597[[package]]8622[[package]]8598name = "predicates"8623name = "predicates"8850 "cumulus-primitives-utility",8875 "cumulus-primitives-utility",8851 "derivative",8876 "derivative",8852 "evm-coder",8877 "evm-coder",8878 "fp-evm",8853 "fp-evm-mapping",8879 "fp-evm-mapping",8854 "fp-rpc",8880 "fp-rpc",8855 "fp-self-contained",8881 "fp-self-contained",8864 "impl-trait-for-tuples",8890 "impl-trait-for-tuples",8865 "log",8891 "log",8866 "logtest",8892 "logtest",8893 "num_enum",8867 "orml-tokens",8894 "orml-tokens",8868 "orml-traits",8895 "orml-traits",8869 "orml-vesting",8896 "orml-vesting",8879 "pallet-evm-coder-substrate",8906 "pallet-evm-coder-substrate",8880 "pallet-evm-contract-helpers",8907 "pallet-evm-contract-helpers",8881 "pallet-evm-migration",8908 "pallet-evm-migration",8909 "pallet-evm-precompile-simple",8882 "pallet-evm-transaction-payment",8910 "pallet-evm-transaction-payment",8883 "pallet-foreign-assets",8911 "pallet-foreign-assets",8884 "pallet-fungible",8912 "pallet-fungible",8901 "parachain-info",8929 "parachain-info",8902 "parity-scale-codec 3.2.1",8930 "parity-scale-codec 3.2.1",8903 "polkadot-parachain",8931 "polkadot-parachain",8932 "precompile-utils-macro",8904 "rmrk-rpc",8933 "rmrk-rpc",8905 "scale-info",8934 "scale-info",8906 "serde",8935 "serde",9248 "winapi",9277 "winapi",9249]9278]92799280[[package]]9281name = "ripemd"9282version = "0.1.3"9283source = "registry+https://github.com/rust-lang/crates.io-index"9284checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f"9285dependencies = [9286 "digest 0.10.6",9287]925092889251[[package]]9289[[package]]9252name = "rlp"9290name = "rlp"10959 "digest 0.10.6",10997 "digest 0.10.6",10960]10998]1099911000[[package]]11001name = "sha3"11002version = "0.8.2"11003source = "registry+https://github.com/rust-lang/crates.io-index"11004checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"11005dependencies = [11006 "block-buffer 0.7.3",11007 "byte-tools",11008 "digest 0.8.1",11009 "keccak",11010 "opaque-debug 0.2.3",11011]109611101210962[[package]]11013[[package]]10963name = "sha3"11014name = "sha3"11396 "byteorder",11447 "byteorder",11397 "digest 0.10.6",11448 "digest 0.10.6",11398 "sha2 0.10.6",11449 "sha2 0.10.6",11399 "sha3",11450 "sha3 0.10.6",11400 "sp-std",11451 "sp-std",11401 "twox-hash",11452 "twox-hash",11402]11453]13026 "cumulus-primitives-utility",13077 "cumulus-primitives-utility",13027 "derivative",13078 "derivative",13028 "evm-coder",13079 "evm-coder",13080 "fp-evm",13029 "fp-evm-mapping",13081 "fp-evm-mapping",13030 "fp-rpc",13082 "fp-rpc",13031 "fp-self-contained",13083 "fp-self-contained",13040 "impl-trait-for-tuples",13092 "impl-trait-for-tuples",13041 "log",13093 "log",13042 "logtest",13094 "logtest",13095 "num_enum",13043 "orml-tokens",13096 "orml-tokens",13044 "orml-traits",13097 "orml-traits",13045 "orml-vesting",13098 "orml-vesting",13055 "pallet-evm-coder-substrate",13108 "pallet-evm-coder-substrate",13056 "pallet-evm-contract-helpers",13109 "pallet-evm-contract-helpers",13057 "pallet-evm-migration",13110 "pallet-evm-migration",13111 "pallet-evm-precompile-simple",13058 "pallet-evm-transaction-payment",13112 "pallet-evm-transaction-payment",13059 "pallet-foreign-assets",13113 "pallet-foreign-assets",13060 "pallet-fungible",13114 "pallet-fungible",13077 "parachain-info",13131 "parachain-info",13078 "parity-scale-codec 3.2.1",13132 "parity-scale-codec 3.2.1",13079 "polkadot-parachain",13133 "polkadot-parachain",13134 "precompile-utils-macro",13080 "rmrk-rpc",13135 "rmrk-rpc",13081 "scale-info",13136 "scale-info",13082 "serde",13137 "serde",crates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth740 /// Some docs740 /// Some docs741 /// At multi741 /// At multi742 /// line742 /// line743 #[derive(AbiCoder, Debug, PartialEq, Default)]743 #[derive(AbiCoder, Debug, PartialEq, Default, Clone, Copy)]744 #[repr(u8)]744 #[repr(u8)]745 enum Color {745 enum Color {746 /// Docs for Red746 /// Docs for Redpallets/app-promotion/src/lib.rsdiffbeforeafterboth564 /// # Arguments564 /// # Arguments565 ///565 ///566 /// * `stakers_number`: the number of stakers for which recalculation will be performed566 /// * `stakers_number`: the number of stakers for which recalculation will be performed567 #[pallet::weight(<T as Config>::WeightInfo::payout_stakers(stakers_number.unwrap_or(20) as u32))]567 #[pallet::weight(<T as Config>::WeightInfo::payout_stakers(stakers_number.unwrap_or(DEFAULT_NUMBER_PAYOUTS) as u32))]568 pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {568 pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {569 let admin_id = ensure_signed(admin)?;569 let admin_id = ensure_signed(admin)?;570570pallets/common/src/eth.rsdiffbeforeafterboth163 TokenOwner,163 TokenOwner,164}164}165166/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.167#[derive(AbiCoder, Copy, Clone, Default, Debug)]168#[repr(u8)]169pub enum EthTokenPermissions {170 /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]171 #[default]172 Mutable,173174 /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]175 TokenOwner,176177 /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]178 CollectionAdmin,179}165180pallets/common/src/lib.rsdiffbeforeafterboth1222 Ok(())1222 Ok(())1223 }1223 }122412241225 /// Set scouped collection property.1225 /// Set a scoped collection property, where the scope is a special prefix1226 /// prohibiting a user to change the property.1226 ///1227 ///1227 /// * `collection_id` - ID of the collection for which the property is being set.1228 /// * `collection_id` - ID of the collection for which the property is being set.1228 /// * `scope` - Property scope.1229 /// * `scope` - Property scope.1240 Ok(())1241 Ok(())1241 }1242 }124212431243 /// Set scouped collection properties.1244 /// Set scoped collection properties, where the scope is a special prefix1245 /// prohibiting a user to change the properties.1244 ///1246 ///1245 /// * `collection_id` - ID of the collection for which the properties is being set.1247 /// * `collection_id` - ID of the collection for which the properties is being set.1246 /// * `scope` - Property scope.1248 /// * `scope` - Property scope.pallets/configuration/src/lib.rsdiffbeforeafterboth52 type DefaultMinGasPrice: Get<u64>;52 type DefaultMinGasPrice: Get<u64>;535354 #[pallet::constant]54 #[pallet::constant]55 type MaxOverridedAllowedLocations: Get<u32>;55 type MaxXcmAllowedLocations: Get<u32>;56 #[pallet::constant]56 #[pallet::constant]57 type AppPromotionDailyRate: Get<Perbill>;57 type AppPromotionDailyRate: Get<Perbill>;58 #[pallet::constant]58 #[pallet::constant]777778 #[pallet::storage]78 #[pallet::storage]79 pub type XcmAllowedLocationsOverride<T: Config> = StorageValue<79 pub type XcmAllowedLocationsOverride<T: Config> = StorageValue<80 Value = BoundedVec<MultiLocation, T::MaxOverridedAllowedLocations>,80 Value = BoundedVec<MultiLocation, T::MaxXcmAllowedLocations>,81 QueryKind = OptionQuery,81 QueryKind = OptionQuery,82 >;82 >;8383118 #[pallet::weight(T::DbWeight::get().writes(1))]118 #[pallet::weight(T::DbWeight::get().writes(1))]119 pub fn set_xcm_allowed_locations(119 pub fn set_xcm_allowed_locations(120 origin: OriginFor<T>,120 origin: OriginFor<T>,121 locations: Option<BoundedVec<MultiLocation, T::MaxOverridedAllowedLocations>>,121 locations: Option<BoundedVec<MultiLocation, T::MaxXcmAllowedLocations>>,122 ) -> DispatchResult {122 ) -> DispatchResult {123 ensure_root(origin)?;123 ensure_root(origin)?;124 <XcmAllowedLocationsOverride<T>>::set(locations);124 <XcmAllowedLocationsOverride<T>>::set(locations);pallets/fungible/src/common.rsdiffbeforeafterboth19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};19use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};20use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget, CreateItemData};20use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget, CreateItemData};21use pallet_common::{CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight};21use pallet_common::{22 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,23 weights::WeightInfo as _,24};22use pallet_structure::Error as StructureError;25use pallet_structure::Error as StructureError;23use sp_runtime::ArithmeticError;26use sp_runtime::ArithmeticError;53 <SelfWeightOf<T>>::burn_item()56 <SelfWeightOf<T>>::burn_item()54 }57 }555856 fn set_collection_properties(_amount: u32) -> Weight {59 fn set_collection_properties(amount: u32) -> Weight {57 // Error58 Weight::zero()60 <pallet_common::SelfWeightOf<T>>::set_collection_properties(amount)59 }61 }606261 fn delete_collection_properties(_amount: u32) -> Weight {63 fn delete_collection_properties(amount: u32) -> Weight {62 // Error63 Weight::zero()64 <pallet_common::SelfWeightOf<T>>::delete_collection_properties(amount)64 }65 }656666 fn set_token_properties(_amount: u32) -> Weight {67 fn set_token_properties(_amount: u32) -> Weight {294295295 fn set_collection_properties(296 fn set_collection_properties(296 &self,297 &self,297 _sender: T::CrossAccountId,298 sender: T::CrossAccountId,298 _property: Vec<Property>,299 properties: Vec<Property>,299 ) -> DispatchResultWithPostInfo {300 ) -> DispatchResultWithPostInfo {301 let weight = <CommonWeights<T>>::set_collection_properties(properties.len() as u32);302300 fail!(<Error<T>>::SettingPropertiesNotAllowed)303 with_weight(304 <Pallet<T>>::set_collection_properties(self, &sender, properties),305 weight,306 )301 }307 }302308303 fn delete_collection_properties(309 fn delete_collection_properties(304 &self,310 &self,305 _sender: &T::CrossAccountId,311 sender: &T::CrossAccountId,306 _property_keys: Vec<PropertyKey>,312 property_keys: Vec<PropertyKey>,307 ) -> DispatchResultWithPostInfo {313 ) -> DispatchResultWithPostInfo {314 let weight = <CommonWeights<T>>::delete_collection_properties(property_keys.len() as u32);315308 fail!(<Error<T>>::SettingPropertiesNotAllowed)316 with_weight(317 <Pallet<T>>::delete_collection_properties(self, sender, property_keys),318 weight,319 )309 }320 }310321pallets/fungible/src/lib.rsdiffbeforeafterboth808081use core::ops::Deref;81use core::ops::Deref;82use evm_coder::ToLog;82use evm_coder::ToLog;83use frame_support::{ensure};83use frame_support::ensure;84use pallet_evm::account::CrossAccountId;84use pallet_evm::account::CrossAccountId;85use up_data_structs::{85use up_data_structs::{86 AccessMode, CollectionId, CollectionFlags, TokenId, CreateCollectionData,86 AccessMode, CollectionId, CollectionFlags, TokenId, CreateCollectionData,87 mapping::TokenAddressMapping, budget::Budget,87 mapping::TokenAddressMapping, budget::Budget, PropertyKey, Property,88};88};89use pallet_common::{89use pallet_common::{90 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,90 Error as CommonError, Event as CommonEvent, Pallet as PalletCommon,260 Ok(())260 Ok(())261 }261 }262263 /// Add properties to the collection.264 pub fn set_collection_properties(265 collection: &FungibleHandle<T>,266 sender: &T::CrossAccountId,267 properties: Vec<Property>,268 ) -> DispatchResult {269 <PalletCommon<T>>::set_collection_properties(collection, sender, properties)270 }271272 /// Delete properties of the collection, associated with the provided keys.273 pub fn delete_collection_properties(274 collection: &FungibleHandle<T>,275 sender: &T::CrossAccountId,276 property_keys: Vec<PropertyKey>,277 ) -> DispatchResult {278 <PalletCommon<T>>::delete_collection_properties(collection, sender, property_keys)279 }262280263 ///Checks if collection has tokens. Return `true` if it has.281 /// Checks if collection has tokens. Return `true` if it has.264 fn collection_has_tokens(collection_id: CollectionId) -> bool {282 fn collection_has_tokens(collection_id: CollectionId) -> bool {265 <TotalSupply<T>>::get(collection_id) != 0283 <TotalSupply<T>>::get(collection_id) != 0266 }284 }pallets/nonfungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.1.11] - 2022-12-1689### Added1011- The function `tokenPropertyPermissions` and `setTokenPropertyPermissions` to `TokenProperties` interface.1213### Changed1415- Hide `setTokenPropertyPermission` function in `TokenProperties` interface.167## [0.1.10] - 2022-11-1817## [0.1.10] - 2022-11-188189### Added19### Addedpallets/nonfungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-nonfungible"2name = "pallet-nonfungible"3version = "0.1.9"3version = "0.1.11"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/nonfungible/src/erc.rsdiffbeforeafterboth34 CollectionPropertiesVec,34 CollectionPropertiesVec,35};35};36use pallet_evm_coder_substrate::dispatch_to_evm;36use pallet_evm_coder_substrate::dispatch_to_evm;37use sp_std::vec::Vec;37use sp_std::{vec::Vec, vec};38use pallet_common::{38use pallet_common::{39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,39 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},40 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},41 eth::EthCrossAccount,41 eth::{EthCrossAccount, EthTokenPermissions},42};42};43use pallet_evm::{account::CrossAccountId, PrecompileHandle};43use pallet_evm::{account::CrossAccountId, PrecompileHandle};44use pallet_evm_coder_substrate::call;44use pallet_evm_coder_substrate::call;60 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.60 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.61 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.61 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.62 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]62 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]63 #[solidity(hide)]63 fn set_token_property_permission(64 fn set_token_property_permission(64 &mut self,65 &mut self,65 caller: caller,66 caller: caller,69 token_owner: bool,70 token_owner: bool,70 ) -> Result<()> {71 ) -> Result<()> {71 let caller = T::CrossAccountId::from_eth(caller);72 let caller = T::CrossAccountId::from_eth(caller);72 <Pallet<T>>::set_property_permission(73 <Pallet<T>>::set_token_property_permissions(73 self,74 self,74 &caller,75 &caller,75 PropertyKeyPermission {76 vec![PropertyKeyPermission {76 key: <Vec<u8>>::from(key)77 key: <Vec<u8>>::from(key)77 .try_into()78 .try_into()78 .map_err(|_| "too long key")?,79 .map_err(|_| "too long key")?,79 permission: PropertyPermission {80 permission: PropertyPermission {80 mutable: is_mutable,81 mutable: is_mutable,81 collection_admin,82 collection_admin,82 token_owner,83 token_owner,83 },84 },84 },85 }],85 )86 )86 .map_err(dispatch_to_evm::<T>)87 .map_err(dispatch_to_evm::<T>)87 }88 }8990 /// @notice Set permissions for token property.91 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.92 /// @param permissions Permissions for keys.93 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]94 fn set_token_property_permissions(95 &mut self,96 caller: caller,97 permissions: Vec<(string, Vec<(EthTokenPermissions, bool)>)>,98 ) -> Result<()> {99 let caller = T::CrossAccountId::from_eth(caller);100 const PERMISSIONS_FIELDS_COUNT: usize = 3;101102 let mut perms = Vec::new();103104 for (key, pp) in permissions {105 if pp.len() > PERMISSIONS_FIELDS_COUNT {106 return Err(alloc::format!(107 "Actual number of fields {} for {}, which exceeds the maximum value of {}",108 pp.len(),109 stringify!(EthTokenPermissions),110 PERMISSIONS_FIELDS_COUNT111 )112 .as_str()113 .into());114 }115116 let mut token_permission = PropertyPermission::default();117118 for (perm, value) in pp {119 match perm {120 EthTokenPermissions::Mutable => token_permission.mutable = value,121 EthTokenPermissions::TokenOwner => token_permission.token_owner = value,122 EthTokenPermissions::CollectionAdmin => {123 token_permission.collection_admin = value124 }125 }126 }127128 perms.push(PropertyKeyPermission {129 key: key.into_bytes().try_into().map_err(|_| "too long key")?,130 permission: token_permission,131 });132 }133134 <Pallet<T>>::set_token_property_permissions(self, &caller, perms)135 .map_err(dispatch_to_evm::<T>)136 }137138 /// @notice Get permissions for token properties.139 fn token_property_permissions(140 &self,141 ) -> Result<Vec<(string, Vec<(EthTokenPermissions, bool)>)>> {142 let perms = <Pallet<T>>::token_property_permission(self.id);143 Ok(perms144 .into_iter()145 .map(|(key, pp)| {146 let key = string::from_utf8(key.into_inner()).expect("Stored key must be valid");147 let pp = vec![148 (EthTokenPermissions::Mutable, pp.mutable),149 (EthTokenPermissions::TokenOwner, pp.token_owner),150 (EthTokenPermissions::CollectionAdmin, pp.collection_admin),151 ];152 (key, pp)153 })154 .collect())155 }8815689 /// @notice Set token property value.157 /// @notice Set token property value.90 /// @dev Throws error if `msg.sender` has no permission to edit the property.158 /// @dev Throws error if `msg.sender` has no permission to edit the property.pallets/nonfungible/src/lib.rsdiffbeforeafterboth103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,105 PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,105 PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,106 TokenChild, AuxPropertyValue,106 TokenChild, AuxPropertyValue, PropertiesPermissionMap,107};107};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};109use pallet_common::{109use pallet_common::{824 )824 )825 }825 }826826827 /// Set property permissions for the collection.828 ///829 /// Sender should be the owner or admin of the collection.830 pub fn set_property_permission(827 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {831 collection: &CollectionHandle<T>,832 sender: &T::CrossAccountId,833 permission: PropertyKeyPermission,834 ) -> DispatchResult {835 <PalletCommon<T>>::set_property_permission(collection, sender, permission)828 <PalletCommon<T>>::property_permissions(collection_id)836 }829 }837830838 pub fn check_token_immediate_ownership(831 pub fn check_token_immediate_ownership(pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth18}18}191920/// @title A contract that allows to set and delete token properties and change token property permissions.20/// @title A contract that allows to set and delete token properties and change token property permissions.21/// @dev the ERC-165 identifier for this interface is 0x91a97a6821/// @dev the ERC-165 identifier for this interface is 0xde0695c222contract TokenProperties is Dummy, ERC165 {22contract TokenProperties is Dummy, ERC165 {23 // /// @notice Set permissions for token property.24 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 // /// @param key Property key.26 // /// @param isMutable Permission to mutate property.27 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 // /// @dev EVM selector for this function is: 0x222d97fa,30 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)31 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) public {32 // require(false, stub_error);33 // key;34 // isMutable;35 // collectionAdmin;36 // tokenOwner;37 // dummy = 0;38 // }3923 /// @notice Set permissions for token property.40 /// @notice Set permissions for token property.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.41 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 /// @param key Property key.42 /// @param permissions Permissions for keys.26 /// @param isMutable Permission to mutate property.27 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 /// @dev EVM selector for this function is: 0x222d97fa,43 /// @dev EVM selector for this function is: 0xbd92983a,30 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)44 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])31 function setTokenPropertyPermission(45 function setTokenPropertyPermissions(Tuple48[] memory permissions) public {32 string memory key,33 bool isMutable,34 bool collectionAdmin,35 bool tokenOwner36 ) public {37 require(false, stub_error);46 require(false, stub_error);38 key;47 permissions;39 isMutable;40 collectionAdmin;41 tokenOwner;42 dummy = 0;48 dummy = 0;43 }49 }5051 /// @dev EVM selector for this function is: 0xf23d7790,52 /// or in textual repr: tokenPropertyPermissions()53 function tokenPropertyPermissions() public view returns (Tuple48[] memory) {54 require(false, stub_error);55 dummy;56 return new Tuple48[](0);57 }445845 // /// @notice Set token property value.59 // /// @notice Set token property value.46 // /// @dev Throws error if `msg.sender` has no permission to edit the property.60 // /// @dev Throws error if `msg.sender` has no permission to edit the property.118 bytes value;132 bytes value;119}133}134135enum EthTokenPermissions {136 Mutable,137 TokenOwner,138 CollectionAdmin139}140141/// @dev anonymous struct142struct Tuple48 {143 string field_0;144 Tuple46[] field_1;145}146147/// @dev anonymous struct148struct Tuple46 {149 EthTokenPermissions field_0;150 bool field_1;151}120152121/// @title A contract that allows you to work with collections.153/// @title A contract that allows you to work with collections.122/// @dev the ERC-165 identifier for this interface is 0xb5e1747f154/// @dev the ERC-165 identifier for this interface is 0xb5e1747fpallets/refungible/CHANGELOG.mddiffbeforeafterboth445<!-- bureaucrate goes here -->5<!-- bureaucrate goes here -->667## [0.2.10] - 2022-12-1689### Added1011- The function `tokenPropertyPermissions` and `setTokenPropertyPermissions` to `TokenProperties` interface.1213### Changed1415- Hide `setTokenPropertyPermission` function in `TokenProperties` interface.167## [0.2.9] - 2022-11-1817## [0.2.9] - 2022-11-188189### Added19### Addedpallets/refungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-refungible"2name = "pallet-refungible"3version = "0.2.8"3version = "0.2.10"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/refungible/src/erc.rsdiffbeforeafterboth33use pallet_common::{33use pallet_common::{34 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,34 CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,35 erc::{CommonEvmHandler, CollectionCall, static_property::key},35 erc::{CommonEvmHandler, CollectionCall, static_property::key},36 eth::EthCrossAccount,36 eth::{EthCrossAccount, EthTokenPermissions},37 Error as CommonError,37 Error as CommonError,38};38};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};63 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.63 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.64 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.64 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.65 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]65 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(1))]66 #[solidity(hide)]66 fn set_token_property_permission(67 fn set_token_property_permission(67 &mut self,68 &mut self,68 caller: caller,69 caller: caller,89 .map_err(dispatch_to_evm::<T>)90 .map_err(dispatch_to_evm::<T>)90 }91 }9293 /// @notice Set permissions for token property.94 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.95 /// @param permissions Permissions for keys.96 #[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]97 fn set_token_property_permissions(98 &mut self,99 caller: caller,100 permissions: Vec<(string, Vec<(EthTokenPermissions, bool)>)>,101 ) -> Result<()> {102 let caller = T::CrossAccountId::from_eth(caller);103 const PERMISSIONS_FIELDS_COUNT: usize = 3;104105 let mut perms = Vec::new();106107 for (key, pp) in permissions {108 if pp.len() > PERMISSIONS_FIELDS_COUNT {109 return Err(alloc::format!(110 "Actual number of fields {} for {}, which exceeds the maximum value of {}",111 pp.len(),112 stringify!(EthTokenPermissions),113 PERMISSIONS_FIELDS_COUNT114 )115 .as_str()116 .into());117 }118119 let mut token_permission = PropertyPermission {120 mutable: false,121 collection_admin: false,122 token_owner: false,123 };124125 for (perm, value) in pp {126 match perm {127 EthTokenPermissions::Mutable => token_permission.mutable = value,128 EthTokenPermissions::TokenOwner => token_permission.token_owner = value,129 EthTokenPermissions::CollectionAdmin => {130 token_permission.collection_admin = value131 }132 }133 }134135 perms.push(PropertyKeyPermission {136 key: key.into_bytes().try_into().map_err(|_| "too long key")?,137 permission: token_permission,138 });139 }140141 <Pallet<T>>::set_token_property_permissions(self, &caller, perms)142 .map_err(dispatch_to_evm::<T>)143 }144145 /// @notice Get permissions for token properties.146 fn token_property_permissions(147 &self,148 ) -> Result<Vec<(string, Vec<(EthTokenPermissions, bool)>)>> {149 let perms = <Pallet<T>>::token_property_permission(self.id);150 Ok(perms151 .into_iter()152 .map(|(key, pp)| {153 let key = string::from_utf8(key.into_inner()).expect("Stored key must be valid");154 let pp = vec![155 (EthTokenPermissions::Mutable, pp.mutable),156 (EthTokenPermissions::TokenOwner, pp.token_owner),157 (EthTokenPermissions::CollectionAdmin, pp.collection_admin),158 ];159 (key, pp)160 })161 .collect())162 }9116392 /// @notice Set token property value.164 /// @notice Set token property value.93 /// @dev Throws error if `msg.sender` has no permission to edit the property.165 /// @dev Throws error if `msg.sender` has no permission to edit the property.pallets/refungible/src/erc_token.rsdiffbeforeafterboth19//! Provides ERC-20 standart support implementation and EVM API for unique extensions for Refungible Pallet.19//! Provides ERC-20 standart support implementation and EVM API for unique extensions for Refungible Pallet.20//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.20//! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods.2122extern crate alloc;2324#[cfg(not(feature = "std"))]25use alloc::format;262127use core::{22use core::{28 char::{REPLACEMENT_CHARACTER, decode_utf16},23 char::{REPLACEMENT_CHARACTER, decode_utf16},35use pallet_common::{30use pallet_common::{36 CommonWeightInfo,31 CommonWeightInfo,37 erc::{CommonEvmHandler, PrecompileResult},32 erc::{CommonEvmHandler, PrecompileResult},38 eth::collection_id_to_address,33 eth::{collection_id_to_address, EthCrossAccount},39};34};40use pallet_evm::{account::CrossAccountId, PrecompileHandle};35use pallet_evm::{account::CrossAccountId, PrecompileHandle};41use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};36use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};200195201#[solidity_interface(name = ERC20UniqueExtensions)]196#[solidity_interface(name = ERC20UniqueExtensions)]202impl<T: Config> RefungibleTokenHandle<T> {197impl<T: Config> RefungibleTokenHandle<T>198where199 T::AccountId: From<[u8; 32]>,200{203 /// @dev Function that burns an amount of the token of a given account,201 /// @dev Function that burns an amount of the token of a given account,204 /// deducting from the sender's allowance for said account.202 /// deducting from the sender's allowance for said account.218 Ok(true)216 Ok(true)219 }217 }220218219 /// @dev Function that burns an amount of the token of a given account,220 /// deducting from the sender's allowance for said account.221 /// @param from The account whose tokens will be burnt.222 /// @param amount The amount that will be burnt.223 #[weight(<SelfWeightOf<T>>::burn_from())]224 fn burn_from_cross(225 &mut self,226 caller: caller,227 from: EthCrossAccount,228 amount: uint256,229 ) -> Result<bool> {230 let caller = T::CrossAccountId::from_eth(caller);231 let from = from.into_sub_cross_account::<T>()?;232 let amount = amount.try_into().map_err(|_| "amount overflow")?;233 let budget = self234 .recorder235 .weight_calls_budget(<StructureWeight<T>>::find_parent());236237 <Pallet<T>>::burn_from(self, &caller, &from, self.1, amount, &budget)238 .map_err(dispatch_to_evm::<T>)?;239 Ok(true)240 }241242 /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.243 /// Beware that changing an allowance with this method brings the risk that someone may use both the old244 /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this245 /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:246 /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729247 /// @param spender The crossaccount which will spend the funds.248 /// @param amount The amount of tokens to be spent.249 #[weight(<SelfWeightOf<T>>::approve())]250 fn approve_cross(251 &mut self,252 caller: caller,253 spender: EthCrossAccount,254 amount: uint256,255 ) -> Result<bool> {256 let caller = T::CrossAccountId::from_eth(caller);257 let spender = spender.into_sub_cross_account::<T>()?;258 let amount = amount.try_into().map_err(|_| "amount overflow")?;259260 <Pallet<T>>::set_allowance(self, &caller, &spender, self.1, amount)261 .map_err(dispatch_to_evm::<T>)?;262 Ok(true)263 }221 /// @dev Function that changes total amount of the tokens.264 /// @dev Function that changes total amount of the tokens.222 /// Throws if `msg.sender` doesn't owns all of the tokens.265 /// Throws if `msg.sender` doesn't owns all of the tokens.223 /// @param amount New total amount of the tokens.266 /// @param amount New total amount of the tokens.230 Ok(true)273 Ok(true)231 }274 }275276 /// @dev Transfer token for a specified address277 /// @param to The crossaccount to transfer to.278 /// @param amount The amount to be transferred.279 #[weight(<CommonWeights<T>>::transfer())]280 fn transfer_cross(281 &mut self,282 caller: caller,283 to: EthCrossAccount,284 amount: uint256,285 ) -> Result<bool> {286 let caller = T::CrossAccountId::from_eth(caller);287 let to = to.into_sub_cross_account::<T>()?;288 let amount = amount.try_into().map_err(|_| "amount overflow")?;289 let budget = self290 .recorder291 .weight_calls_budget(<StructureWeight<T>>::find_parent());292293 <Pallet<T>>::transfer(self, &caller, &to, self.1, amount, &budget)294 .map_err(dispatch_to_evm::<T>)?;295 Ok(true)296 }297298 /// @dev Transfer tokens from one address to another299 /// @param from The address which you want to send tokens from300 /// @param to The address which you want to transfer to301 /// @param amount the amount of tokens to be transferred302 #[weight(<CommonWeights<T>>::transfer_from())]303 fn transfer_from_cross(304 &mut self,305 caller: caller,306 from: EthCrossAccount,307 to: EthCrossAccount,308 amount: uint256,309 ) -> Result<bool> {310 let caller = T::CrossAccountId::from_eth(caller);311 let from = from.into_sub_cross_account::<T>()?;312 let to = to.into_sub_cross_account::<T>()?;313 let amount = amount.try_into().map_err(|_| "amount overflow")?;314 let budget = self315 .recorder316 .weight_calls_budget(<StructureWeight<T>>::find_parent());317318 <Pallet<T>>::transfer_from(self, &caller, &from, &to, self.1, amount, &budget)319 .map_err(dispatch_to_evm::<T>)?;320 Ok(true)321 }232}322}233323234impl<T: Config> RefungibleTokenHandle<T> {324impl<T: Config> RefungibleTokenHandle<T> {pallets/refungible/src/lib.rsdiffbeforeafterboth113 AccessMode, budget::Budget, CollectionId, CollectionFlags, CollectionPropertiesVec,113 AccessMode, budget::Budget, CollectionId, CollectionFlags, CollectionPropertiesVec,114 CreateCollectionData, CustomDataLimit, mapping::TokenAddressMapping, MAX_ITEMS_PER_BATCH,114 CreateCollectionData, CustomDataLimit, mapping::TokenAddressMapping, MAX_ITEMS_PER_BATCH,115 MAX_REFUNGIBLE_PIECES, Property, PropertyKey, PropertyKeyPermission, PropertyPermission,115 MAX_REFUNGIBLE_PIECES, Property, PropertyKey, PropertyKeyPermission, PropertyPermission,116 PropertyScope, PropertyValue, TokenId, TrySetProperty,116 PropertyScope, PropertyValue, TokenId, TrySetProperty, PropertiesPermissionMap,117};117};118118119pub use pallet::*;119pub use pallet::*;1378 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1378 <PalletCommon<T>>::set_token_property_permissions(collection, sender, property_permissions)1379 }1379 }13801381 pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap {1382 <PalletCommon<T>>::property_permissions(collection_id)1383 }138013841381 pub fn set_scoped_token_property_permissions(1385 pub fn set_scoped_token_property_permissions(1382 collection: &RefungibleHandle<T>,1386 collection: &RefungibleHandle<T>,pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth18}18}191920/// @title A contract that allows to set and delete token properties and change token property permissions.20/// @title A contract that allows to set and delete token properties and change token property permissions.21/// @dev the ERC-165 identifier for this interface is 0x91a97a6821/// @dev the ERC-165 identifier for this interface is 0xde0695c222contract TokenProperties is Dummy, ERC165 {22contract TokenProperties is Dummy, ERC165 {23 // /// @notice Set permissions for token property.24 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 // /// @param key Property key.26 // /// @param isMutable Permission to mutate property.27 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 // /// @dev EVM selector for this function is: 0x222d97fa,30 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)31 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) public {32 // require(false, stub_error);33 // key;34 // isMutable;35 // collectionAdmin;36 // tokenOwner;37 // dummy = 0;38 // }3923 /// @notice Set permissions for token property.40 /// @notice Set permissions for token property.24 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.41 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.25 /// @param key Property key.42 /// @param permissions Permissions for keys.26 /// @param isMutable Permission to mutate property.27 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.28 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.29 /// @dev EVM selector for this function is: 0x222d97fa,43 /// @dev EVM selector for this function is: 0xbd92983a,30 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)44 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])31 function setTokenPropertyPermission(45 function setTokenPropertyPermissions(Tuple53[] memory permissions) public {32 string memory key,33 bool isMutable,34 bool collectionAdmin,35 bool tokenOwner36 ) public {37 require(false, stub_error);46 require(false, stub_error);38 key;47 permissions;39 isMutable;40 collectionAdmin;41 tokenOwner;42 dummy = 0;48 dummy = 0;43 }49 }5051 /// @notice Get permissions for token properties.52 /// @dev EVM selector for this function is: 0xf23d7790,53 /// or in textual repr: tokenPropertyPermissions()54 function tokenPropertyPermissions() public view returns (Tuple53[] memory) {55 require(false, stub_error);56 dummy;57 return new Tuple53[](0);58 }445945 // /// @notice Set token property value.60 // /// @notice Set token property value.46 // /// @dev Throws error if `msg.sender` has no permission to edit the property.61 // /// @dev Throws error if `msg.sender` has no permission to edit the property.118 bytes value;133 bytes value;119}134}135136enum EthTokenPermissions {137 Mutable,138 TokenOwner,139 CollectionAdmin140}141142/// @dev anonymous struct143struct Tuple53 {144 string field_0;145 Tuple51[] field_1;146}147148/// @dev anonymous struct149struct Tuple51 {150 EthTokenPermissions field_0;151 bool field_1;152}120153121/// @title A contract that allows you to work with collections.154/// @title A contract that allows you to work with collections.122/// @dev the ERC-165 identifier for this interface is 0xb5e1747f155/// @dev the ERC-165 identifier for this interface is 0xb5e1747fpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth36 }36 }37}37}383839/// @dev the ERC-165 identifier for this interface is 0xab8deb3739/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b40contract ERC20UniqueExtensions is Dummy, ERC165 {40contract ERC20UniqueExtensions is Dummy, ERC165 {41 /// @dev Function that burns an amount of the token of a given account,41 /// @dev Function that burns an amount of the token of a given account,42 /// deducting from the sender's allowance for said account.42 /// deducting from the sender's allowance for said account.52 return false;52 return false;53 }53 }5455 /// @dev Function that burns an amount of the token of a given account,56 /// deducting from the sender's allowance for said account.57 /// @param from The account whose tokens will be burnt.58 /// @param amount The amount that will be burnt.59 /// @dev EVM selector for this function is: 0xbb2f5a58,60 /// or in textual repr: burnFromCross((address,uint256),uint256)61 function burnFromCross(EthCrossAccount memory from, uint256 amount) public returns (bool) {62 require(false, stub_error);63 from;64 amount;65 dummy = 0;66 return false;67 }6869 /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.70 /// Beware that changing an allowance with this method brings the risk that someone may use both the old71 /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this72 /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:73 /// https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472974 /// @param spender The crossaccount which will spend the funds.75 /// @param amount The amount of tokens to be spent.76 /// @dev EVM selector for this function is: 0x0ecd0ab0,77 /// or in textual repr: approveCross((address,uint256),uint256)78 function approveCross(EthCrossAccount memory spender, uint256 amount) public returns (bool) {79 require(false, stub_error);80 spender;81 amount;82 dummy = 0;83 return false;84 }548555 /// @dev Function that changes total amount of the tokens.86 /// @dev Function that changes total amount of the tokens.56 /// Throws if `msg.sender` doesn't owns all of the tokens.87 /// Throws if `msg.sender` doesn't owns all of the tokens.64 return false;95 return false;65 }96 }9798 /// @dev Transfer token for a specified address99 /// @param to The crossaccount to transfer to.100 /// @param amount The amount to be transferred.101 /// @dev EVM selector for this function is: 0x2ada85ff,102 /// or in textual repr: transferCross((address,uint256),uint256)103 function transferCross(EthCrossAccount memory to, uint256 amount) public returns (bool) {104 require(false, stub_error);105 to;106 amount;107 dummy = 0;108 return false;109 }110111 /// @dev Transfer tokens from one address to another112 /// @param from The address which you want to send tokens from113 /// @param to The address which you want to transfer to114 /// @param amount the amount of tokens to be transferred115 /// @dev EVM selector for this function is: 0xd5cf430b,116 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)117 function transferFromCross(118 EthCrossAccount memory from,119 EthCrossAccount memory to,120 uint256 amount121 ) public returns (bool) {122 require(false, stub_error);123 from;124 to;125 amount;126 dummy = 0;127 return false;128 }66}129}130131/// @dev Cross account struct132struct EthCrossAccount {133 address eth;134 uint256 sub;135}6713668/// @dev inlined interface137/// @dev inlined interface69contract ERC20Events {138contract ERC20Events {primitives/data-structs/src/lib.rsdiffbeforeafterboth1010pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;1010pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;101110111012/// Property permission.1012/// Property permission.1013#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1013#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)]1014#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1014#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1015pub struct PropertyPermission {1015pub struct PropertyPermission {1016 /// Permission to change the property and property permission.1016 /// Permission to change the property and property permission.runtime/common/config/ethereum.rsdiffbeforeafterboth7use sp_runtime::{RuntimeAppPublic, Perbill};7use sp_runtime::{RuntimeAppPublic, Perbill};8use crate::{8use crate::{9 runtime_common::{9 runtime_common::{10 config::sponsoring::DefaultSponsoringRateLimit,11 DealWithFees,10 dispatch::CollectionDispatchT, ethereum::sponsoring::EvmSponsorshipHandler,12 dispatch::CollectionDispatchT,11 config::sponsoring::DefaultSponsoringRateLimit, DealWithFees,13 ethereum::{precompiles::UniquePrecompiles, sponsoring::EvmSponsorshipHandler},12 },14 },13 Runtime, Aura, Balances, RuntimeEvent, ChainId,15 Runtime, Aura, Balances, RuntimeEvent, ChainId,14};16};34const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);36const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);35parameter_types! {37parameter_types! {36 pub BlockGasLimit: U256 = U256::from((NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightTimePerGas::get()).ref_time());38 pub BlockGasLimit: U256 = U256::from((NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightTimePerGas::get()).ref_time());39 pub PrecompilesValue: UniquePrecompiles<Runtime> = UniquePrecompiles::<_>::new();37}40}384139pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);42pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);62 type CallOrigin = EnsureAddressTruncated<Self>;65 type CallOrigin = EnsureAddressTruncated<Self>;63 type WithdrawOrigin = EnsureAddressTruncated<Self>;66 type WithdrawOrigin = EnsureAddressTruncated<Self>;64 type AddressMapping = HashedAddressMapping<Self::Hashing>;67 type AddressMapping = HashedAddressMapping<Self::Hashing>;65 type PrecompilesType = ();68 type PrecompilesType = UniquePrecompiles<Self>;66 type PrecompilesValue = ();69 type PrecompilesValue = PrecompilesValue;67 type Currency = Balances;70 type Currency = Balances;68 type RuntimeEvent = RuntimeEvent;71 type RuntimeEvent = RuntimeEvent;69 type OnMethodCall = (72 type OnMethodCall = (runtime/common/config/pallets/mod.rsdiffbeforeafterboth106impl pallet_configuration::Config for Runtime {106impl pallet_configuration::Config for Runtime {107 type DefaultWeightToFeeCoefficient = ConstU32<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>;107 type DefaultWeightToFeeCoefficient = ConstU32<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>;108 type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>;108 type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>;109 type MaxOverridedAllowedLocations = ConstU32<16>;109 type MaxXcmAllowedLocations = ConstU32<16>;110 type AppPromotionDailyRate = AppPromotionDailyRate;110 type AppPromotionDailyRate = AppPromotionDailyRate;111 type DayRelayBlocks = DayRelayBlocks;111 type DayRelayBlocks = DayRelayBlocks;112}112}runtime/common/construct_runtime/mod.rsdiffbeforeafterboth82 #[runtimes(opal, quartz)]82 #[runtimes(opal, quartz)]83 AppPromotion: pallet_app_promotion::{Pallet, Call, Storage, Event<T>} = 73,83 AppPromotion: pallet_app_promotion::{Pallet, Call, Storage, Event<T>} = 73,848485 #[runtimes(opal)]85 #[runtimes(opal, quartz, unique)]86 ForeignAssets: pallet_foreign_assets::{Pallet, Call, Storage, Event<T>} = 80,86 ForeignAssets: pallet_foreign_assets::{Pallet, Call, Storage, Event<T>} = 80,878788 // Frontier88 // Frontierruntime/common/ethereum/mod.rsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617pub mod precompiles;17pub mod self_contained_call;18pub mod self_contained_call;18pub mod sponsoring;19pub mod sponsoring;19pub mod transaction_converter;20pub mod transaction_converter;runtime/common/ethereum/precompiles/mod.rsdiffbeforeafterbothno changes
runtime/common/ethereum/precompiles/sr25519.rsdiffbeforeafterbothno changes
runtime/common/ethereum/precompiles/utils/data.rsdiffbeforeafterbothno changes
runtime/common/ethereum/precompiles/utils/macro/Cargo.tomldiffbeforeafterbothno changes
runtime/common/ethereum/precompiles/utils/macro/src/lib.rsdiffbeforeafterbothno changes
runtime/common/ethereum/precompiles/utils/mod.rsdiffbeforeafterbothno changes
runtime/opal/Cargo.tomldiffbeforeafterboth471up-rpc = { path = "../../primitives/rpc", default-features = false }471up-rpc = { path = "../../primitives/rpc", default-features = false }472app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }472app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }473rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false }473rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false }474fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }474fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }475fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }475pallet-inflation = { path = '../../pallets/inflation', default-features = false }476pallet-inflation = { path = '../../pallets/inflation', default-features = false }476pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }477pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }494pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }495pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }495fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }496fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }496fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }497fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }498pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }497evm-coder = { default-features = false, path = '../../crates/evm-coder' }499evm-coder = { default-features = false, path = '../../crates/evm-coder' }498up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.33' }500up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.33' }499pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }501pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }500pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" }502pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" }503precompile-utils-macro = { path = "../common/ethereum/precompiles/utils/macro" }504num_enum = { version = "0.5.3", default-features = false }501505502################################################################################506################################################################################503# Test dependencies507# Test dependenciesruntime/opal/src/lib.rsdiffbeforeafterboth25#[cfg(feature = "std")]25#[cfg(feature = "std")]26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));2728extern crate alloc;272928use frame_support::parameter_types;30use frame_support::parameter_types;2931runtime/quartz/Cargo.tomldiffbeforeafterboth169 "pallet-maintenance/std",169 "pallet-maintenance/std",170]170]171limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']171limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']172quartz-runtime = ['refungible', 'app-promotion']172quartz-runtime = ['refungible', 'app-promotion', 'foreign-assets']173173174refungible = []174refungible = []175scheduler = []175scheduler = []463pallet-unique = { path = '../../pallets/unique', default-features = false }463pallet-unique = { path = '../../pallets/unique', default-features = false }464up-rpc = { path = "../../primitives/rpc", default-features = false }464up-rpc = { path = "../../primitives/rpc", default-features = false }465app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }465app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }466fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }466fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }467fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }467pallet-inflation = { path = '../../pallets/inflation', default-features = false }468pallet-inflation = { path = '../../pallets/inflation', default-features = false }468pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }469pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }486pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }487pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }487fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }488fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }488fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }489fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }490pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }489evm-coder = { default-features = false, path = '../../crates/evm-coder' }491evm-coder = { default-features = false, path = '../../crates/evm-coder' }490up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.33' }492up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.33' }491pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }493pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }492pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" }494pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" }495precompile-utils-macro = { path = "../common/ethereum/precompiles/utils/macro" }496num_enum = { version = "0.5.3", default-features = false }493497494################################################################################498################################################################################495# Other Dependencies499# Other Dependenciesruntime/quartz/src/lib.rsdiffbeforeafterboth25#[cfg(feature = "std")]25#[cfg(feature = "std")]26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));2728extern crate alloc;272928use frame_support::parameter_types;30use frame_support::parameter_types;2931runtime/quartz/src/xcm_barrier.rsdiffbeforeafterboth52 parents: 1,52 parents: 1,53 interior: Here,53 interior: Here,54 },54 },55 // Statemint/Statemint location56 MultiLocation {57 parents: 1,58 interior: X1(Parachain(1000)),59 },55 // Karura/Acala location60 // Karura/Acala location56 MultiLocation {61 MultiLocation {57 parents: 1,62 parents: 1,runtime/unique/Cargo.tomldiffbeforeafterboth170 "pallet-maintenance/std",170 "pallet-maintenance/std",171]171]172limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']172limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']173unique-runtime = []173unique-runtime = ['foreign-assets']174stubgen = ["evm-coder/stubgen"]174stubgen = ["evm-coder/stubgen"]175175176refungible = []176refungible = []479pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }479pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }480fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }480fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }481fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }481fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }482fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }482fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }483fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }484pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.33" }483evm-coder = { default-features = false, path = '../../crates/evm-coder' }485evm-coder = { default-features = false, path = '../../crates/evm-coder' }484up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.33' }486up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.33' }485pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }487pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }486pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" }488pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" }489precompile-utils-macro = { path = "../common/ethereum/precompiles/utils/macro" }490num_enum = { version = "0.5.3", default-features = false }487491488################################################################################492################################################################################489# Other Dependencies493# Other Dependenciesruntime/unique/src/lib.rsdiffbeforeafterboth25#[cfg(feature = "std")]25#[cfg(feature = "std")]26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));26include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));2728extern crate alloc;272928use frame_support::parameter_types;30use frame_support::parameter_types;2931runtime/unique/src/xcm_barrier.rsdiffbeforeafterboth52 parents: 1,52 parents: 1,53 interior: Here,53 interior: Here,54 },54 },55 // Statemint/Statemint location56 MultiLocation {57 parents: 1,58 interior: X1(Parachain(1000)),59 },55 // Karura/Acala location60 // Karura/Acala location56 MultiLocation {61 MultiLocation {57 parents: 1,62 parents: 1,tests/package.jsondiffbeforeafterboth45 "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",45 "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",46 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",46 "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",47 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts ./**/tokenProperties.test.ts ./**/getPropertiesRpc.test.ts",47 "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts ./**/tokenProperties.test.ts ./**/getPropertiesRpc.test.ts",48 "testCollectionProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts",48 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",49 "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",49 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",50 "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",50 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",51 "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",tests/src/eth/abi/nonFungible.jsondiffbeforeafterboth697 },697 },698 {698 {699 "inputs": [699 "inputs": [700 {701 "components": [700 { "internalType": "string", "name": "key", "type": "string" },702 { "internalType": "string", "name": "field_0", "type": "string" },703 {704 "components": [701 { "internalType": "bool", "name": "isMutable", "type": "bool" },705 {706 "internalType": "enum EthTokenPermissions",707 "name": "field_0",708 "type": "uint8"709 },702 { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },710 { "internalType": "bool", "name": "field_1", "type": "bool" }711 ],712 "internalType": "struct Tuple46[]",713 "name": "field_1",714 "type": "tuple[]"715 }716 ],703 { "internalType": "bool", "name": "tokenOwner", "type": "bool" }717 "internalType": "struct Tuple48[]",718 "name": "permissions",719 "type": "tuple[]"720 }704 ],721 ],705 "name": "setTokenPropertyPermission",722 "name": "setTokenPropertyPermissions",706 "outputs": [],723 "outputs": [],707 "stateMutability": "nonpayable",724 "stateMutability": "nonpayable",708 "type": "function"725 "type": "function"742 "stateMutability": "view",759 "stateMutability": "view",743 "type": "function"760 "type": "function"744 },761 },762 {763 "inputs": [],764 "name": "tokenPropertyPermissions",765 "outputs": [766 {767 "components": [768 { "internalType": "string", "name": "field_0", "type": "string" },769 {770 "components": [771 {772 "internalType": "enum EthTokenPermissions",773 "name": "field_0",774 "type": "uint8"775 },776 { "internalType": "bool", "name": "field_1", "type": "bool" }777 ],778 "internalType": "struct Tuple46[]",779 "name": "field_1",780 "type": "tuple[]"781 }782 ],783 "internalType": "struct Tuple48[]",784 "name": "",785 "type": "tuple[]"786 }787 ],788 "stateMutability": "view",789 "type": "function"790 },745 {791 {746 "inputs": [792 "inputs": [747 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }793 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }tests/src/eth/abi/reFungible.jsondiffbeforeafterboth679 },679 },680 {680 {681 "inputs": [681 "inputs": [682 {683 "components": [682 { "internalType": "string", "name": "key", "type": "string" },684 { "internalType": "string", "name": "field_0", "type": "string" },685 {686 "components": [683 { "internalType": "bool", "name": "isMutable", "type": "bool" },687 {688 "internalType": "enum EthTokenPermissions",689 "name": "field_0",690 "type": "uint8"691 },684 { "internalType": "bool", "name": "collectionAdmin", "type": "bool" },692 { "internalType": "bool", "name": "field_1", "type": "bool" }693 ],694 "internalType": "struct Tuple51[]",695 "name": "field_1",696 "type": "tuple[]"697 }698 ],685 { "internalType": "bool", "name": "tokenOwner", "type": "bool" }699 "internalType": "struct Tuple53[]",700 "name": "permissions",701 "type": "tuple[]"702 }686 ],703 ],687 "name": "setTokenPropertyPermission",704 "name": "setTokenPropertyPermissions",688 "outputs": [],705 "outputs": [],689 "stateMutability": "nonpayable",706 "stateMutability": "nonpayable",690 "type": "function"707 "type": "function"733 "stateMutability": "view",750 "stateMutability": "view",734 "type": "function"751 "type": "function"735 },752 },753 {754 "inputs": [],755 "name": "tokenPropertyPermissions",756 "outputs": [757 {758 "components": [759 { "internalType": "string", "name": "field_0", "type": "string" },760 {761 "components": [762 {763 "internalType": "enum EthTokenPermissions",764 "name": "field_0",765 "type": "uint8"766 },767 { "internalType": "bool", "name": "field_1", "type": "bool" }768 ],769 "internalType": "struct Tuple51[]",770 "name": "field_1",771 "type": "tuple[]"772 }773 ],774 "internalType": "struct Tuple53[]",775 "name": "",776 "type": "tuple[]"777 }778 ],779 "stateMutability": "view",780 "type": "function"781 },736 {782 {737 "inputs": [783 "inputs": [738 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }784 { "internalType": "uint256", "name": "tokenId", "type": "uint256" }tests/src/eth/abi/reFungibleToken.jsondiffbeforeafterboth69 "stateMutability": "nonpayable",69 "stateMutability": "nonpayable",70 "type": "function"70 "type": "function"71 },71 },72 {73 "inputs": [74 {75 "components": [76 { "internalType": "address", "name": "eth", "type": "address" },77 { "internalType": "uint256", "name": "sub", "type": "uint256" }78 ],79 "internalType": "struct EthCrossAccount",80 "name": "spender",81 "type": "tuple"82 },83 { "internalType": "uint256", "name": "amount", "type": "uint256" }84 ],85 "name": "approveCross",86 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],87 "stateMutability": "nonpayable",88 "type": "function"89 },72 {90 {73 "inputs": [91 "inputs": [74 { "internalType": "address", "name": "owner", "type": "address" }92 { "internalType": "address", "name": "owner", "type": "address" }88 "stateMutability": "nonpayable",106 "stateMutability": "nonpayable",89 "type": "function"107 "type": "function"90 },108 },109 {110 "inputs": [111 {112 "components": [113 { "internalType": "address", "name": "eth", "type": "address" },114 { "internalType": "uint256", "name": "sub", "type": "uint256" }115 ],116 "internalType": "struct EthCrossAccount",117 "name": "from",118 "type": "tuple"119 },120 { "internalType": "uint256", "name": "amount", "type": "uint256" }121 ],122 "name": "burnFromCross",123 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],124 "stateMutability": "nonpayable",125 "type": "function"126 },91 {127 {92 "inputs": [],128 "inputs": [],93 "name": "decimals",129 "name": "decimals",158 "stateMutability": "nonpayable",194 "stateMutability": "nonpayable",159 "type": "function"195 "type": "function"160 },196 },197 {198 "inputs": [199 {200 "components": [201 { "internalType": "address", "name": "eth", "type": "address" },202 { "internalType": "uint256", "name": "sub", "type": "uint256" }203 ],204 "internalType": "struct EthCrossAccount",205 "name": "to",206 "type": "tuple"207 },208 { "internalType": "uint256", "name": "amount", "type": "uint256" }209 ],210 "name": "transferCross",211 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],212 "stateMutability": "nonpayable",213 "type": "function"214 },161 {215 {162 "inputs": [216 "inputs": [163 { "internalType": "address", "name": "from", "type": "address" },217 { "internalType": "address", "name": "from", "type": "address" },168 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],222 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],169 "stateMutability": "nonpayable",223 "stateMutability": "nonpayable",170 "type": "function"224 "type": "function"171 }225 },226 {227 "inputs": [228 {229 "components": [230 { "internalType": "address", "name": "eth", "type": "address" },231 { "internalType": "uint256", "name": "sub", "type": "uint256" }232 ],233 "internalType": "struct EthCrossAccount",234 "name": "from",235 "type": "tuple"236 },237 {238 "components": [239 { "internalType": "address", "name": "eth", "type": "address" },240 { "internalType": "uint256", "name": "sub", "type": "uint256" }241 ],242 "internalType": "struct EthCrossAccount",243 "name": "to",244 "type": "tuple"245 },246 { "internalType": "uint256", "name": "amount", "type": "uint256" }247 ],248 "name": "transferFromCross",249 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],250 "stateMutability": "nonpayable",251 "type": "function"252 }172]253]173254tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth13}13}141415/// @title A contract that allows to set and delete token properties and change token property permissions.15/// @title A contract that allows to set and delete token properties and change token property permissions.16/// @dev the ERC-165 identifier for this interface is 0x91a97a6816/// @dev the ERC-165 identifier for this interface is 0xde0695c217interface TokenProperties is Dummy, ERC165 {17interface TokenProperties is Dummy, ERC165 {18 // /// @notice Set permissions for token property.19 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 // /// @param key Property key.21 // /// @param isMutable Permission to mutate property.22 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 // /// @dev EVM selector for this function is: 0x222d97fa,25 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)26 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;2718 /// @notice Set permissions for token property.28 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.29 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 /// @param key Property key.30 /// @param permissions Permissions for keys.21 /// @param isMutable Permission to mutate property.22 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 /// @dev EVM selector for this function is: 0x222d97fa,31 /// @dev EVM selector for this function is: 0xbd92983a,25 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)32 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])26 function setTokenPropertyPermission(33 function setTokenPropertyPermissions(Tuple43[] memory permissions) external;27 string memory key,3428 bool isMutable,35 /// @dev EVM selector for this function is: 0xf23d7790,29 bool collectionAdmin,36 /// or in textual repr: tokenPropertyPermissions()30 bool tokenOwner37 function tokenPropertyPermissions() external view returns (Tuple43[] memory);31 ) external;323833 // /// @notice Set token property value.39 // /// @notice Set token property value.79 bytes value;85 bytes value;80}86}8788enum EthTokenPermissions {89 Mutable,90 TokenOwner,91 CollectionAdmin92}9394/// @dev anonymous struct95struct Tuple43 {96 string field_0;97 Tuple41[] field_1;98}99100/// @dev anonymous struct101struct Tuple41 {102 EthTokenPermissions field_0;103 bool field_1;104}8110582/// @title A contract that allows you to work with collections.106/// @title A contract that allows you to work with collections.83/// @dev the ERC-165 identifier for this interface is 0xb5e1747f107/// @dev the ERC-165 identifier for this interface is 0xb5e1747ftests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth13}13}141415/// @title A contract that allows to set and delete token properties and change token property permissions.15/// @title A contract that allows to set and delete token properties and change token property permissions.16/// @dev the ERC-165 identifier for this interface is 0x91a97a6816/// @dev the ERC-165 identifier for this interface is 0xde0695c217interface TokenProperties is Dummy, ERC165 {17interface TokenProperties is Dummy, ERC165 {18 // /// @notice Set permissions for token property.19 // /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 // /// @param key Property key.21 // /// @param isMutable Permission to mutate property.22 // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 // /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 // /// @dev EVM selector for this function is: 0x222d97fa,25 // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)26 // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;2718 /// @notice Set permissions for token property.28 /// @notice Set permissions for token property.19 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.29 /// @dev Throws error if `msg.sender` is not admin or owner of the collection.20 /// @param key Property key.30 /// @param permissions Permissions for keys.21 /// @param isMutable Permission to mutate property.22 /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.23 /// @param tokenOwner Permission to mutate property by token owner if property is mutable.24 /// @dev EVM selector for this function is: 0x222d97fa,31 /// @dev EVM selector for this function is: 0xbd92983a,25 /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)32 /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])26 function setTokenPropertyPermission(33 function setTokenPropertyPermissions(Tuple47[] memory permissions) external;27 string memory key,3428 bool isMutable,35 /// @notice Get permissions for token properties.29 bool collectionAdmin,36 /// @dev EVM selector for this function is: 0xf23d7790,30 bool tokenOwner37 /// or in textual repr: tokenPropertyPermissions()31 ) external;38 function tokenPropertyPermissions() external view returns (Tuple47[] memory);323933 // /// @notice Set token property value.40 // /// @notice Set token property value.34 // /// @dev Throws error if `msg.sender` has no permission to edit the property.41 // /// @dev Throws error if `msg.sender` has no permission to edit the property.79 bytes value;86 bytes value;80}87}8889enum EthTokenPermissions {90 Mutable,91 TokenOwner,92 CollectionAdmin93}9495/// @dev anonymous struct96struct Tuple47 {97 string field_0;98 Tuple45[] field_1;99}100101/// @dev anonymous struct102struct Tuple45 {103 EthTokenPermissions field_0;104 bool field_1;105}8110682/// @title A contract that allows you to work with collections.107/// @title A contract that allows you to work with collections.83/// @dev the ERC-165 identifier for this interface is 0xb5e1747f108/// @dev the ERC-165 identifier for this interface is 0xb5e1747ftests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth23 function parentTokenId() external view returns (uint256);23 function parentTokenId() external view returns (uint256);24}24}252526/// @dev the ERC-165 identifier for this interface is 0xab8deb3726/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b27interface ERC20UniqueExtensions is Dummy, ERC165 {27interface ERC20UniqueExtensions is Dummy, ERC165 {28 /// @dev Function that burns an amount of the token of a given account,28 /// @dev Function that burns an amount of the token of a given account,29 /// deducting from the sender's allowance for said account.29 /// deducting from the sender's allowance for said account.33 /// or in textual repr: burnFrom(address,uint256)33 /// or in textual repr: burnFrom(address,uint256)34 function burnFrom(address from, uint256 amount) external returns (bool);34 function burnFrom(address from, uint256 amount) external returns (bool);3536 /// @dev Function that burns an amount of the token of a given account,37 /// deducting from the sender's allowance for said account.38 /// @param from The account whose tokens will be burnt.39 /// @param amount The amount that will be burnt.40 /// @dev EVM selector for this function is: 0xbb2f5a58,41 /// or in textual repr: burnFromCross((address,uint256),uint256)42 function burnFromCross(EthCrossAccount memory from, uint256 amount) external returns (bool);4344 /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.45 /// Beware that changing an allowance with this method brings the risk that someone may use both the old46 /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this47 /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:48 /// https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472949 /// @param spender The crossaccount which will spend the funds.50 /// @param amount The amount of tokens to be spent.51 /// @dev EVM selector for this function is: 0x0ecd0ab0,52 /// or in textual repr: approveCross((address,uint256),uint256)53 function approveCross(EthCrossAccount memory spender, uint256 amount) external returns (bool);355436 /// @dev Function that changes total amount of the tokens.55 /// @dev Function that changes total amount of the tokens.37 /// Throws if `msg.sender` doesn't owns all of the tokens.56 /// Throws if `msg.sender` doesn't owns all of the tokens.40 /// or in textual repr: repartition(uint256)59 /// or in textual repr: repartition(uint256)41 function repartition(uint256 amount) external returns (bool);60 function repartition(uint256 amount) external returns (bool);6162 /// @dev Transfer token for a specified address63 /// @param to The crossaccount to transfer to.64 /// @param amount The amount to be transferred.65 /// @dev EVM selector for this function is: 0x2ada85ff,66 /// or in textual repr: transferCross((address,uint256),uint256)67 function transferCross(EthCrossAccount memory to, uint256 amount) external returns (bool);6869 /// @dev Transfer tokens from one address to another70 /// @param from The address which you want to send tokens from71 /// @param to The address which you want to transfer to72 /// @param amount the amount of tokens to be transferred73 /// @dev EVM selector for this function is: 0xd5cf430b,74 /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)75 function transferFromCross(76 EthCrossAccount memory from,77 EthCrossAccount memory to,78 uint256 amount79 ) external returns (bool);42}80}8182/// @dev Cross account struct83struct EthCrossAccount {84 address eth;85 uint256 sub;86}438744/// @dev inlined interface88/// @dev inlined interface45interface ERC20Events {89interface ERC20Events {tests/src/eth/events.test.tsdiffbeforeafterboth19import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util';19import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util';20import {IEvent, TCollectionMode} from '../util/playgrounds/types';20import {IEvent, TCollectionMode} from '../util/playgrounds/types';21import {Pallets, requirePalletsOrSkip} from '../util';21import {Pallets, requirePalletsOrSkip} from '../util';22import {NormalizedEvent} from './util/playgrounds/types';22import {EthTokenPermissions, NormalizedEvent} from './util/playgrounds/types';232324let donor: IKeyringPair;24let donor: IKeyringPair;25 25 119 ethEvents.push(event);119 ethEvents.push(event);120 });120 });121 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);121 const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]);122 await collection.methods.setTokenPropertyPermission('testKey', true, true, true).send({from: owner});122 await collection.methods.setTokenPropertyPermissions([123 ['A', [124 [EthTokenPermissions.Mutable, true], 125 [EthTokenPermissions.TokenOwner, true], 126 [EthTokenPermissions.CollectionAdmin, true]],127 ],128 ]).send({from: owner});123 await helper.wait.newBlocks(1);129 await helper.wait.newBlocks(1);124 expect(ethEvents).to.be.like([130 expect(ethEvents).to.be.like([125 {131 {374 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);380 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);375 const result = await collection.methods.mint(owner).send({from: owner});381 const result = await collection.methods.mint(owner).send({from: owner});376 const tokenId = result.events.Transfer.returnValues.tokenId;382 const tokenId = result.events.Transfer.returnValues.tokenId;377 await collection.methods.setTokenPropertyPermission('A', true, true, true).send({from: owner});383 await collection.methods.setTokenPropertyPermissions([384 ['A', [385 [EthTokenPermissions.Mutable, true], 386 [EthTokenPermissions.TokenOwner, true], 387 [EthTokenPermissions.CollectionAdmin, true]],388 ],389 ]).send({from: owner});378390379391380 const ethEvents: any = [];392 const ethEvents: any = [];tests/src/eth/precompile.test.tsdiffbeforeafterbothno changes
tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth160 }160 }161 });161 });162162 163 itEth('Can perform approveCross()', async ({helper}) => {164 const owner = await helper.eth.createAccountWithBalance(donor);165 const spender = helper.eth.createAccount();166 const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0];167 const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);168 const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub);169 170171 const collection = await helper.rft.mintCollection(alice);172 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});173174 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);175 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);176177 {178 const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});179 const event = result.events.Approval;180 expect(event.address).to.be.equal(tokenAddress);181 expect(event.returnValues.owner).to.be.equal(owner);182 expect(event.returnValues.spender).to.be.equal(spender);183 expect(event.returnValues.value).to.be.equal('100');184 }185186 {187 const allowance = await contract.methods.allowance(owner, spender).call();188 expect(+allowance).to.equal(100);189 }190 191 192 {193 const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner});194 const event = result.events.Approval;195 expect(event.address).to.be.equal(tokenAddress);196 expect(event.returnValues.owner).to.be.equal(owner);197 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address));198 expect(event.returnValues.value).to.be.equal('100');199 }200201 {202 const allowance = await collection.getTokenApprovedPieces(tokenId, {Ethereum: owner}, {Substrate: spenderSub.address});203 expect(allowance).to.equal(100n);204 }205 206 {207 //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call()208 }209 });210 163 itEth('Can perform transferFrom()', async ({helper}) => {211 itEth('Can perform transferFrom()', async ({helper}) => {164 const owner = await helper.eth.createAccountWithBalance(donor);212 const owner = await helper.eth.createAccountWithBalance(donor);198 }246 }199 });247 });248 249 itEth('Can perform transferFromCross()', async ({helper}) => {250 const owner = await helper.eth.createAccountWithBalance(donor);251 const ownerCross = helper.ethCrossAccount.fromAddress(owner);252 const spender = await helper.eth.createAccountWithBalance(donor);253 const receiver = helper.eth.createAccount();254 const receiverSub = (await helper.arrange.createAccounts([1n], donor))[0];255 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiver);256 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);257 258 const collection = await helper.rft.mintCollection(alice);259 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});260261 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);262 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);263264 await contract.methods.approve(spender, 100).send({from: owner});265 266 {267 const result = await contract.methods.transferFromCross(ownerCross, receiverCrossEth, 49).send({from: spender});268 let event = result.events.Transfer;269 expect(event.address).to.be.equal(tokenAddress);270 expect(event.returnValues.from).to.be.equal(owner);271 expect(event.returnValues.to).to.be.equal(receiver);272 expect(event.returnValues.value).to.be.equal('49');273274 event = result.events.Approval;275 expect(event.address).to.be.equal(tokenAddress);276 expect(event.returnValues.owner).to.be.equal(owner);277 expect(event.returnValues.spender).to.be.equal(spender);278 expect(event.returnValues.value).to.be.equal('51');279 }280281 {282 const balance = await contract.methods.balanceOf(receiver).call();283 expect(+balance).to.equal(49);284 }285286 {287 const balance = await contract.methods.balanceOf(owner).call();288 expect(+balance).to.equal(151);289 }290 291 {292 const result = await contract.methods.transferFromCross(ownerCross, receiverCrossSub, 51).send({from: spender});293 let event = result.events.Transfer;294 expect(event.address).to.be.equal(tokenAddress);295 expect(event.returnValues.from).to.be.equal(owner);296 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));297 expect(event.returnValues.value).to.be.equal('51');298299 event = result.events.Approval;300 expect(event.address).to.be.equal(tokenAddress);301 expect(event.returnValues.owner).to.be.equal(owner);302 expect(event.returnValues.spender).to.be.equal(spender);303 expect(event.returnValues.value).to.be.equal('0');304 }305306 {307 const balance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});308 expect(balance).to.equal(51n);309 }310311 {312 const balance = await contract.methods.balanceOf(owner).call();313 expect(+balance).to.equal(100);314 }315 });200316201 itEth('Can perform transfer()', async ({helper}) => {317 itEth('Can perform transfer()', async ({helper}) => {202 const owner = await helper.eth.createAccountWithBalance(donor);318 const owner = await helper.eth.createAccountWithBalance(donor);267 expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);383 expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);268 }));384 }));269385386 itEth('Can perform transferCross()', async ({helper}) => {387 const owner = await helper.eth.createAccountWithBalance(donor);388 const receiver = helper.eth.createAccount();389 const receiverSub = (await helper.arrange.createAccounts([1n], donor))[0];390 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiver);391 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);392 const collection = await helper.rft.mintCollection(alice);393 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});394395 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);396 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);397398 {399 const result = await contract.methods.transferCross(receiverCrossEth, 50).send({from: owner});400 const event = result.events.Transfer;401 expect(event.address).to.be.equal(tokenAddress);402 expect(event.returnValues.from).to.be.equal(owner);403 expect(event.returnValues.to).to.be.equal(receiver);404 expect(event.returnValues.value).to.be.equal('50');405 }406407 {408 const balance = await contract.methods.balanceOf(owner).call();409 expect(+balance).to.equal(150);410 }411412 {413 const balance = await contract.methods.balanceOf(receiver).call();414 expect(+balance).to.equal(50);415 }416 417 {418 const result = await contract.methods.transferCross(receiverCrossSub, 50).send({from: owner});419 const event = result.events.Transfer;420 expect(event.address).to.be.equal(tokenAddress);421 expect(event.returnValues.from).to.be.equal(owner);422 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));423 expect(event.returnValues.value).to.be.equal('50');424 }425426 {427 const balance = await contract.methods.balanceOf(owner).call();428 expect(+balance).to.equal(100);429 }430431 {432 const balance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});433 expect(balance).to.equal(50n);434 }435 });270 itEth('Can perform repartition()', async ({helper}) => {436 itEth('Can perform repartition()', async ({helper}) => {271 const owner = await helper.eth.createAccountWithBalance(donor);437 const owner = await helper.eth.createAccountWithBalance(donor);272 const receiver = await helper.eth.createAccountWithBalance(donor);438 const receiver = await helper.eth.createAccountWithBalance(donor);354 expect(event.returnValues.tokenId).to.be.equal(tokenId);520 expect(event.returnValues.tokenId).to.be.equal(tokenId);355 });521 });522 523 itEth('Can perform burnFromCross()', async ({helper}) => {524 const owner = await helper.eth.createAccountWithBalance(donor);525 const ownerSub = (await helper.arrange.createAccounts([10n], donor))[0];526 const ownerCross = helper.ethCrossAccount.fromAddress(owner);527 const spender = await helper.eth.createAccountWithBalance(donor);528 529 const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);530 const ownerSubCross = helper.ethCrossAccount.fromKeyringPair(ownerSub);531532 const collection = await helper.rft.mintCollection(alice);533 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});534 535536 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);537 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);538539 {540 await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});541 542 await expect(contract.methods.burnFromCross(ownerCross, 50).send({from: spender})).to.be.fulfilled;543 await expect(contract.methods.burnFromCross(ownerCross, 100).send({from: spender})).to.be.rejected;544 expect(await contract.methods.balanceOf(owner).call({from: owner})).to.be.equal('150');545 }546 {547 const {tokenId} = await collection.mintToken(alice, 200n, {Substrate: ownerSub.address});548 await collection.approveToken(ownerSub, tokenId, {Ethereum: spender}, 100n);549 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);550 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);551 552 await expect(contract.methods.burnFromCross(ownerSubCross, 50).send({from: spender})).to.be.fulfilled;553 await expect(contract.methods.burnFromCross(ownerSubCross, 100).send({from: spender})).to.be.rejected;554 expect(await collection.getTokenBalance(tokenId, {Substrate: ownerSub.address})).to.be.equal(150n);555 }556 });356});557});357558358describe('Refungible: Fees', () => {559describe('Refungible: Fees', () => {tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth20import {ITokenPropertyPermission} from '../util/playgrounds/types';20import {ITokenPropertyPermission} from '../util/playgrounds/types';21import {Pallets} from '../util';21import {Pallets} from '../util';22import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '../util/playgrounds/unique';22import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '../util/playgrounds/unique';23import {EthTokenPermissions} from './util/playgrounds/types';232424describe('EVM token properties', () => {25describe('EVM token properties', () => {25 let donor: IKeyringPair;26 let donor: IKeyringPair;32 });33 });33 });34 });343536 [37 {mode: 'nft' as const, requiredPallets: []},38 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},39 ].map(testCase =>35 itEth('Can be reconfigured', async({helper}) => {40 itEth.ifWithPallets(`[${testCase.mode}] Set and get token property permissions`, testCase.requiredPallets, async({helper}) => {36 const caller = await helper.eth.createAccountWithBalance(donor);41 const owner = await helper.eth.createAccountWithBalance(donor);42 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);37 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {43 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {38 const collection = await helper.nft.mintCollection(alice);44 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');39 await collection.addAdmin(alice, {Ethereum: caller});40 41 const address = helper.ethAddress.fromCollectionId(collection.collectionId);45 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);42 const contract = helper.ethNativeContract.collection(address, 'nft', caller);46 await collection.methods.addCollectionAdminCross(caller).send({from: owner});43 4744 await contract.methods.setTokenPropertyPermission('testKey', mutable, collectionAdmin, tokenOwner).send({from: caller});48 await collection.methods.setTokenPropertyPermissions([45 49 ['testKey', [50 [EthTokenPermissions.Mutable, mutable], 51 [EthTokenPermissions.TokenOwner, tokenOwner], 52 [EthTokenPermissions.CollectionAdmin, collectionAdmin]],53 ],54 ]).send({from: caller.eth});55 46 expect(await collection.getPropertyPermissions()).to.be.deep.equal([{56 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{47 key: 'testKey',57 key: 'testKey',48 permission: {mutable, collectionAdmin, tokenOwner},58 permission: {mutable, collectionAdmin, tokenOwner},49 }]);59 }]);6061 expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([62 ['testKey', [63 [EthTokenPermissions.Mutable.toString(), mutable], 64 [EthTokenPermissions.TokenOwner.toString(), tokenOwner], 65 [EthTokenPermissions.CollectionAdmin.toString(), collectionAdmin]],66 ],67 ]);50 }68 }51 });69 }));7071 [72 {mode: 'nft' as const, requiredPallets: []},73 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},74 ].map(testCase =>75 itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => {76 const owner = await helper.eth.createAccountWithBalance(donor);77 78 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');79 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);8081 await collection.methods.setTokenPropertyPermissions([82 ['testKey_0', [83 [EthTokenPermissions.Mutable, true], 84 [EthTokenPermissions.TokenOwner, true], 85 [EthTokenPermissions.CollectionAdmin, true]],86 ],87 ['testKey_1', [88 [EthTokenPermissions.Mutable, true], 89 [EthTokenPermissions.TokenOwner, false], 90 [EthTokenPermissions.CollectionAdmin, true]],91 ],92 ['testKey_2', [93 [EthTokenPermissions.Mutable, false], 94 [EthTokenPermissions.TokenOwner, true], 95 [EthTokenPermissions.CollectionAdmin, false]],96 ],97 ]).send({from: owner});98 99 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([100 {101 key: 'testKey_0',102 permission: {mutable: true, tokenOwner: true, collectionAdmin: true},103 },104 {105 key: 'testKey_1',106 permission: {mutable: true, tokenOwner: false, collectionAdmin: true},107 },108 {109 key: 'testKey_2',110 permission: {mutable: false, tokenOwner: true, collectionAdmin: false},111 },112 ]);113114 expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([115 ['testKey_0', [116 [EthTokenPermissions.Mutable.toString(), true], 117 [EthTokenPermissions.TokenOwner.toString(), true], 118 [EthTokenPermissions.CollectionAdmin.toString(), true]],119 ],120 ['testKey_1', [121 [EthTokenPermissions.Mutable.toString(), true], 122 [EthTokenPermissions.TokenOwner.toString(), false], 123 [EthTokenPermissions.CollectionAdmin.toString(), true]],124 ],125 ['testKey_2', [126 [EthTokenPermissions.Mutable.toString(), false], 127 [EthTokenPermissions.TokenOwner.toString(), true], 128 [EthTokenPermissions.CollectionAdmin.toString(), false]],129 ],130 ]);131 132 }));133134 [135 {mode: 'nft' as const, requiredPallets: []},136 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},137 ].map(testCase =>138 itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => {139 const owner = await helper.eth.createAccountWithBalance(donor);140 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);141 142 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');143 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);144 await collection.methods.addCollectionAdminCross(caller).send({from: owner});145146 await collection.methods.setTokenPropertyPermissions([147 ['testKey_0', [148 [EthTokenPermissions.Mutable, true], 149 [EthTokenPermissions.TokenOwner, true], 150 [EthTokenPermissions.CollectionAdmin, true]],151 ],152 ['testKey_1', [153 [EthTokenPermissions.Mutable, true], 154 [EthTokenPermissions.TokenOwner, false], 155 [EthTokenPermissions.CollectionAdmin, true]],156 ],157 ['testKey_2', [158 [EthTokenPermissions.Mutable, false], 159 [EthTokenPermissions.TokenOwner, true], 160 [EthTokenPermissions.CollectionAdmin, false]],161 ],162 ]).send({from: caller.eth});163 164 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([165 {166 key: 'testKey_0',167 permission: {mutable: true, tokenOwner: true, collectionAdmin: true},168 },169 {170 key: 'testKey_1',171 permission: {mutable: true, tokenOwner: false, collectionAdmin: true},172 },173 {174 key: 'testKey_2',175 permission: {mutable: false, tokenOwner: true, collectionAdmin: false},176 },177 ]);178179 expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([180 ['testKey_0', [181 [EthTokenPermissions.Mutable.toString(), true], 182 [EthTokenPermissions.TokenOwner.toString(), true], 183 [EthTokenPermissions.CollectionAdmin.toString(), true]],184 ],185 ['testKey_1', [186 [EthTokenPermissions.Mutable.toString(), true], 187 [EthTokenPermissions.TokenOwner.toString(), false], 188 [EthTokenPermissions.CollectionAdmin.toString(), true]],189 ],190 ['testKey_2', [191 [EthTokenPermissions.Mutable.toString(), false], 192 [EthTokenPermissions.TokenOwner.toString(), true], 193 [EthTokenPermissions.CollectionAdmin.toString(), false]],194 ],195 ]);196 197 }));5219853 [199 [54 {200 {302 expect(actualProps).to.deep.eq(expectedProps);448 expect(actualProps).to.deep.eq(expectedProps);303 }));449 }));450451 [452 {mode: 'nft' as const, requiredPallets: []},453 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},454 ].map(testCase =>455 itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => {456 const owner = await helper.eth.createAccountWithBalance(donor);457 const caller = await helper.eth.createAccountWithBalance(donor);458 459 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');460 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);461 462 await expect(collection.methods.setTokenPropertyPermissions([463 ['testKey_0', [464 [EthTokenPermissions.Mutable, true], 465 [EthTokenPermissions.TokenOwner, true], 466 [EthTokenPermissions.CollectionAdmin, true]],467 ],468 ]).call({from: caller})).to.be.rejectedWith('NoPermission'); 469 }));470471 [472 {mode: 'nft' as const, requiredPallets: []},473 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},474 ].map(testCase =>475 itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => {476 const owner = await helper.eth.createAccountWithBalance(donor);477 478 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');479 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);480 481 await expect(collection.methods.setTokenPropertyPermissions([482 // "Space" is invalid character483 ['testKey 0', [484 [EthTokenPermissions.Mutable, true], 485 [EthTokenPermissions.TokenOwner, true], 486 [EthTokenPermissions.CollectionAdmin, true]],487 ],488 ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey'); 489 }));490 304});491});305492tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth202021export type EthProperty = string[];21export type EthProperty = string[];22222323export enum EthTokenPermissions {24 Mutable,25 TokenOwner,26 CollectionAdmin27}tests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth60 }60 }616162 async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {62 async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {63 const out = JSON.parse(solc.compile(JSON.stringify({63 const compiled = JSON.parse(solc.compile(JSON.stringify({64 language: 'Solidity',64 language: 'Solidity',65 sources: {65 sources: {66 [`${name}.sol`]: {66 [`${name}.sol`]: {74 },74 },75 },75 },76 },76 },77 }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name];77 }), {import: await this.findImports(imports)}));7879 const hasErrors = compiled['errors']80 && compiled['errors'].length > 081 && compiled.errors.some(function(err: any) {82 return err.severity == 'error';83 });84 85 if (hasErrors) {86 throw compiled.errors;87 }88 const out = compiled.contracts[`${name}.sol`][name];788979 return {90 return {80 abi: out.abi,91 abi: out.abi,tests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth16import type { BlockHash } from '@polkadot/types/interfaces/chain';16import type { BlockHash } from '@polkadot/types/interfaces/chain';17import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';17import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';18import type { AuthorityId } from '@polkadot/types/interfaces/consensus';18import type { AuthorityId } from '@polkadot/types/interfaces/consensus';19import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequestV1 } from '@polkadot/types/interfaces/contracts';19import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequest } from '@polkadot/types/interfaces/contracts';20import type { BlockStats } from '@polkadot/types/interfaces/dev';20import type { BlockStats } from '@polkadot/types/interfaces/dev';21import type { CreatedBlock } from '@polkadot/types/interfaces/engine';21import type { CreatedBlock } from '@polkadot/types/interfaces/engine';22import type { EthAccount, EthCallRequest, EthFeeHistory, EthFilter, EthFilterChanges, EthLog, EthReceipt, EthRichBlock, EthSubKind, EthSubParams, EthSyncStatus, EthTransaction, EthTransactionRequest, EthWork } from '@polkadot/types/interfaces/eth';22import type { EthAccount, EthCallRequest, EthFeeHistory, EthFilter, EthFilterChanges, EthLog, EthReceipt, EthRichBlock, EthSubKind, EthSubParams, EthSyncStatus, EthTransaction, EthTransactionRequest, EthWork } from '@polkadot/types/interfaces/eth';23import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';23import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';24import type { EncodedFinalityProofs, JustificationNotification, ReportedRoundStates } from '@polkadot/types/interfaces/grandpa';24import type { EncodedFinalityProofs, JustificationNotification, ReportedRoundStates } from '@polkadot/types/interfaces/grandpa';25import type { MmrLeafBatchProof, MmrLeafProof } from '@polkadot/types/interfaces/mmr';25import type { MmrLeafBatchProof, MmrLeafProof } from '@polkadot/types/interfaces/mmr';26import type { StorageKind } from '@polkadot/types/interfaces/offchain';26import type { StorageKind } from '@polkadot/types/interfaces/offchain';27import type { FeeDetails, RuntimeDispatchInfoV1 } from '@polkadot/types/interfaces/payment';27import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';28import type { RpcMethods } from '@polkadot/types/interfaces/rpc';28import type { RpcMethods } from '@polkadot/types/interfaces/rpc';29import type { AccountId, AccountId32, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';29import type { AccountId, AccountId32, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';30import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';30import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';174 * @deprecated Use the runtime interface `api.call.contractsApi.instantiate` instead174 * @deprecated Use the runtime interface `api.call.contractsApi.instantiate` instead175 * Instantiate a new contract175 * Instantiate a new contract176 **/176 **/177 instantiate: AugmentedRpc<(request: InstantiateRequestV1 | { origin?: any; value?: any; gasLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;177 instantiate: AugmentedRpc<(request: InstantiateRequest | { origin?: any; value?: any; gasLimit?: any; storageDepositLimit?: any; code?: any; data?: any; salt?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<ContractInstantiateResult>>;178 /**178 /**179 * @deprecated Not available in newer versions of the contracts interfaces179 * @deprecated Not available in newer versions of the contracts interfaces180 * Returns the projected time a given contract will be able to sustain paying its rent180 * Returns the projected time a given contract will be able to sustain paying its rent425 localStorageSet: AugmentedRpc<(kind: StorageKind | 'PERSISTENT' | 'LOCAL' | number | Uint8Array, key: Bytes | string | Uint8Array, value: Bytes | string | Uint8Array) => Observable<Null>>;425 localStorageSet: AugmentedRpc<(kind: StorageKind | 'PERSISTENT' | 'LOCAL' | number | Uint8Array, key: Bytes | string | Uint8Array, value: Bytes | string | Uint8Array) => Observable<Null>>;426 };426 };427 payment: {427 payment: {428 /**428 /**429 * @deprecated Use `api.call.transactionPaymentApi.queryFeeDetails` instead429 * Query the detailed fee of a given encoded extrinsic430 * Query the detailed fee of a given encoded extrinsic430 **/431 **/432 queryFeeDetails: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<FeeDetails>>;431 queryFeeDetails: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<FeeDetails>>;433 /**432 /**434 * @deprecated Use `api.call.transactionPaymentApi.queryInfo` instead433 * Retrieves the fee information for an encoded extrinsic435 * Retrieves the fee information for an encoded extrinsic434 **/436 **/437 queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfoV1>>;435 queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<RuntimeDispatchInfo>>;438 };436 };439 rmrk: {437 rmrk: {440 /**438 /**tests/src/interfaces/augment-api-runtime.tsdiffbeforeafterboth6import '@polkadot/api-base/types/calls';6import '@polkadot/api-base/types/calls';778import type { ApiTypes, AugmentedCall, DecoratedCallBase } from '@polkadot/api-base/types';8import type { ApiTypes, AugmentedCall, DecoratedCallBase } from '@polkadot/api-base/types';9import type { Bytes, Null, Option, Result, U256, Vec, bool, u256, u32, u64 } from '@polkadot/types-codec';9import type { Bytes, Null, Option, Result, U256, Vec, bool, u256, u64 } from '@polkadot/types-codec';10import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';10import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';11import type { CheckInherentsResult, InherentData } from '@polkadot/types/interfaces/blockbuilder';11import type { CheckInherentsResult, InherentData } from '@polkadot/types/interfaces/blockbuilder';12import type { BlockHash } from '@polkadot/types/interfaces/chain';12import type { BlockHash } from '@polkadot/types/interfaces/chain';16import type { EvmAccount, EvmCallInfo, EvmCreateInfo } from '@polkadot/types/interfaces/evm';16import type { EvmAccount, EvmCallInfo, EvmCreateInfo } from '@polkadot/types/interfaces/evm';17import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';17import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';18import type { OpaqueMetadata } from '@polkadot/types/interfaces/metadata';18import type { OpaqueMetadata } from '@polkadot/types/interfaces/metadata';19import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';20import type { AccountId, Block, H160, H256, Header, Index, KeyTypeId, Permill, SlotDuration } from '@polkadot/types/interfaces/runtime';19import type { AccountId, Block, H160, H256, Header, Index, KeyTypeId, Permill, SlotDuration } from '@polkadot/types/interfaces/runtime';21import type { RuntimeVersion } from '@polkadot/types/interfaces/state';20import type { RuntimeVersion } from '@polkadot/types/interfaces/state';22import type { ApplyExtrinsicResult, DispatchError } from '@polkadot/types/interfaces/system';21import type { ApplyExtrinsicResult, DispatchError } from '@polkadot/types/interfaces/system';229 **/228 **/230 [key: string]: DecoratedCallBase<ApiType>;229 [key: string]: DecoratedCallBase<ApiType>;231 };230 };232 /** 0x37c8bb1350a9a2a8/2 */233 transactionPaymentApi: {234 /**235 * The transaction fee details236 **/237 queryFeeDetails: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<FeeDetails>>;238 /**239 * The transaction info240 **/241 queryInfo: AugmentedCall<ApiType, (uxt: Extrinsic | IExtrinsic | string | Uint8Array, len: u32 | AnyNumber | Uint8Array) => Observable<RuntimeDispatchInfo>>;242 /**243 * Generic call244 **/245 [key: string]: DecoratedCallBase<ApiType>;246 };247 } // AugmentedCalls231 } // AugmentedCalls248} // declare module232} // declare module249233tests/src/interfaces/augment-types.tsdiffbeforeafterboth24import type { StatementKind } from '@polkadot/types/interfaces/claims';24import type { StatementKind } from '@polkadot/types/interfaces/claims';25import type { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective';25import type { CollectiveOrigin, MemberCount, ProposalIndex, Votes, VotesTo230 } from '@polkadot/types/interfaces/collective';26import type { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus';26import type { AuthorityId, RawVRFOutput } from '@polkadot/types/interfaces/consensus';27import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractExecResultU64, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractInstantiateResultU64, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts';27import type { AliveContractInfo, CodeHash, CodeSource, CodeUploadRequest, CodeUploadResult, CodeUploadResultValue, ContractCallFlags, ContractCallRequest, ContractExecResult, ContractExecResultOk, ContractExecResultResult, ContractExecResultSuccessTo255, ContractExecResultSuccessTo260, ContractExecResultTo255, ContractExecResultTo260, ContractExecResultTo267, ContractInfo, ContractInstantiateResult, ContractInstantiateResultTo267, ContractInstantiateResultTo299, ContractReturnFlags, ContractStorageKey, DeletedContract, ExecReturnValue, Gas, HostFnWeights, HostFnWeightsTo264, InstantiateRequest, InstantiateRequestV1, InstantiateRequestV2, InstantiateReturnValue, InstantiateReturnValueOk, InstantiateReturnValueTo267, InstructionWeights, Limits, LimitsTo264, PrefabWasmModule, RentProjection, Schedule, ScheduleTo212, ScheduleTo258, ScheduleTo264, SeedOf, StorageDeposit, TombstoneContractInfo, TrieId } from '@polkadot/types/interfaces/contracts';28import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractMetadataV4, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi';28import type { ContractConstructorSpecLatest, ContractConstructorSpecV0, ContractConstructorSpecV1, ContractConstructorSpecV2, ContractConstructorSpecV3, ContractContractSpecV0, ContractContractSpecV1, ContractContractSpecV2, ContractContractSpecV3, ContractContractSpecV4, ContractCryptoHasher, ContractDiscriminant, ContractDisplayName, ContractEventParamSpecLatest, ContractEventParamSpecV0, ContractEventParamSpecV2, ContractEventSpecLatest, ContractEventSpecV0, ContractEventSpecV1, ContractEventSpecV2, ContractLayoutArray, ContractLayoutCell, ContractLayoutEnum, ContractLayoutHash, ContractLayoutHashingStrategy, ContractLayoutKey, ContractLayoutStruct, ContractLayoutStructField, ContractMessageParamSpecLatest, ContractMessageParamSpecV0, ContractMessageParamSpecV2, ContractMessageSpecLatest, ContractMessageSpecV0, ContractMessageSpecV1, ContractMessageSpecV2, ContractMetadata, ContractMetadataLatest, ContractMetadataV0, ContractMetadataV1, ContractMetadataV2, ContractMetadataV3, ContractMetadataV4, ContractProject, ContractProjectContract, ContractProjectInfo, ContractProjectSource, ContractProjectV0, ContractSelector, ContractStorageLayout, ContractTypeSpec } from '@polkadot/types/interfaces/contractsAbi';29import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan';29import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan';30import type { CollationInfo, CollationInfoV1, ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus';30import type { CollationInfo, CollationInfoV1, ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus';47import type { StorageKind } from '@polkadot/types/interfaces/offchain';47import type { StorageKind } from '@polkadot/types/interfaces/offchain';48import type { DeferredOffenceOf, Kind, OffenceDetails, Offender, OpaqueTimeSlot, ReportIdOf, Reporter } from '@polkadot/types/interfaces/offences';48import type { DeferredOffenceOf, Kind, OffenceDetails, Offender, OpaqueTimeSlot, ReportIdOf, Reporter } from '@polkadot/types/interfaces/offences';49import type { AbridgedCandidateReceipt, AbridgedHostConfiguration, AbridgedHrmpChannel, AssignmentId, AssignmentKind, AttestedCandidate, AuctionIndex, AuthorityDiscoveryId, AvailabilityBitfield, AvailabilityBitfieldRecord, BackedCandidate, Bidder, BufferedSessionChange, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateInfo, CandidatePendingAvailability, CandidateReceipt, CollatorId, CollatorSignature, CommittedCandidateReceipt, CoreAssignment, CoreIndex, CoreOccupied, CoreState, DisputeLocation, DisputeResult, DisputeState, DisputeStatement, DisputeStatementSet, DoubleVoteReport, DownwardMessage, ExplicitDisputeStatement, GlobalValidationData, GlobalValidationSchedule, GroupIndex, GroupRotationInfo, HeadData, HostConfiguration, HrmpChannel, HrmpChannelId, HrmpOpenChannelRequest, InboundDownwardMessage, InboundHrmpMessage, InboundHrmpMessages, IncomingParachain, IncomingParachainDeploy, IncomingParachainFixed, InvalidDisputeStatementKind, LeasePeriod, LeasePeriodOf, LocalValidationData, MessageIngestionType, MessageQueueChain, MessagingStateSnapshot, MessagingStateSnapshotEgressEntry, MultiDisputeStatementSet, NewBidder, OccupiedCore, OccupiedCoreAssumption, OldV1SessionInfo, OutboundHrmpMessage, ParaGenesisArgs, ParaId, ParaInfo, ParaLifecycle, ParaPastCodeMeta, ParaScheduling, ParaValidatorIndex, ParachainDispatchOrigin, ParachainInherentData, ParachainProposal, ParachainsInherentData, ParathreadClaim, ParathreadClaimQueue, ParathreadEntry, PersistedValidationData, PvfCheckStatement, QueuedParathread, RegisteredParachainInfo, RelayBlockNumber, RelayChainBlockNumber, RelayChainHash, RelayHash, Remark, ReplacementTimes, Retriable, ScheduledCore, Scheduling, ScrapedOnChainVotes, ServiceQuality, SessionInfo, SessionInfoValidatorGroup, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, SlotRange, SlotRange10, Statement, SubId, SystemInherentData, TransientValidationData, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidationData, ValidationDataType, ValidationFunctionParams, ValidatorSignature, ValidityAttestation, VecInboundHrmpMessage, WinnersData, WinnersData10, WinnersDataTuple, WinnersDataTuple10, WinningData, WinningData10, WinningDataEntry } from '@polkadot/types/interfaces/parachains';49import type { AbridgedCandidateReceipt, AbridgedHostConfiguration, AbridgedHrmpChannel, AssignmentId, AssignmentKind, AttestedCandidate, AuctionIndex, AuthorityDiscoveryId, AvailabilityBitfield, AvailabilityBitfieldRecord, BackedCandidate, Bidder, BufferedSessionChange, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateInfo, CandidatePendingAvailability, CandidateReceipt, CollatorId, CollatorSignature, CommittedCandidateReceipt, CoreAssignment, CoreIndex, CoreOccupied, CoreState, DisputeLocation, DisputeResult, DisputeState, DisputeStatement, DisputeStatementSet, DoubleVoteReport, DownwardMessage, ExplicitDisputeStatement, GlobalValidationData, GlobalValidationSchedule, GroupIndex, GroupRotationInfo, HeadData, HostConfiguration, HrmpChannel, HrmpChannelId, HrmpOpenChannelRequest, InboundDownwardMessage, InboundHrmpMessage, InboundHrmpMessages, IncomingParachain, IncomingParachainDeploy, IncomingParachainFixed, InvalidDisputeStatementKind, LeasePeriod, LeasePeriodOf, LocalValidationData, MessageIngestionType, MessageQueueChain, MessagingStateSnapshot, MessagingStateSnapshotEgressEntry, MultiDisputeStatementSet, NewBidder, OccupiedCore, OccupiedCoreAssumption, OldV1SessionInfo, OutboundHrmpMessage, ParaGenesisArgs, ParaId, ParaInfo, ParaLifecycle, ParaPastCodeMeta, ParaScheduling, ParaValidatorIndex, ParachainDispatchOrigin, ParachainInherentData, ParachainProposal, ParachainsInherentData, ParathreadClaim, ParathreadClaimQueue, ParathreadEntry, PersistedValidationData, PvfCheckStatement, QueuedParathread, RegisteredParachainInfo, RelayBlockNumber, RelayChainBlockNumber, RelayChainHash, RelayHash, Remark, ReplacementTimes, Retriable, ScheduledCore, Scheduling, ScrapedOnChainVotes, ServiceQuality, SessionInfo, SessionInfoValidatorGroup, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SigningContext, SlotRange, SlotRange10, Statement, SubId, SystemInherentData, TransientValidationData, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidationData, ValidationDataType, ValidationFunctionParams, ValidatorSignature, ValidityAttestation, VecInboundHrmpMessage, WinnersData, WinnersData10, WinnersDataTuple, WinnersDataTuple10, WinningData, WinningData10, WinningDataEntry } from '@polkadot/types/interfaces/parachains';50import type { FeeDetails, InclusionFee, RuntimeDispatchInfo, RuntimeDispatchInfoV1, RuntimeDispatchInfoV2 } from '@polkadot/types/interfaces/payment';50import type { FeeDetails, InclusionFee, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';51import type { Approvals } from '@polkadot/types/interfaces/poll';51import type { Approvals } from '@polkadot/types/interfaces/poll';52import type { ProxyAnnouncement, ProxyDefinition, ProxyType } from '@polkadot/types/interfaces/proxy';52import type { ProxyAnnouncement, ProxyDefinition, ProxyType } from '@polkadot/types/interfaces/proxy';53import type { AccountStatus, AccountValidity } from '@polkadot/types/interfaces/purchase';53import type { AccountStatus, AccountValidity } from '@polkadot/types/interfaces/purchase';273 ContractExecResultTo255: ContractExecResultTo255;273 ContractExecResultTo255: ContractExecResultTo255;274 ContractExecResultTo260: ContractExecResultTo260;274 ContractExecResultTo260: ContractExecResultTo260;275 ContractExecResultTo267: ContractExecResultTo267;275 ContractExecResultTo267: ContractExecResultTo267;276 ContractExecResultU64: ContractExecResultU64;277 ContractInfo: ContractInfo;276 ContractInfo: ContractInfo;278 ContractInstantiateResult: ContractInstantiateResult;277 ContractInstantiateResult: ContractInstantiateResult;279 ContractInstantiateResultTo267: ContractInstantiateResultTo267;278 ContractInstantiateResultTo267: ContractInstantiateResultTo267;280 ContractInstantiateResultTo299: ContractInstantiateResultTo299;279 ContractInstantiateResultTo299: ContractInstantiateResultTo299;281 ContractInstantiateResultU64: ContractInstantiateResultU64;282 ContractLayoutArray: ContractLayoutArray;280 ContractLayoutArray: ContractLayoutArray;283 ContractLayoutCell: ContractLayoutCell;281 ContractLayoutCell: ContractLayoutCell;284 ContractLayoutEnum: ContractLayoutEnum;282 ContractLayoutEnum: ContractLayoutEnum;1059 RpcMethods: RpcMethods;1057 RpcMethods: RpcMethods;1060 RuntimeDbWeight: RuntimeDbWeight;1058 RuntimeDbWeight: RuntimeDbWeight;1061 RuntimeDispatchInfo: RuntimeDispatchInfo;1059 RuntimeDispatchInfo: RuntimeDispatchInfo;1062 RuntimeDispatchInfoV1: RuntimeDispatchInfoV1;1063 RuntimeDispatchInfoV2: RuntimeDispatchInfoV2;1064 RuntimeVersion: RuntimeVersion;1060 RuntimeVersion: RuntimeVersion;1065 RuntimeVersionApi: RuntimeVersionApi;1061 RuntimeVersionApi: RuntimeVersionApi;1066 RuntimeVersionPartial: RuntimeVersionPartial;1062 RuntimeVersionPartial: RuntimeVersionPartial;tests/src/nesting/collectionProperties.test.tsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {itSub, Pallets, usingPlaygrounds, expect} from '../util';18import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util';19import {UniqueBaseCollection} from '../util/playgrounds/unique';201921describe('Integration Test: Collection Properties', () => {20describe('Integration Test: Collection Properties', () => {22 let alice: IKeyringPair;21 let alice: IKeyringPair;34 expect(await collection.getProperties()).to.be.empty;33 expect(await collection.getProperties()).to.be.empty;35 });34 });36 3537 async function testSetsPropertiesForCollection(collection: UniqueBaseCollection) {36 [38 // As owner37 {mode: 'nft' as const, requiredPallets: []},39 await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;38 {mode: 'ft' as const, requiredPallets: []},40 39 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, 41 await collection.addAdmin(alice, {Substrate: bob.address});40 ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {42 41 before(async function() {43 // As administrator42 // eslint-disable-next-line require-await44 await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled;43 await usingPlaygrounds(async helper => {45 44 requirePalletsOrSkip(this, helper, testSuite.requiredPallets);46 const properties = await collection.getProperties();45 });47 expect(properties).to.include.deep.members([48 {key: 'electron', value: 'come bond'},49 {key: 'black_hole', value: ''},50 ]);51 }52 53 itSub('Sets properties for a NFT collection', async ({helper}) => {54 await testSetsPropertiesForCollection(await helper.nft.mintCollection(alice));55 });46 });56 4748 itSub('Sets properties for a collection', async ({helper}) => {49 const collection = await helper[testSuite.mode].mintCollection(alice);5051 // As owner52 await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;53 57 itSub.ifWithPallets('Sets properties for a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {54 await collection.addAdmin(alice, {Substrate: bob.address});58 await testSetsPropertiesForCollection(await helper.rft.mintCollection(alice));55 56 // As administrator57 await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled;58 59 const properties = await collection.getProperties();60 expect(properties).to.include.deep.members([61 {key: 'electron', value: 'come bond'},62 {key: 'black_hole', value: ''},63 ]);59 });64 });60 65 61 async function testCheckValidNames(collection: UniqueBaseCollection) {66 itSub('Check valid names for collection properties keys', async ({helper}) => {67 const collection = await helper[testSuite.mode].mintCollection(alice);6862 // alpha symbols69 // alpha symbols63 await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;70 await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;82 {key: '-', value: ''},89 {key: '-', value: ''},83 {key: 'once.in.a.long.long.while...', value: 'you get a little lost'},90 {key: 'once.in.a.long.long.while...', value: 'you get a little lost'},84 ]);91 ]);85 }92 });86 93 87 itSub('Check valid names for NFT collection properties keys', async ({helper}) => {88 await testCheckValidNames(await helper.nft.mintCollection(alice));89 });90 91 itSub.ifWithPallets('Check valid names for ReFungible collection properties keys', [Pallets.ReFungible], async ({helper}) => {92 await testCheckValidNames(await helper.rft.mintCollection(alice));93 });94 95 async function testChangesProperties(collection: UniqueBaseCollection) {94 itSub('Changes properties of a collection', async ({helper}) => {95 const collection = await helper[testSuite.mode].mintCollection(alice);9696 await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;97 await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;97 98 103 {key: 'electron', value: 'come bond'},104 {key: 'electron', value: 'come bond'},104 {key: 'black_hole', value: 'LIGO'},105 {key: 'black_hole', value: 'LIGO'},105 ]);106 ]);106 }107 });107 108 108 itSub('Changes properties of a NFT collection', async ({helper}) => {109 await testChangesProperties(await helper.nft.mintCollection(alice));110 });111 112 itSub.ifWithPallets('Changes properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {113 await testChangesProperties(await helper.rft.mintCollection(alice));114 });115 116 async function testDeleteProperties(collection: UniqueBaseCollection) {109 itSub('Deletes properties of a collection', async ({helper}) => {110 const collection = await helper[testSuite.mode].mintCollection(alice);111117 await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;112 await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;118 113 122 expect(properties).to.be.deep.equal([117 expect(properties).to.be.deep.equal([123 {key: 'black_hole', value: 'LIGO'},118 {key: 'black_hole', value: 'LIGO'},124 ]);119 ]);125 }120 });126 121127 itSub('Deletes properties of a NFT collection', async ({helper}) => {128 await testDeleteProperties(await helper.nft.mintCollection(alice));129 });130 131 itSub.ifWithPallets('Deletes properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {132 await testDeleteProperties(await helper.rft.mintCollection(alice));133 });134135 [136 // TODO enable properties for FT collection in Substrate (release 040)137 // {mode: 'ft' as const, requiredPallets: []},138 {mode: 'nft' as const, requiredPallets: []},139 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, 140 ].map(testCase =>141 itSub.ifWithPallets(`Allows modifying a collection property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {122 itSub('Allows modifying a collection property multiple times with the same size', async({helper}) => {142 const propKey = 'tok-prop';123 const propKey = 'tok-prop';143124144 const collection = await helper[testCase.mode].mintCollection(alice);125 const collection = await helper[testSuite.mode].mintCollection(alice);145126146 const maxCollectionPropertiesSize = 40960;127 const maxCollectionPropertiesSize = 40960;147128166 const consumedSpace = await collection.getPropertiesConsumedSpace();147 const consumedSpace = await collection.getPropertiesConsumedSpace();167 expect(consumedSpace).to.be.equal(originalSpace);148 expect(consumedSpace).to.be.equal(originalSpace);168 }149 }169 }));150 });170151171 [172 // TODO enable properties for FT collection in Substrate (release 040)173 // {mode: 'ft' as const, requiredPallets: []},174 {mode: 'nft' as const, requiredPallets: []},175 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, 176 ].map(testCase =>177 itSub.ifWithPallets(`Adding then removing a collection property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {152 itSub('Adding then removing a collection property doesn\'t change the consumed space', async({helper}) => {178 const propKey = 'tok-prop';153 const propKey = 'tok-prop';179154180 const collection = await helper[testCase.mode].mintCollection(alice);155 const collection = await helper[testSuite.mode].mintCollection(alice);181 const originalSpace = await collection.getPropertiesConsumedSpace();156 const originalSpace = await collection.getPropertiesConsumedSpace();182157183 const propDataSize = 4096;158 const propDataSize = 4096;190 await collection.deleteProperties(alice, [propKey]);165 await collection.deleteProperties(alice, [propKey]);191 consumedSpace = await collection.getPropertiesConsumedSpace();166 consumedSpace = await collection.getPropertiesConsumedSpace();192 expect(consumedSpace).to.be.equal(originalSpace);167 expect(consumedSpace).to.be.equal(originalSpace);193 }));168 });194169195 [196 // TODO enable properties for FT collection in Substrate (release 040)197 // {mode: 'ft' as const, requiredPallets: []},198 {mode: 'nft' as const, requiredPallets: []},199 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, 200 ].map(testCase =>201 itSub.ifWithPallets(`Modifying a collection property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {170 itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {202 const propKey = 'tok-prop';171 const propKey = 'tok-prop';203172204 const collection = await helper[testCase.mode].mintCollection(alice);173 const collection = await helper[testSuite.mode].mintCollection(alice);205 const originalSpace = await collection.getPropertiesConsumedSpace();174 const originalSpace = await collection.getPropertiesConsumedSpace();206175207 const initPropDataSize = 4096;176 const initPropDataSize = 4096;229 consumedSpace = await collection.getPropertiesConsumedSpace();198 consumedSpace = await collection.getPropertiesConsumedSpace();230 expectedConsumedSpaceDiff = biggerPropDataSize - smallerPropDataSize;199 expectedConsumedSpaceDiff = biggerPropDataSize - smallerPropDataSize;231 expect(consumedSpace).to.be.equal(biggerPropDataSize - expectedConsumedSpaceDiff);200 expect(consumedSpace).to.be.equal(biggerPropDataSize - expectedConsumedSpaceDiff);232 }));201 });202 }));233});203});234 204 235describe('Negative Integration Test: Collection Properties', () => {205describe('Negative Integration Test: Collection Properties', () => {243 });213 });244 });214 });245 215246 async function testFailsSetPropertiesIfNotOwnerOrAdmin(collection: UniqueBaseCollection) { 216 [247 await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))217 {mode: 'nft' as const, requiredPallets: []},248 .to.be.rejectedWith(/common\.NoPermission/);218 {mode: 'ft' as const, requiredPallets: []},249 219 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, 250 expect(await collection.getProperties()).to.be.empty;220 ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {251 }221 before(async function() {252 222 // eslint-disable-next-line require-await253 itSub('Fails to set properties in a NFT collection if not its onwer/administrator', async ({helper}) => {223 await usingPlaygrounds(async helper => {254 await testFailsSetPropertiesIfNotOwnerOrAdmin(await helper.nft.mintCollection(alice));224 requirePalletsOrSkip(this, helper, testSuite.requiredPallets);225 });255 });226 });256 227 228 itSub('Fails to set properties in a collection if not its onwer/administrator', async ({helper}) => {257 itSub.ifWithPallets('Fails to set properties in a ReFungible collection if not its onwer/administrator', [Pallets.ReFungible], async ({helper}) => {229 const collection = await helper[testSuite.mode].mintCollection(alice);258 await testFailsSetPropertiesIfNotOwnerOrAdmin(await helper.rft.mintCollection(alice));230231 await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))232 .to.be.rejectedWith(/common\.NoPermission/);233 259 });234 expect(await collection.getProperties()).to.be.empty;260 235 });236 261 async function testFailsSetPropertiesThatExeedLimits(collection: UniqueBaseCollection) {237 itSub('Fails to set properties that exceed the limits', async ({helper}) => {238 const collection = await helper[testSuite.mode].mintCollection(alice);239262 const spaceLimit = (await (collection.helper!.api! as any).query.common.collectionProperties(collection.collectionId)).spaceLimit.toNumber();240 const spaceLimit = (await (collection.helper!.api! as any).query.common.collectionProperties(collection.collectionId)).spaceLimit.toNumber();263 241 277 ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);255 ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);278 256 279 expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty;257 expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty;280 }258 });281 259 282 itSub('Fails to set properties that exceed the limits (NFT)', async ({helper}) => {283 await testFailsSetPropertiesThatExeedLimits(await helper.nft.mintCollection(alice));284 });285 286 itSub.ifWithPallets('Fails to set properties that exceed the limits (ReFungible)', [Pallets.ReFungible], async ({helper}) => {287 await testFailsSetPropertiesThatExeedLimits(await helper.rft.mintCollection(alice));288 });289 290 async function testFailsSetMorePropertiesThanAllowed(collection: UniqueBaseCollection) {260 itSub('Fails to set more properties than it is allowed', async ({helper}) => {261 const collection = await helper[testSuite.mode].mintCollection(alice);262291 const propertiesToBeSet = [];263 const propertiesToBeSet = [];292 for (let i = 0; i < 65; i++) {264 for (let i = 0; i < 65; i++) {300 to.be.rejectedWith(/common\.PropertyLimitReached/);272 to.be.rejectedWith(/common\.PropertyLimitReached/);301 273 302 expect(await collection.getProperties()).to.be.empty;274 expect(await collection.getProperties()).to.be.empty;303 }275 });304 276305 itSub('Fails to set more properties than it is allowed (NFT)', async ({helper}) => {306 await testFailsSetMorePropertiesThanAllowed(await helper.nft.mintCollection(alice));307 });308 309 itSub.ifWithPallets('Fails to set more properties than it is allowed (ReFungible)', [Pallets.ReFungible], async ({helper}) => {310 await testFailsSetMorePropertiesThanAllowed(await helper.rft.mintCollection(alice));311 });312 313 async function testFailsSetPropertiesWithInvalidNames(collection: UniqueBaseCollection) {277 itSub('Fails to set properties with invalid names', async ({helper}) => {278 const collection = await helper[testSuite.mode].mintCollection(alice);279314 const invalidProperties = [280 const invalidProperties = [315 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],281 [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],347 `on trying to delete the non-existent badly-named property #${i}`,313 `on trying to delete the non-existent badly-named property #${i}`,348 ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);314 ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);349 }315 }350 }316 });351 352 itSub('Fails to set properties with invalid names (NFT)', async ({helper}) => {353 await testFailsSetPropertiesWithInvalidNames(await helper.nft.mintCollection(alice));354 });317 }));355 356 itSub.ifWithPallets('Fails to set properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => {357 await testFailsSetPropertiesWithInvalidNames(await helper.rft.mintCollection(alice));358 });359});318});360 319 tests/src/pallet-presence.test.tsdiffbeforeafterboth80 requiredPallets.push(80 requiredPallets.push(81 refungible,81 refungible,82 appPromotion,82 appPromotion,83 foreignAssets,83 );84 );84 } else if (chain.eq('UNIQUE')) {85 } else if (chain.eq('UNIQUE')) {85 // Insert Unique additional pallets here86 // Insert Unique additional pallets here