git.delta.rocks / unique-network / refs/commits / afcf32ad6db4

difftreelog

feat implement sponsoring primitive for nft

Yaroslav Bolyukin2021-06-24parent: #a9bfe04.patch.diff
in: master

3 files changed

modifiedpallets/nft/Cargo.tomldiffbeforeafterboth
before · pallets/nft/Cargo.toml
1################################################################################2# Package34[package]5authors = ['Unique Network <support@uniquenetwork.io>']6description = 'Substrate node nft'7edition = '2018'8homepage = 'https://unique.network'9license = 'All Rights Reserved'10name = 'pallet-nft'11repository = 'https://github.com/usetech-llc/nft_private/'12version = '3.0.0'1314[package.metadata.docs.rs]15targets = ['x86_64-unknown-linux-gnu']1617[features]18default = ['std']19runtime-benchmarks = ['frame-benchmarking']20std = [21    'codec/std',22    'serde/std',23    'frame-support/std',24    'frame-system/std',25    'pallet-balances/std',26    'pallet-evm/std',27    'pallet-timestamp/std',28    'pallet-contracts/std',29    'pallet-randomness-collective-flip/std',30    'pallet-transaction-payment/std',31    'fp-evm/std',32    'nft-data-structs/std',33    'sp-std/std',34    'sp-api/std',35    'sp-runtime/std',36    'frame-benchmarking/std',37    'ethereum/std',38    'rlp/std',3940    'ethereum-tx-sign',41    'primitive-types/std',42    'evm-coder/std',43]4445################################################################################46# Substrate Dependencies4748[dependencies.codec]49default-features = false50features = ['derive']51package = 'parity-scale-codec'52version = '2.0.0'5354[dependencies.frame-benchmarking]55default-features = false56optional = true57git = 'https://github.com/paritytech/substrate.git'58branch = 'polkadot-v0.9.3'59version = '3.0.0'6061[dependencies.frame-support]62default-features = false63git = 'https://github.com/paritytech/substrate.git'64branch = 'polkadot-v0.9.3'65version = '3.0.0'6667[dependencies.frame-system]68default-features = false69git = 'https://github.com/paritytech/substrate.git'70branch = 'polkadot-v0.9.3'71version = '3.0.0'7273[dependencies.pallet-balances]74default-features = false75git = 'https://github.com/paritytech/substrate.git'76branch = 'polkadot-v0.9.3'77version = '3.0.0'7879[dependencies.pallet-timestamp]80default-features = false81git = 'https://github.com/paritytech/substrate.git'82branch = 'polkadot-v0.9.3'83version = '3.0.0'8485[dependencies.pallet-randomness-collective-flip]86default-features = false87git = 'https://github.com/paritytech/substrate.git'88branch = 'polkadot-v0.9.3'89version = '3.0.0'9091[dependencies.sp-std]92default-features = false93git = 'https://github.com/paritytech/substrate.git'94branch = 'polkadot-v0.9.3'95version = '3.0.0'9697[dependencies.pallet-contracts]98default-features = false99git = 'https://github.com/paritytech/substrate.git'100branch = 'polkadot-v0.9.3'101version = '3.0.0'102103[dependencies.pallet-transaction-payment]104default-features = false105git = 'https://github.com/paritytech/substrate.git'106branch = 'polkadot-v0.9.3'107version = '3.0.0'108109[dependencies.serde]110default-features = false111features = ['derive']112version = '1.0.119'113114[dependencies.sp-runtime]115default-features = false116git = 'https://github.com/paritytech/substrate.git'117branch = 'polkadot-v0.9.3'118version = '3.0.0'119120[dependencies.sp-core]121default-features = false122git = 'https://github.com/paritytech/substrate.git'123branch = 'polkadot-v0.9.3'124version = '3.0.0'125126[dependencies.sp-io]127default-features = false128git = 'https://github.com/paritytech/substrate.git'129branch = 'polkadot-v0.9.3'130version = '3.0.0'131132133################################################################################134# Local Dependencies135136[dependencies.nft-data-structs]137default-features = false138path = '../../primitives'139version = '0.9.0'140141142[dependencies]143ethereum-tx-sign = { version = "3.0.4", optional = true }144ethereum = { default-features = false, version = "0.7.1" }145rlp = { default-features = false, version = "0.5.0" }146sp-api = { default-features = false, version = '3.0.0', git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.3" }147148evm-coder = { default-features = false, path = "../../crates/evm-coder" }149primitive-types = { version = "0.9.0", default-features = false, features = ["serde_no_std"] }150151pallet-evm = { default-features = false, version = "4.0.0-dev", git = "https://github.com/usetech-llc/frontier.git", branch = "injected-transactions-parachain" }152pallet-ethereum = { default-features = false, version = "2.0.0-dev", git = "https://github.com/usetech-llc/frontier.git", branch = "injected-transactions-parachain" }153fp-evm = { default-features = false, version = '2.0.0', git = "https://github.com/usetech-llc/frontier.git", branch = "injected-transactions-parachain" }154hex-literal = "0.3.1"
after · pallets/nft/Cargo.toml
1################################################################################2# Package34[package]5authors = ['Unique Network <support@uniquenetwork.io>']6description = 'Substrate node nft'7edition = '2018'8homepage = 'https://unique.network'9license = 'All Rights Reserved'10name = 'pallet-nft'11repository = 'https://github.com/usetech-llc/nft_private/'12version = '3.0.0'1314[package.metadata.docs.rs]15targets = ['x86_64-unknown-linux-gnu']1617[features]18default = ['std']19runtime-benchmarks = ['frame-benchmarking']20std = [21    'codec/std',22    'serde/std',23    'frame-support/std',24    'frame-system/std',25    'pallet-balances/std',26    'pallet-evm/std',27    'pallet-timestamp/std',28    'pallet-contracts/std',29    'pallet-randomness-collective-flip/std',30    'pallet-transaction-payment/std',31    'fp-evm/std',32    'nft-data-structs/std',33    'up-sponsorship/std',34    'sp-std/std',35    'sp-api/std',36    'sp-runtime/std',37    'frame-benchmarking/std',38    'ethereum/std',39    'rlp/std',4041    'ethereum-tx-sign',42    'primitive-types/std',43    'evm-coder/std',44]4546################################################################################47# Substrate Dependencies4849[dependencies.codec]50default-features = false51features = ['derive']52package = 'parity-scale-codec'53version = '2.0.0'5455[dependencies.frame-benchmarking]56default-features = false57optional = true58git = 'https://github.com/paritytech/substrate.git'59branch = 'polkadot-v0.9.3'60version = '3.0.0'6162[dependencies.frame-support]63default-features = false64git = 'https://github.com/paritytech/substrate.git'65branch = 'polkadot-v0.9.3'66version = '3.0.0'6768[dependencies.frame-system]69default-features = false70git = 'https://github.com/paritytech/substrate.git'71branch = 'polkadot-v0.9.3'72version = '3.0.0'7374[dependencies.pallet-balances]75default-features = false76git = 'https://github.com/paritytech/substrate.git'77branch = 'polkadot-v0.9.3'78version = '3.0.0'7980[dependencies.pallet-timestamp]81default-features = false82git = 'https://github.com/paritytech/substrate.git'83branch = 'polkadot-v0.9.3'84version = '3.0.0'8586[dependencies.pallet-randomness-collective-flip]87default-features = false88git = 'https://github.com/paritytech/substrate.git'89branch = 'polkadot-v0.9.3'90version = '3.0.0'9192[dependencies.sp-std]93default-features = false94git = 'https://github.com/paritytech/substrate.git'95branch = 'polkadot-v0.9.3'96version = '3.0.0'9798[dependencies.pallet-contracts]99default-features = false100git = 'https://github.com/paritytech/substrate.git'101branch = 'polkadot-v0.9.3'102version = '3.0.0'103104[dependencies.pallet-transaction-payment]105default-features = false106git = 'https://github.com/paritytech/substrate.git'107branch = 'polkadot-v0.9.3'108version = '3.0.0'109110[dependencies.serde]111default-features = false112features = ['derive']113version = '1.0.119'114115[dependencies.sp-runtime]116default-features = false117git = 'https://github.com/paritytech/substrate.git'118branch = 'polkadot-v0.9.3'119version = '3.0.0'120121[dependencies.sp-core]122default-features = false123git = 'https://github.com/paritytech/substrate.git'124branch = 'polkadot-v0.9.3'125version = '3.0.0'126127[dependencies.sp-io]128default-features = false129git = 'https://github.com/paritytech/substrate.git'130branch = 'polkadot-v0.9.3'131version = '3.0.0'132133134################################################################################135# Local Dependencies136137[dependencies.nft-data-structs]138default-features = false139path = '../../primitives/nft'140version = '0.9.0'141142[dependencies.up-sponsorship]143default-features = false144path = '../../primitives/sponsorship'145version = '0.1.0'146147148[dependencies]149ethereum-tx-sign = { version = "3.0.4", optional = true }150ethereum = { default-features = false, version = "0.7.1" }151rlp = { default-features = false, version = "0.5.0" }152sp-api = { default-features = false, version = '3.0.0', git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.3" }153154evm-coder = { default-features = false, path = "../../crates/evm-coder" }155primitive-types = { version = "0.9.0", default-features = false, features = ["serde_no_std"] }156157pallet-evm = { default-features = false, version = "4.0.0-dev", git = "https://github.com/usetech-llc/frontier.git", branch = "injected-transactions-parachain" }158pallet-ethereum = { default-features = false, version = "2.0.0-dev", git = "https://github.com/usetech-llc/frontier.git", branch = "injected-transactions-parachain" }159fp-evm = { default-features = false, version = '2.0.0', git = "https://github.com/usetech-llc/frontier.git", branch = "injected-transactions-parachain" }160hex-literal = "0.3.1"
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -50,6 +50,8 @@
 
 mod default_weights;
 mod eth;
+mod sponsorship;
+pub use sponsorship::NftSponsorshipHandler;
 
 pub use eth::NftErcSupport;
 pub use eth::account::*;
@@ -2232,12 +2234,6 @@
     ) -> DispatchResult {
         Self::remove_token_index(collection_id, item_index, old_owner)?;
         Self::add_token_index(collection_id, item_index, new_owner)?;
-
-        Ok(())
-    }
-    
-    fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {
-        ensure!(<ContractOwner<T>>::get(contract) == Some(account), Error::<T>::NoPermission);
 
         Ok(())
     }
addedpallets/nft/src/sponsorship.rsdiffbeforeafterboth
--- /dev/null
+++ b/pallets/nft/src/sponsorship.rs
@@ -0,0 +1,203 @@
+use crate::{Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, ChainLimit, CreateItemData, CollectionMode};
+use core::marker::PhantomData;
+use up_sponsorship::SponsorshipHandler;
+use frame_support::{
+	traits::IsSubType,
+	storage::{StorageMap, StorageDoubleMap, StorageValue},
+};
+use nft_data_structs::{TokenId, CollectionId};
+use alloc::vec::Vec;
+
+pub struct NftSponsorshipHandler<T>(PhantomData<T>);
+impl<T: Config> NftSponsorshipHandler<T> {
+	pub fn withdraw_create_item(
+		who: &T::AccountId,
+		collection_id: &CollectionId,
+		_properties: &CreateItemData,
+	) -> Option<T::AccountId> {
+	
+		let collection = CollectionById::<T>::get(collection_id)?;
+
+		// sponsor timeout
+		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+
+		let limit = collection.limits.sponsor_transfer_timeout;
+		if CreateItemBasket::<T>::contains_key((collection_id, &who)) {
+			let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));
+			let limit_time = last_tx_block + limit.into();
+			if block_number <= limit_time {
+				return None;
+			}
+		}
+		CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);
+
+		// check free create limit
+		if collection.limits.sponsored_data_size >= (_properties.len() as u32) {
+			collection.sponsorship.sponsor()
+				.cloned()
+		} else {
+			None
+		}
+	}
+
+	pub fn withdraw_transfer(
+		who: &T::AccountId,
+		collection_id: &CollectionId,
+		item_id: &TokenId,
+	) -> Option<T::AccountId> {
+
+		let collection = CollectionById::<T>::get(collection_id)?;
+		let limits = ChainLimit::get();
+
+		let mut sponsor_transfer = false;
+		if collection.sponsorship.confirmed() {
+
+			let collection_limits = collection.limits.clone();
+			let collection_mode = collection.mode.clone();
+
+			// sponsor timeout
+			let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+			sponsor_transfer = match collection_mode {
+				CollectionMode::NFT => {
+
+					// get correct limit
+					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
+						collection_limits.sponsor_transfer_timeout
+					} else {
+						limits.nft_sponsor_transfer_timeout
+					};
+
+					let mut sponsored = true;
+					if NftTransferBasket::<T>::contains_key(collection_id, item_id) {
+						let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);
+						let limit_time = last_tx_block + limit.into();
+						if block_number <= limit_time {
+							sponsored = false;
+						}
+					}
+					if sponsored {
+						NftTransferBasket::<T>::insert(collection_id, item_id, block_number);
+					}
+
+					sponsored
+				}
+				CollectionMode::Fungible(_) => {
+
+					// get correct limit
+					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
+						collection_limits.sponsor_transfer_timeout
+					} else {
+						limits.fungible_sponsor_transfer_timeout
+					};
+
+					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+					let mut sponsored = true;
+					if FungibleTransferBasket::<T>::contains_key(collection_id, who) {
+						let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);
+						let limit_time = last_tx_block + limit.into();
+						if block_number <= limit_time {
+							sponsored = false;
+						}
+					}
+					if sponsored {
+						FungibleTransferBasket::<T>::insert(collection_id, who, block_number);
+					}
+
+					sponsored
+				}
+				CollectionMode::ReFungible => {
+
+					// get correct limit
+					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
+						collection_limits.sponsor_transfer_timeout
+					} else {
+						limits.refungible_sponsor_transfer_timeout
+					};
+
+					let mut sponsored = true;
+					if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {
+						let last_tx_block = ReFungibleTransferBasket::<T>::get(collection_id, item_id);
+						let limit_time = last_tx_block + limit.into();
+						if block_number <= limit_time {
+							sponsored = false;
+						}
+					}
+					if sponsored {
+						ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);
+					}
+
+					sponsored
+				}
+				_ => {
+					false
+				},
+			};
+		}
+
+		if !sponsor_transfer {
+			None
+		} else {
+			collection.sponsorship.sponsor()
+				.cloned()
+		}
+	}
+	
+	pub fn withdraw_set_variable_meta_data(
+		collection_id: &CollectionId,
+		item_id: &TokenId,
+		data: &Vec<u8>,
+	) -> Option<T::AccountId> {
+
+		let mut sponsor_metadata_changes = false;
+
+		let collection = CollectionById::<T>::get(collection_id)?;
+
+		if
+			collection.sponsorship.confirmed() &&
+			// Can't sponsor fungible collection, this tx will be rejected
+			// as invalid
+			!matches!(collection.mode, CollectionMode::Fungible(_)) &&
+			data.len() <= collection.limits.sponsored_data_size as usize
+		{
+			if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {
+				let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+
+				if VariableMetaDataBasket::<T>::get(collection_id, item_id)
+					.map(|last_block| block_number - last_block > rate_limit)
+					.unwrap_or(true) 
+				{
+					sponsor_metadata_changes = true;
+					VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);
+				}
+			}
+		}
+
+		if !sponsor_metadata_changes {
+			None
+		} else {
+			collection.sponsorship.sponsor().cloned()
+		}
+
+	}
+}
+
+impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>
+where 
+    T: Config,
+    C: IsSubType<Call<T>>
+{
+    fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {
+        match IsSubType::<Call<T>>::is_sub_type(call)? {
+            Call::create_item(collection_id, _owner, _properties) => {
+                Self::withdraw_create_item(who, collection_id, &_properties)
+            },
+            Call::transfer(_new_owner, collection_id, item_id, _value) => {
+                Self::withdraw_transfer(who, collection_id, item_id)
+            },
+            Call::set_variable_meta_data(collection_id, item_id, data) => {
+                Self::withdraw_set_variable_meta_data(collection_id, item_id, &data)
+			},
+			_ => None,
+        }
+    }
+}
\ No newline at end of file