difftreelog
Merge pull request #113 from usetech-llc/feature/NFTPAR-196_sponsor_setVariableMetadata
in: master
Sponsored setVariableMetadata
19 files changed
node/src/chain_spec.rsdiffbeforeafterboth--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -180,9 +180,9 @@
.collect(),
}),
pallet_nft: Some(NftConfig {
- collection: vec![(
+ collection_id: vec![(
1,
- CollectionType {
+ Collection {
owner: get_account_id_from_seed::<sr25519::Public>("Alice"),
mode: CollectionMode::NFT,
access: AccessMode::Normal,
pallets/nft/src/default_weights.rsdiffbeforeafterboth--- a/pallets/nft/src/default_weights.rs
+++ b/pallets/nft/src/default_weights.rs
@@ -127,6 +127,11 @@
.saturating_add(DbWeight::get().reads(0 as Weight))
.saturating_add(DbWeight::get().writes(2 as Weight))
}
+ fn set_variable_meta_data_sponsoring_rate_limit() -> Weight {
+ (3_500_000 as Weight)
+ .saturating_add(DbWeight::get().reads(2 as Weight))
+ .saturating_add(DbWeight::get().writes(1 as Weight))
+ }
fn toggle_contract_white_list() -> Weight {
(3_000_000 as Weight)
.saturating_add(DbWeight::get().reads(0 as Weight))
pallets/nft/src/lib.rsdiffbeforeafterboth13#[cfg(feature = "std")]13#[cfg(feature = "std")]14pub use serde::*;14pub use serde::*;151516use core::ops::{Deref, DerefMut};16use codec::{Decode, Encode};17use codec::{Decode, Encode};17pub use frame_support::{18pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 construct_runtime, decl_event, decl_module, decl_storage, decl_error,160 }161 }161}162}162163163#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]164#[derive(Encode, Decode, Clone, PartialEq)]164#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]165#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]165pub struct CollectionType<AccountId> {166pub struct Collection<T: Config> {166 pub owner: AccountId,167 pub owner: T::AccountId,167 pub mode: CollectionMode,168 pub mode: CollectionMode,168 pub access: AccessMode,169 pub access: AccessMode,169 pub decimal_points: DecimalPoints,170 pub decimal_points: DecimalPoints,174 pub offchain_schema: Vec<u8>,175 pub offchain_schema: Vec<u8>,175 pub schema_version: SchemaVersion,176 pub schema_version: SchemaVersion,176 pub sponsorship: SponsorshipState<AccountId>,177 pub sponsorship: SponsorshipState<AccountId>,177 pub limits: CollectionLimits, // Collection private restrictions 178 pub limits: CollectionLimits<T::BlockNumber>, // Collection private restrictions 178 pub variable_on_chain_schema: Vec<u8>, //179 pub variable_on_chain_schema: Vec<u8>, //179 pub const_on_chain_schema: Vec<u8>, //180 pub const_on_chain_schema: Vec<u8>, //180}181}181182183pub struct CollectionHandle<T: Config> {184 pub id: CollectionId,185 collection: Collection<T>,186}187188impl<T: Config> Deref for CollectionHandle<T> {189 type Target = Collection<T>;190191 fn deref(&self) -> &Self::Target {192 &self.collection193 }194}195196impl<T: Config> DerefMut for CollectionHandle<T> {197 fn deref_mut(&mut self) -> &mut Self::Target {198 &mut self.collection199 }200}201182#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]202#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]183#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]203#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]184pub struct NftItemType<AccountId> {204pub struct NftItemType<AccountId> {214234215#[derive(Encode, Decode, Debug, Clone, PartialEq)]235#[derive(Encode, Decode, Debug, Clone, PartialEq)]216#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]236#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]217pub struct CollectionLimits {237pub struct CollectionLimits<BlockNumber: Encode + Decode> {218 pub account_token_ownership_limit: u32,238 pub account_token_ownership_limit: u32,219 pub sponsored_data_size: u32,239 pub sponsored_data_size: u32,240 /// None - setVariableMetadata is not sponsored241 /// Some(v) - setVariableMetadata is sponsored 242 /// if there is v block between txs243 pub sponsored_data_rate_limit: Option<BlockNumber>,220 pub token_limit: u32,244 pub token_limit: u32,221245222 // Timeouts for item types in passed blocks246 // Timeouts for item types in passed blocks225 pub owner_can_destroy: bool,249 pub owner_can_destroy: bool,226}250}227251228impl Default for CollectionLimits {252impl<BlockNumber: Encode + Decode> Default for CollectionLimits<BlockNumber> {229 fn default() -> CollectionLimits {253 fn default() -> Self {230 CollectionLimits { 254 Self { 231 account_token_ownership_limit: 10_000_000, 255 account_token_ownership_limit: 10_000_000, 232 token_limit: u32::max_value(),256 token_limit: u32::max_value(),233 sponsored_data_size: u32::MAX,257 sponsored_data_size: u32::MAX, 258 sponsored_data_rate_limit: None,234 sponsor_transfer_timeout: 14400,259 sponsor_transfer_timeout: 14400,235 owner_can_transfer: true,260 owner_can_transfer: true,236 owner_can_destroy: true261 owner_can_destroy: true283 fn set_schema_version() -> Weight;308 fn set_schema_version() -> Weight;284 fn set_chain_limits() -> Weight;309 fn set_chain_limits() -> Weight;285 fn set_contract_sponsoring_rate_limit() -> Weight;310 fn set_contract_sponsoring_rate_limit() -> Weight;311 fn set_variable_meta_data_sponsoring_rate_limit() -> Weight;286 fn toggle_contract_white_list() -> Weight;312 fn toggle_contract_white_list() -> Weight;287 fn add_to_contract_white_list() -> Weight;313 fn add_to_contract_white_list() -> Weight;288 fn remove_from_contract_white_list() -> Weight;314 fn remove_from_contract_white_list() -> Weight;496 //#region Basic collections522 //#region Basic collections497 /// Collection info523 /// Collection info498 /// Collection id (controlled?1)524 /// Collection id (controlled?1)499 pub Collection get(fn collection) config(): map hasher(blake2_128_concat) CollectionId => CollectionType<T::AccountId>;525 pub CollectionById get(fn collection_id) config(): map hasher(blake2_128_concat) CollectionId => Option<Collection<T>> = None;500 /// List of collection admins526 /// List of collection admins501 /// Collection id (controlled?2)527 /// Collection id (controlled?2)502 pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;528 pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;538 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;564 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;539 //#endregion565 //#endregion540566567 /// Variable metadata sponsoring568 /// Collection id (controlled?2), token id (controlled?2)569 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber> = None;570 541 //#region Contract Sponsorship and Ownership571 //#region Contract Sponsorship and Ownership542 /// Contract address (real)572 /// Contract address (real)543 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;573 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;556 add_extra_genesis {586 add_extra_genesis {557 build(|config: &GenesisConfig<T>| {587 build(|config: &GenesisConfig<T>| {558 // Modification of storage588 // Modification of storage559 for (_num, _c) in &config.collection {589 for (_num, _c) in &config.collection_id {560 <Module<T>>::init_collection(_c);590 <Module<T>>::init_collection(_c);561 }591 }562592710 };740 };711741712 // Create new collection742 // Create new collection713 let new_collection = CollectionType {743 let new_collection = Collection {714 owner: who.clone(),744 owner: who.clone(),715 name: collection_name,745 name: collection_name,716 mode: mode.clone(),746 mode: mode.clone(),728 };758 };729759730 // Add new collection to map760 // Add new collection to map731 <Collection<T>>::insert(next_id, new_collection);761 <CollectionById<T>>::insert(next_id, new_collection);732762733 // call event763 // call event734 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));764 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));750 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {780 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {751781752 let sender = ensure_signed(origin)?;782 let sender = ensure_signed(origin)?;753 Self::check_owner_permissions(collection_id, sender)?;783 let collection = Self::get_collection(collection_id)?;754755 let target_collection = <Collection<T>>::get(collection_id);784 Self::check_owner_permissions(&collection, sender)?;756 if !target_collection.limits.owner_can_destroy {785 if !collection.limits.owner_can_destroy {757 fail!(Error::<T>::NoPermission);786 fail!(Error::<T>::NoPermission);758 }787 }759788762 <Balance<T>>::remove_prefix(collection_id);791 <Balance<T>>::remove_prefix(collection_id);763 <ItemListIndex>::remove(collection_id);792 <ItemListIndex>::remove(collection_id);764 <AdminList<T>>::remove(collection_id);793 <AdminList<T>>::remove(collection_id);765 <Collection<T>>::remove(collection_id);794 <CollectionById<T>>::remove(collection_id);766 <WhiteList<T>>::remove_prefix(collection_id);795 <WhiteList<T>>::remove_prefix(collection_id);767796768 <NftItemList<T>>::remove_prefix(collection_id);797 <NftItemList<T>>::remove_prefix(collection_id);773 <FungibleTransferBasket<T>>::remove_prefix(collection_id);802 <FungibleTransferBasket<T>>::remove_prefix(collection_id);774 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);803 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);775804805 <VariableMetaDataBasket<T>>::remove_prefix(collection_id);806776 DestroyedCollectionCount::put(DestroyedCollectionCount::get()807 DestroyedCollectionCount::put(DestroyedCollectionCount::get()777 .checked_add(1)808 .checked_add(1)778 .ok_or(Error::<T>::NumOverflow)?);809 .ok_or(Error::<T>::NumOverflow)?);797 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{828 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{798829799 let sender = ensure_signed(origin)?;830 let sender = ensure_signed(origin)?;800 Self::check_owner_or_admin_permissions(collection_id, sender)?;831 let collection = Self::get_collection(collection_id)?;832 Self::check_owner_or_admin_permissions(&collection, sender)?;801833802 <WhiteList<T>>::insert(collection_id, address, true);834 <WhiteList<T>>::insert(collection_id, address, true);803 835 821 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{853 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{822854823 let sender = ensure_signed(origin)?;855 let sender = ensure_signed(origin)?;824 Self::check_owner_or_admin_permissions(collection_id, sender)?;856 let collection = Self::get_collection(collection_id)?;857 Self::check_owner_or_admin_permissions(&collection, sender)?;825858826 <WhiteList<T>>::remove(collection_id, address);859 <WhiteList<T>>::remove(collection_id, address);827860845 {878 {846 let sender = ensure_signed(origin)?;879 let sender = ensure_signed(origin)?;847880848 Self::check_owner_permissions(collection_id, sender)?;881 let mut target_collection = Self::get_collection(collection_id)?;849 let mut target_collection = <Collection<T>>::get(collection_id);882 Self::check_owner_permissions(&target_collection, sender)?;850 target_collection.access = mode;883 target_collection.access = mode;851 <Collection<T>>::insert(collection_id, target_collection);884 Self::save_collection(target_collection);852885853 Ok(())886 Ok(())854 }887 }872 {905 {873 let sender = ensure_signed(origin)?;906 let sender = ensure_signed(origin)?;874907875 Self::check_owner_permissions(collection_id, sender)?;908 let mut target_collection = Self::get_collection(collection_id)?;876 let mut target_collection = <Collection<T>>::get(collection_id);909 Self::check_owner_permissions(&target_collection, sender)?;877 target_collection.mint_mode = mint_permission;910 target_collection.mint_mode = mint_permission;878 <Collection<T>>::insert(collection_id, target_collection);911 Self::save_collection(target_collection);879912880 Ok(())913 Ok(())881 }914 }896 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {929 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {897930898 let sender = ensure_signed(origin)?;931 let sender = ensure_signed(origin)?;899 Self::check_owner_permissions(collection_id, sender)?;932 let mut target_collection = Self::get_collection(collection_id)?;900 let mut target_collection = <Collection<T>>::get(collection_id);933 Self::check_owner_permissions(&target_collection, sender)?;901 target_collection.owner = new_owner;934 target_collection.owner = new_owner;902 <Collection<T>>::insert(collection_id, target_collection);935 Self::save_collection(target_collection);903936904 Ok(())937 Ok(())905 }938 }922 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {955 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {923956924 let sender = ensure_signed(origin)?;957 let sender = ensure_signed(origin)?;925 Self::check_owner_or_admin_permissions(collection_id, sender)?;958 let collection = Self::get_collection(collection_id)?;959 Self::check_owner_or_admin_permissions(&collection, sender)?;926 let mut admin_arr: Vec<T::AccountId> = Vec::new();960 let mut admin_arr: Vec<T::AccountId> = Vec::new();927961928 if <AdminList<T>>::contains_key(collection_id)962 if <AdminList<T>>::contains_key(collection_id)957 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {991 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {958992959 let sender = ensure_signed(origin)?;993 let sender = ensure_signed(origin)?;960 Self::check_owner_or_admin_permissions(collection_id, sender)?;994 let collection = Self::get_collection(collection_id)?;995 Self::check_owner_or_admin_permissions(&collection, sender)?;961 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);996 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);962997963 let mut admin_arr = <AdminList<T>>::get(collection_id);998 let mut admin_arr = <AdminList<T>>::get(collection_id);981 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {1016 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {9821017983 let sender = ensure_signed(origin)?;1018 let sender = ensure_signed(origin)?;984 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);1019 let mut target_collection = Self::get_collection(collection_id)?;1020 Self::check_owner_permissions(&target_collection, sender)?;9851021986 let mut target_collection = <Collection<T>>::get(collection_id);987 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);988989 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);1022 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);990 <Collection<T>>::insert(collection_id, target_collection);1023 Self::save_collection(target_collection);9911024992 Ok(())1025 Ok(())993 }1026 }1004 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {1037 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {100510381006 let sender = ensure_signed(origin)?;1039 let sender = ensure_signed(origin)?;1007 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);100810401009 let mut target_collection = <Collection<T>>::get(collection_id);1041 let mut target_collection = Self::get_collection(collection_id)?;1010 ensure!(1042 ensure!(1011 target_collection.sponsorship.pending_sponsor() == Some(&sender),1043 target_collection.sponsorship.pending_sponsor() == Some(&sender),1012 Error::<T>::ConfirmUnsetSponsorFail1044 Error::<T>::ConfirmUnsetSponsorFail1013 );1045 );101410461015 target_collection.sponsorship = SponsorshipState::Confirmed(sender);1047 target_collection.sponsorship = SponsorshipState::Confirmed(sender);1016 <Collection<T>>::insert(collection_id, target_collection);1048 Self::save_collection(target_collection);101710491018 Ok(())1050 Ok(())1019 }1051 }1032 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {1064 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {103310651034 let sender = ensure_signed(origin)?;1066 let sender = ensure_signed(origin)?;1035 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);103610671037 let mut target_collection = <Collection<T>>::get(collection_id);1068 let mut target_collection = Self::get_collection(collection_id)?;1038 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);1069 Self::check_owner_permissions(&target_collection, sender)?;103910701040 target_collection.sponsorship = SponsorshipState::Disabled;1071 target_collection.sponsorship = SponsorshipState::Disabled;1041 <Collection<T>>::insert(collection_id, target_collection);1072 Self::save_collection(target_collection);104210731043 Ok(())1074 Ok(())1044 }1075 }107311041074 let sender = ensure_signed(origin)?;1105 let sender = ensure_signed(origin)?;107511061076 Self::collection_exists(collection_id)?;1107 let target_collection = Self::get_collection(collection_id)?;107711081078 let target_collection = <Collection<T>>::get(collection_id);1109 Self::can_create_items_in_collection(&target_collection, &sender, &owner, 1)?;10791080 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, 1)?;1081 Self::validate_create_item_args(&target_collection, &data)?;1110 Self::validate_create_item_args(&target_collection, &data)?;1082 Self::create_item_no_validation(collection_id, owner, data)?;1111 Self::create_item_no_validation(&target_collection, owner, data)?;108311121084 Ok(())1113 Ok(())1085 }1114 }1111 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1140 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1112 let sender = ensure_signed(origin)?;1141 let sender = ensure_signed(origin)?;111311421114 Self::collection_exists(collection_id)?;1143 let target_collection = Self::get_collection(collection_id)?;1115 let target_collection = <Collection<T>>::get(collection_id);111611441117 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, items_data.len() as u32)?;1145 Self::can_create_items_in_collection(&target_collection, &sender, &owner, items_data.len() as u32)?;111811461119 for data in &items_data {1147 for data in &items_data {1120 Self::validate_create_item_args(&target_collection, data)?;1148 Self::validate_create_item_args(&target_collection, data)?;1121 }1149 }1122 for data in &items_data {1150 for data in &items_data {1123 Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;1151 Self::create_item_no_validation(&target_collection, owner.clone(), data.clone())?;1124 }1152 }112511531126 Ok(())1154 Ok(())1144 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1172 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {114511731146 let sender = ensure_signed(origin)?;1174 let sender = ensure_signed(origin)?;1147 Self::collection_exists(collection_id)?;114811751149 // Transfer permissions check1176 // Transfer permissions check1150 let target_collection = <Collection<T>>::get(collection_id);1177 let target_collection = Self::get_collection(collection_id)?;1151 ensure!(1178 ensure!(1152 Self::is_item_owner(sender.clone(), collection_id, item_id) ||1179 Self::is_item_owner(sender.clone(), &target_collection, item_id) ||1153 (1180 (1154 target_collection.limits.owner_can_transfer &&1181 target_collection.limits.owner_can_transfer &&1155 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1182 Self::is_owner_or_admin_permissions(&target_collection, sender.clone())1156 ),1183 ),1157 Error::<T>::NoPermission1184 Error::<T>::NoPermission1158 );1185 );115911861160 if target_collection.access == AccessMode::WhiteList {1187 if target_collection.access == AccessMode::WhiteList {1161 Self::check_white_list(collection_id, &sender)?;1188 Self::check_white_list(&target_collection, &sender)?;1162 }1189 }116311901164 match target_collection.mode1191 match target_collection.mode1165 {1192 {1166 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1193 CollectionMode::NFT => Self::burn_nft_item(&target_collection, item_id)?,1167 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1194 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, &target_collection, value)?,1168 CollectionMode::ReFungible => Self::burn_refungible_item(collection_id, item_id, &sender)?,1195 CollectionMode::ReFungible => Self::burn_refungible_item(&target_collection, item_id, &sender)?,1169 _ => ()1196 _ => ()1170 };1197 };117111981172 // call event1199 // call event1173 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));1200 Self::deposit_event(RawEvent::ItemDestroyed(target_collection.id, item_id));117412011175 Ok(())1202 Ok(())1176 }1203 }1202 #[transactional]1229 #[transactional]1203 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1230 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1204 let sender = ensure_signed(origin)?;1231 let sender = ensure_signed(origin)?;1205 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1232 let collection = Self::get_collection(collection_id)?;12331234 Self::transfer_internal(sender, recipient, &collection, item_id, value)1206 }1235 }120712361208 /// Set, change, or remove approved address to transfer the ownership of the NFT.1237 /// Set, change, or remove approved address to transfer the ownership of the NFT.1225 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {1254 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {122612551227 let sender = ensure_signed(origin)?;1256 let sender = ensure_signed(origin)?;1257 let target_collection = Self::get_collection(collection_id)?;122812581229 Self::collection_exists(collection_id)?;1259 Self::token_exists(&target_collection, item_id, &sender)?;1230 Self::token_exists(collection_id, item_id, &sender)?;123112601232 // Transfer permissions check1261 // Transfer permissions check1233 let target_collection = <Collection<T>>::get(collection_id);12341235 let bypasses_limits = target_collection.limits.owner_can_transfer &&1262 let bypasses_limits = target_collection.limits.owner_can_transfer &&1236 Self::is_owner_or_admin_permissions(1263 Self::is_owner_or_admin_permissions(1237 collection_id,1264 &target_collection,1238 sender.clone(),1265 sender.clone(),1239 );1266 );124012671241 let allowance_limit = if bypasses_limits {1268 let allowance_limit = if bypasses_limits {1242 None1269 None1243 } else if let Some(amount) = Self::owned_amount(1270 } else if let Some(amount) = Self::owned_amount(1244 sender.clone(),1271 sender.clone(),1245 collection_id,1272 &target_collection,1246 item_id,1273 item_id,1247 ) {1274 ) {1248 Some(amount)1275 Some(amount)1251 };1278 };125212791253 if target_collection.access == AccessMode::WhiteList {1280 if target_collection.access == AccessMode::WhiteList {1254 Self::check_white_list(collection_id, &sender)?;1281 Self::check_white_list(&target_collection, &sender)?;1255 Self::check_white_list(collection_id, &spender)?;1282 Self::check_white_list(&target_collection, &spender)?;1256 }1283 }125712841258 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1285 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1292 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {1319 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {129313201294 let sender = ensure_signed(origin)?;1321 let sender = ensure_signed(origin)?;1322 let target_collection = Self::get_collection(collection_id)?;13231295 let mut appoved_transfer = false;1324 let mut appoved_transfer = false;129613251297 // Check approval1326 // Check approval1302 appoved_transfer = true;1331 appoved_transfer = true;1303 }1332 }130413331305 let target_collection = <Collection<T>>::get(collection_id);13061307 // Limits check1334 // Limits check1308 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;1335 Self::is_correct_transfer(&target_collection, &recipient)?;130913361310 // Transfer permissions check 1337 // Transfer permissions check 1311 ensure!(1338 ensure!(1312 appoved_transfer || 1339 appoved_transfer || 1313 (1340 (1314 target_collection.limits.owner_can_transfer &&1341 target_collection.limits.owner_can_transfer &&1315 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1342 Self::is_owner_or_admin_permissions(&target_collection, sender.clone())1316 ),1343 ),1317 Error::<T>::NoPermission1344 Error::<T>::NoPermission1318 );1345 );131913461320 if target_collection.access == AccessMode::WhiteList {1347 if target_collection.access == AccessMode::WhiteList {1321 Self::check_white_list(collection_id, &sender)?;1348 Self::check_white_list(&target_collection, &sender)?;1322 Self::check_white_list(collection_id, &recipient)?;1349 Self::check_white_list(&target_collection, &recipient)?;1323 }1350 }132413511325 // Reduce approval by transferred amount or remove if remaining approval drops to 01352 // Reduce approval by transferred amount or remove if remaining approval drops to 0133213591333 match target_collection.mode1360 match target_collection.mode1334 {1361 {1335 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1362 CollectionMode::NFT => Self::transfer_nft(&target_collection, item_id, from, recipient)?,1336 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1363 CollectionMode::Fungible(_) => Self::transfer_fungible(&target_collection, value, &from, &recipient)?,1337 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1364 CollectionMode::ReFungible => Self::transfer_refungible(&target_collection, item_id, value, from.clone(), recipient)?,1338 _ => ()1365 _ => ()1339 };1366 };134013671378 ) -> DispatchResult {1405 ) -> DispatchResult {1379 let sender = ensure_signed(origin)?;1406 let sender = ensure_signed(origin)?;1380 1407 1381 Self::collection_exists(collection_id)?;1408 let target_collection = Self::get_collection(collection_id)?;1382 Self::token_exists(collection_id, item_id, &sender)?;1409 Self::token_exists(&target_collection, item_id, &sender)?;138314101384 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1411 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);138514121386 // Modify permissions check1413 // Modify permissions check1387 let target_collection = <Collection<T>>::get(collection_id);1414 ensure!(Self::is_item_owner(sender.clone(), &target_collection, item_id) ||1388 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1389 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1415 Self::is_owner_or_admin_permissions(&target_collection, sender.clone()),1390 Error::<T>::NoPermission);1416 Error::<T>::NoPermission);139114171392 match target_collection.mode1418 match target_collection.mode1393 {1419 {1394 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1420 CollectionMode::NFT => Self::set_nft_variable_data(&target_collection, item_id, data)?,1395 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1421 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(&target_collection, item_id, data)?,1396 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1422 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1397 _ => fail!(Error::<T>::UnexpectedCollectionType)1423 _ => fail!(Error::<T>::UnexpectedCollectionType)1398 };1424 };1422 version: SchemaVersion1448 version: SchemaVersion1423 ) -> DispatchResult {1449 ) -> DispatchResult {1424 let sender = ensure_signed(origin)?;1450 let sender = ensure_signed(origin)?;1425 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1451 let mut target_collection = Self::get_collection(collection_id)?;1426 let mut target_collection = <Collection<T>>::get(collection_id);1452 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;1427 target_collection.schema_version = version;1453 target_collection.schema_version = version;1428 <Collection<T>>::insert(collection_id, target_collection);1454 Self::save_collection(target_collection);142914551430 Ok(())1456 Ok(())1431 }1457 }1450 schema: Vec<u8>1476 schema: Vec<u8>1451 ) -> DispatchResult {1477 ) -> DispatchResult {1452 let sender = ensure_signed(origin)?;1478 let sender = ensure_signed(origin)?;1453 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1479 let mut target_collection = Self::get_collection(collection_id)?;1480 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;145414811455 // check schema limit1482 // check schema limit1456 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");1483 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");145714841458 let mut target_collection = <Collection<T>>::get(collection_id);1459 target_collection.offchain_schema = schema;1485 target_collection.offchain_schema = schema;1460 <Collection<T>>::insert(collection_id, target_collection);1486 Self::save_collection(target_collection);146114871462 Ok(())1488 Ok(())1463 }1489 }1482 schema: Vec<u8>1508 schema: Vec<u8>1483 ) -> DispatchResult {1509 ) -> DispatchResult {1484 let sender = ensure_signed(origin)?;1510 let sender = ensure_signed(origin)?;1485 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1511 let mut target_collection = Self::get_collection(collection_id)?;1512 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;148615131487 // check schema limit1514 // check schema limit1488 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");1515 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");148915161490 let mut target_collection = <Collection<T>>::get(collection_id);1491 target_collection.const_on_chain_schema = schema;1517 target_collection.const_on_chain_schema = schema;1492 <Collection<T>>::insert(collection_id, target_collection);1518 Self::save_collection(target_collection);149315191494 Ok(())1520 Ok(())1495 }1521 }1514 schema: Vec<u8>1540 schema: Vec<u8>1515 ) -> DispatchResult {1541 ) -> DispatchResult {1516 let sender = ensure_signed(origin)?;1542 let sender = ensure_signed(origin)?;1517 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1543 let mut target_collection = Self::get_collection(collection_id)?;1544 Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;151815451519 // check schema limit1546 // check schema limit1520 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");1547 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");152115481522 let mut target_collection = <Collection<T>>::get(collection_id);1523 target_collection.variable_on_chain_schema = schema;1549 target_collection.variable_on_chain_schema = schema;1524 <Collection<T>>::insert(collection_id, target_collection);1550 Self::save_collection(target_collection);152515511526 Ok(())1552 Ok(())1527 }1553 }1694 pub fn set_collection_limits(1720 pub fn set_collection_limits(1695 origin,1721 origin,1696 collection_id: u32,1722 collection_id: u32,1697 new_limits: CollectionLimits,1723 new_limits: CollectionLimits<T::BlockNumber>,1698 ) -> DispatchResult {1724 ) -> DispatchResult {1699 let sender = ensure_signed(origin)?;1725 let sender = ensure_signed(origin)?;1700 Self::check_owner_permissions(collection_id, sender.clone())?;1726 let mut target_collection = Self::get_collection(collection_id)?;1701 let mut target_collection = <Collection<T>>::get(collection_id);1727 Self::check_owner_permissions(&target_collection, sender.clone())?;1702 let old_limits = target_collection.limits;1728 let old_limits = &target_collection.limits;1703 let chain_limits = ChainLimit::get();1729 let chain_limits = ChainLimit::get();170417301705 // collection bounds1731 // collection bounds1719 );1745 );172017461721 target_collection.limits = new_limits;1747 target_collection.limits = new_limits;1722 <Collection<T>>::insert(collection_id, target_collection);1748 Self::save_collection(target_collection);172317491724 Ok(())1750 Ok(())1725 } 1751 } 172817541729impl<T: Config> Module<T> {1755impl<T: Config> Module<T> {173017561731 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1757 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId, value: u128) -> DispatchResult {17321733 let target_collection = <Collection<T>>::get(collection_id);17341735 // Limits check1758 // Limits check1736 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;1759 Self::is_correct_transfer(target_collection, &recipient)?;173717601738 // Transfer permissions check1761 // Transfer permissions check1739 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1762 ensure!(Self::is_item_owner(sender.clone(), target_collection, item_id) ||1740 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1763 Self::is_owner_or_admin_permissions(target_collection, sender.clone()),1741 Error::<T>::NoPermission);1764 Error::<T>::NoPermission);174217651743 if target_collection.access == AccessMode::WhiteList {1766 if target_collection.access == AccessMode::WhiteList {1744 Self::check_white_list(collection_id, &sender)?;1767 Self::check_white_list(target_collection, &sender)?;1745 Self::check_white_list(collection_id, &recipient)?;1768 Self::check_white_list(target_collection, &recipient)?;1746 }1769 }174717701748 match target_collection.mode1771 match target_collection.mode1749 {1772 {1750 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,1773 CollectionMode::NFT => Self::transfer_nft(target_collection, item_id, sender.clone(), recipient.clone())?,1751 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1774 CollectionMode::Fungible(_) => Self::transfer_fungible(target_collection, value, &sender, &recipient)?,1752 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,1775 CollectionMode::ReFungible => Self::transfer_refungible(target_collection, item_id, value, sender.clone(), recipient.clone())?,1753 _ => ()1776 _ => ()1754 };1777 };175517781756 Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));1779 Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, sender, recipient, value));175717801758 Ok(())1781 Ok(())1759 }1782 }17601783176117841762 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {1785 fn is_correct_transfer(collection: &CollectionHandle<T>, recipient: &T::AccountId) -> DispatchResult {1786 let collection_id = collection.id;176317871764 // check token limit and account token limit1788 // check token limit and account token limit1765 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1789 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1768 Ok(())1792 Ok(())1769 }1793 }177017941771 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult {1795 fn can_create_items_in_collection(collection: &CollectionHandle<T>, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult {1796 let collection_id = collection.id;177217971773 // check token limit and account token limit1798 // check token limit and account token limit1774 let total_items: u32 = ItemListIndex::get(collection_id)1799 let total_items: u32 = ItemListIndex::get(collection_id)1780 ensure!(collection.limits.token_limit >= total_items, Error::<T>::CollectionTokenLimitExceeded);1805 ensure!(collection.limits.token_limit >= total_items, Error::<T>::CollectionTokenLimitExceeded);1781 ensure!(collection.limits.account_token_ownership_limit >= account_items, Error::<T>::AccountTokenLimitExceeded);1806 ensure!(collection.limits.account_token_ownership_limit >= account_items, Error::<T>::AccountTokenLimitExceeded);178218071783 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1808 if !Self::is_owner_or_admin_permissions(collection, sender.clone()) {1784 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1809 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1785 Self::check_white_list(collection_id, owner)?;1810 Self::check_white_list(collection, owner)?;1786 Self::check_white_list(collection_id, sender)?;1811 Self::check_white_list(collection, sender)?;1787 }1812 }178818131789 Ok(())1814 Ok(())1790 }1815 }179118161792 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1817 fn validate_create_item_args(target_collection: &CollectionHandle<T>, data: &CreateItemData) -> DispatchResult {1793 match target_collection.mode1818 match target_collection.mode1794 {1819 {1795 CollectionMode::NFT => {1820 CollectionMode::NFT => {1827 Ok(())1852 Ok(())1828 }1853 }182918541830 fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1855 fn create_item_no_validation(collection: &CollectionHandle<T>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1856 let collection_id = collection.id;18571831 match data1858 match data1832 {1859 {1837 variable_data: data.variable_data1864 variable_data: data.variable_data1838 };1865 };183918661840 Self::add_nft_item(collection_id, item)?;1867 Self::add_nft_item(collection, item)?;1841 },1868 },1842 CreateItemData::Fungible(data) => {1869 CreateItemData::Fungible(data) => {1843 Self::add_fungible_item(collection_id, &owner, data.value)?;1870 Self::add_fungible_item(collection, &owner, data.value)?;1844 },1871 },1845 CreateItemData::ReFungible(data) => {1872 CreateItemData::ReFungible(data) => {1846 let mut owner_list = Vec::new();1873 let mut owner_list = Vec::new();1852 variable_data: data.variable_data1879 variable_data: data.variable_data1853 };1880 };185418811855 Self::add_refungible_item(collection_id, item)?;1882 Self::add_refungible_item(collection, item)?;1856 }1883 }1857 };1884 };185818851859 Ok(())1886 Ok(())1860 }1887 }186118881862 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {1889 fn add_fungible_item(collection: &CollectionHandle<T>, owner: &T::AccountId, value: u128) -> DispatchResult {1890 let collection_id = collection.id;186318911864 // Does new owner already have an account?1892 // Does new owner already have an account?1865 let mut balance: u128 = 0;1893 let mut balance: u128 = 0;1883 Ok(())1911 Ok(())1884 }1912 }188519131886 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1914 fn add_refungible_item(collection: &CollectionHandle<T>, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1915 let collection_id = collection.id;19161887 let current_index = <ItemListIndex>::get(collection_id)1917 let current_index = <ItemListIndex>::get(collection_id)1888 .checked_add(1)1918 .checked_add(1)1913 Ok(())1943 Ok(())1914 }1944 }191519451916 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1946 fn add_nft_item(collection: &CollectionHandle<T>, item: NftItemType<T::AccountId>) -> DispatchResult {1947 let collection_id = collection.id;19481917 let current_index = <ItemListIndex>::get(collection_id)1949 let current_index = <ItemListIndex>::get(collection_id)1918 .checked_add(1)1950 .checked_add(1)1935 }1967 }193619681937 fn burn_refungible_item(1969 fn burn_refungible_item(1938 collection_id: CollectionId,1970 collection: &CollectionHandle<T>,1939 item_id: TokenId,1971 item_id: TokenId,1940 owner: &T::AccountId,1972 owner: &T::AccountId,1941 ) -> DispatchResult {1973 ) -> DispatchResult {1974 let collection_id = collection.id;19751942 ensure!(1976 ensure!(1943 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1977 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1944 Error::<T>::TokenNotFound1978 Error::<T>::TokenNotFound1969 // Burn the token completely if this was the last (only) owner2003 // Burn the token completely if this was the last (only) owner1970 if owner_count == 0 {2004 if owner_count == 0 {1971 <ReFungibleItemList<T>>::remove(collection_id, item_id);2005 <ReFungibleItemList<T>>::remove(collection_id, item_id);2006 <VariableMetaDataBasket<T>>::remove(collection_id, item_id);1972 }2007 }1973 else {2008 else {1974 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);2009 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1977 Ok(())2012 Ok(())1978 }2013 }197920141980 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {2015 fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {2016 let collection_id = collection.id;20171981 ensure!(2018 ensure!(1982 <NftItemList<T>>::contains_key(collection_id, item_id),2019 <NftItemList<T>>::contains_key(collection_id, item_id),1991 .ok_or(Error::<T>::NumOverflow)?;2028 .ok_or(Error::<T>::NumOverflow)?;1992 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);2029 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1993 <NftItemList<T>>::remove(collection_id, item_id);2030 <NftItemList<T>>::remove(collection_id, item_id);2031 <VariableMetaDataBasket<T>>::remove(collection_id, item_id);199420321995 Ok(())2033 Ok(())1996 }2034 }199720351998 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {2036 fn burn_fungible_item(owner: &T::AccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {2037 let collection_id = collection.id;20381999 ensure!(2039 ensure!(2000 <FungibleItemList<T>>::contains_key(collection_id, owner),2040 <FungibleItemList<T>>::contains_key(collection_id, owner),2020 Ok(())2060 Ok(())2021 }2061 }202220622023 fn collection_exists(collection_id: CollectionId) -> DispatchResult {2063 pub fn get_collection(collection_id: CollectionId) -> Result<CollectionHandle<T>, sp_runtime::DispatchError> {2024 ensure!(2064 Ok(<CollectionById<T>>::get(collection_id)2025 <Collection<T>>::contains_key(collection_id),2065 .map(|collection| CollectionHandle {2066 id: collection_id,2026 Error::<T>::CollectionNotFound2067 collection2027 );2068 })2028 Ok(())2069 .ok_or(Error::<T>::CollectionNotFound)?)2029 }2070 }203020712031 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {2072 fn save_collection(collection: CollectionHandle<T>) {2032 Self::collection_exists(collection_id)?;2073 <CollectionById<T>>::insert(collection.id, collection.collection);2074 }203320752034 let target_collection = <Collection<T>>::get(collection_id);2076 fn check_owner_permissions(target_collection: &CollectionHandle<T>, subject: T::AccountId) -> DispatchResult {2035 ensure!(2077 ensure!(2036 subject == target_collection.owner,2078 subject == target_collection.owner,2037 Error::<T>::NoPermission2079 Error::<T>::NoPermission2040 Ok(())2082 Ok(())2041 }2083 }204220842043 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {2085 fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: T::AccountId) -> bool {2044 let target_collection = <Collection<T>>::get(collection_id);2086 let mut result: bool = subject == collection.owner;2045 let mut result: bool = subject == target_collection.owner;2046 let exists = <AdminList<T>>::contains_key(collection_id);2087 let exists = <AdminList<T>>::contains_key(collection.id);204720882048 if !result & exists {2089 if !result & exists {2049 if <AdminList<T>>::get(collection_id).contains(&subject) {2090 if <AdminList<T>>::get(collection.id).contains(&subject) {2050 result = true2091 result = true2051 }2092 }2052 }2093 }2055 }2096 }205620972057 fn check_owner_or_admin_permissions(2098 fn check_owner_or_admin_permissions(2058 collection_id: CollectionId,2099 collection: &CollectionHandle<T>,2059 subject: T::AccountId,2100 subject: T::AccountId,2060 ) -> DispatchResult {2101 ) -> DispatchResult {2061 Self::collection_exists(collection_id)?;2102 let result = Self::is_owner_or_admin_permissions(collection, subject.clone());2062 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());206321032064 ensure!(2104 ensure!(2065 result,2105 result,207021102071 fn owned_amount(2111 fn owned_amount(2072 subject: T::AccountId,2112 subject: T::AccountId,2073 collection_id: CollectionId,2113 target_collection: &CollectionHandle<T>,2074 item_id: TokenId,2114 item_id: TokenId,2075 ) -> Option<u128> {2115 ) -> Option<u128> {2076 let target_collection = <Collection<T>>::get(collection_id);2116 let collection_id = target_collection.id;207721172078 match target_collection.mode {2118 match target_collection.mode {2079 CollectionMode::NFT => {2119 CollectionMode::NFT => {2098 }2138 }2099 }2139 }210021402101 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {2141 fn is_item_owner(subject: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {2102 let target_collection = <Collection<T>>::get(collection_id);2142 let collection_id = target_collection.id;210321432104 match target_collection.mode {2144 match target_collection.mode {2105 CollectionMode::NFT => {2145 CollectionMode::NFT => {2118 }2158 }2119 }2159 }212021602121 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {2161 fn check_white_list(collection: &CollectionHandle<T>, address: &T::AccountId) -> DispatchResult {2162 let collection_id = collection.id;21632122 let mes = Error::<T>::AddresNotInWhiteList;2164 let mes = Error::<T>::AddresNotInWhiteList;2123 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);2165 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);2128 /// Check if token exists. In case of Fungible, check if there is an entry for 2170 /// Check if token exists. In case of Fungible, check if there is an entry for 2129 /// the owner in fungible balances double map2171 /// the owner in fungible balances double map2130 fn token_exists(2172 fn token_exists(2131 collection_id: CollectionId,2173 target_collection: &CollectionHandle<T>,2132 item_id: TokenId,2174 item_id: TokenId,2133 owner: &T::AccountId2175 owner: &T::AccountId2134 ) -> DispatchResult {2176 ) -> DispatchResult {2135 let target_collection = <Collection<T>>::get(collection_id);2177 let collection_id = target_collection.id;2136 let exists = match target_collection.mode2178 let exists = match target_collection.mode2137 {2179 {2138 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2180 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2146 }2188 }214721892148 fn transfer_fungible(2190 fn transfer_fungible(2149 collection_id: CollectionId,2191 collection: &CollectionHandle<T>,2150 value: u128,2192 value: u128,2151 owner: &T::AccountId,2193 owner: &T::AccountId,2152 recipient: &T::AccountId,2194 recipient: &T::AccountId,2153 ) -> DispatchResult {2195 ) -> DispatchResult {2154 Self::token_exists(collection_id, 0, owner)?;2196 let collection_id = collection.id;2197 Self::token_exists(&collection, 0, owner)?;215521982156 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2199 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2157 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);2200 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);215822012159 // Send balance to recipient (updates balanceOf of recipient)2202 // Send balance to recipient (updates balanceOf of recipient)2160 Self::add_fungible_item(collection_id, recipient, value)?;2203 Self::add_fungible_item(collection, recipient, value)?;216122042162 // update balanceOf of sender2205 // update balanceOf of sender2163 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);2206 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);2175 }2218 }217622192177 fn transfer_refungible(2220 fn transfer_refungible(2178 collection_id: CollectionId,2221 collection: &CollectionHandle<T>,2179 item_id: TokenId,2222 item_id: TokenId,2180 value: u128,2223 value: u128,2181 owner: T::AccountId,2224 owner: T::AccountId,2182 new_owner: T::AccountId,2225 new_owner: T::AccountId,2183 ) -> DispatchResult {2226 ) -> DispatchResult {2184 Self::token_exists(collection_id, item_id, &owner)?;2227 let collection_id = collection.id;2228 Self::token_exists(collection, item_id, &owner)?;218522292186 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2230 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2187 let item = full_item2231 let item = full_item2257 }2301 }225823022259 fn transfer_nft(2303 fn transfer_nft(2260 collection_id: CollectionId,2304 collection: &CollectionHandle<T>,2261 item_id: TokenId,2305 item_id: TokenId,2262 sender: T::AccountId,2306 sender: T::AccountId,2263 new_owner: T::AccountId,2307 new_owner: T::AccountId,2264 ) -> DispatchResult {2308 ) -> DispatchResult {2265 Self::token_exists(collection_id, item_id, &sender)?;2309 let collection_id = collection.id;2310 Self::token_exists(&collection, item_id, &sender)?;226623112267 let mut item = <NftItemList<T>>::get(collection_id, item_id);2312 let mut item = <NftItemList<T>>::get(collection_id, item_id);226823132294 }2339 }2295 2340 2296 fn set_re_fungible_variable_data(2341 fn set_re_fungible_variable_data(2297 collection_id: CollectionId,2342 collection: &CollectionHandle<T>,2298 item_id: TokenId,2343 item_id: TokenId,2299 data: Vec<u8>2344 data: Vec<u8>2300 ) -> DispatchResult {2345 ) -> DispatchResult {2346 let collection_id = collection.id;2301 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);2347 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);230223482303 item.variable_data = data;2349 item.variable_data = data;2308 }2354 }230923552310 fn set_nft_variable_data(2356 fn set_nft_variable_data(2311 collection_id: CollectionId,2357 collection: &CollectionHandle<T>,2312 item_id: TokenId,2358 item_id: TokenId,2313 data: Vec<u8>2359 data: Vec<u8>2314 ) -> DispatchResult {2360 ) -> DispatchResult {2361 let collection_id = collection.id;2315 let mut item = <NftItemList<T>>::get(collection_id, item_id);2362 let mut item = <NftItemList<T>>::get(collection_id, item_id);2316 2363 2317 item.variable_data = data;2364 item.variable_data = data;2321 Ok(())2368 Ok(())2322 }2369 }232323702324 fn init_collection(item: &CollectionType<T::AccountId>) {2371 fn init_collection(item: &Collection<T>) {2325 // check params2372 // check params2326 assert!(2373 assert!(2327 item.decimal_points <= MAX_DECIMAL_POINTS,2374 item.decimal_points <= MAX_DECIMAL_POINTS,2401 }2448 }240224492403 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {2450 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {24042405 // add to account limit2451 // add to account limit2406 if <AccountItemCount<T>>::contains_key(owner) {2452 if <AccountItemCount<T>>::contains_key(owner) {24072453256926152570 // Determine who is paying transaction fee based on ecnomic model2616 // Determine who is paying transaction fee based on ecnomic model2571 // Parse call to extract collection ID and access collection sponsor2617 // Parse call to extract collection ID and access collection sponsor2572 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2618 let mut sponsor: Option<T::AccountId> = (|| match IsSubType::<Call<T>>::is_sub_type(call) {2573 Some(Call::create_item(collection_id, _owner, _properties)) => {2619 Some(Call::create_item(collection_id, _owner, _properties)) => {2620 let collection = <CollectionById<T>>::get(collection_id)?;257426212575 // sponsor timeout2622 // sponsor timeout2576 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2623 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2583 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2630 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2584 let limit_time = last_tx_block + limit.into();2631 let limit_time = last_tx_block + limit.into();2585 if block_number <= limit_time {2632 if block_number <= limit_time {2586 sponsored = false;2633 return None;2587 }2634 }2588 }2635 }2589 if sponsored {2636 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2590 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2591 }259226372593 // check free create limit2638 // check free create limit2594 if (collection.limits.sponsored_data_size >= (_properties.len() as u32)) &&2639 if (collection.limits.sponsored_data_size >= (_properties.len() as u32)) &&2595 (sponsored)2640 (sponsored)2596 {2641 {2597 collection.sponsorship.sponsor()2642 collection.sponsorship.sponsor()2598 .cloned()2643 .cloned()2599 .unwrap_or_default()2600 } else {2644 } else {2601 T::AccountId::default()2645 None2602 }2646 }2603 }2647 }2604 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2648 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2649 let collection = <CollectionById<T>>::get(collection_id)?;2605 2650 2606 let mut sponsor_transfer = false;2651 let mut sponsor_transfer = false;2607 if <Collection<T>>::get(collection_id).sponsorship.confirmed() {2652 if collection.sponsorship.confirmed() {260826532609 let collection_limits = <Collection<T>>::get(collection_id).limits;2654 let collection_limits = collection.limits;2610 let collection_mode = <Collection<T>>::get(collection_id).mode;2655 let collection_mode = collection.mode;2611 2656 2612 // sponsor timeout2657 // sponsor timeout2613 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2658 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2689 }2734 }269027352691 if !sponsor_transfer {2736 if !sponsor_transfer {2692 T::AccountId::default()2737 None2693 } else {2738 } else {2694 <Collection<T>>::get(collection_id).sponsorship.sponsor()2739 collection.sponsorship.sponsor()2695 .cloned()2740 .cloned()2696 .unwrap_or_default()2697 }2741 }2698 }2742 }269927432700 _ => T::AccountId::default(),2744 Some(Call::set_variable_meta_data(collection_id, item_id, data)) => {2701 };2745 let mut sponsor_metadata_changes = false;270227462747 let collection = <CollectionById<T>>::get(collection_id)?;27482749 if2750 collection.sponsor_confirmed &&2751 // Can't sponsor fungible collection, this tx will be rejected2752 // as invalid2753 !matches!(collection.mode, CollectionMode::Fungible(_)) &&2754 data.len() <= collection.limits.sponsored_data_size as usize2755 {2756 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {2757 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;27582759 if <VariableMetaDataBasket<T>>::get(collection_id, item_id)2760 .map(|last_block| block_number - last_block > rate_limit)2761 .unwrap_or(true) 2762 {2763 sponsor_metadata_changes = true;2764 <VariableMetaDataBasket<T>>::insert(collection_id, item_id, block_number);2765 }2766 }2767 }27682769 if !sponsor_metadata_changes {2770 None2771 } else {2772 Some(collection.sponsor)2773 }2774 }27752776 _ => None,2777 })();27782779 match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {2780 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {27812782 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());27832784 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2785 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2786 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2787 2788 if !owned_contract && white_list_enabled {2789 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2790 return Err(InvalidTransaction::Call.into());2791 }2792 }2793 },2794 _ => {},2795 }27962703 // Sponsor smart contracts2797 // Sponsor smart contracts2704 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {2798 sponsor = sponsor.or_else(|| match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {270527992706 // On instantiation: set the contract owner2800 // On instantiation: set the contract owner2707 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {2801 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {2713 );2807 );2714 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());2808 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());271528092716 T::AccountId::default()2810 None2717 },2811 },271828122719 // On instantiation with code: set the contract owner2813 // On instantiation with code: set the contract owner272728212728 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());2822 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());272928232730 T::AccountId::default()2824 None2731 }2825 }273228262733 // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2827 // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2734 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {2828 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {273528292736 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());2830 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());273728312738 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2739 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2740 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2741 2742 if !owned_contract && white_list_enabled {2743 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2744 return Err(InvalidTransaction::Call.into());2745 }2746 }27472748 let mut sponsor_transfer = false;2832 let mut sponsor_transfer = false;2749 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2833 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2750 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2834 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2760 sponsor_transfer = false;2844 sponsor_transfer = false;2761 }2845 }2762 2846 2763 2764 let mut sp = T::AccountId::default();2765 if sponsor_transfer {2847 if sponsor_transfer {2766 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2848 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2767 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2849 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2768 sp = called_contract;2850 return Some(called_contract);2769 }2851 }2770 }2852 }2771 }2853 }277228542773 sp2855 None2774 },2856 },277528572776 _ => sponsor,2858 _ => None,2777 };2859 });277828602779 let mut who_pays_fee: T::AccountId = sponsor.clone();2861 let who_pays_fee = sponsor.unwrap_or_else(|| who.clone());2780 if sponsor == T::AccountId::default() {2781 who_pays_fee = who.clone();2782 }278328622784 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2863 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2785 .map(|i| (fee, i))2864 .map(|i| (fee, i))pallets/nft/src/tests.rsdiffbeforeafterboth--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -55,11 +55,11 @@
let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();
- assert_eq!(TemplateModule::collection(id).owner, owner);
- assert_eq!(TemplateModule::collection(id).name, saved_col_name);
- assert_eq!(TemplateModule::collection(id).mode, *mode);
- assert_eq!(TemplateModule::collection(id).description, saved_description);
- assert_eq!(TemplateModule::collection(id).token_prefix, saved_prefix);
+ assert_eq!(TemplateModule::collection_id(id).unwrap().owner, owner);
+ assert_eq!(TemplateModule::collection_id(id).unwrap().name, saved_col_name);
+ assert_eq!(TemplateModule::collection_id(id).unwrap().mode, *mode);
+ assert_eq!(TemplateModule::collection_id(id).unwrap().description, saved_description);
+ assert_eq!(TemplateModule::collection_id(id).unwrap().token_prefix, saved_prefix);
id
}
@@ -89,7 +89,7 @@
let collection_id = create_test_collection(&CollectionMode::NFT, 1);
assert_ok!(TemplateModule::set_schema_version(origin1, collection_id, SchemaVersion::Unique));
- assert_eq!(TemplateModule::collection(collection_id).schema_version, SchemaVersion::Unique);
+ assert_eq!(TemplateModule::collection_id(collection_id).unwrap().schema_version, SchemaVersion::Unique);
});
}
@@ -622,7 +622,7 @@
collection_id,
2
));
- assert_eq!(TemplateModule::collection(collection_id).owner, 2);
+ assert_eq!(TemplateModule::collection_id(collection_id).unwrap().owner, 2);
});
}
@@ -1841,8 +1841,8 @@
let origin1 = Origin::signed(1);
assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec()));
- assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"test const on chain schema".to_vec());
- assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"".to_vec());
+ assert_eq!(TemplateModule::collection_id(collection_id).unwrap().const_on_chain_schema, b"test const on chain schema".to_vec());
+ assert_eq!(TemplateModule::collection_id(collection_id).unwrap().variable_on_chain_schema, b"".to_vec());
});
}
@@ -1856,8 +1856,8 @@
let origin1 = Origin::signed(1);
assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec()));
- assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"".to_vec());
- assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"test variable on chain schema".to_vec());
+ assert_eq!(TemplateModule::collection_id(collection_id).unwrap().const_on_chain_schema, b"".to_vec());
+ assert_eq!(TemplateModule::collection_id(collection_id).unwrap().variable_on_chain_schema, b"test variable on chain schema".to_vec());
});
}
runtime/src/chain_extension.rsdiffbeforeafterboth--- a/runtime/src/chain_extension.rs
+++ b/runtime/src/chain_extension.rs
@@ -60,7 +60,9 @@
}
let recipient = AccountId32::from(bytes_rec);
- match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, input.collection_id, input.token_id, input.amount) {
+ let collection = pallet_nft::Module::<Runtime>::get_collection(input.collection_id)?;
+
+ match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, &collection, input.token_id, input.amount) {
Ok(_) => Ok(RetVal::Converging(func_id)),
_ => Err(DispatchError::Other("Transfer error"))
}
runtime/src/nft_weights.rsdiffbeforeafterboth--- a/runtime/src/nft_weights.rs
+++ b/runtime/src/nft_weights.rs
@@ -133,6 +133,11 @@
.saturating_add(DbWeight::get().reads(0 as Weight))
.saturating_add(DbWeight::get().writes(2 as Weight))
}
+ fn set_variable_meta_data_sponsoring_rate_limit() -> Weight {
+ (3_500_000 as Weight)
+ .saturating_add(DbWeight::get().reads(1 as Weight))
+ .saturating_add(DbWeight::get().writes(2 as Weight))
+ }
fn toggle_contract_white_list() -> Weight {
(3_000_000 as Weight)
.saturating_add(DbWeight::get().reads(0 as Weight))
runtime_types.jsondiffbeforeafterboth--- a/runtime_types.json
+++ b/runtime_types.json
@@ -38,7 +38,7 @@
"Confirmed": "AccountId"
}
},
- "CollectionType": {
+ "Collection": {
"Owner": "AccountId",
"Mode": "CollectionMode",
"Access": "AccessMode",
@@ -99,7 +99,8 @@
},
"CollectionLimits": {
"AccountTokenOwnershipLimit": "u32",
- "SponsoredMintSize": "u32",
+ "SponsoredDataSize": "u32",
+ "SponsoredDataRateLimit": "Option<BlockNumber>",
"TokenLimit": "u32",
"SponsorTimeout": "u32",
"OwnerCanTransfer": "bool",
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -46,7 +46,8 @@
"testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",
"testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",
"testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",
- "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts"
+ "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
+ "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts"
},
"author": "",
"license": "SEE LICENSE IN ../LICENSE",
tests/src/addCollectionAdmin.test.tsdiffbeforeafterboth--- a/tests/src/addCollectionAdmin.test.ts
+++ b/tests/src/addCollectionAdmin.test.ts
@@ -1,135 +1,135 @@
-//
-// This file is subject to the terms and conditions defined in
-// file 'LICENSE', which is part of this source code package.
-//
-
-import { ApiPromise } from '@polkadot/api';
-import BN from 'bn.js';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import privateKey from './substrate/privateKey';
-import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
-import {createCollectionExpectSuccess, destroyCollectionExpectSuccess} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
- it('Add collection admin.', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const alice = privateKey('//Alice');
- const bob = privateKey('//Bob');
-
- const collection: any = (await api.query.nft.collection(collectionId));
- expect(collection.Owner.toString()).to.be.eq(alice.address);
-
- const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
- await submitTransactionAsync(alice, changeAdminTx);
-
- const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
- expect(adminListAfterAddAdmin).to.be.contains(bob.address);
- });
- });
-
- it('Add admin using added collection admin.', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const Alice = privateKey('//Alice');
- const Bob = privateKey('//Bob');
- const Charlie = privateKey('//CHARLIE');
-
- const collection: any = (await api.query.nft.collection(collectionId));
- expect(collection.Owner.toString()).to.be.eq(Alice.address);
-
- const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
- await submitTransactionAsync(Alice, changeAdminTx);
-
- const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
- expect(adminListAfterAddAdmin).to.be.contains(Bob.address);
-
- const changeAdminTxCharlie = api.tx.nft.addCollectionAdmin(collectionId, Charlie.address);
- await submitTransactionAsync(Bob, changeAdminTxCharlie);
- const adminListAfterAddNewAdmin: any = (await api.query.nft.adminList(collectionId));
- expect(adminListAfterAddNewAdmin).to.be.contains(Bob.address);
- expect(adminListAfterAddNewAdmin).to.be.contains(Charlie.address);
- });
- });
-});
-
-describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
- it("Not owner can't add collection admin.", async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const alice = privateKey('//Alice');
- const nonOwner = privateKey('//Bob_stash');
-
- const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, alice.address);
- await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected;
-
- const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
- expect(adminListAfterAddAdmin).not.to.be.contains(alice.address);
-
- // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
- await createCollectionExpectSuccess();
- });
- });
- it("Can't add collection admin of not existing collection.", async () => {
- await usingApi(async (api) => {
- // tslint:disable-next-line: no-bitwise
- const collectionId = (1 << 32) - 1;
- const alice = privateKey('//Alice');
- const bob = privateKey('//Bob');
-
- const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
- await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;
-
- // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
- await createCollectionExpectSuccess();
- });
- });
-
- it("Can't add an admin to a destroyed collection.", async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const Alice = privateKey('//Alice');
- const Bob = privateKey('//Bob');
- await destroyCollectionExpectSuccess(collectionId);
- const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
- await expect(submitTransactionExpectFailAsync(Alice, changeOwnerTx)).to.be.rejected;
-
- // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
- await createCollectionExpectSuccess();
- });
- });
-
- it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
- await usingApi(async (api: ApiPromise) => {
- const Alice = privateKey('//Alice');
- const accounts = [
- 'GsvVmjr1CBHwQHw84pPHMDxgNY3iBLz6Qn7qS3CH8qPhrHz',
- 'FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP',
- 'JKspFU6ohf1Grg3Phdzj2pSgWvsYWzSfKghhfzMbdhNBWs5',
- 'Fr4NzY1udSFFLzb2R3qxVQkwz9cZraWkyfH4h3mVVk7BK7P',
- 'DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK',
- 'HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam',
- 'DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM',
- ];
- const collectionId = await createCollectionExpectSuccess();
-
- const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN };
- const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber();
- expect(chainAdminLimit).to.be.equal(5);
-
- for (let i = 0; i < chainAdminLimit; i++) {
- const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]);
- await submitTransactionAsync(Alice, changeAdminTx);
- const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
- expect(adminListAfterAddAdmin).to.be.contains(accounts[i]);
- }
-
- const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]);
- await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected;
- });
- });
-});
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { ApiPromise } from '@polkadot/api';
+import BN from 'bn.js';
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import privateKey from './substrate/privateKey';
+import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
+import {createCollectionExpectSuccess, destroyCollectionExpectSuccess} from './util/helpers';
+
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
+ it('Add collection admin.', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const alice = privateKey('//Alice');
+ const bob = privateKey('//Bob');
+
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+ expect(collection.Owner.toString()).to.be.eq(alice.address);
+
+ const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
+ await submitTransactionAsync(alice, changeAdminTx);
+
+ const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+ expect(adminListAfterAddAdmin).to.be.contains(bob.address);
+ });
+ });
+
+ it('Add admin using added collection admin.', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const Alice = privateKey('//Alice');
+ const Bob = privateKey('//Bob');
+ const Charlie = privateKey('//CHARLIE');
+
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+ expect(collection.Owner.toString()).to.be.eq(Alice.address);
+
+ const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
+ await submitTransactionAsync(Alice, changeAdminTx);
+
+ const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+ expect(adminListAfterAddAdmin).to.be.contains(Bob.address);
+
+ const changeAdminTxCharlie = api.tx.nft.addCollectionAdmin(collectionId, Charlie.address);
+ await submitTransactionAsync(Bob, changeAdminTxCharlie);
+ const adminListAfterAddNewAdmin: any = (await api.query.nft.adminList(collectionId));
+ expect(adminListAfterAddNewAdmin).to.be.contains(Bob.address);
+ expect(adminListAfterAddNewAdmin).to.be.contains(Charlie.address);
+ });
+ });
+});
+
+describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
+ it("Not owner can't add collection admin.", async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const alice = privateKey('//Alice');
+ const nonOwner = privateKey('//Bob_stash');
+
+ const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, alice.address);
+ await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected;
+
+ const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+ expect(adminListAfterAddAdmin).not.to.be.contains(alice.address);
+
+ // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+ await createCollectionExpectSuccess();
+ });
+ });
+ it("Can't add collection admin of not existing collection.", async () => {
+ await usingApi(async (api) => {
+ // tslint:disable-next-line: no-bitwise
+ const collectionId = (1 << 32) - 1;
+ const alice = privateKey('//Alice');
+ const bob = privateKey('//Bob');
+
+ const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
+ await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;
+
+ // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+ await createCollectionExpectSuccess();
+ });
+ });
+
+ it("Can't add an admin to a destroyed collection.", async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const Alice = privateKey('//Alice');
+ const Bob = privateKey('//Bob');
+ await destroyCollectionExpectSuccess(collectionId);
+ const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
+ await expect(submitTransactionExpectFailAsync(Alice, changeOwnerTx)).to.be.rejected;
+
+ // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+ await createCollectionExpectSuccess();
+ });
+ });
+
+ it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const Alice = privateKey('//Alice');
+ const accounts = [
+ 'GsvVmjr1CBHwQHw84pPHMDxgNY3iBLz6Qn7qS3CH8qPhrHz',
+ 'FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP',
+ 'JKspFU6ohf1Grg3Phdzj2pSgWvsYWzSfKghhfzMbdhNBWs5',
+ 'Fr4NzY1udSFFLzb2R3qxVQkwz9cZraWkyfH4h3mVVk7BK7P',
+ 'DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK',
+ 'HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam',
+ 'DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM',
+ ];
+ const collectionId = await createCollectionExpectSuccess();
+
+ const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN };
+ const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber();
+ expect(chainAdminLimit).to.be.equal(5);
+
+ for (let i = 0; i < chainAdminLimit; i++) {
+ const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]);
+ await submitTransactionAsync(Alice, changeAdminTx);
+ const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+ expect(adminListAfterAddAdmin).to.be.contains(accounts[i]);
+ }
+
+ const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]);
+ await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected;
+ });
+ });
+});
tests/src/change-collection-owner.test.tsdiffbeforeafterboth--- a/tests/src/change-collection-owner.test.ts
+++ b/tests/src/change-collection-owner.test.ts
@@ -19,13 +19,13 @@
const alice = privateKey('//Alice');
const bob = privateKey('//Bob');
- const collection: any = (await api.query.nft.collection(collectionId));
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collection.Owner.toString()).to.be.eq(alice.address);
const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
await submitTransactionAsync(alice, changeOwnerTx);
- const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId));
+ const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(bob.address);
});
});
@@ -41,7 +41,7 @@
const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected;
- const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId));
+ const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(alice.address);
// Verifying that nothing bad happened (network is live, new collections can be created, etc.)
tests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -19,7 +19,7 @@
const collectionId = await createCollectionExpectSuccess();
const Alice = privateKey('//Alice');
const Bob = privateKey('//Bob');
- const collection: any = (await api.query.nft.collection(collectionId));
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collection.Owner.toString()).to.be.eq(Alice.address);
// first - add collection admin Bob
const addAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
tests/src/setCollectionLimits.test.tsdiffbeforeafterboth--- a/tests/src/setCollectionLimits.test.ts
+++ b/tests/src/setCollectionLimits.test.ts
@@ -61,12 +61,12 @@
// tslint:disable-next-line:no-unused-expression
expect(result.success).to.be.true;
- expect(collectionInfo.Limits.AccountTokenOwnershipLimit.toNumber()).to.be.equal(accountTokenOwnershipLimit);
- expect(collectionInfo.Limits.SponsoredMintSize.toNumber()).to.be.equal(sponsoredDataSize);
- expect(collectionInfo.Limits.TokenLimit.toNumber()).to.be.equal(tokenLimit);
- expect(collectionInfo.Limits.SponsorTimeout.toNumber()).to.be.equal(sponsorTimeout);
- expect(collectionInfo.Limits.OwnerCanTransfer.valueOf()).to.be.true;
- expect(collectionInfo.Limits.OwnerCanDestroy.valueOf()).to.be.true;
+ expect(collectionInfo.Limits.AccountTokenOwnershipLimit).to.be.equal(accountTokenOwnershipLimit);
+ expect(collectionInfo.Limits.SponsoredDataSize).to.be.equal(sponsoredDataSize);
+ expect(collectionInfo.Limits.TokenLimit).to.be.equal(tokenLimit);
+ expect(collectionInfo.Limits.SponsorTimeout).to.be.equal(sponsorTimeout);
+ expect(collectionInfo.Limits.OwnerCanTransfer).to.be.true;
+ expect(collectionInfo.Limits.OwnerCanDestroy).to.be.true;
});
});
});
tests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth--- a/tests/src/setConstOnChainSchema.test.ts
+++ b/tests/src/setConstOnChainSchema.test.ts
@@ -36,7 +36,7 @@
it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
await usingApi(async (api) => {
const collectionId = await createCollectionExpectSuccess();
- const collection: any = (await api.query.nft.collection(collectionId));
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collection.Owner.toString()).to.be.eq(Alice.address);
const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
await submitTransactionAsync(Alice, setShema);
@@ -48,7 +48,7 @@
const collectionId = await createCollectionExpectSuccess();
const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
await submitTransactionAsync(Alice, setShema);
- const collection: any = (await api.query.nft.collection(collectionId));
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collection.ConstOnChainSchema.toString()).to.be.eq(Shema);
});
@@ -86,7 +86,7 @@
it('Execute method not on behalf of the collection owner', async () => {
await usingApi(async (api) => {
const collectionId = await createCollectionExpectSuccess();
- const collection: any = (await api.query.nft.collection(collectionId));
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
expect(collection.Owner.toString()).to.be.eq(Alice.address);
const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
await expect(submitTransactionExpectFailAsync(Bob, setShema)).to.be.rejected;
tests/src/setOffchainSchema.test.tsdiffbeforeafterboth--- a/tests/src/setOffchainSchema.test.ts
+++ b/tests/src/setOffchainSchema.test.ts
@@ -36,7 +36,7 @@
await setOffchainSchemaExpectSuccess(alice, collectionId, DATA);
const collection = await queryCollectionExpectSuccess(collectionId);
- expect(Array.from(collection.OffchainSchema)).to.be.deep.equal(DATA);
+ expect(collection.OffchainSchema).to.be.equal('0x' + Buffer.from(DATA).toString('hex'));
});
});
tests/src/setVariableMetadataSponsoringRateLimit.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/setVariableMetadataSponsoringRateLimit.test.ts
@@ -0,0 +1,80 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { IKeyringPair } from '@polkadot/types/types';
+import privateKey from './substrate/privateKey';
+import usingApi from './substrate/substrate-api';
+import {
+ confirmSponsorshipExpectSuccess,
+ createCollectionExpectSuccess,
+ createItemExpectSuccess,
+ findUnusedAddress,
+ setCollectionLimitsExpectSuccess,
+ setCollectionSponsorExpectSuccess,
+ setVariableMetaDataExpectFailure,
+ setVariableMetaDataExpectSuccess,
+} from './util/helpers';
+
+describe('Integration Test setVariableMetadataSponsoringRateLimit', () => {
+ let alice: IKeyringPair;
+ let userWithNoBalance: IKeyringPair;
+
+ before(async () => {
+ await usingApi(async (api) => {
+ alice = privateKey('//Alice');
+ userWithNoBalance = await findUnusedAddress(api);
+ });
+ });
+
+ it('sponsored setVariableMetaData can be called twice with pause for free', async () => {
+ const collectionId = await createCollectionExpectSuccess();
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId);
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {
+ SponsoredDataRateLimit: 0,
+ });
+
+ const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+ await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+ await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+ });
+
+ it('sponsored setVariableMetaData can\'t be called twice without pause for free', async () => {
+ const collectionId = await createCollectionExpectSuccess();
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId);
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {
+ SponsoredDataRateLimit: 10,
+ });
+
+ const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+ await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+ await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+ });
+
+ it('sponsored setVariableMetaData can\'t be called for free with variable metadata above collection limits', async () => {
+ const collectionId = await createCollectionExpectSuccess();
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId);
+ await setCollectionLimitsExpectSuccess(alice, collectionId, {
+ SponsoredDataRateLimit: 0,
+ SponsoredDataSize: 1,
+ });
+ const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+
+ await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1]);
+ await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2]);
+ });
+
+ it.only('Default value of rate limit does not sponsor setting variable metadata', async () => {
+ const collectionId = await createCollectionExpectSuccess();
+ await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+ await confirmSponsorshipExpectSuccess(collectionId);
+
+ const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+ await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1]);
+ });
+
+});
tests/src/setVariableOnChainSchema.test.tsdiffbeforeafterboth--- a/tests/src/setVariableOnChainSchema.test.ts
+++ b/tests/src/setVariableOnChainSchema.test.ts
@@ -1,96 +1,96 @@
-//
-// This file is subject to the terms and conditions defined in
-// file 'LICENSE', which is part of this source code package.
-//
-
-import { Keyring } from '@polkadot/api';
-import { IKeyringPair } from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
-import {
- createCollectionExpectSuccess,
- destroyCollectionExpectSuccess,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-let Alice: IKeyringPair;
-let Bob: IKeyringPair;
-let Schema: any;
-let largeSchema: any;
-
-before(async () => {
- await usingApi(async (api) => {
- const keyring = new Keyring({ type: 'sr25519' });
- Alice = keyring.addFromUri('//Alice');
- Bob = keyring.addFromUri('//Bob');
- Schema = '0x31';
- largeSchema = new Array(4097).fill(0xff);
-
- });
-});
-describe('Integration Test ext. setVariableOnChainSchema()', () => {
-
- it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const collection: any = (await api.query.nft.collection(collectionId));
- expect(collection.Owner.toString()).to.be.eq(Alice.address);
- const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
- await submitTransactionAsync(Alice, setSchema);
- });
- });
-
- it('Checking collection data using the setVariableOnChainSchema parameter', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
- await submitTransactionAsync(Alice, setSchema);
- const collection: any = (await api.query.nft.collection(collectionId));
- expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema);
-
- });
- });
-});
-
-describe('Negative Integration Test ext. setVariableOnChainSchema()', () => {
-
- it('Set a non-existent collection', async () => {
- await usingApi(async (api) => {
- // tslint:disable-next-line: radix
- const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1;
- const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
- await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
- });
- });
-
- it('Set a previously deleted collection', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- await destroyCollectionExpectSuccess(collectionId);
- const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
- await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
- });
- });
-
- it('Set invalid data in schema (size too large:> 1024b)', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, largeSchema);
- await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
- });
- });
-
- it('Execute method not on behalf of the collection owner', async () => {
- await usingApi(async (api) => {
- const collectionId = await createCollectionExpectSuccess();
- const collection: any = (await api.query.nft.collection(collectionId));
- expect(collection.Owner.toString()).to.be.eq(Alice.address);
- const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
- await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected;
- });
- });
-
-});
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { Keyring } from '@polkadot/api';
+import { IKeyringPair } from '@polkadot/types/types';
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
+import {
+ createCollectionExpectSuccess,
+ destroyCollectionExpectSuccess,
+} from './util/helpers';
+
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+let Alice: IKeyringPair;
+let Bob: IKeyringPair;
+let Schema: any;
+let largeSchema: any;
+
+before(async () => {
+ await usingApi(async (api) => {
+ const keyring = new Keyring({ type: 'sr25519' });
+ Alice = keyring.addFromUri('//Alice');
+ Bob = keyring.addFromUri('//Bob');
+ Schema = '0x31';
+ largeSchema = new Array(4097).fill(0xff);
+
+ });
+});
+describe('Integration Test ext. setVariableOnChainSchema()', () => {
+
+ it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+ expect(collection.Owner.toString()).to.be.eq(Alice.address);
+ const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+ await submitTransactionAsync(Alice, setSchema);
+ });
+ });
+
+ it('Checking collection data using the setVariableOnChainSchema parameter', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+ await submitTransactionAsync(Alice, setSchema);
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+ expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema);
+
+ });
+ });
+});
+
+describe('Negative Integration Test ext. setVariableOnChainSchema()', () => {
+
+ it('Set a non-existent collection', async () => {
+ await usingApi(async (api) => {
+ // tslint:disable-next-line: radix
+ const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1;
+ const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+ await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
+ });
+ });
+
+ it('Set a previously deleted collection', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ await destroyCollectionExpectSuccess(collectionId);
+ const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+ await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
+ });
+ });
+
+ it('Set invalid data in schema (size too large:> 1024b)', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, largeSchema);
+ await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
+ });
+ });
+
+ it('Execute method not on behalf of the collection owner', async () => {
+ await usingApi(async (api) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+ expect(collection.Owner.toString()).to.be.eq(Alice.address);
+ const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+ await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected;
+ });
+ });
+
+});
tests/src/types.tsdiffbeforeafterboth--- a/tests/src/types.ts
+++ b/tests/src/types.ts
@@ -13,10 +13,11 @@
Description: [BN, BN]; // utf16
isReFungible: boolean;
Limits: {
- AccountTokenOwnershipLimit: BN;
- SponsoredMintSize: BN;
- TokenLimit: BN;
- SponsorTimeout: BN;
+ AccountTokenOwnershipLimit: number;
+ SponsoredDataSize: number;
+ SponsoredDataRateLimit?: number,
+ TokenLimit: number;
+ SponsorTimeout: number;
OwnerCanTransfer: boolean;
OwnerCanDestroy: boolean;
};
tests/src/util/contracthelpers.tsdiffbeforeafterboth--- a/tests/src/util/contracthelpers.ts
+++ b/tests/src/util/contracthelpers.ts
@@ -22,9 +22,9 @@
function deployContract(alice: IKeyringPair, code: CodePromise, constructor: string = 'default', ...args: any[]): Promise<Contract> {
return new Promise<Contract>(async (resolve, reject) => {
- const unsub = await code
+ const unsub = await (code as any)
.tx[constructor]({value: endowment, gasLimit}, ...args)
- .signAndSend(alice, (result) => {
+ .signAndSend(alice, (result: any) => {
if (result.status.isInBlock || result.status.isFinalized) {
// here we have an additional field in the result, containing the blueprint
resolve((result as any).contract);
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -212,7 +212,7 @@
const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);
// Get the collection
- const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(result.collectionId)).toJSON();
// What to expect
// tslint:disable-next-line:no-unused-expression
@@ -324,18 +324,17 @@
const result = getDestroyResult(events);
// Get the collection
- const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
// What to expect
expect(result).to.be.true;
- expect(collection).to.be.not.null;
- expect(collection.Owner).to.be.equal(nullPublicKey);
+ expect(collection).to.be.null;
});
}
export async function queryCollectionLimits(collectionId: number) {
return await usingApi(async (api) => {
- return ((await api.query.nft.collection(collectionId)).toJSON() as any).Limits;
+ return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;
});
}
@@ -373,7 +372,7 @@
const result = getGenericResult(events);
// Get the collection
- const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
// What to expect
expect(result.success).to.be.true;
@@ -393,7 +392,7 @@
const result = getGenericResult(events);
// Get the collection
- const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
// What to expect
expect(result.success).to.be.true;
@@ -431,7 +430,7 @@
const result = getGenericResult(events);
// Get the collection
- const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
// What to expect
expect(result.success).to.be.true;
@@ -839,7 +838,7 @@
const result = getGenericResult(events);
// Get the collection
- const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
// What to expect
// tslint:disable-next-line:no-unused-expression
@@ -865,7 +864,7 @@
const result = getGenericResult(events);
// Get the collection
- const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+ const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
// What to expect
// tslint:disable-next-line:no-unused-expression
@@ -947,7 +946,7 @@
export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)
: Promise<ICollectionInterface | null> => {
- return await api.query.nft.collection(collectionId) as unknown as ICollectionInterface;
+ return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;
};
export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {
@@ -957,6 +956,6 @@
export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {
return await usingApi(async (api) => {
- return (await api.query.nft.collection(collectionId)) as unknown as ICollectionInterface;
+ return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;
});
}