difftreelog
feature: make collection creation methods `payable`
in: master
19 files changed
crates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth560 selector: u32,560 selector: u32,561 args: Vec<MethodArg>,561 args: Vec<MethodArg>,562 has_normal_args: bool,562 has_normal_args: bool,563 has_value_args: bool,563 mutability: Mutability,564 mutability: Mutability,564 result: Type,565 result: Type,565 weight: Option<Expr>,566 weight: Option<Expr>,647 .unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));648 .unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string()));648 let mut selector_str = camel_name.clone();649 let mut selector_str = camel_name.clone();649 selector_str.push('(');650 selector_str.push('(');651 let mut normal_args_count = 0u32;650 let mut has_normal_args = false;652 let mut has_value_args = false;651 for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() {653 for arg in args.iter() {654 if arg.is_value() {655 has_value_args = true;656 } else if !arg.is_special() {652 if i != 0 {657 if normal_args_count != 0 {653 selector_str.push(',');658 selector_str.push(',');654 }659 }655 write!(selector_str, "{}", arg.selector_ty()).unwrap();660 write!(selector_str, "{}", arg.selector_ty()).unwrap();656 has_normal_args = true;661 normal_args_count = normal_args_count.saturating_add(1);657 }662 }663 }664 let has_normal_args = normal_args_count > 0;658 selector_str.push(')');665 selector_str.push(')');659 let selector = fn_selector_str(&selector_str);666 let selector = fn_selector_str(&selector_str);660667667 selector,674 selector,668 args,675 args,669 has_normal_args,676 has_normal_args,677 has_value_args,670 mutability,678 mutability,671 result: result.clone(),679 result: result.clone(),672 weight,680 weight,823 let docs = &self.docs;831 let docs = &self.docs;824 let selector_str = &self.selector_str;832 let selector_str = &self.selector_str;825 let selector = self.selector;833 let selector = self.selector;826834 let is_payable = self.has_value_args;827 quote! {835 quote! {828 SolidityFunction {836 SolidityFunction {829 docs: &[#(#docs),*],837 docs: &[#(#docs),*],830 selector_str: #selector_str,838 selector_str: #selector_str,831 selector: #selector,839 selector: #selector,832 name: #camel_name,840 name: #camel_name,833 mutability: #mutability,841 mutability: #mutability,842 is_payable: #is_payable,834 args: (843 args: (835 #(844 #(836 #args,845 #args,crates/evm-coder/src/solidity.rsdiffbeforeafterboth422 pub args: A,422 pub args: A,423 pub result: R,423 pub result: R,424 pub mutability: SolidityMutability,424 pub mutability: SolidityMutability,425 pub is_payable: bool,425}426}426impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {427impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {427 fn solidity_name(428 fn solidity_name(452 SolidityMutability::View => write!(writer, " view")?,453 SolidityMutability::View => write!(writer, " view")?,453 SolidityMutability::Mutable => {}454 SolidityMutability::Mutable => {}454 }455 }456 if self.is_payable {457 write!(writer, " payable")?;458 }455 if !self.result.is_empty() {459 if !self.result.is_empty() {456 write!(writer, " returns (")?;460 write!(writer, " returns (")?;457 self.result.solidity_name(writer, tc)?;461 self.result.solidity_name(writer, tc)?;pallets/common/src/dispatch.rsdiffbeforeafterboth78 /// * `data` - Description of the created collection.78 /// * `data` - Description of the created collection.79 fn create(79 fn create(80 sender: T::CrossAccountId,80 sender: T::CrossAccountId,81 payer: T::CrossAccountId,81 data: CreateCollectionData<T::AccountId>,82 data: CreateCollectionData<T::AccountId>,82 ) -> Result<CollectionId, DispatchError>;83 ) -> Result<CollectionId, DispatchError>;8384pallets/common/src/lib.rsdiffbeforeafterboth866 /// * `flags` - Extra flags to store.866 /// * `flags` - Extra flags to store.867 pub fn init_collection(867 pub fn init_collection(868 owner: T::CrossAccountId,868 owner: T::CrossAccountId,869 payer: T::CrossAccountId,869 data: CreateCollectionData<T::AccountId>,870 data: CreateCollectionData<T::AccountId>,870 flags: CollectionFlags,871 flags: CollectionFlags,871 ) -> Result<CollectionId, DispatchError> {872 ) -> Result<CollectionId, DispatchError> {939 ),940 ),940 );941 );941 <T as Config>::Currency::settle(942 <T as Config>::Currency::settle(942 owner.as_sub(),943 payer.as_sub(),943 imbalance,944 imbalance,944 WithdrawReasons::TRANSFER,945 WithdrawReasons::TRANSFER,945 ExistenceRequirement::KeepAlive,946 ExistenceRequirement::KeepAlive,pallets/foreign-assets/src/lib.rsdiffbeforeafterboth309 mode: CollectionMode::Fungible(md.decimals),309 mode: CollectionMode::Fungible(md.decimals),310 ..Default::default()310 ..Default::default()311 };311 };312312 let owner = T::CrossAccountId::from_sub(owner);313 let bounded_collection_id = <PalletFungible<T>>::init_foreign_collection(313 let bounded_collection_id = <PalletFungible<T>>::init_foreign_collection(314 CrossAccountId::from_sub(owner),314 owner.clone(),315 owner,315 data,316 data,316 )?;317 )?;317 let foreign_asset_id =318 let foreign_asset_id =pallets/fungible/src/lib.rsdiffbeforeafterboth210 /// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.210 /// Initializes the collection. Returns [CollectionId] on success, [DispatchError] otherwise.211 pub fn init_collection(211 pub fn init_collection(212 owner: T::CrossAccountId,212 owner: T::CrossAccountId,213 payer: T::CrossAccountId,213 data: CreateCollectionData<T::AccountId>,214 data: CreateCollectionData<T::AccountId>,214 ) -> Result<CollectionId, DispatchError> {215 ) -> Result<CollectionId, DispatchError> {215 <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())216 <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())216 }217 }217218218 /// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise.219 /// Initializes the collection with ForeignCollection flag. Returns [CollectionId] on success, [DispatchError] otherwise.219 pub fn init_foreign_collection(220 pub fn init_foreign_collection(220 owner: T::CrossAccountId,221 owner: T::CrossAccountId,222 payer: T::CrossAccountId,221 data: CreateCollectionData<T::AccountId>,223 data: CreateCollectionData<T::AccountId>,222 ) -> Result<CollectionId, DispatchError> {224 ) -> Result<CollectionId, DispatchError> {223 let id = <PalletCommon<T>>::init_collection(225 let id = <PalletCommon<T>>::init_collection(224 owner,226 owner,227 payer,225 data,228 data,226 CollectionFlags {229 CollectionFlags {227 foreign: true,230 foreign: true,pallets/nonfungible/src/lib.rsdiffbeforeafterboth405 /// - `data`: Contains settings for collection limits and permissions.405 /// - `data`: Contains settings for collection limits and permissions.406 pub fn init_collection(406 pub fn init_collection(407 owner: T::CrossAccountId,407 owner: T::CrossAccountId,408 payer: T::CrossAccountId,408 data: CreateCollectionData<T::AccountId>,409 data: CreateCollectionData<T::AccountId>,409 is_external: bool,410 is_external: bool,410 ) -> Result<CollectionId, DispatchError> {411 ) -> Result<CollectionId, DispatchError> {411 <PalletCommon<T>>::init_collection(412 <PalletCommon<T>>::init_collection(412 owner,413 owner,414 payer,413 data,415 data,414 CollectionFlags {416 CollectionFlags {415 external: is_external,417 external: is_external,pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth1448 data: CreateCollectionData<T::AccountId>,1448 data: CreateCollectionData<T::AccountId>,1449 properties: impl Iterator<Item = Property>,1449 properties: impl Iterator<Item = Property>,1450 ) -> Result<CollectionId, DispatchError> {1450 ) -> Result<CollectionId, DispatchError> {1451 let collection_id = <PalletNft<T>>::init_collection(sender, data, true);1451 let collection_id = <PalletNft<T>>::init_collection(sender.clone(), sender, data, true);145214521453 if let Err(DispatchError::Arithmetic(_)) = &collection_id {1453 if let Err(DispatchError::Arithmetic(_)) = &collection_id {1454 return Err(<Error<T>>::NoAvailableCollectionId.into());1454 return Err(<Error<T>>::NoAvailableCollectionId.into());pallets/proxy-rmrk-equip/src/lib.rsdiffbeforeafterboth251 };251 };252252253 let collection_id_res =253 let collection_id_res =254 <PalletNft<T>>::init_collection(cross_sender.clone(), data, true);254 <PalletNft<T>>::init_collection(cross_sender.clone(), cross_sender.clone(), data, true);255255256 if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {256 if let Err(DispatchError::Arithmetic(_)) = &collection_id_res {257 return Err(<Error<T>>::NoAvailableBaseId.into());257 return Err(<Error<T>>::NoAvailableBaseId.into());pallets/refungible/src/lib.rsdiffbeforeafterboth373 /// - `data`: Contains settings for collection limits and permissions.373 /// - `data`: Contains settings for collection limits and permissions.374 pub fn init_collection(374 pub fn init_collection(375 owner: T::CrossAccountId,375 owner: T::CrossAccountId,376 payer: T::CrossAccountId,376 data: CreateCollectionData<T::AccountId>,377 data: CreateCollectionData<T::AccountId>,377 ) -> Result<CollectionId, DispatchError> {378 ) -> Result<CollectionId, DispatchError> {378 <PalletCommon<T>>::init_collection(owner, data, CollectionFlags::default())379 <PalletCommon<T>>::init_collection(owner, payer, data, CollectionFlags::default())379 }380 }380381381 /// Destroy RFT collection382 /// Destroy RFT collectionpallets/unique/src/eth/mod.rsdiffbeforeafterboth28 static_property::{key, value as property_value},28 static_property::{key, value as property_value},29 },29 },30};30};31use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};31use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};32use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};33use up_data_structs::{33use up_data_structs::{34 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,34 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,156 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,156 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,157>(157>(158 caller: caller,158 caller: caller,159 value: value,159 name: string,160 name: string,160 description: string,161 description: string,161 token_prefix: string,162 token_prefix: string,172 base_uri_value,173 base_uri_value,173 add_properties,174 add_properties,174 )?;175 )?;176 let value = value.as_u128();177 let creation_price: Result<u128> = T::CollectionCreationPrice::get()178 .try_into()179 .map_err(|_| "collection creation price should be convertible to u128".into());180 if value != creation_price? {181 return Err("Sent amount not equals to collection creation price".into());182 }183 let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());175184176 let collection_id = T::CollectionDispatch::create(caller.clone(), data)185 let collection_id = T::CollectionDispatch::create(caller.clone(), collection_helpers_address, data)177 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;186 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;178 let address = pallet_common::eth::collection_id_to_address(collection_id);187 let address = pallet_common::eth::collection_id_to_address(collection_id);179 Ok(address)188 Ok(address)183#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]192#[solidity_interface(name = CollectionHelpers, events(CollectionHelpersEvents))]184impl<T> EvmCollectionHelpers<T>193impl<T> EvmCollectionHelpers<T>185where194where186 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,195 T: Config + pallet_common::Config + pallet_nonfungible::Config + pallet_refungible::Config,187{196{188 /// Create an NFT collection197 /// Create an NFT collection189 /// @param name Name of the collection198 /// @param name Name of the collection209 Default::default(),218 Default::default(),210 false,219 false,211 )?;220 )?;221 let value = value.as_u128();222 let creation_price: Result<u128> = T::CollectionCreationPrice::get()223 .try_into()224 .map_err(|_| "collection creation price should be convertible to u128".into());225 let creation_price = creation_price?;226 if value != creation_price {227 return Err(format!("Sent amount not equals to collection creation price ({0})", creation_price).into());228 }229 let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());212 let collection_id = T::CollectionDispatch::create(caller, data)230 let collection_id =213 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;231 T::CollectionDispatch::create(caller, collection_helpers_address, data).map_err(dispatch_to_evm::<T>)?;214232215 let address = pallet_common::eth::collection_id_to_address(collection_id);233 let address = pallet_common::eth::collection_id_to_address(collection_id);216 Ok(address)234 Ok(address)221 fn create_nonfungible_collection_with_properties(239 fn create_nonfungible_collection_with_properties(222 &mut self,240 &mut self,223 caller: caller,241 caller: caller,242 value: value,224 name: string,243 name: string,225 description: string,244 description: string,226 token_prefix: string,245 token_prefix: string,236 base_uri_value,255 base_uri_value,237 true,256 true,238 )?;257 )?;258 let value = value.as_u128();259 let creation_price: Result<u128> = T::CollectionCreationPrice::get()260 .try_into()261 .map_err(|_| "collection creation price should be convertible to u128".into());262 if value != creation_price? {263 return Err("Sent amount not equals to collection creation price".into());264 }265 let collection_helpers_address = T::CrossAccountId::from_eth(<T as pallet_common::Config>::ContractAddress::get());239 let collection_id = T::CollectionDispatch::create(caller, data)266 let collection_id = T::CollectionDispatch::create(caller, collection_helpers_address, data)240 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;267 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;241268242 let address = pallet_common::eth::collection_id_to_address(collection_id);269 let address = pallet_common::eth::collection_id_to_address(collection_id);248 fn create_refungible_collection(275 fn create_refungible_collection(249 &mut self,276 &mut self,250 caller: caller,277 caller: caller,278 value: value,251 name: string,279 name: string,252 description: string,280 description: string,253 token_prefix: string,281 token_prefix: string,254 ) -> Result<address> {282 ) -> Result<address> {255 create_refungible_collection_internal::<T>(283 create_refungible_collection_internal::<T>(256 caller,284 caller,285 value,257 name,286 name,258 description,287 description,259 token_prefix,288 token_prefix,267 fn create_refungible_collection_with_properties(296 fn create_refungible_collection_with_properties(268 &mut self,297 &mut self,269 caller: caller,298 caller: caller,299 value: value,270 name: string,300 name: string,271 description: string,301 description: string,272 token_prefix: string,302 token_prefix: string,273 base_uri: string,303 base_uri: string,274 ) -> Result<address> {304 ) -> Result<address> {275 create_refungible_collection_internal::<T>(305 create_refungible_collection_internal::<T>(276 caller,306 caller,307 value,277 name,308 name,278 description,309 description,279 token_prefix,310 token_prefix,pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth36 string memory name,36 string memory name,37 string memory description,37 string memory description,38 string memory tokenPrefix38 string memory tokenPrefix39 ) public returns (address) {39 ) public payable returns (address) {40 require(false, stub_error);40 require(false, stub_error);41 name;41 name;42 description;42 description;52 string memory description,52 string memory description,53 string memory tokenPrefix,53 string memory tokenPrefix,54 string memory baseUri54 string memory baseUri55 ) public returns (address) {55 ) public payable returns (address) {56 require(false, stub_error);56 require(false, stub_error);57 name;57 name;58 description;58 description;68 string memory name,68 string memory name,69 string memory description,69 string memory description,70 string memory tokenPrefix70 string memory tokenPrefix71 ) public returns (address) {71 ) public payable returns (address) {72 require(false, stub_error);72 require(false, stub_error);73 name;73 name;74 description;74 description;84 string memory description,84 string memory description,85 string memory tokenPrefix,85 string memory tokenPrefix,86 string memory baseUri86 string memory baseUri87 ) public returns (address) {87 ) public payable returns (address) {88 require(false, stub_error);88 require(false, stub_error);89 name;89 name;90 description;90 description;pallets/unique/src/lib.rsdiffbeforeafterboth344 let sender = ensure_signed(origin)?;344 let sender = ensure_signed(origin)?;345345346 // =========346 // =========347347 let sender = T::CrossAccountId::from_sub(sender);348 let _id = T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;348 let _id = T::CollectionDispatch::create(sender.clone(), sender, data)?;349349350 Ok(())350 Ok(())351 }351 }runtime/common/dispatch.rsdiffbeforeafterboth55{55{56 fn create(56 fn create(57 sender: T::CrossAccountId,57 sender: T::CrossAccountId,58 payer: T::CrossAccountId,58 data: CreateCollectionData<T::AccountId>,59 data: CreateCollectionData<T::AccountId>,59 ) -> Result<CollectionId, DispatchError> {60 ) -> Result<CollectionId, DispatchError> {60 let id = match data.mode {61 let id = match data.mode {61 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,62 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, payer, data, false)?,62 CollectionMode::Fungible(decimal_points) => {63 CollectionMode::Fungible(decimal_points) => {63 // check params64 // check params64 ensure!(65 ensure!(65 decimal_points <= MAX_DECIMAL_POINTS,66 decimal_points <= MAX_DECIMAL_POINTS,66 pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded67 pallet_unique::Error::<T>::CollectionDecimalPointLimitExceeded67 );68 );68 <PalletFungible<T>>::init_collection(sender, data)?69 <PalletFungible<T>>::init_collection(sender, payer, data)?69 }70 }707171 #[cfg(feature = "refungible")]72 #[cfg(feature = "refungible")]72 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,73 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, payer, data)?,737474 #[cfg(not(feature = "refungible"))]75 #[cfg(not(feature = "refungible"))]75 CollectionMode::ReFungible => return unsupported!(T),76 CollectionMode::ReFungible => return unsupported!(T),tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth31 string memory name,31 string memory name,32 string memory description,32 string memory description,33 string memory tokenPrefix33 string memory tokenPrefix34 ) external returns (address);34 ) external payable returns (address);353536 /// @dev EVM selector for this function is: 0xa634a5f9,36 /// @dev EVM selector for this function is: 0xa634a5f9,37 /// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)37 /// or in textual repr: createERC721MetadataCompatibleCollection(string,string,string,string)40 string memory description,40 string memory description,41 string memory tokenPrefix,41 string memory tokenPrefix,42 string memory baseUri42 string memory baseUri43 ) external returns (address);43 ) external payable returns (address);444445 /// @dev EVM selector for this function is: 0xab173450,45 /// @dev EVM selector for this function is: 0xab173450,46 /// or in textual repr: createRFTCollection(string,string,string)46 /// or in textual repr: createRFTCollection(string,string,string)47 function createRFTCollection(47 function createRFTCollection(48 string memory name,48 string memory name,49 string memory description,49 string memory description,50 string memory tokenPrefix50 string memory tokenPrefix51 ) external returns (address);51 ) external payable returns (address);525253 /// @dev EVM selector for this function is: 0xa5596388,53 /// @dev EVM selector for this function is: 0xa5596388,54 /// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)54 /// or in textual repr: createERC721MetadataCompatibleRFTCollection(string,string,string,string)57 string memory description,57 string memory description,58 string memory tokenPrefix,58 string memory tokenPrefix,59 string memory baseUri59 string memory baseUri60 ) external returns (address);60 ) external payable returns (address);616162 /// Check if a collection exists62 /// Check if a collection exists63 /// @param collectionAddress Address of the collection in question63 /// @param collectionAddress Address of the collection in questiontests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth27 ],27 ],28 "name": "createERC721MetadataCompatibleCollection",28 "name": "createERC721MetadataCompatibleCollection",29 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],29 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],30 "stateMutability": "nonpayable",30 "stateMutability": "payable",31 "type": "function"31 "type": "function"32 },32 },33 {33 {39 ],39 ],40 "name": "createERC721MetadataCompatibleRFTCollection",40 "name": "createERC721MetadataCompatibleRFTCollection",41 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],41 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],42 "stateMutability": "nonpayable",42 "stateMutability": "payable",43 "type": "function"43 "type": "function"44 },44 },45 {45 {50 ],50 ],51 "name": "createNonfungibleCollection",51 "name": "createNonfungibleCollection",52 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],52 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],53 "stateMutability": "nonpayable",53 "stateMutability": "payable",54 "type": "function"54 "type": "function"55 },55 },56 {56 {61 ],61 ],62 "name": "createRFTCollection",62 "name": "createRFTCollection",63 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],63 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],64 "stateMutability": "nonpayable",64 "stateMutability": "payable",65 "type": "function"65 "type": "function"66 },66 },67 {67 {tests/src/eth/fractionalizer/Fractionalizer.soldiffbeforeafterboth18 mapping(address => bool) nftCollectionAllowList;18 mapping(address => bool) nftCollectionAllowList;19 mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;19 mapping(address => mapping(uint256 => uint256)) public nft2rftMapping;20 mapping(address => Token) public rft2nftMapping;20 mapping(address => Token) public rft2nftMapping;21 //use constant to reduce gas cost21 bytes32 refungibleCollectionType = keccak256(bytes("ReFungible"));22 bytes32 constant refungibleCollectionType = keccak256(bytes("ReFungible"));222323 receive() external payable onlyOwner {}24 receive() external payable onlyOwner {}242551 /// Throws if `msg.sender` is not owner or admin of provided RFT collection.52 /// Throws if `msg.sender` is not owner or admin of provided RFT collection.52 /// Can only be called by contract owner.53 /// Can only be called by contract owner.53 /// @param _collection address of RFT collection.54 /// @param _collection address of RFT collection.54 function setRFTCollection(address _collection) public onlyOwner {55 function setRFTCollection(address _collection) external onlyOwner {55 require(rftCollection == address(0), "RFT collection is already set");56 require(rftCollection == address(0), "RFT collection is already set");56 UniqueRefungible refungibleContract = UniqueRefungible(_collection);57 UniqueRefungible refungibleContract = UniqueRefungible(_collection);57 string memory collectionType = refungibleContract.uniqueCollectionType();58 string memory collectionType = refungibleContract.uniqueCollectionType();585960 // compare hashed to reduce gas cost59 require(61 require(60 keccak256(bytes(collectionType)) == refungibleCollectionType,62 keccak256(bytes(collectionType)) == refungibleCollectionType,61 "Wrong collection type. Collection is not refungible."63 "Wrong collection type. Collection is not refungible."79 string calldata _name,81 string calldata _name,80 string calldata _description,82 string calldata _description,81 string calldata _tokenPrefix83 string calldata _tokenPrefix82 ) public onlyOwner {84 ) external onlyOwner {83 require(rftCollection == address(0), "RFT collection is already set");85 require(rftCollection == address(0), "RFT collection is already set");84 address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;86 address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;85 rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection(_name, _description, _tokenPrefix);87 rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection(_name, _description, _tokenPrefix);90 /// @dev Can only be called by contract owner.92 /// @dev Can only be called by contract owner.91 /// @param collection NFT token address.93 /// @param collection NFT token address.92 /// @param status `true` to allow and `false` to disallow NFT token.94 /// @param status `true` to allow and `false` to disallow NFT token.93 function setNftCollectionIsAllowed(address collection, bool status) public onlyOwner {95 function setNftCollectionIsAllowed(address collection, bool status) external onlyOwner {94 nftCollectionAllowList[collection] = status;96 nftCollectionAllowList[collection] = status;95 emit AllowListSet(collection, status);97 emit AllowListSet(collection, status);96 }98 }109 address _collection,111 address _collection,110 uint256 _token,112 uint256 _token,111 uint128 _pieces113 uint128 _pieces112 ) public {114 ) external {113 require(rftCollection != address(0), "RFT collection is not set");115 require(rftCollection != address(0), "RFT collection is not set");114 UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);116 UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);115 require(117 require(148 /// Throws if `msg.sender` isn't owner of all RFT token pieces.150 /// Throws if `msg.sender` isn't owner of all RFT token pieces.149 /// @param _collection RFT collection address151 /// @param _collection RFT collection address150 /// @param _token id of RFT token152 /// @param _token id of RFT token151 function rft2nft(address _collection, uint256 _token) public {153 function rft2nft(address _collection, uint256 _token) external {152 require(rftCollection != address(0), "RFT collection is not set");154 require(rftCollection != address(0), "RFT collection is not set");153 require(rftCollection == _collection, "Wrong RFT collection");155 require(rftCollection == _collection, "Wrong RFT collection");154 UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);156 UniqueRefungible rftCollectionContract = UniqueRefungible(rftCollection);tests/src/eth/payable.test.tsdiffbeforeafterboth140 });140 });141 141 142 itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {142 itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => {143 const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();143 const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();144144145 const deployer = await helper.eth.createAccountWithBalance(donor);145 const deployer = await helper.eth.createAccountWithBalance(donor);146 const caller = await helper.eth.createAccountWithBalance(donor);146 const caller = await helper.eth.createAccountWithBalance(donor);147 const contract = await deployProxyContract(helper, deployer);147 const contract = await deployProxyContract(helper, deployer);148 149 const web3 = helper.getWeb3();150 await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});151148152 const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller})).events.CollectionCreated.returnValues.collection;149 const collectionAddress = (await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)})).events.CollectionCreated.returnValues.collection;153 const initialCallerBalance = await helper.balance.getEthereum(caller);150 const initialCallerBalance = await helper.balance.getEthereum(caller);154 const initialContractBalance = await helper.balance.getEthereum(contract.options.address);151 const initialContractBalance = await helper.balance.getEthereum(contract.options.address);155 await contract.methods.mintNftToken(collectionAddress).send({from: caller});152 await contract.methods.mintNftToken(collectionAddress).send({from: caller});160 });157 });161 158 162 itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {159 itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => {163 const CONTRACT_BALANCE = 3n * helper.balance.getOneTokenNominal();160 const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal();164165 const deployer = await helper.eth.createAccountWithBalance(donor);161 const deployer = await helper.eth.createAccountWithBalance(donor);166 const caller = await helper.eth.createAccountWithBalance(donor);162 const caller = await helper.eth.createAccountWithBalance(donor);167 const contract = await deployProxyContract(helper, deployer);163 const contract = await deployProxyContract(helper, deployer);168 169 const web3 = helper.getWeb3();170 await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});171164172 const initialCallerBalance = await helper.balance.getEthereum(caller);165 const initialCallerBalance = await helper.balance.getEthereum(caller);173 const initialContractBalance = await helper.balance.getEthereum(contract.options.address);166 const initialContractBalance = await helper.balance.getEthereum(contract.options.address);174 await contract.methods.createNonfungibleCollection().send({from: caller});167 await contract.methods.createNonfungibleCollection().send({from: caller, value: Number(CONTRACT_BALANCE)});175 const finalCallerBalance = await helper.balance.getEthereum(caller);168 const finalCallerBalance = await helper.balance.getEthereum(caller);176 const finalContractBalance = await helper.balance.getEthereum(contract.options.address);169 const finalContractBalance = await helper.balance.getEthereum(contract.options.address);177 expect(finalCallerBalance < initialCallerBalance).to.be.true;170 expect(finalCallerBalance < initialCallerBalance).to.be.true;178 expect(finalContractBalance < initialContractBalance).to.be.true;171 expect(finalContractBalance == initialContractBalance).to.be.true;179 });172 });180173181 async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {174 async function deployProxyContract(helper: EthUniqueHelper, deployer: string) {182 return await helper.ethContract.deployByCode(175 return await helper.ethContract.deployByCode(183 deployer,176 deployer,184 'ProxyContract',177 'ProxyContract',185 `178 `186 // SPDX-License-Identifier: UNLICENSED179 // SPDX-License-Identifier: UNLICENSED187 pragma solidity ^0.8.6;180 pragma solidity ^0.8.6;188181189 import {CollectionHelpers} from "../api/CollectionHelpers.sol";182 import {CollectionHelpers} from "../api/CollectionHelpers.sol";190 import {UniqueNFT} from "../api/UniqueNFT.sol";183 import {UniqueNFT} from "../api/UniqueNFT.sol";191184192 contract ProxyContract {185 error Value(uint256 value);186187 contract ProxyContract {193 bool value = false;188 bool value = false;194 address flipper;189 address flipper;195190196 event CollectionCreated(address collection);191 event CollectionCreated(address collection);197 event TokenMinted(uint256 tokenId);192 event TokenMinted(uint256 tokenId);198193199 receive() external payable {}194 receive() external payable {}200195201 constructor() {196 constructor() {202 flipper = address(new Flipper());197 flipper = address(new Flipper());203 }198 }204199205 function flip() public {200 function flip() public {206 value = !value;201 value = !value;207 Flipper(flipper).flip();202 Flipper(flipper).flip();208 }203 }209204210 function createNonfungibleCollection() public {205 function createNonfungibleCollection() external payable {211 address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;206 address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F;212 address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection("A", "B", "C");207 address nftCollection = CollectionHelpers(collectionHelpers).createNonfungibleCollection{value: msg.value}("A", "B", "C");213 emit CollectionCreated(nftCollection);208 emit CollectionCreated(nftCollection);214 }209 }215210216 function mintNftToken(address collectionAddress) public {211 function mintNftToken(address collectionAddress) external {217 UniqueNFT collection = UniqueNFT(collectionAddress);212 UniqueNFT collection = UniqueNFT(collectionAddress);218 uint256 tokenId = collection.nextTokenId();213 uint256 tokenId = collection.nextTokenId();219 collection.mint(msg.sender, tokenId);214 collection.mint(msg.sender, tokenId);220 emit TokenMinted(tokenId);215 emit TokenMinted(tokenId);221 }216 }222217223 function getValue() public view returns (bool) {218 function getValue() external view returns (bool) {224 return Flipper(flipper).getValue();219 return Flipper(flipper).getValue();225 }220 }226 }221 }227222228 contract Flipper {223 contract Flipper {229 bool value = false;224 bool value = false;230 function flip() public {225 function flip() external {231 value = !value;226 value = !value;232 }227 }233 function getValue() public view returns (bool) {228 function getValue() external view returns (bool) {234 return value;229 return value;235 }230 }236 }231 }237 `,232 `,238 [233 [239 {234 {240 solPath: 'api/CollectionHelpers.sol',235 solPath: 'api/CollectionHelpers.sol',