git.delta.rocks / unique-network / refs/commits / 23e0b8caf5e4

difftreelog

Merge pull request #113 from usetech-llc/feature/NFTPAR-196_sponsor_setVariableMetadata

Greg Zaitsev2021-03-22parents: #105eff5 #9180c84.patch.diff
in: master
Sponsored setVariableMetadata

19 files changed

modifiednode/src/chain_spec.rsdiffbeforeafterboth
180 .collect(),180 .collect(),
181 }),181 }),
182 pallet_nft: Some(NftConfig {182 pallet_nft: Some(NftConfig {
183 collection: vec![(183 collection_id: vec![(
184 1,184 1,
185 CollectionType {185 Collection {
186 owner: get_account_id_from_seed::<sr25519::Public>("Alice"),186 owner: get_account_id_from_seed::<sr25519::Public>("Alice"),
187 mode: CollectionMode::NFT,187 mode: CollectionMode::NFT,
188 access: AccessMode::Normal,188 access: AccessMode::Normal,
modifiedpallets/nft/src/default_weights.rsdiffbeforeafterboth
127 .saturating_add(DbWeight::get().reads(0 as Weight))127 .saturating_add(DbWeight::get().reads(0 as Weight))
128 .saturating_add(DbWeight::get().writes(2 as Weight))128 .saturating_add(DbWeight::get().writes(2 as Weight))
129 } 129 }
130 fn set_variable_meta_data_sponsoring_rate_limit() -> Weight {
131 (3_500_000 as Weight)
132 .saturating_add(DbWeight::get().reads(2 as Weight))
133 .saturating_add(DbWeight::get().writes(1 as Weight))
134 }
130 fn toggle_contract_white_list() -> Weight {135 fn toggle_contract_white_list() -> Weight {
131 (3_000_000 as Weight)136 (3_000_000 as Weight)
132 .saturating_add(DbWeight::get().reads(0 as Weight))137 .saturating_add(DbWeight::get().reads(0 as Weight))
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
13#[cfg(feature = "std")]13#[cfg(feature = "std")]
14pub use serde::*;14pub use serde::*;
1515
16use 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}
162163
163#[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}
181182
183pub struct CollectionHandle<T: Config> {
184 pub id: CollectionId,
185 collection: Collection<T>,
186}
187
188impl<T: Config> Deref for CollectionHandle<T> {
189 type Target = Collection<T>;
190
191 fn deref(&self) -> &Self::Target {
192 &self.collection
193 }
194}
195
196impl<T: Config> DerefMut for CollectionHandle<T> {
197 fn deref_mut(&mut self) -> &mut Self::Target {
198 &mut self.collection
199 }
200}
201
182#[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> {
214234
215#[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 sponsored
241 /// Some(v) - setVariableMetadata is sponsored
242 /// if there is v block between txs
243 pub sponsored_data_rate_limit: Option<BlockNumber>,
220 pub token_limit: u32,244 pub token_limit: u32,
221245
222 // Timeouts for item types in passed blocks246 // Timeouts for item types in passed blocks
225 pub owner_can_destroy: bool,249 pub owner_can_destroy: bool,
226}250}
227251
228impl 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: true
283 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 collections
497 /// Collection info523 /// Collection info
498 /// 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 admins
501 /// 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 //#endregion
540566
567 /// Variable metadata sponsoring
568 /// 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 Ownership
542 /// 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 storage
559 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 }
562592
710 };740 };
711741
712 // Create new collection742 // Create new collection
713 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 };
729759
730 // Add new collection to map760 // Add new collection to map
731 <Collection<T>>::insert(next_id, new_collection);761 <CollectionById<T>>::insert(next_id, new_collection);
732762
733 // call event763 // call event
734 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 {
751781
752 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)?;
754
755 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 }
759788
762 <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);
767796
768 <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);
775804
805 <VariableMetaDataBasket<T>>::remove_prefix(collection_id);
806
776 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{
798829
799 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)?;
801833
802 <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{
822854
823 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)?;
825858
826 <WhiteList<T>>::remove(collection_id, address);859 <WhiteList<T>>::remove(collection_id, address);
827860
845 {878 {
846 let sender = ensure_signed(origin)?;879 let sender = ensure_signed(origin)?;
847880
848 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);
852885
853 Ok(())886 Ok(())
854 }887 }
872 {905 {
873 let sender = ensure_signed(origin)?;906 let sender = ensure_signed(origin)?;
874907
875 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);
879912
880 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 {
897930
898 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);
903936
904 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 {
923956
924 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();
927961
928 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 {
958992
959 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);
962997
963 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 {
9821017
983 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)?;
9851021
986 let mut target_collection = <Collection<T>>::get(collection_id);
987 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);
988
989 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);
9911024
992 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 {
10051038
1006 let sender = ensure_signed(origin)?;1039 let sender = ensure_signed(origin)?;
1007 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);
10081040
1009 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>::ConfirmUnsetSponsorFail
1013 );1045 );
10141046
1015 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);
10171049
1018 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 {
10331065
1034 let sender = ensure_signed(origin)?;1066 let sender = ensure_signed(origin)?;
1035 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);
10361067
1037 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)?;
10391070
1040 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);
10421073
1043 Ok(())1074 Ok(())
1044 }1075 }
10731104
1074 let sender = ensure_signed(origin)?;1105 let sender = ensure_signed(origin)?;
10751106
1076 Self::collection_exists(collection_id)?;1107 let target_collection = Self::get_collection(collection_id)?;
10771108
1078 let target_collection = <Collection<T>>::get(collection_id);1109 Self::can_create_items_in_collection(&target_collection, &sender, &owner, 1)?;
1079
1080 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)?;
10831112
1084 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)?;
11131142
1114 Self::collection_exists(collection_id)?;1143 let target_collection = Self::get_collection(collection_id)?;
1115 let target_collection = <Collection<T>>::get(collection_id);
11161144
1117 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)?;
11181146
1119 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 }
11251153
1126 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 {
11451173
1146 let sender = ensure_signed(origin)?;1174 let sender = ensure_signed(origin)?;
1147 Self::collection_exists(collection_id)?;
11481175
1149 // Transfer permissions check1176 // Transfer permissions check
1150 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>::NoPermission
1158 );1185 );
11591186
1160 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 }
11631190
1164 match target_collection.mode1191 match target_collection.mode
1165 {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 };
11711198
1172 // call event1199 // call event
1173 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));1200 Self::deposit_event(RawEvent::ItemDestroyed(target_collection.id, item_id));
11741201
1175 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)?;
1233
1234 Self::transfer_internal(sender, recipient, &collection, item_id, value)
1206 }1235 }
12071236
1208 /// 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 {
12261255
1227 let sender = ensure_signed(origin)?;1256 let sender = ensure_signed(origin)?;
1257 let target_collection = Self::get_collection(collection_id)?;
12281258
1229 Self::collection_exists(collection_id)?;1259 Self::token_exists(&target_collection, item_id, &sender)?;
1230 Self::token_exists(collection_id, item_id, &sender)?;
12311260
1232 // Transfer permissions check1261 // Transfer permissions check
1233 let target_collection = <Collection<T>>::get(collection_id);
1234
1235 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 );
12401267
1241 let allowance_limit = if bypasses_limits {1268 let allowance_limit = if bypasses_limits {
1242 None1269 None
1243 } 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 };
12521279
1253 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 }
12571284
1258 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 {
12931320
1294 let sender = ensure_signed(origin)?;1321 let sender = ensure_signed(origin)?;
1322 let target_collection = Self::get_collection(collection_id)?;
1323
1295 let mut appoved_transfer = false;1324 let mut appoved_transfer = false;
12961325
1297 // Check approval1326 // Check approval
1302 appoved_transfer = true;1331 appoved_transfer = true;
1303 }1332 }
13041333
1305 let target_collection = <Collection<T>>::get(collection_id);
1306
1307 // Limits check1334 // Limits check
1308 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;1335 Self::is_correct_transfer(&target_collection, &recipient)?;
13091336
1310 // 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>::NoPermission
1318 );1345 );
13191346
1320 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 }
13241351
1325 // 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 0
13321359
1333 match target_collection.mode1360 match target_collection.mode
1334 {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 };
13401367
1378 ) -> 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)?;
13831410
1384 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);
13851412
1386 // Modify permissions check1413 // Modify permissions check
1387 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);
13911417
1392 match target_collection.mode1418 match target_collection.mode
1393 {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: SchemaVersion
1423 ) -> 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);
14291455
1430 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())?;
14541481
1455 // check schema limit1482 // check schema limit
1456 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");1483 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");
14571484
1458 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);
14611487
1462 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())?;
14861513
1487 // check schema limit1514 // check schema limit
1488 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, "");
14891516
1490 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);
14931519
1494 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())?;
15181545
1519 // check schema limit1546 // check schema limit
1520 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, "");
15211548
1522 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);
15251551
1526 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();
17041730
1705 // collection bounds1731 // collection bounds
1719 );1745 );
17201746
1721 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);
17231749
1724 Ok(())1750 Ok(())
1725 } 1751 }
17281754
1729impl<T: Config> Module<T> {1755impl<T: Config> Module<T> {
17301756
1731 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 {
1732
1733 let target_collection = <Collection<T>>::get(collection_id);
1734
1735 // Limits check1758 // Limits check
1736 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;1759 Self::is_correct_transfer(target_collection, &recipient)?;
17371760
1738 // Transfer permissions check1761 // Transfer permissions check
1739 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);
17421765
1743 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 }
17471770
1748 match target_collection.mode1771 match target_collection.mode
1749 {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 };
17551778
1756 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));
17571780
1758 Ok(())1781 Ok(())
1759 }1782 }
17601783
17611784
1762 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;
17631787
1764 // check token limit and account token limit1788 // check token limit and account token limit
1765 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 }
17701794
1771 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;
17721797
1773 // check token limit and account token limit1798 // check token limit and account token limit
1774 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);
17821807
1783 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 }
17881813
1789 Ok(())1814 Ok(())
1790 }1815 }
17911816
1792 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.mode
1794 {1819 {
1795 CollectionMode::NFT => {1820 CollectionMode::NFT => {
1827 Ok(())1852 Ok(())
1828 }1853 }
18291854
1830 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;
1857
1831 match data1858 match data
1832 {1859 {
1837 variable_data: data.variable_data1864 variable_data: data.variable_data
1838 };1865 };
18391866
1840 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_data
1853 };1880 };
18541881
1855 Self::add_refungible_item(collection_id, item)?;1882 Self::add_refungible_item(collection, item)?;
1856 }1883 }
1857 };1884 };
18581885
1859 Ok(())1886 Ok(())
1860 }1887 }
18611888
1862 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;
18631891
1864 // 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 }
18851913
1886 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;
1916
1887 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 }
19151945
1916 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;
1948
1917 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 }
19361968
1937 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;
1975
1942 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>::TokenNotFound
1969 // Burn the token completely if this was the last (only) owner2003 // Burn the token completely if this was the last (only) owner
1970 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 }
19792014
1980 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;
2017
1981 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);
19942032
1995 Ok(())2033 Ok(())
1996 }2034 }
19972035
1998 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;
2038
1999 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 }
20222062
2023 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 collection
2027 );2068 })
2028 Ok(())2069 .ok_or(Error::<T>::CollectionNotFound)?)
2029 }2070 }
20302071
2031 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 }
20332075
2034 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>::NoPermission
2040 Ok(())2082 Ok(())
2041 }2083 }
20422084
2043 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);
20472088
2048 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 = true
2051 }2092 }
2052 }2093 }
2055 }2096 }
20562097
2057 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());
20632103
2064 ensure!(2104 ensure!(
2065 result,2105 result,
20702110
2071 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;
20772117
2078 match target_collection.mode {2118 match target_collection.mode {
2079 CollectionMode::NFT => {2119 CollectionMode::NFT => {
2098 }2138 }
2099 }2139 }
21002140
2101 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;
21032143
2104 match target_collection.mode {2144 match target_collection.mode {
2105 CollectionMode::NFT => {2145 CollectionMode::NFT => {
2118 }2158 }
2119 }2159 }
21202160
2121 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;
2163
2122 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 map
2130 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::AccountId
2134 ) -> 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.mode
2137 {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 }
21472189
2148 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)?;
21552198
2156 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);
21582201
2159 // 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)?;
21612204
2162 // update balanceOf of sender2205 // update balanceOf of sender
2163 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);2206 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);
2175 }2218 }
21762219
2177 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)?;
21852229
2186 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_item
2257 }2301 }
22582302
2259 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)?;
22662311
2267 let mut item = <NftItemList<T>>::get(collection_id, item_id);2312 let mut item = <NftItemList<T>>::get(collection_id, item_id);
22682313
2294 }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);
23022348
2303 item.variable_data = data;2349 item.variable_data = data;
2308 }2354 }
23092355
2310 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 }
23232370
2324 fn init_collection(item: &CollectionType<T::AccountId>) {2371 fn init_collection(item: &Collection<T>) {
2325 // check params2372 // check params
2326 assert!(2373 assert!(
2327 item.decimal_points <= MAX_DECIMAL_POINTS,2374 item.decimal_points <= MAX_DECIMAL_POINTS,
2401 }2448 }
24022449
2403 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 {
2404
2405 // add to account limit2451 // add to account limit
2406 if <AccountItemCount<T>>::contains_key(owner) {2452 if <AccountItemCount<T>>::contains_key(owner) {
24072453
25692615
2570 // Determine who is paying transaction fee based on ecnomic model2616 // Determine who is paying transaction fee based on ecnomic model
2571 // Parse call to extract collection ID and access collection sponsor2617 // Parse call to extract collection ID and access collection sponsor
2572 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)?;
25742621
2575 // sponsor timeout2622 // sponsor timeout
2576 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 }
25922637
2593 // check free create limit2638 // check free create limit
2594 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 None
2602 }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() {
26082653
2609 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 timeout
2613 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 }
26902735
2691 if !sponsor_transfer {2736 if !sponsor_transfer {
2692 T::AccountId::default()2737 None
2693 } 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 }
26992743
2700 _ => T::AccountId::default(),2744 Some(Call::set_variable_meta_data(collection_id, item_id, data)) => {
2701 };2745 let mut sponsor_metadata_changes = false;
27022746
2747 let collection = <CollectionById<T>>::get(collection_id)?;
2748
2749 if
2750 collection.sponsor_confirmed &&
2751 // Can't sponsor fungible collection, this tx will be rejected
2752 // as invalid
2753 !matches!(collection.mode, CollectionMode::Fungible(_)) &&
2754 data.len() <= collection.limits.sponsored_data_size as usize
2755 {
2756 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {
2757 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
2758
2759 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 }
2768
2769 if !sponsor_metadata_changes {
2770 None
2771 } else {
2772 Some(collection.sponsor)
2773 }
2774 }
2775
2776 _ => None,
2777 })();
2778
2779 match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {
2780 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {
2781
2782 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());
2783
2784 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 }
2796
2703 // Sponsor smart contracts2797 // Sponsor smart contracts
2704 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) {
27052799
2706 // On instantiation: set the contract owner2800 // On instantiation: set the contract owner
2707 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());
27152809
2716 T::AccountId::default()2810 None
2717 },2811 },
27182812
2719 // On instantiation with code: set the contract owner2813 // On instantiation with code: set the contract owner
27272821
2728 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());2822 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());
27292823
2730 T::AccountId::default()2824 None
2731 }2825 }
27322826
2733 // 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 is
2734 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {2828 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {
27352829
2736 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());
27372831
2738 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 }
2747
2748 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 }
27722854
2773 sp2855 None
2774 },2856 },
27752857
2776 _ => sponsor,2858 _ => None,
2777 };2859 });
27782860
2779 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 }
27832862
2784 <<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))
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
55 let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();55 let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
56 let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();56 let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
57 let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();57 let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();
58 assert_eq!(TemplateModule::collection(id).owner, owner);58 assert_eq!(TemplateModule::collection_id(id).unwrap().owner, owner);
59 assert_eq!(TemplateModule::collection(id).name, saved_col_name);59 assert_eq!(TemplateModule::collection_id(id).unwrap().name, saved_col_name);
60 assert_eq!(TemplateModule::collection(id).mode, *mode);60 assert_eq!(TemplateModule::collection_id(id).unwrap().mode, *mode);
61 assert_eq!(TemplateModule::collection(id).description, saved_description);61 assert_eq!(TemplateModule::collection_id(id).unwrap().description, saved_description);
62 assert_eq!(TemplateModule::collection(id).token_prefix, saved_prefix);62 assert_eq!(TemplateModule::collection_id(id).unwrap().token_prefix, saved_prefix);
63 id63 id
64}64}
6565
89 let collection_id = create_test_collection(&CollectionMode::NFT, 1);89 let collection_id = create_test_collection(&CollectionMode::NFT, 1);
90 90
91 assert_ok!(TemplateModule::set_schema_version(origin1, collection_id, SchemaVersion::Unique));91 assert_ok!(TemplateModule::set_schema_version(origin1, collection_id, SchemaVersion::Unique));
92 assert_eq!(TemplateModule::collection(collection_id).schema_version, SchemaVersion::Unique);92 assert_eq!(TemplateModule::collection_id(collection_id).unwrap().schema_version, SchemaVersion::Unique);
93 });93 });
94}94}
9595
622 collection_id,622 collection_id,
623 2623 2
624 ));624 ));
625 assert_eq!(TemplateModule::collection(collection_id).owner, 2);625 assert_eq!(TemplateModule::collection_id(collection_id).unwrap().owner, 2);
626 });626 });
627}627}
628628
1841 let origin1 = Origin::signed(1);1841 let origin1 = Origin::signed(1);
1842 assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec()));1842 assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec()));
18431843
1844 assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"test const on chain schema".to_vec());1844 assert_eq!(TemplateModule::collection_id(collection_id).unwrap().const_on_chain_schema, b"test const on chain schema".to_vec());
1845 assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"".to_vec());1845 assert_eq!(TemplateModule::collection_id(collection_id).unwrap().variable_on_chain_schema, b"".to_vec());
1846 });1846 });
1847}1847}
18481848
1856 let origin1 = Origin::signed(1);1856 let origin1 = Origin::signed(1);
1857 assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec()));1857 assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec()));
18581858
1859 assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"".to_vec());1859 assert_eq!(TemplateModule::collection_id(collection_id).unwrap().const_on_chain_schema, b"".to_vec());
1860 assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"test variable on chain schema".to_vec());1860 assert_eq!(TemplateModule::collection_id(collection_id).unwrap().variable_on_chain_schema, b"test variable on chain schema".to_vec());
1861 });1861 });
1862}1862}
18631863
modifiedruntime/src/chain_extension.rsdiffbeforeafterboth
60 }60 }
61 let recipient = AccountId32::from(bytes_rec);61 let recipient = AccountId32::from(bytes_rec);
62
63 let collection = pallet_nft::Module::<Runtime>::get_collection(input.collection_id)?;
6264
63 match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, input.collection_id, input.token_id, input.amount) {65 match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, &collection, input.token_id, input.amount) {
64 Ok(_) => Ok(RetVal::Converging(func_id)),66 Ok(_) => Ok(RetVal::Converging(func_id)),
65 _ => Err(DispatchError::Other("Transfer error"))67 _ => Err(DispatchError::Other("Transfer error"))
66 }68 }
modifiedruntime/src/nft_weights.rsdiffbeforeafterboth
133 .saturating_add(DbWeight::get().reads(0 as Weight))133 .saturating_add(DbWeight::get().reads(0 as Weight))
134 .saturating_add(DbWeight::get().writes(2 as Weight))134 .saturating_add(DbWeight::get().writes(2 as Weight))
135 } 135 }
136 fn set_variable_meta_data_sponsoring_rate_limit() -> Weight {
137 (3_500_000 as Weight)
138 .saturating_add(DbWeight::get().reads(1 as Weight))
139 .saturating_add(DbWeight::get().writes(2 as Weight))
140 }
136 fn toggle_contract_white_list() -> Weight {141 fn toggle_contract_white_list() -> Weight {
137 (3_000_000 as Weight)142 (3_000_000 as Weight)
138 .saturating_add(DbWeight::get().reads(0 as Weight))143 .saturating_add(DbWeight::get().reads(0 as Weight))
modifiedruntime_types.jsondiffbeforeafterboth
38 "Confirmed": "AccountId"38 "Confirmed": "AccountId"
39 }39 }
40 },40 },
41 "CollectionType": {41 "Collection": {
42 "Owner": "AccountId",42 "Owner": "AccountId",
43 "Mode": "CollectionMode",43 "Mode": "CollectionMode",
44 "Access": "AccessMode",44 "Access": "AccessMode",
99 },99 },
100 "CollectionLimits": {100 "CollectionLimits": {
101 "AccountTokenOwnershipLimit": "u32",101 "AccountTokenOwnershipLimit": "u32",
102 "SponsoredMintSize": "u32",102 "SponsoredDataSize": "u32",
103 "SponsoredDataRateLimit": "Option<BlockNumber>",
103 "TokenLimit": "u32",104 "TokenLimit": "u32",
104 "SponsorTimeout": "u32",105 "SponsorTimeout": "u32",
105 "OwnerCanTransfer": "bool",106 "OwnerCanTransfer": "bool",
modifiedtests/package.jsondiffbeforeafterboth
46 "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",46 "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",
47 "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",47 "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",
48 "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",48 "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",
49 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts"49 "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
50 "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts"
50 },51 },
51 "author": "",52 "author": "",
52 "license": "SEE LICENSE IN ../LICENSE",53 "license": "SEE LICENSE IN ../LICENSE",
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
21 const alice = privateKey('//Alice'); 21 const alice = privateKey('//Alice');
22 const bob = privateKey('//Bob'); 22 const bob = privateKey('//Bob');
23 23
24 const collection: any = (await api.query.nft.collection(collectionId)); 24 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
25 expect(collection.Owner.toString()).to.be.eq(alice.address); 25 expect(collection.Owner.toString()).to.be.eq(alice.address);
26 26
27 const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address); 27 const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
39 const Bob = privateKey('//Bob'); 39 const Bob = privateKey('//Bob');
40 const Charlie = privateKey('//CHARLIE'); 40 const Charlie = privateKey('//CHARLIE');
41 41
42 const collection: any = (await api.query.nft.collection(collectionId)); 42 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
43 expect(collection.Owner.toString()).to.be.eq(Alice.address); 43 expect(collection.Owner.toString()).to.be.eq(Alice.address);
44 44
45 const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address); 45 const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
19 const alice = privateKey('//Alice');19 const alice = privateKey('//Alice');
20 const bob = privateKey('//Bob');20 const bob = privateKey('//Bob');
2121
22 const collection: any = (await api.query.nft.collection(collectionId));22 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
23 expect(collection.Owner.toString()).to.be.eq(alice.address);23 expect(collection.Owner.toString()).to.be.eq(alice.address);
2424
25 const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);25 const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
26 await submitTransactionAsync(alice, changeOwnerTx);26 await submitTransactionAsync(alice, changeOwnerTx);
2727
28 const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId));28 const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
29 expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(bob.address);29 expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(bob.address);
30 });30 });
31 });31 });
41 const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);41 const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
42 await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected;42 await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected;
4343
44 const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId));44 const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
45 expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(alice.address);45 expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(alice.address);
4646
47 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)47 // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
19 const collectionId = await createCollectionExpectSuccess();19 const collectionId = await createCollectionExpectSuccess();
20 const Alice = privateKey('//Alice');20 const Alice = privateKey('//Alice');
21 const Bob = privateKey('//Bob');21 const Bob = privateKey('//Bob');
22 const collection: any = (await api.query.nft.collection(collectionId));22 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
23 expect(collection.Owner.toString()).to.be.eq(Alice.address);23 expect(collection.Owner.toString()).to.be.eq(Alice.address);
24 // first - add collection admin Bob24 // first - add collection admin Bob
25 const addAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);25 const addAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
6161
62 // tslint:disable-next-line:no-unused-expression62 // tslint:disable-next-line:no-unused-expression
63 expect(result.success).to.be.true;63 expect(result.success).to.be.true;
64 expect(collectionInfo.Limits.AccountTokenOwnershipLimit.toNumber()).to.be.equal(accountTokenOwnershipLimit);64 expect(collectionInfo.Limits.AccountTokenOwnershipLimit).to.be.equal(accountTokenOwnershipLimit);
65 expect(collectionInfo.Limits.SponsoredMintSize.toNumber()).to.be.equal(sponsoredDataSize);65 expect(collectionInfo.Limits.SponsoredDataSize).to.be.equal(sponsoredDataSize);
66 expect(collectionInfo.Limits.TokenLimit.toNumber()).to.be.equal(tokenLimit);66 expect(collectionInfo.Limits.TokenLimit).to.be.equal(tokenLimit);
67 expect(collectionInfo.Limits.SponsorTimeout.toNumber()).to.be.equal(sponsorTimeout);67 expect(collectionInfo.Limits.SponsorTimeout).to.be.equal(sponsorTimeout);
68 expect(collectionInfo.Limits.OwnerCanTransfer.valueOf()).to.be.true;68 expect(collectionInfo.Limits.OwnerCanTransfer).to.be.true;
69 expect(collectionInfo.Limits.OwnerCanDestroy.valueOf()).to.be.true;69 expect(collectionInfo.Limits.OwnerCanDestroy).to.be.true;
70 });70 });
71 });71 });
72});72});
modifiedtests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth
36 it('Run extrinsic with parameters of the collection id, set the scheme', async () => {36 it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
37 await usingApi(async (api) => {37 await usingApi(async (api) => {
38 const collectionId = await createCollectionExpectSuccess();38 const collectionId = await createCollectionExpectSuccess();
39 const collection: any = (await api.query.nft.collection(collectionId));39 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
40 expect(collection.Owner.toString()).to.be.eq(Alice.address);40 expect(collection.Owner.toString()).to.be.eq(Alice.address);
41 const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);41 const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
42 await submitTransactionAsync(Alice, setShema);42 await submitTransactionAsync(Alice, setShema);
48 const collectionId = await createCollectionExpectSuccess();48 const collectionId = await createCollectionExpectSuccess();
49 const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);49 const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
50 await submitTransactionAsync(Alice, setShema);50 await submitTransactionAsync(Alice, setShema);
51 const collection: any = (await api.query.nft.collection(collectionId));51 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
52 expect(collection.ConstOnChainSchema.toString()).to.be.eq(Shema);52 expect(collection.ConstOnChainSchema.toString()).to.be.eq(Shema);
5353
54 });54 });
86 it('Execute method not on behalf of the collection owner', async () => {86 it('Execute method not on behalf of the collection owner', async () => {
87 await usingApi(async (api) => {87 await usingApi(async (api) => {
88 const collectionId = await createCollectionExpectSuccess();88 const collectionId = await createCollectionExpectSuccess();
89 const collection: any = (await api.query.nft.collection(collectionId));89 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
90 expect(collection.Owner.toString()).to.be.eq(Alice.address);90 expect(collection.Owner.toString()).to.be.eq(Alice.address);
91 const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);91 const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
92 await expect(submitTransactionExpectFailAsync(Bob, setShema)).to.be.rejected;92 await expect(submitTransactionExpectFailAsync(Bob, setShema)).to.be.rejected;
modifiedtests/src/setOffchainSchema.test.tsdiffbeforeafterboth
36 await setOffchainSchemaExpectSuccess(alice, collectionId, DATA);36 await setOffchainSchemaExpectSuccess(alice, collectionId, DATA);
37 const collection = await queryCollectionExpectSuccess(collectionId);37 const collection = await queryCollectionExpectSuccess(collectionId);
3838
39 expect(Array.from(collection.OffchainSchema)).to.be.deep.equal(DATA);39 expect(collection.OffchainSchema).to.be.equal('0x' + Buffer.from(DATA).toString('hex'));
40 });40 });
41});41});
4242
addedtests/src/setVariableMetadataSponsoringRateLimit.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/setVariableOnChainSchema.test.tsdiffbeforeafterboth
36 it('Run extrinsic with parameters of the collection id, set the scheme', async () => { 36 it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
37 await usingApi(async (api) => { 37 await usingApi(async (api) => {
38 const collectionId = await createCollectionExpectSuccess(); 38 const collectionId = await createCollectionExpectSuccess();
39 const collection: any = (await api.query.nft.collection(collectionId)); 39 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
40 expect(collection.Owner.toString()).to.be.eq(Alice.address); 40 expect(collection.Owner.toString()).to.be.eq(Alice.address);
41 const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); 41 const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
42 await submitTransactionAsync(Alice, setSchema); 42 await submitTransactionAsync(Alice, setSchema);
48 const collectionId = await createCollectionExpectSuccess(); 48 const collectionId = await createCollectionExpectSuccess();
49 const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); 49 const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
50 await submitTransactionAsync(Alice, setSchema); 50 await submitTransactionAsync(Alice, setSchema);
51 const collection: any = (await api.query.nft.collection(collectionId)); 51 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
52 expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema); 52 expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema);
53 53
54 }); 54 });
86 it('Execute method not on behalf of the collection owner', async () => { 86 it('Execute method not on behalf of the collection owner', async () => {
87 await usingApi(async (api) => { 87 await usingApi(async (api) => {
88 const collectionId = await createCollectionExpectSuccess(); 88 const collectionId = await createCollectionExpectSuccess();
89 const collection: any = (await api.query.nft.collection(collectionId)); 89 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
90 expect(collection.Owner.toString()).to.be.eq(Alice.address); 90 expect(collection.Owner.toString()).to.be.eq(Alice.address);
91 const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema); 91 const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
92 await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected; 92 await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected;
modifiedtests/src/types.tsdiffbeforeafterboth
13 Description: [BN, BN]; // utf1613 Description: [BN, BN]; // utf16
14 isReFungible: boolean;14 isReFungible: boolean;
15 Limits: {15 Limits: {
16 AccountTokenOwnershipLimit: BN;16 AccountTokenOwnershipLimit: number;
17 SponsoredMintSize: BN;17 SponsoredDataSize: number;
18 SponsoredDataRateLimit?: number,
18 TokenLimit: BN;19 TokenLimit: number;
19 SponsorTimeout: BN;20 SponsorTimeout: number;
20 OwnerCanTransfer: boolean;21 OwnerCanTransfer: boolean;
21 OwnerCanDestroy: boolean;22 OwnerCanDestroy: boolean;
22 };23 };
modifiedtests/src/util/contracthelpers.tsdiffbeforeafterboth
2222
23function deployContract(alice: IKeyringPair, code: CodePromise, constructor: string = 'default', ...args: any[]): Promise<Contract> {23function deployContract(alice: IKeyringPair, code: CodePromise, constructor: string = 'default', ...args: any[]): Promise<Contract> {
24 return new Promise<Contract>(async (resolve, reject) => {24 return new Promise<Contract>(async (resolve, reject) => {
25 const unsub = await code25 const unsub = await (code as any)
26 .tx[constructor]({value: endowment, gasLimit}, ...args)26 .tx[constructor]({value: endowment, gasLimit}, ...args)
27 .signAndSend(alice, (result) => {27 .signAndSend(alice, (result: any) => {
28 if (result.status.isInBlock || result.status.isFinalized) {28 if (result.status.isInBlock || result.status.isFinalized) {
29 // here we have an additional field in the result, containing the blueprint29 // here we have an additional field in the result, containing the blueprint
30 resolve((result as any).contract);30 resolve((result as any).contract);
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
212 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);212 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);
213213
214 // Get the collection214 // Get the collection
215 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();215 const collection: any = (await api.query.nft.collectionById(result.collectionId)).toJSON();
216216
217 // What to expect217 // What to expect
218 // tslint:disable-next-line:no-unused-expression218 // tslint:disable-next-line:no-unused-expression
324 const result = getDestroyResult(events);324 const result = getDestroyResult(events);
325325
326 // Get the collection326 // Get the collection
327 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();327 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
328328
329 // What to expect329 // What to expect
330 expect(result).to.be.true;330 expect(result).to.be.true;
331 expect(collection).to.be.not.null;331 expect(collection).to.be.null;
332 expect(collection.Owner).to.be.equal(nullPublicKey);
333 });332 });
334}333}
335334
336export async function queryCollectionLimits(collectionId: number) {335export async function queryCollectionLimits(collectionId: number) {
337 return await usingApi(async (api) => {336 return await usingApi(async (api) => {
338 return ((await api.query.nft.collection(collectionId)).toJSON() as any).Limits;337 return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;
339 });338 });
340}339}
341340
373 const result = getGenericResult(events);372 const result = getGenericResult(events);
374373
375 // Get the collection374 // Get the collection
376 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();375 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
377376
378 // What to expect377 // What to expect
379 expect(result.success).to.be.true;378 expect(result.success).to.be.true;
393 const result = getGenericResult(events);392 const result = getGenericResult(events);
394393
395 // Get the collection394 // Get the collection
396 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();395 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
397396
398 // What to expect397 // What to expect
399 expect(result.success).to.be.true;398 expect(result.success).to.be.true;
431 const result = getGenericResult(events);430 const result = getGenericResult(events);
432431
433 // Get the collection432 // Get the collection
434 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();433 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
435434
436 // What to expect435 // What to expect
437 expect(result.success).to.be.true;436 expect(result.success).to.be.true;
839 const result = getGenericResult(events);838 const result = getGenericResult(events);
840839
841 // Get the collection840 // Get the collection
842 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();841 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
843842
844 // What to expect843 // What to expect
845 // tslint:disable-next-line:no-unused-expression844 // tslint:disable-next-line:no-unused-expression
865 const result = getGenericResult(events);864 const result = getGenericResult(events);
866865
867 // Get the collection866 // Get the collection
868 const collection: any = (await api.query.nft.collection(collectionId)).toJSON();867 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
869868
870 // What to expect869 // What to expect
871 // tslint:disable-next-line:no-unused-expression870 // tslint:disable-next-line:no-unused-expression
947946
948export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)947export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)
949 : Promise<ICollectionInterface | null> => {948 : Promise<ICollectionInterface | null> => {
950 return await api.query.nft.collection(collectionId) as unknown as ICollectionInterface;949 return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;
951};950};
952951
953export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {952export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {
957956
958export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {957export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {
959 return await usingApi(async (api) => {958 return await usingApi(async (api) => {
960 return (await api.query.nft.collection(collectionId)) as unknown as ICollectionInterface;959 return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;
961 });960 });
962}961}
963962