difftreelog
Merge branch 'develop' into feature/NFTPAR-142
in: master
# Conflicts: # pallets/nft/src/lib.rs
5 files changed
Cargo.lockdiffbeforeafterboth3737 "frame-support",3737 "frame-support",3738 "frame-system",3738 "frame-system",3739 "log",3739 "log",3740 "pallet-balances",3740 "pallet-contracts",3741 "pallet-contracts",3742 "pallet-randomness-collective-flip",3743 "pallet-timestamp",3741 "pallet-transaction-payment",3744 "pallet-transaction-payment",3742 "parity-scale-codec",3745 "parity-scale-codec",3743 "serde",3746 "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.rsdiffbeforeafterboth--- 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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::NoPermission
);
});
}
@@ -947,7 +949,7 @@
assert_noop!(
TemplateModule::add_to_white_list(origin1.clone(), 1, 2),
- "This collection does not exist"
+ Error::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::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::<Test>::AddresNotInWhiteList
);
});
}
@@ -1155,7 +1157,7 @@
assert_noop!(
TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),
- "Address is not in white list"
+ Error::<Test>::AddresNotInWhiteList
);
});
}
@@ -1182,7 +1184,7 @@
assert_noop!(
TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),
- "Address is not in white list"
+ Error::<Test>::AddresNotInWhiteList
);
});
}
@@ -1219,7 +1221,7 @@
assert_noop!(
TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),
- "Address is not in white list"
+ Error::<Test>::AddresNotInWhiteList
);
});
}
@@ -1244,7 +1246,7 @@
));
assert_noop!(
TemplateModule::burn_item(origin1.clone(), 1, 1),
- "Address is not in white list"
+ Error::<Test>::AddresNotInWhiteList
);
});
}
@@ -1267,7 +1269,7 @@
// do approve
assert_noop!(
TemplateModule::approve(origin1.clone(), 1, 1, 1),
- "Address is not in white list"
+ Error::<Test>::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::<Test>::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::<Test>::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::<Test>::AddresNotInWhiteList
);
});
}
@@ -1603,7 +1605,7 @@
col_desc1.clone(),
token_prefix1.clone(),
CollectionMode::NFT
- ), "Total collections bound exceeded");
+ ), Error::<Test>::TotalCollectionsLimitExceeded);
});
}
@@ -1646,7 +1648,7 @@
1,
1,
data.into()
- ), "Owned tokens by a single address bound exceeded");
+ ), Error::<Test>::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::<Test>::CollectionAdminsLimitExceeded);
});
}
runtime/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))
+ // }
}