From e51699278c066a32287b4836974a032594453923 Mon Sep 17 00:00:00 2001 From: Trubnikov Sergey Date: Mon, 25 Jul 2022 09:33:33 +0000 Subject: [PATCH] misk: docs & changelogs. Some refactor for func & mod names. --- --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh -UniqueRFT.sol: +UniqueRefungible.sol: PACKAGE=pallet-refungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh PACKAGE=pallet-refungible NAME=erc::gen_impl OUTPUT=$(REFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh @@ -65,8 +65,8 @@ INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRefungibleToken.raw ./.maintain/scripts/compile_stub.sh INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(RENFUNGIBLE_TOKEN_EVM_ABI) ./.maintain/scripts/generate_abi.sh -UniqueRefungible: UniqueRFT.sol - INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRFT.raw ./.maintain/scripts/compile_stub.sh +UniqueRefungible: UniqueRefungible.sol + INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRefungible.raw ./.maintain/scripts/compile_stub.sh INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh ContractHelpers: ContractHelpers.sol --- a/pallets/common/CHANGELOG.MD +++ b/pallets/common/CHANGELOG.MD @@ -8,3 +8,8 @@ - Some methods in `#[solidity_interface]` for `CollectionHandle` had invalid mutability modifiers, causing invalid stub/abi generation. + + +## [0.1.3] - 2022-07-25 +### Add +- Some static property keys and values. \ No newline at end of file --- a/pallets/common/Cargo.toml +++ b/pallets/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-common" -version = "0.1.2" +version = "0.1.3" license = "GPLv3" edition = "2021" --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -430,7 +430,8 @@ Ok(()) } -pub mod static_property_key_value { +/// Contains static property keys and values. +pub mod static_property { use evm_coder::{ execution::{Result, Error}, }; @@ -438,27 +439,45 @@ const EXPECT_CONVERT_ERROR: &str = "length < limit"; - pub fn schema_name_key() -> up_data_structs::PropertyKey { - property_key_from_bytes(b"schemaName").expect(EXPECT_CONVERT_ERROR) - } + /// Keys. + pub mod key { + use super::*; - pub fn base_uri_key() -> up_data_structs::PropertyKey { - property_key_from_bytes(b"baseURI").expect(EXPECT_CONVERT_ERROR) + /// Key "schemaName". + pub fn schema_name() -> up_data_structs::PropertyKey { + property_key_from_bytes(b"schemaName").expect(EXPECT_CONVERT_ERROR) + } + + /// Key "baseURI". + pub fn base_uri() -> up_data_structs::PropertyKey { + property_key_from_bytes(b"baseURI").expect(EXPECT_CONVERT_ERROR) + } + + /// Key "url". + pub fn url() -> up_data_structs::PropertyKey { + property_key_from_bytes(b"url").expect(EXPECT_CONVERT_ERROR) + } + + /// Key "suffix". + pub fn suffix() -> up_data_structs::PropertyKey { + property_key_from_bytes(b"suffix").expect(EXPECT_CONVERT_ERROR) + } } - pub fn url_key() -> up_data_structs::PropertyKey { - property_key_from_bytes(b"url").expect(EXPECT_CONVERT_ERROR) - } + /// Values. + pub mod value { + use super::*; - pub fn suffix_key() -> up_data_structs::PropertyKey { - property_key_from_bytes(b"suffix").expect(EXPECT_CONVERT_ERROR) - } + /// Value "ERC721Metadata". + pub const ERC721_METADATA: &[u8] = b"ERC721Metadata"; - pub const ERC721_METADATA: &[u8] = b"ERC721Metadata"; - pub fn erc721_value() -> up_data_structs::PropertyValue { - property_value_from_bytes(ERC721_METADATA).expect(EXPECT_CONVERT_ERROR) + /// Value for [`ERC721_METADATA`]. + pub fn erc721() -> up_data_structs::PropertyValue { + property_value_from_bytes(ERC721_METADATA).expect(EXPECT_CONVERT_ERROR) + } } + /// Convert `byte` to [`PropertyKey`]. pub fn property_key_from_bytes(bytes: &[u8]) -> Result { bytes.to_vec().try_into().map_err(|_| { Error::Revert(format!( @@ -468,6 +487,7 @@ }) } + /// Convert `bytes` to [`PropertyValue`]. pub fn property_value_from_bytes(bytes: &[u8]) -> Result { bytes.to_vec().try_into().map_err(|_| { Error::Revert(format!( --- a/pallets/nonfungible/CHANGELOG.md +++ b/pallets/nonfungible/CHANGELOG.md @@ -2,10 +2,13 @@ All notable changes to this project will be documented in this file. -## [0.1.1] - 2022-07-14 +## [0.1.2] - 2022-07-25 +### Changed +- New alghoritm for retrieving `token_iri`. +## [0.1.1] - 2022-07-14 ### Added - Implementation of RPC method `token_owners`. For reasons of compatibility with this pallet, returns only one owner if token exists. - This was an internal request to improve the web interface and support fractionalization event. \ No newline at end of file + This was an internal request to improve the web interface and support fractionalization event. --- a/pallets/nonfungible/Cargo.toml +++ b/pallets/nonfungible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-nonfungible" -version = "0.1.1" +version = "0.1.2" license = "GPLv3" edition = "2021" --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -33,7 +33,7 @@ use pallet_evm_coder_substrate::dispatch_to_evm; use sp_std::vec::Vec; use pallet_common::{ - erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property_key_value::*}, + erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::{key, value as property_value}}, CollectionHandle, CollectionPropertyPermissions, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; @@ -221,10 +221,10 @@ fn token_uri(&self, token_id: uint256) -> Result { let is_erc721 = || { if let Some(shema_name) = - pallet_common::Pallet::::get_collection_property(self.id, &schema_name_key()) + pallet_common::Pallet::::get_collection_property(self.id, &key::schema_name()) { let shema_name = shema_name.into_inner(); - shema_name == ERC721_METADATA + shema_name == property_value::ERC721_METADATA } else { false } @@ -232,7 +232,7 @@ let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?; - if let Ok(url) = get_token_property(self, token_id_u32, &url_key()) { + if let Ok(url) = get_token_property(self, token_id_u32, &key::url()) { if !url.is_empty() { return Ok(url); } @@ -241,7 +241,7 @@ } if let Some(base_uri) = - pallet_common::Pallet::::get_collection_property(self.id, &base_uri_key()) + pallet_common::Pallet::::get_collection_property(self.id, &key::base_uri()) { if !base_uri.is_empty() { let base_uri = string::from_utf8(base_uri.into_inner()).map_err(|e| { @@ -250,7 +250,7 @@ e )) })?; - if let Ok(suffix) = get_token_property(self, token_id_u32, &suffix_key()) { + if let Ok(suffix) = get_token_property(self, token_id_u32, &key::suffix()) { if !suffix.is_empty() { return Ok(base_uri + suffix.as_str()); } @@ -497,7 +497,7 @@ token_id: uint256, token_uri: string, ) -> Result { - let key = url_key(); + let key = key::url(); let permission = get_token_permission::(self.id, &key)?; if !permission.collection_admin { return Err("Operation is not allowed".into()); @@ -702,7 +702,7 @@ to: address, tokens: Vec<(uint256, string)>, ) -> Result { - let key = url_key(); + let key = key::url(); let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let mut expected_index = >::get(self.id) --- a/pallets/refungible/CHANGELOG.md +++ b/pallets/refungible/CHANGELOG.md @@ -10,6 +10,8 @@ test(refungible-pallet): add tests for ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413)) ## [v0.1.1] - 2022-07-14 +### Added +- Support for properties for RFT collections and tokens. ### Other changes --- a/pallets/refungible/Changelog.md +++ /dev/null @@ -1,3 +0,0 @@ -### 0.1.1 ---- -* Added support for properties for RFT collections and tokens. --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -25,24 +25,24 @@ use crate::{Config, RefungibleHandle}; #[solidity_interface( - name = "UniqueRFT", + name = "UniqueRefungible", is(via("CollectionHandle", common_mut, Collection),) )] impl RefungibleHandle where T::AccountId: From<[u8; 32]> {} // Not a tests, but code generators -generate_stubgen!(gen_impl, UniqueRFTCall<()>, true); -generate_stubgen!(gen_iface, UniqueRFTCall<()>, false); +generate_stubgen!(gen_impl, UniqueRefungibleCall<()>, true); +generate_stubgen!(gen_iface, UniqueRefungibleCall<()>, false); impl CommonEvmHandler for RefungibleHandle where T::AccountId: From<[u8; 32]>, { - const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRFT.raw"); + const CODE: &'static [u8] = include_bytes!("./stubs/UniqueRefungible.raw"); fn call( self, handle: &mut impl PrecompileHandle, ) -> Option { - call::, _, _>(handle, self) + call::, _, _>(handle, self) } } --- a/pallets/refungible/src/stubs/UniqueRFT.sol +++ /dev/null @@ -1,251 +0,0 @@ -// SPDX-License-Identifier: OTHER -// This code is automatically generated - -pragma solidity >=0.8.0 <0.9.0; - -// Common stubs holder -contract Dummy { - uint8 dummy; - string stub_error = "this contract is implemented in native"; -} - -contract ERC165 is Dummy { - function supportsInterface(bytes4 interfaceID) - external - view - returns (bool) - { - require(false, stub_error); - interfaceID; - return true; - } -} - -// Selector: 7d9262e6 -contract Collection is Dummy, ERC165 { - // Set collection property. - // - // @param key Property key. - // @param value Propery value. - // - // Selector: setCollectionProperty(string,bytes) 2f073f66 - function setCollectionProperty(string memory key, bytes memory value) - public - { - require(false, stub_error); - key; - value; - dummy = 0; - } - - // Delete collection property. - // - // @param key Property key. - // - // Selector: deleteCollectionProperty(string) 7b7debce - function deleteCollectionProperty(string memory key) public { - require(false, stub_error); - key; - dummy = 0; - } - - // Get collection property. - // - // @dev Throws error if key not found. - // - // @param key Property key. - // @return bytes The property corresponding to the key. - // - // Selector: collectionProperty(string) cf24fd6d - function collectionProperty(string memory key) - public - view - returns (bytes memory) - { - require(false, stub_error); - key; - dummy; - return hex""; - } - - // Set the sponsor of the collection. - // - // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. - // - // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - // - // Selector: setCollectionSponsor(address) 7623402e - function setCollectionSponsor(address sponsor) public { - require(false, stub_error); - sponsor; - dummy = 0; - } - - // Collection sponsorship confirmation. - // - // @dev After setting the sponsor for the collection, it must be confirmed with this function. - // - // Selector: confirmCollectionSponsorship() 3c50e97a - function confirmCollectionSponsorship() public { - require(false, stub_error); - dummy = 0; - } - - // Set limits for the collection. - // @dev Throws error if limit not found. - // @param limit Name of the limit. Valid names: - // "accountTokenOwnershipLimit", - // "sponsoredDataSize", - // "sponsoredDataRateLimit", - // "tokenLimit", - // "sponsorTransferTimeout", - // "sponsorApproveTimeout" - // @param value Value of the limit. - // - // Selector: setCollectionLimit(string,uint32) 6a3841db - function setCollectionLimit(string memory limit, uint32 value) public { - require(false, stub_error); - limit; - value; - dummy = 0; - } - - // Set limits for the collection. - // @dev Throws error if limit not found. - // @param limit Name of the limit. Valid names: - // "ownerCanTransfer", - // "ownerCanDestroy", - // "transfersEnabled" - // @param value Value of the limit. - // - // Selector: setCollectionLimit(string,bool) 993b7fba - function setCollectionLimit(string memory limit, bool value) public { - require(false, stub_error); - limit; - value; - dummy = 0; - } - - // Get contract address. - // - // Selector: contractAddress() f6b4dfb4 - function contractAddress() public view returns (address) { - require(false, stub_error); - dummy; - return 0x0000000000000000000000000000000000000000; - } - - // Add collection admin by substrate address. - // @param new_admin Substrate administrator address. - // - // Selector: addCollectionAdminSubstrate(uint256) 5730062b - function addCollectionAdminSubstrate(uint256 newAdmin) public { - require(false, stub_error); - newAdmin; - dummy = 0; - } - - // Remove collection admin by substrate address. - // @param admin Substrate administrator address. - // - // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9 - function removeCollectionAdminSubstrate(uint256 admin) public { - require(false, stub_error); - admin; - dummy = 0; - } - - // Add collection admin. - // @param new_admin Address of the added administrator. - // - // Selector: addCollectionAdmin(address) 92e462c7 - function addCollectionAdmin(address newAdmin) public { - require(false, stub_error); - newAdmin; - dummy = 0; - } - - // Remove collection admin. - // - // @param new_admin Address of the removed administrator. - // - // Selector: removeCollectionAdmin(address) fafd7b42 - function removeCollectionAdmin(address admin) public { - require(false, stub_error); - admin; - dummy = 0; - } - - // Toggle accessibility of collection nesting. - // - // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled' - // - // Selector: setCollectionNesting(bool) 112d4586 - function setCollectionNesting(bool enable) public { - require(false, stub_error); - enable; - dummy = 0; - } - - // Toggle accessibility of collection nesting. - // - // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled' - // @param collections Addresses of collections that will be available for nesting. - // - // Selector: setCollectionNesting(bool,address[]) 64872396 - function setCollectionNesting(bool enable, address[] memory collections) - public - { - require(false, stub_error); - enable; - collections; - dummy = 0; - } - - // Set the collection access method. - // @param mode Access mode - // 0 for Normal - // 1 for AllowList - // - // Selector: setCollectionAccess(uint8) 41835d4c - function setCollectionAccess(uint8 mode) public { - require(false, stub_error); - mode; - dummy = 0; - } - - // Add the user to the allowed list. - // - // @param user Address of a trusted user. - // - // Selector: addToCollectionAllowList(address) 67844fe6 - function addToCollectionAllowList(address user) public { - require(false, stub_error); - user; - dummy = 0; - } - - // Remove the user from the allowed list. - // - // @param user Address of a removed user. - // - // Selector: removeFromCollectionAllowList(address) 85c51acb - function removeFromCollectionAllowList(address user) public { - require(false, stub_error); - user; - dummy = 0; - } - - // Switch permission for minting. - // - // @param mode Enable if "true". - // - // Selector: setCollectionMintMode(bool) 00018e84 - function setCollectionMintMode(bool mode) public { - require(false, stub_error); - mode; - dummy = 0; - } -} - -contract UniqueRFT is Dummy, ERC165, Collection {} --- /dev/null +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: OTHER +// This code is automatically generated + +pragma solidity >=0.8.0 <0.9.0; + +// Common stubs holder +contract Dummy { + uint8 dummy; + string stub_error = "this contract is implemented in native"; +} + +contract ERC165 is Dummy { + function supportsInterface(bytes4 interfaceID) + external + view + returns (bool) + { + require(false, stub_error); + interfaceID; + return true; + } +} + +// Selector: 7d9262e6 +contract Collection is Dummy, ERC165 { + // Set collection property. + // + // @param key Property key. + // @param value Propery value. + // + // Selector: setCollectionProperty(string,bytes) 2f073f66 + function setCollectionProperty(string memory key, bytes memory value) + public + { + require(false, stub_error); + key; + value; + dummy = 0; + } + + // Delete collection property. + // + // @param key Property key. + // + // Selector: deleteCollectionProperty(string) 7b7debce + function deleteCollectionProperty(string memory key) public { + require(false, stub_error); + key; + dummy = 0; + } + + // Get collection property. + // + // @dev Throws error if key not found. + // + // @param key Property key. + // @return bytes The property corresponding to the key. + // + // Selector: collectionProperty(string) cf24fd6d + function collectionProperty(string memory key) + public + view + returns (bytes memory) + { + require(false, stub_error); + key; + dummy; + return hex""; + } + + // Set the sponsor of the collection. + // + // @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // + // @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // + // Selector: setCollectionSponsor(address) 7623402e + function setCollectionSponsor(address sponsor) public { + require(false, stub_error); + sponsor; + dummy = 0; + } + + // Collection sponsorship confirmation. + // + // @dev After setting the sponsor for the collection, it must be confirmed with this function. + // + // Selector: confirmCollectionSponsorship() 3c50e97a + function confirmCollectionSponsorship() public { + require(false, stub_error); + dummy = 0; + } + + // Set limits for the collection. + // @dev Throws error if limit not found. + // @param limit Name of the limit. Valid names: + // "accountTokenOwnershipLimit", + // "sponsoredDataSize", + // "sponsoredDataRateLimit", + // "tokenLimit", + // "sponsorTransferTimeout", + // "sponsorApproveTimeout" + // @param value Value of the limit. + // + // Selector: setCollectionLimit(string,uint32) 6a3841db + function setCollectionLimit(string memory limit, uint32 value) public { + require(false, stub_error); + limit; + value; + dummy = 0; + } + + // Set limits for the collection. + // @dev Throws error if limit not found. + // @param limit Name of the limit. Valid names: + // "ownerCanTransfer", + // "ownerCanDestroy", + // "transfersEnabled" + // @param value Value of the limit. + // + // Selector: setCollectionLimit(string,bool) 993b7fba + function setCollectionLimit(string memory limit, bool value) public { + require(false, stub_error); + limit; + value; + dummy = 0; + } + + // Get contract address. + // + // Selector: contractAddress() f6b4dfb4 + function contractAddress() public view returns (address) { + require(false, stub_error); + dummy; + return 0x0000000000000000000000000000000000000000; + } + + // Add collection admin by substrate address. + // @param new_admin Substrate administrator address. + // + // Selector: addCollectionAdminSubstrate(uint256) 5730062b + function addCollectionAdminSubstrate(uint256 newAdmin) public { + require(false, stub_error); + newAdmin; + dummy = 0; + } + + // Remove collection admin by substrate address. + // @param admin Substrate administrator address. + // + // Selector: removeCollectionAdminSubstrate(uint256) 4048fcf9 + function removeCollectionAdminSubstrate(uint256 admin) public { + require(false, stub_error); + admin; + dummy = 0; + } + + // Add collection admin. + // @param new_admin Address of the added administrator. + // + // Selector: addCollectionAdmin(address) 92e462c7 + function addCollectionAdmin(address newAdmin) public { + require(false, stub_error); + newAdmin; + dummy = 0; + } + + // Remove collection admin. + // + // @param new_admin Address of the removed administrator. + // + // Selector: removeCollectionAdmin(address) fafd7b42 + function removeCollectionAdmin(address admin) public { + require(false, stub_error); + admin; + dummy = 0; + } + + // Toggle accessibility of collection nesting. + // + // @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled' + // + // Selector: setCollectionNesting(bool) 112d4586 + function setCollectionNesting(bool enable) public { + require(false, stub_error); + enable; + dummy = 0; + } + + // Toggle accessibility of collection nesting. + // + // @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled' + // @param collections Addresses of collections that will be available for nesting. + // + // Selector: setCollectionNesting(bool,address[]) 64872396 + function setCollectionNesting(bool enable, address[] memory collections) + public + { + require(false, stub_error); + enable; + collections; + dummy = 0; + } + + // Set the collection access method. + // @param mode Access mode + // 0 for Normal + // 1 for AllowList + // + // Selector: setCollectionAccess(uint8) 41835d4c + function setCollectionAccess(uint8 mode) public { + require(false, stub_error); + mode; + dummy = 0; + } + + // Add the user to the allowed list. + // + // @param user Address of a trusted user. + // + // Selector: addToCollectionAllowList(address) 67844fe6 + function addToCollectionAllowList(address user) public { + require(false, stub_error); + user; + dummy = 0; + } + + // Remove the user from the allowed list. + // + // @param user Address of a removed user. + // + // Selector: removeFromCollectionAllowList(address) 85c51acb + function removeFromCollectionAllowList(address user) public { + require(false, stub_error); + user; + dummy = 0; + } + + // Switch permission for minting. + // + // @param mode Enable if "true". + // + // Selector: setCollectionMintMode(bool) 00018e84 + function setCollectionMintMode(bool mode) public { + require(false, stub_error); + mode; + dummy = 0; + } +} + +contract UniqueRefungible is Dummy, ERC165, Collection {} --- a/pallets/unique/src/eth/mod.rs +++ b/pallets/unique/src/eth/mod.rs @@ -28,7 +28,7 @@ use frame_support::traits::Get; use pallet_common::{ CollectionById, - erc::{static_property_key_value::*, CollectionHelpersEvents}, + erc::{static_property::{key, value as property_value}, CollectionHelpersEvents}, }; use crate::{SelfWeightOf, Config, weights::WeightInfo}; @@ -83,7 +83,6 @@ Ok((caller, name, description, token_prefix, base_uri_value)) } -// fn make_data( name: CollectionName, mode: CollectionMode, @@ -98,7 +97,7 @@ token_property_permissions .try_push(up_data_structs::PropertyKeyPermission { - key: url_key(), + key: key::url(), permission: up_data_structs::PropertyPermission { mutable: false, collection_admin: true, @@ -110,7 +109,7 @@ if add_properties { token_property_permissions .try_push(up_data_structs::PropertyKeyPermission { - key: suffix_key(), + key: key::suffix(), permission: up_data_structs::PropertyPermission { mutable: false, collection_admin: true, @@ -121,15 +120,15 @@ properties .try_push(up_data_structs::Property { - key: schema_name_key(), - value: erc721_value(), + key: key::schema_name(), + value: property_value::erc721(), }) .map_err(|e| Error::Revert(format!("{:?}", e)))?; if !base_uri_value.is_empty() { properties .try_push(up_data_structs::Property { - key: base_uri_key(), + key: key::base_uri(), value: base_uri_value, }) .map_err(|e| Error::Revert(format!("{:?}", e)))?; @@ -152,7 +151,7 @@ #[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))] impl EvmCollectionHelpers where - T: Config + pallet_nonfungible::Config + pallet_refungible::Config + T: Config + pallet_nonfungible::Config + pallet_refungible::Config, { /// Create an NFT collection /// @param name Name of the collection -- gitstuff