difftreelog
Merge branch 'develop' into feature/NFTPAR-142
in: master
# Conflicts: # pallets/nft/src/lib.rs
5 files changed
Cargo.lockdiffbeforeafterboth--- 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",
pallets/nft/src/default_weights.rsdiffbeforeafterboth--- 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))
+ // }
}
pallets/nft/src/lib.rsdiffbeforeafterboth--- 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<T>| {
@@ -1335,6 +1337,42 @@
<ContractSelfSponsoring<T>>::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 <ContractOwner<T>>::contains_key(contract_address.clone()) {
+ let owner = <ContractOwner<T>>::get(&contract_address);
+ is_owner = sender == owner;
+ }
+ ensure!(is_owner, Error::<T>::NoPermission);
+
+ <ContractSponsoringRateLimit<T>>::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 <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {
+ let last_tx_block = <ContractSponsorBasket<T>>::get(&called_contract);
+ let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
+ let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);
+ let limit_time = last_tx_block + rate_limit;
+
+ if block_number >= limit_time {
+ <ContractSponsorBasket<T>>::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 <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {
- if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {
- sp = called_contract;
+ if sponsor_transfer {
+ if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {
+ if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {
+ sp = called_contract;
+ }
}
}
pallets/nft/src/tests.rsdiffbeforeafterboth1// Tests to be written here1// Tests to be written here2use super::*;2use crate::mock::*;3use crate::mock::*;3use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData};4use crate::{AccessMode, ApprovePermissions, CollectionMode,5 Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData}; //Err4use frame_support::{assert_noop, assert_ok};6use frame_support::{assert_noop, assert_ok};5use frame_system::{ RawOrigin };7use frame_system::{ RawOrigin };68392 2,394 2,393 1,395 1,394 1,396 1,395 1), "Only item owner, collection owner and admins can modify items");397 1), Error::<Test>::NoPermission);396398397 // do approve399 // do approve398 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));400 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));672 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));674 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));673 assert_noop!(675 assert_noop!(674 TemplateModule::burn_item(origin1.clone(), 1, 1),676 TemplateModule::burn_item(origin1.clone(), 1, 1),675 "Item does not exists"677 Error::<Test>::TokenNotFound676 );678 );677679678 assert_eq!(TemplateModule::balance_count(1, 1), 0);680 assert_eq!(TemplateModule::balance_count(1, 1), 0);699 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));701 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));700 assert_noop!(702 assert_noop!(701 TemplateModule::burn_item(origin1.clone(), 1, 1),703 TemplateModule::burn_item(origin1.clone(), 1, 1),702 "Item does not exists"704 Error::<Test>::TokenNotFound703 );705 );704706705 assert_eq!(TemplateModule::balance_count(1, 1), 0);707 assert_eq!(TemplateModule::balance_count(1, 1), 0);738 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));740 assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));739 assert_noop!(741 assert_noop!(740 TemplateModule::burn_item(origin1.clone(), 1, 1),742 TemplateModule::burn_item(origin1.clone(), 1, 1),741 "Item does not exists"743 Error::<Test>::TokenNotFound742 );744 );743745744 assert_eq!(TemplateModule::balance_count(1, 1), 0);746 assert_eq!(TemplateModule::balance_count(1, 1), 0);933 let origin2 = Origin::signed(2);935 let origin2 = Origin::signed(2);934 assert_noop!(936 assert_noop!(935 TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),937 TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),936 "You do not have permissions to modify this collection"938 Error::<Test>::NoPermission937 );939 );938 });940 });939}941}947949948 assert_noop!(950 assert_noop!(949 TemplateModule::add_to_white_list(origin1.clone(), 1, 2),951 TemplateModule::add_to_white_list(origin1.clone(), 1, 2),950 "This collection does not exist"952 Error::<Test>::CollectionNotFound951 );953 );952 });954 });953}955}963 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));965 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));964 assert_noop!(966 assert_noop!(965 TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),967 TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),966 "This collection does not exist"968 Error::<Test>::CollectionNotFound967 );969 );968 });970 });969}971}1035 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1037 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1036 assert_noop!(1038 assert_noop!(1037 TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1039 TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1038 "You do not have permissions to modify this collection"1040 Error::<Test>::NoPermission1039 );1041 );1040 assert_eq!(TemplateModule::white_list(collection_id)[0], 2);1042 assert_eq!(TemplateModule::white_list(collection_id)[0], 2);1041 });1043 });104910511050 assert_noop!(1052 assert_noop!(1051 TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),1053 TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),1052 "This collection does not exist"1054 Error::<Test>::CollectionNotFound1053 );1055 );1054 });1056 });1055}1057}1067 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));1069 assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));1068 assert_noop!(1070 assert_noop!(1069 TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1071 TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1070 "This collection does not exist"1072 Error::<Test>::CollectionNotFound1071 );1073 );1072 assert_eq!(TemplateModule::white_list(collection_id).len(), 0);1074 assert_eq!(TemplateModule::white_list(collection_id).len(), 0);1073 });1075 });111911211120 assert_noop!(1122 assert_noop!(1121 TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1123 TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1122 "Address is not in white list"1124 Error::<Test>::AddresNotInWhiteList1123 );1125 );1124 });1126 });1125}1127}115511571156 assert_noop!(1158 assert_noop!(1157 TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1159 TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1158 "Address is not in white list"1160 Error::<Test>::AddresNotInWhiteList1159 );1161 );1160 });1162 });1161}1163}118211841183 assert_noop!(1185 assert_noop!(1184 TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1186 TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1185 "Address is not in white list"1187 Error::<Test>::AddresNotInWhiteList1186 );1188 );1187 });1189 });1188}1190}121912211220 assert_noop!(1222 assert_noop!(1221 TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1223 TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1222 "Address is not in white list"1224 Error::<Test>::AddresNotInWhiteList1223 );1225 );1224 });1226 });1225}1227}1244 ));1246 ));1245 assert_noop!(1247 assert_noop!(1246 TemplateModule::burn_item(origin1.clone(), 1, 1),1248 TemplateModule::burn_item(origin1.clone(), 1, 1),1247 "Address is not in white list"1249 Error::<Test>::AddresNotInWhiteList1248 );1250 );1249 });1251 });1250}1252}1267 // do approve1269 // do approve1268 assert_noop!(1270 assert_noop!(1269 TemplateModule::approve(origin1.clone(), 1, 1, 1),1271 TemplateModule::approve(origin1.clone(), 1, 1, 1),1270 "Address is not in white list"1272 Error::<Test>::AddresNotInWhiteList1271 );1273 );1272 });1274 });1273}1275}141614181417 assert_noop!(1419 assert_noop!(1418 TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1420 TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1419 "Public minting is not allowed for this collection"1421 Error::<Test>::PublicMintingNotAllowed1420 );1422 );1421 });1423 });1422}1424}144514471446 assert_noop!(1448 assert_noop!(1447 TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1449 TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1448 "Public minting is not allowed for this collection"1450 Error::<Test>::PublicMintingNotAllowed1449 );1451 );1450 });1452 });1451}1453}153315351534 assert_noop!(1536 assert_noop!(1535 TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1537 TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1536 "Address is not in white list"1538 Error::<Test>::AddresNotInWhiteList1537 );1539 );1538 });1540 });1539}1541}1603 col_desc1.clone(),1605 col_desc1.clone(),1604 token_prefix1.clone(),1606 token_prefix1.clone(),1605 CollectionMode::NFT1607 CollectionMode::NFT1606 ), "Total collections bound exceeded");1608 ), Error::<Test>::TotalCollectionsLimitExceeded);1607 });1609 });1608}1610}160916111646 1,1648 1,1647 1,1649 1,1648 data.into()1650 data.into()1649 ), "Owned tokens by a single address bound exceeded");1651 ), Error::<Test>::AddressOwnershipLimitExceeded);1650 });1652 });1651}1653}165216541692 let origin1 = Origin::signed(1);1694 let origin1 = Origin::signed(1);169316951694 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));1696 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));1695 assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), "Number of collection admins bound exceeded");1697 assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), Error::<Test>::CollectionAdminsLimitExceeded);1696 });1698 });1697}1699}16981700runtime/src/nft_weights.rsdiffbeforeafterboth--- 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))
+ // }
}