difftreelog
feat implement sponsoring primitive for nft
in: master
3 files changed
pallets/nft/Cargo.tomldiffbeforeafterboth1################################################################################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"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"pallets/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(())
}
pallets/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