From 7ff84981c059ea5d647c6a228b908066a0e9e205 Mon Sep 17 00:00:00 2001 From: sotmorskiy Date: Thu, 03 Dec 2020 04:39:31 +0000 Subject: [PATCH] Merge branch 'develop' into feature/NFTPAR-142 # Conflicts: # pallets/nft/src/lib.rs --- --- a/Cargo.lock +++ b/Cargo.lock @@ -3737,7 +3737,10 @@ "frame-support", "frame-system", "log", + "pallet-balances", "pallet-contracts", + "pallet-randomness-collective-flip", + "pallet-timestamp", "pallet-transaction-payment", "parity-scale-codec", "serde", --- a/pallets/nft/src/default_weights.rs +++ b/pallets/nft/src/default_weights.rs @@ -107,9 +107,19 @@ .saturating_add(DbWeight::get().reads(2 as Weight)) .saturating_add(DbWeight::get().writes(1 as Weight)) } + // fn set_chain_limits() -> Weight { + // (0 as Weight) + // .saturating_add(DbWeight::get().reads(1 as Weight)) + // .saturating_add(DbWeight::get().writes(1 as Weight)) + // } // fn enable_contract_sponsoring() -> Weight { // (0 as Weight) // .saturating_add(DbWeight::get().reads(1 as Weight)) // .saturating_add(DbWeight::get().writes(1 as Weight)) // } + // fn set_contract_sponsoring_rate_limit() -> Weight { + // (0 as Weight) + // .saturating_add(DbWeight::get().reads(1 as Weight)) + // .saturating_add(DbWeight::get().writes(1 as Weight)) + // } } --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -378,8 +378,10 @@ pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber; // Contract Sponsorship and Ownership - pub ContractOwner get(fn contract_owner): map hasher(identity) T::AccountId => T::AccountId; - pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(identity) T::AccountId => bool; + pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId; + pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool; + pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) T::AccountId => T::BlockNumber; + pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber; } add_extra_genesis { build(|config: &GenesisConfig| { @@ -1335,6 +1337,42 @@ >::insert(contract_address, enable); Ok(()) } + + /// Set the rate limit for contract sponsoring to specified number of blocks. + /// + /// If not set (has the default value of 0 blocks), the sponsoring will be disabled. + /// If set to the number B (for blocks), the transactions will be sponsored with a rate + /// limit of B, i.e. fees for every transaction sent to this smart contract will be paid + /// from contract endowment if there are at least B blocks between such transactions. + /// Nonetheless, if transactions are sent more frequently, the fees are paid by the sender. + /// + /// # Permissions + /// + /// * Contract Owner + /// + /// # Arguments + /// + /// -`contract_address`: Address of the contract to sponsor + /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed + /// + #[weight = 0] + pub fn set_contract_sponsoring_rate_limit( + origin, + contract_address: T::AccountId, + rate_limit: T::BlockNumber + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + let mut is_owner = false; + if >::contains_key(contract_address.clone()) { + let owner = >::get(&contract_address); + is_owner = sender == owner; + } + ensure!(is_owner, Error::::NoPermission); + + >::insert(contract_address, rate_limit); + Ok(()) + } + } } @@ -2242,11 +2280,30 @@ // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => { + let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default()); + + let mut sponsor_transfer = false; + if >::contains_key(called_contract.clone()) { + let last_tx_block = >::get(&called_contract); + let block_number = >::block_number() as T::BlockNumber; + let rate_limit = >::get(&called_contract); + let limit_time = last_tx_block + rate_limit; + + if block_number >= limit_time { + >::insert(called_contract.clone(), block_number); + sponsor_transfer = true; + } + } else { + sponsor_transfer = false; + } + + let mut sp = T::AccountId::default(); - let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default()); - if >::contains_key(called_contract.clone()) { - if >::get(called_contract.clone()) { - sp = called_contract; + if sponsor_transfer { + if >::contains_key(called_contract.clone()) { + if >::get(called_contract.clone()) { + sp = called_contract; + } } } --- a/pallets/nft/src/tests.rs +++ b/pallets/nft/src/tests.rs @@ -1,6 +1,8 @@ // Tests to be written here +use super::*; use crate::mock::*; -use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData}; +use crate::{AccessMode, ApprovePermissions, CollectionMode, + Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData}; //Err use frame_support::{assert_noop, assert_ok}; use frame_system::{ RawOrigin }; @@ -392,7 +394,7 @@ 2, 1, 1, - 1), "Only item owner, collection owner and admins can modify items"); + 1), Error::::NoPermission); // do approve assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1)); @@ -672,7 +674,7 @@ assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1)); assert_noop!( TemplateModule::burn_item(origin1.clone(), 1, 1), - "Item does not exists" + Error::::TokenNotFound ); assert_eq!(TemplateModule::balance_count(1, 1), 0); @@ -699,7 +701,7 @@ assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1)); assert_noop!( TemplateModule::burn_item(origin1.clone(), 1, 1), - "Item does not exists" + Error::::TokenNotFound ); assert_eq!(TemplateModule::balance_count(1, 1), 0); @@ -738,7 +740,7 @@ assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1)); assert_noop!( TemplateModule::burn_item(origin1.clone(), 1, 1), - "Item does not exists" + Error::::TokenNotFound ); assert_eq!(TemplateModule::balance_count(1, 1), 0); @@ -933,7 +935,7 @@ let origin2 = Origin::signed(2); assert_noop!( TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3), - "You do not have permissions to modify this collection" + Error::::NoPermission ); }); } @@ -947,7 +949,7 @@ assert_noop!( TemplateModule::add_to_white_list(origin1.clone(), 1, 2), - "This collection does not exist" + Error::::CollectionNotFound ); }); } @@ -963,7 +965,7 @@ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id)); assert_noop!( TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2), - "This collection does not exist" + Error::::CollectionNotFound ); }); } @@ -1035,7 +1037,7 @@ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2)); assert_noop!( TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2), - "You do not have permissions to modify this collection" + Error::::NoPermission ); assert_eq!(TemplateModule::white_list(collection_id)[0], 2); }); @@ -1049,7 +1051,7 @@ assert_noop!( TemplateModule::remove_from_white_list(origin1.clone(), 1, 2), - "This collection does not exist" + Error::::CollectionNotFound ); }); } @@ -1067,7 +1069,7 @@ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id)); assert_noop!( TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2), - "This collection does not exist" + Error::::CollectionNotFound ); assert_eq!(TemplateModule::white_list(collection_id).len(), 0); }); @@ -1119,7 +1121,7 @@ assert_noop!( TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1155,7 +1157,7 @@ assert_noop!( TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1182,7 +1184,7 @@ assert_noop!( TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1219,7 +1221,7 @@ assert_noop!( TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1244,7 +1246,7 @@ )); assert_noop!( TemplateModule::burn_item(origin1.clone(), 1, 1), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1267,7 +1269,7 @@ // do approve assert_noop!( TemplateModule::approve(origin1.clone(), 1, 1, 1), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1416,7 +1418,7 @@ assert_noop!( TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()), - "Public minting is not allowed for this collection" + Error::::PublicMintingNotAllowed ); }); } @@ -1445,7 +1447,7 @@ assert_noop!( TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()), - "Public minting is not allowed for this collection" + Error::::PublicMintingNotAllowed ); }); } @@ -1533,7 +1535,7 @@ assert_noop!( TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()), - "Address is not in white list" + Error::::AddresNotInWhiteList ); }); } @@ -1603,7 +1605,7 @@ col_desc1.clone(), token_prefix1.clone(), CollectionMode::NFT - ), "Total collections bound exceeded"); + ), Error::::TotalCollectionsLimitExceeded); }); } @@ -1646,7 +1648,7 @@ 1, 1, data.into() - ), "Owned tokens by a single address bound exceeded"); + ), Error::::AddressOwnershipLimitExceeded); }); } @@ -1692,7 +1694,7 @@ let origin1 = Origin::signed(1); assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2)); - assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), "Number of collection admins bound exceeded"); + assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), Error::::CollectionAdminsLimitExceeded); }); } --- a/runtime/src/nft_weights.rs +++ b/runtime/src/nft_weights.rs @@ -108,4 +108,19 @@ .saturating_add(DbWeight::get().reads(2 as Weight)) .saturating_add(DbWeight::get().writes(1 as Weight)) } + // fn set_chain_limits() -> Weight { + // (0 as Weight) + // .saturating_add(DbWeight::get().reads(1 as Weight)) + // .saturating_add(DbWeight::get().writes(1 as Weight)) + // } + // fn enable_contract_sponsoring() -> Weight { + // (0 as Weight) + // .saturating_add(DbWeight::get().reads(1 as Weight)) + // .saturating_add(DbWeight::get().writes(1 as Weight)) + // } + // fn set_contract_sponsoring_rate_limit() -> Weight { + // (0 as Weight) + // .saturating_add(DbWeight::get().reads(1 as Weight)) + // .saturating_add(DbWeight::get().writes(1 as Weight)) + // } } -- gitstuff