difftreelog
feature: make collection creation methods `payable`
in: master
19 files changed
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -560,6 +560,7 @@
selector: u32,
args: Vec<MethodArg>,
has_normal_args: bool,
+ has_value_args: bool,
mutability: Mutability,
result: Type,
weight: Option<Expr>,
@@ -647,14 +648,20 @@
.unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));
let mut selector_str = camel_name.clone();
selector_str.push('(');
- let mut has_normal_args = false;
- for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {
- if i != 0 {
- selector_str.push(',');
+ let mut normal_args_count = 0u32;
+ let mut has_value_args = false;
+ for arg in args.iter() {
+ if arg.is_value() {
+ has_value_args = true;
+ } else if !arg.is_special() {
+ if normal_args_count != 0 {
+ selector_str.push(',');
+ }
+ write!(selector_str, "{}", arg.selector_ty()).unwrap();
+ normal_args_count = normal_args_count.saturating_add(1);
}
- write!(selector_str, "{}", arg.selector_ty()).unwrap();
- has_normal_args = true;
}
+ let has_normal_args = normal_args_count > 0;
selector_str.push(')');
let selector = fn_selector_str(&selector_str);
@@ -667,6 +674,7 @@
selector,
args,
has_normal_args,
+ has_value_args,
mutability,
result: result.clone(),
weight,
@@ -823,7 +831,7 @@
let docs = &self.docs;
let selector_str = &self.selector_str;
let selector = self.selector;
-
+ let is_payable = self.has_value_args;
quote! {
SolidityFunction {
docs: &[#(#docs),*],
@@ -831,6 +839,7 @@
selector: #selector,
name: #camel_name,
mutability: #mutability,
+ is_payable: #is_payable,
args: (
#(
#args,
crates/evm-coder/src/solidity.rsdiffbeforeafterboth--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -422,6 +422,7 @@
pub args: A,
pub result: R,
pub mutability: SolidityMutability,
+ pub is_payable: bool,
}
impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {
fn solidity_name(
@@ -452,6 +453,9 @@
SolidityMutability::View => write!(writer, " view")?,
SolidityMutability::Mutable => {}
}
+ if self.is_payable {
+ write!(writer, " payable")?;
+ }
if !self.result.is_empty() {
write!(writer, " returns (")?;
self.result.solidity_name(writer, tc)?;
pallets/common/src/dispatch.rsdiffbeforeafterboth--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -78,6 +78,7 @@
/// * `data` - Description of the created collection.
fn create(
sender: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError>;
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -866,6 +866,7 @@
/// * `flags` - Extra flags to store.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
flags: CollectionFlags,
) -> Result<CollectionId, DispatchError> {
@@ -939,7 +940,7 @@
),
);
<T as Config>::Currency::settle(
- owner.as_sub(),
+ payer.as_sub(),
imbalance,
WithdrawReasons::TRANSFER,
ExistenceRequirement::KeepAlive,
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth--- a/pallets/foreign-assets/src/lib.rs
+++ b/pallets/foreign-assets/src/lib.rs
@@ -309,9 +309,10 @@
mode: CollectionMode::Fungible(md.decimals),
..Default::default()
};
-
+ let owner = T::CrossAccountId::from_sub(owner);
let bounded_collection_id = <PalletFungible<T>>::init_foreign_collection(
- CrossAccountId::from_sub(owner),
+ owner.clone(),
+ owner,
data,
)?;
let foreign_asset_id =
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -210,18 +210,21 @@
/// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())
+ <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())
}
/// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise.
pub fn init_foreign_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
let id = <PalletCommon<T>>::init_collection(
owner,
+ payer,
data,
CollectionFlags {
foreign: true,
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -405,11 +405,13 @@
/// - `data`: Contains settings for collection limits and permissions.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
is_external: bool,
) -> Result<CollectionId, DispatchError> {
<PalletCommon<T>>::init_collection(
owner,
+ payer,
data,
CollectionFlags {
external: is_external,
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -1448,7 +1448,7 @@
data: CreateCollectionData<T::AccountId>,
properties: impl Iterator<Item = Property>,
) -> Result<CollectionId, DispatchError> {
- let collection_id = <PalletNft<T>>::init_collection(sender, data, true);
+ let collection_id = <PalletNft<T>>::init_collection(sender.clone(), sender, data, true);
if let Err(DispatchError::Arithmetic(_)) = &collection_id {
return Err(<Error<T>>::NoAvailableCollectionId.into());
pallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-equip/src/lib.rs
+++ b/pallets/proxy-rmrk-equip/src/lib.rs
@@ -251,7 +251,7 @@
};
let collection_id_res =
- <PalletNft<T>>::init_collection(cross_sender.clone(), data, true);
+ <PalletNft<T>>::init_collection(cross_sender.clone(), cross_sender.clone(), data, true);
if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {
return Err(<Error<T>>::NoAvailableBaseId.into());
pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -373,9 +373,10 @@
/// - `data`: Contains settings for collection limits and permissions.
pub fn init_collection(
owner: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
- <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())
+ <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())
}
/// Destroy RFT collection
pallets/unique/src/eth/mod.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation of CollectionHelpers contract.1819use core::marker::PhantomData;20use ethereum as _;21use evm_coder::{execution::*, generate_stubgen, solidity_interface, solidity, weight, types::*};22use frame_support::traits::Get;23use pallet_common::{24 CollectionById,25 dispatch::CollectionDispatch,26 erc::{27 CollectionHelpersEvents,28 static_property::{key, value as property_value},29 },30};31use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};33use up_data_structs::{34 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,35 CollectionMode, PropertyValue,36};3738use crate::{Config, SelfWeightOf, weights::WeightInfo};3940use sp_std::vec::Vec;41use alloc::format;4243/// See [`CollectionHelpersCall`]44pub struct EvmCollectionHelpers<T: Config>(SubstrateRecorder<T>);45impl<T: Config> WithRecorder<T> for EvmCollectionHelpers<T> {46 fn recorder(&self) -> &SubstrateRecorder<T> {47 &self.048 }4950 fn into_recorder(self) -> SubstrateRecorder<T> {51 self.052 }53}5455fn convert_data<T: Config>(56 caller: caller,57 name: string,58 description: string,59 token_prefix: string,60 base_uri: string,61) -> Result<(62 T::CrossAccountId,63 CollectionName,64 CollectionDescription,65 CollectionTokenPrefix,66 PropertyValue,67)> {68 let caller = T::CrossAccountId::from_eth(caller);69 let name = name70 .encode_utf16()71 .collect::<Vec<u16>>()72 .try_into()73 .map_err(|_| error_field_too_long(stringify!(name), CollectionName::bound()))?;74 let description = description75 .encode_utf16()76 .collect::<Vec<u16>>()77 .try_into()78 .map_err(|_| {79 error_field_too_long(stringify!(description), CollectionDescription::bound())80 })?;81 let token_prefix = token_prefix.into_bytes().try_into().map_err(|_| {82 error_field_too_long(stringify!(token_prefix), CollectionTokenPrefix::bound())83 })?;84 let base_uri_value = base_uri85 .into_bytes()86 .try_into()87 .map_err(|_| error_field_too_long(stringify!(token_prefix), PropertyValue::bound()))?;88 Ok((caller, name, description, token_prefix, base_uri_value))89}9091fn make_data<T: Config>(92 name: CollectionName,93 mode: CollectionMode,94 description: CollectionDescription,95 token_prefix: CollectionTokenPrefix,96 base_uri_value: PropertyValue,97 add_properties: bool,98) -> Result<CreateCollectionData<T::AccountId>> {99 let mut properties = up_data_structs::CollectionPropertiesVec::default();100 let mut token_property_permissions =101 up_data_structs::CollectionPropertiesPermissionsVec::default();102103 token_property_permissions104 .try_push(up_data_structs::PropertyKeyPermission {105 key: key::url(),106 permission: up_data_structs::PropertyPermission {107 mutable: false,108 collection_admin: true,109 token_owner: false,110 },111 })112 .map_err(|e| Error::Revert(format!("{:?}", e)))?;113114 if add_properties {115 token_property_permissions116 .try_push(up_data_structs::PropertyKeyPermission {117 key: key::suffix(),118 permission: up_data_structs::PropertyPermission {119 mutable: false,120 collection_admin: true,121 token_owner: false,122 },123 })124 .map_err(|e| Error::Revert(format!("{:?}", e)))?;125126 properties127 .try_push(up_data_structs::Property {128 key: key::schema_name(),129 value: property_value::erc721(),130 })131 .map_err(|e| Error::Revert(format!("{:?}", e)))?;132133 if !base_uri_value.is_empty() {134 properties135 .try_push(up_data_structs::Property {136 key: key::base_uri(),137 value: base_uri_value,138 })139 .map_err(|e| Error::Revert(format!("{:?}", e)))?;140 }141 }142143 let data = CreateCollectionData {144 name,145 mode,146 description,147 token_prefix,148 token_property_permissions,149 properties,150 ..Default::default()151 };152 Ok(data)153}154155fn create_refungible_collection_internal<156 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,157>(158 caller: caller,159 name: string,160 description: string,161 token_prefix: string,162 base_uri: string,163 add_properties: bool,164) -> Result<address> {165 let (caller, name, description, token_prefix, base_uri_value) =166 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;167 let data = make_data::<T>(168 name,169 CollectionMode::ReFungible,170 description,171 token_prefix,172 base_uri_value,173 add_properties,174 )?;175176 let collection_id = T::CollectionDispatch::create(caller.clone(), data)177 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;178 let address = pallet_common::eth::collection_id_to_address(collection_id);179 Ok(address)180}181182/// @title Contract, which allows users to operate with collections183#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]184impl<T> EvmCollectionHelpers<T>185where186 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,187{188 /// Create an NFT collection189 /// @param name Name of the collection190 /// @param description Informative description of the collection191 /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications192 /// @return address Address of the newly created collection193 #[weight(<SelfWeightOf<T>>::create_collection())]194 fn create_nonfungible_collection(195 &mut self,196 caller: caller,197 value: value,198 name: string,199 description: string,200 token_prefix: string,201 ) -> Result<address> {202 let (caller, name, description, token_prefix, _base_uri_value) =203 convert_data::<T>(caller, name, description, token_prefix, "".into())?;204 let data = make_data::<T>(205 name,206 CollectionMode::NFT,207 description,208 token_prefix,209 Default::default(),210 false,211 )?;212 let collection_id = T::CollectionDispatch::create(caller, data)213 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;214215 let address = pallet_common::eth::collection_id_to_address(collection_id);216 Ok(address)217 }218219 #[weight(<SelfWeightOf<T>>::create_collection())]220 #[solidity(rename_selector = "createERC721MetadataCompatibleCollection")]221 fn create_nonfungible_collection_with_properties(222 &mut self,223 caller: caller,224 name: string,225 description: string,226 token_prefix: string,227 base_uri: string,228 ) -> Result<address> {229 let (caller, name, description, token_prefix, base_uri_value) =230 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;231 let data = make_data::<T>(232 name,233 CollectionMode::NFT,234 description,235 token_prefix,236 base_uri_value,237 true,238 )?;239 let collection_id = T::CollectionDispatch::create(caller, data)240 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;241242 let address = pallet_common::eth::collection_id_to_address(collection_id);243 Ok(address)244 }245246 #[weight(<SelfWeightOf<T>>::create_collection())]247 #[solidity(rename_selector = "createRFTCollection")]248 fn create_refungible_collection(249 &mut self,250 caller: caller,251 name: string,252 description: string,253 token_prefix: string,254 ) -> Result<address> {255 create_refungible_collection_internal::<T>(256 caller,257 name,258 description,259 token_prefix,260 Default::default(),261 false,262 )263 }264265 #[weight(<SelfWeightOf<T>>::create_collection())]266 #[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")]267 fn create_refungible_collection_with_properties(268 &mut self,269 caller: caller,270 name: string,271 description: string,272 token_prefix: string,273 base_uri: string,274 ) -> Result<address> {275 create_refungible_collection_internal::<T>(276 caller,277 name,278 description,279 token_prefix,280 base_uri,281 true,282 )283 }284285 /// Check if a collection exists286 /// @param collectionAddress Address of the collection in question287 /// @return bool Does the collection exist?288 fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {289 if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {290 let collection_id = id;291 return Ok(<CollectionById<T>>::contains_key(collection_id));292 }293294 Ok(false)295 }296}297298/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]299pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);300impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>301 for CollectionHelpersOnMethodCall<T>302{303 fn is_reserved(contract: &sp_core::H160) -> bool {304 contract == &T::ContractAddress::get()305 }306307 fn is_used(contract: &sp_core::H160) -> bool {308 contract == &T::ContractAddress::get()309 }310311 fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {312 if handle.code_address() != T::ContractAddress::get() {313 return None;314 }315316 let helpers =317 EvmCollectionHelpers::<T>(SubstrateRecorder::<T>::new(handle.remaining_gas()));318 pallet_evm_coder_substrate::call(handle, helpers)319 }320321 fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {322 (contract == &T::ContractAddress::get())323 .then(|| include_bytes!("./stubs/CollectionHelpers.raw").to_vec())324 }325}326327generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);328generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);329330fn error_field_too_long(feild: &str, bound: usize) -> Error {331 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))332}pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth--- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol
+++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol
@@ -36,7 +36,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -52,7 +52,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -68,7 +68,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
@@ -84,7 +84,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) public returns (address) {
+ ) public payable returns (address) {
require(false, stub_error);
name;
description;
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -344,8 +344,8 @@
let sender = ensure_signed(origin)?;
// =========
-
- let _id = T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;
+ let sender = T::CrossAccountId::from_sub(sender);
+ let _id = T::CollectionDispatch::create(sender.clone(), sender, data)?;
Ok(())
}
runtime/common/dispatch.rsdiffbeforeafterboth--- a/runtime/common/dispatch.rs
+++ b/runtime/common/dispatch.rs
@@ -55,21 +55,22 @@
{
fn create(
sender: T::CrossAccountId,
+ payer: T::CrossAccountId,
data: CreateCollectionData<T::AccountId>,
) -> Result<CollectionId, DispatchError> {
let id = match data.mode {
- CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,
+ CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, payer, data, false)?,
CollectionMode::Fungible(decimal_points) => {
// check params
ensure!(
decimal_points <= MAX_DECIMAL_POINTS,
pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded
);
- <PalletFungible<T>>::init_collection(sender, data)?
+ <PalletFungible<T>>::init_collection(sender, payer, data)?
}
#[cfg(feature = "refungible")]
- CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,
+ CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, payer, data)?,
#[cfg(not(feature = "refungible"))]
CollectionMode::ReFungible => return unsupported!(T),
tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth--- a/tests/src/eth/api/CollectionHelpers.sol
+++ b/tests/src/eth/api/CollectionHelpers.sol
@@ -31,7 +31,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xa634a5f9,
/// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)
@@ -40,7 +40,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xab173450,
/// or in textual repr: createRFTCollection(string,string,string)
@@ -48,7 +48,7 @@
string memory name,
string memory description,
string memory tokenPrefix
- ) external returns (address);
+ ) external payable returns (address);
/// @dev EVM selector for this function is: 0xa5596388,
/// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)
@@ -57,7 +57,7 @@
string memory description,
string memory tokenPrefix,
string memory baseUri
- ) external returns (address);
+ ) external payable returns (address);
/// Check if a collection exists
/// @param collectionAddress Address of the collection in question
tests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth--- a/tests/src/eth/collectionHelpersAbi.json
+++ b/tests/src/eth/collectionHelpersAbi.json
@@ -27,7 +27,7 @@
],
"name": "createERC721MetadataCompatibleCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -39,7 +39,7 @@
],
"name": "createERC721MetadataCompatibleRFTCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -50,7 +50,7 @@
],
"name": "createNonfungibleCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
@@ -61,7 +61,7 @@
],
"name": "createRFTCollection",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
- "stateMutability": "nonpayable",
+ "stateMutability": "payable",
"type": "function"
},
{
tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth--- a/tests/src/eth/fractionalizer/Fractionalizer.sol
+++ b/tests/src/eth/fractionalizer/Fractionalizer.sol
@@ -18,7 +18,8 @@
mapping(address => bool) nftCollectionAllowList;
mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;
mapping(address => Token) public rft2nftMapping;
- bytes32 refungibleCollectionType = keccak256(bytes("ReFungible"));
+ //use constant to reduce gas cost
+ bytes32 constant refungibleCollectionType = keccak256(bytes("ReFungible"));
receive() external payable onlyOwner {}
@@ -51,11 +52,12 @@
/// Throws if `msg.sender` is not owner or admin of provided RFT collection.
/// Can only be called by contract owner.
/// @param _collection address of RFT collection.
- function setRFTCollection(address _collection) public onlyOwner {
+ function setRFTCollection(address _collection) external onlyOwner {
require(rftCollection == address(0), "RFT collection is already set");
UniqueRefungible refungibleContract = UniqueRefungible(_collection);
string memory collectionType = refungibleContract.uniqueCollectionType();
+ // compare hashed to reduce gas cost
require(
keccak256(bytes(collectionType)) == refungibleCollectionType,
"Wrong collection type. Collection is not refungible."
@@ -79,7 +81,7 @@
string calldata _name,
string calldata _description,
string calldata _tokenPrefix
- ) public onlyOwner {
+ ) external onlyOwner {
require(rftCollection == address(0), "RFT collection is already set");
address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection(_name, _description, _tokenPrefix);
@@ -90,7 +92,7 @@
/// @dev Can only be called by contract owner.
/// @param collection NFT token address.
/// @param status `true` to allow and `false` to disallow NFT token.
- function setNftCollectionIsAllowed(address collection, bool status) public onlyOwner {
+ function setNftCollectionIsAllowed(address collection, bool status) external onlyOwner {
nftCollectionAllowList[collection] = status;
emit AllowListSet(collection, status);
}
@@ -109,7 +111,7 @@
address _collection,
uint256 _token,
uint128 _pieces
- ) public {
+ ) external {
require(rftCollection != address(0), "RFT collection is not set");
UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
require(
@@ -148,7 +150,7 @@
/// Throws if `msg.sender` isn't owner of all RFT token pieces.
/// @param _collection RFT collection address
/// @param _token id of RFT token
- function rft2nft(address _collection, uint256 _token) public {
+ function rft2nft(address _collection, uint256 _token) external {
require(rftCollection != address(0), "RFT collection is not set");
require(rftCollection == _collection, "Wrong RFT collection");
UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);
tests/src/eth/payable.test.tsdiffbeforeafterboth--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -140,16 +140,13 @@
});
itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {
- const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
const deployer = await helper.eth.createAccountWithBalance(donor);
const caller = await helper.eth.createAccountWithBalance(donor);
const contract = await deployProxyContract(helper, deployer);
-
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
- const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller})).events.CollectionCreated.returnValues.collection;
+ const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection;
const initialCallerBalance = await helper.balance.getEthereum(caller);
const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
await contract.methods.mintNftToken(collectionAddress).send({from: caller});
@@ -160,22 +157,18 @@
});
itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {
- const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();
-
+ const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();
const deployer = await helper.eth.createAccountWithBalance(donor);
const caller = await helper.eth.createAccountWithBalance(donor);
const contract = await deployProxyContract(helper, deployer);
-
- const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
const initialCallerBalance = await helper.balance.getEthereum(caller);
const initialContractBalance = await helper.balance.getEthereum(contract.options.address);
- await contract.methods.createNonfungibleCollection().send({from: caller});
+ await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)});
const finalCallerBalance = await helper.balance.getEthereum(caller);
const finalContractBalance = await helper.balance.getEthereum(contract.options.address);
expect(finalCallerBalance < initialCallerBalance).to.be.true;
- expect(finalContractBalance < initialContractBalance).to.be.true;
+ expect(finalContractBalance == initialContractBalance).to.be.true;
});
async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {
@@ -189,6 +182,8 @@
import {CollectionHelpers} from "../api/CollectionHelpers.sol";
import {UniqueNFT} from "../api/UniqueNFT.sol";
+ error Value(uint256 value);
+
contract ProxyContract {
bool value = false;
address flipper;
@@ -207,30 +202,30 @@
Flipper(flipper).flip();
}
- function createNonfungibleCollection() public {
+ function createNonfungibleCollection() external payable {
address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;
- address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection("A", "B", "C");
+ address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection{value: msg.value}("A", "B", "C");
emit CollectionCreated(nftCollection);
}
- function mintNftToken(address collectionAddress) public {
+ function mintNftToken(address collectionAddress) external {
UniqueNFT collection = UniqueNFT(collectionAddress);
uint256 tokenId = collection.nextTokenId();
collection.mint(msg.sender, tokenId);
emit TokenMinted(tokenId);
}
- function getValue() public view returns (bool) {
+ function getValue() external view returns (bool) {
return Flipper(flipper).getValue();
}
}
contract Flipper {
bool value = false;
- function flip() public {
+ function flip() external {
value = !value;
}
- function getValue() public view returns (bool) {
+ function getValue() external view returns (bool) {
return value;
}
}