difftreelog
Merge pull request #391 from UniqueNetwork/feature/CORE-412
in: master
Feature/core 412 Helper for create RFT collection
40 files changed
Cargo.lockdiffbeforeafterboth573157315732[[package]]5732[[package]]5733name = "pallet-common"5733name = "pallet-common"5734version = "0.1.2"5734version = "0.1.3"5735dependencies = [5735dependencies = [5736 "ethereum",5736 "ethereum",5737 "evm-coder",5737 "evm-coder",619861986199[[package]]6199[[package]]6200name = "pallet-nonfungible"6200name = "pallet-nonfungible"6201version = "0.1.1"6201version = "0.1.2"6202dependencies = [6202dependencies = [6203 "ethereum",6203 "ethereum",6204 "evm-coder",6204 "evm-coder",663866386639[[package]]6639[[package]]6640name = "pallet-unique"6640name = "pallet-unique"6641version = "0.1.0"6641version = "0.1.1"6642dependencies = [6642dependencies = [6643 "ethereum",6643 "ethereum",6644 "evm-coder",6644 "evm-coder",6649 "pallet-evm",6649 "pallet-evm",6650 "pallet-evm-coder-substrate",6650 "pallet-evm-coder-substrate",6651 "pallet-nonfungible",6651 "pallet-nonfungible",6652 "pallet-refungible",6652 "parity-scale-codec 3.1.5",6653 "parity-scale-codec 3.1.5",6653 "scale-info",6654 "scale-info",6654 "serde",6655 "serde",127361273712737[[package]]12738[[package]]12738name = "up-data-structs"12739name = "up-data-structs"12739version = "0.1.1"12740version = "0.1.2"12740dependencies = [12741dependencies = [12741 "derivative",12742 "derivative",12742 "frame-support",12743 "frame-support",Makefilediffbeforeafterboth9FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs9FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs10FUNGIBLE_EVM_ABI=./tests/src/eth/fungibleAbi.json10FUNGIBLE_EVM_ABI=./tests/src/eth/fungibleAbi.json1112REFUNGIBLE_EVM_STUBS=./pallets/refungible/src/stubs13REFUNGIBLE_EVM_ABI=./tests/src/eth/refungibleAbi.json111412NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs15NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs13NONFUNGIBLE_EVM_ABI=./tests/src/eth/nonFungibleAbi.json16NONFUNGIBLE_EVM_ABI=./tests/src/eth/nonFungibleAbi.json141715REFUNGIBLE_EVM_STUBS=./pallets/refungible/src/stubs16RENFUNGIBLE_EVM_ABI=./tests/src/eth/reFungibleAbi.json18RENFUNGIBLE_EVM_ABI=./tests/src/eth/reFungibleAbi.json17RENFUNGIBLE_TOKEN_EVM_ABI=./tests/src/eth/reFungibleTokenAbi.json19RENFUNGIBLE_TOKEN_EVM_ABI=./tests/src/eth/reFungibleTokenAbi.json182025TESTS_API=./tests/src/eth/api/27TESTS_API=./tests/src/eth/api/262827.PHONY: regenerate_solidity29.PHONY: regenerate_solidity28regenerate_solidity: UniqueFungible.sol UniqueNFT.sol UniqueRefungibleToken.sol ContractHelpers.sol CollectionHelpers.sol30regenerate_solidity: UniqueFungible.sol UniqueNFT.sol UniqueRefungible.sol UniqueRefungibleToken.sol ContractHelpers.sol CollectionHelpers.sol293130UniqueFungible.sol:32UniqueFungible.sol:31 PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh33 PACKAGE=pallet-fungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh35 PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh37 PACKAGE=pallet-nonfungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh36 PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh38 PACKAGE=pallet-nonfungible NAME=erc::gen_impl OUTPUT=$(NONFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh37 39 40UniqueRefungible.sol:41 PACKAGE=pallet-refungible NAME=erc::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh42 PACKAGE=pallet-refungible NAME=erc::gen_impl OUTPUT=$(REFUNGIBLE_EVM_STUBS)/$@ ./.maintain/scripts/generate_sol.sh4338UniqueRefungibleToken.sol:44UniqueRefungibleToken.sol:39 PACKAGE=pallet-refungible NAME=erc_token::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh45 PACKAGE=pallet-refungible NAME=erc_token::gen_iface OUTPUT=$(TESTS_API)/$@ ./.maintain/scripts/generate_sol.sh59 INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRefungibleToken.raw ./.maintain/scripts/compile_stub.sh65 INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRefungibleToken.raw ./.maintain/scripts/compile_stub.sh60 INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(RENFUNGIBLE_TOKEN_EVM_ABI) ./.maintain/scripts/generate_abi.sh66 INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(RENFUNGIBLE_TOKEN_EVM_ABI) ./.maintain/scripts/generate_abi.sh6768UniqueRefungible: UniqueRefungible.sol69 INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_STUBS)/UniqueRefungible.raw ./.maintain/scripts/compile_stub.sh70 INPUT=$(REFUNGIBLE_EVM_STUBS)/$< OUTPUT=$(REFUNGIBLE_EVM_ABI) ./.maintain/scripts/generate_abi.sh617162ContractHelpers: ContractHelpers.sol72ContractHelpers: ContractHelpers.sol63 INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw ./.maintain/scripts/compile_stub.sh73 INPUT=$(CONTRACT_HELPERS_STUBS)/$< OUTPUT=$(CONTRACT_HELPERS_STUBS)/ContractHelpers.raw ./.maintain/scripts/compile_stub.sh67 INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelpers.raw ./.maintain/scripts/compile_stub.sh77 INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_STUBS)/CollectionHelpers.raw ./.maintain/scripts/compile_stub.sh68 INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh78 INPUT=$(COLLECTION_HELPER_STUBS)/$< OUTPUT=$(COLLECTION_HELPER_ABI) ./.maintain/scripts/generate_abi.sh697970evm_stubs: UniqueFungible UniqueNFT UniqueRefungibleToken ContractHelpers CollectionHelpers80evm_stubs: UniqueFungible UniqueNFT UniqueRefungible UniqueRefungibleToken ContractHelpers CollectionHelpers718172.PHONY: _bench82.PHONY: _bench73_bench:83_bench:pallets/common/CHANGELOG.MDdiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [0.1.3] - 2022-07-256### Add7- Some static property keys and values.85## [0.1.2] - 2022-07-209## [0.1.2] - 2022-07-206107### Fixed11### Fixedpallets/common/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-common"2name = "pallet-common"3version = "0.1.2"3version = "0.1.3"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/common/src/dispatch.rsdiffbeforeafterboth8 weights::Pays,8 weights::Pays,9 traits::Get,9 traits::Get,10};10};11use sp_runtime::DispatchError;11use up_data_structs::{CollectionId, CreateCollectionData};12use up_data_structs::{CollectionId, CreateCollectionData};121313use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};14use crate::{pallet::Config, CommonCollectionOperations, CollectionHandle};78 fn create(79 fn create(79 sender: T::CrossAccountId,80 sender: T::CrossAccountId,80 data: CreateCollectionData<T::AccountId>,81 data: CreateCollectionData<T::AccountId>,81 ) -> DispatchResult;82 ) -> Result<CollectionId, DispatchError>;828383 /// Delete the collection.84 /// Delete the collection.84 ///85 ///pallets/common/src/erc.rsdiffbeforeafterboth430 Ok(())430 Ok(())431}431}432432433/// Get the "tokenURI" key as [PropertyKey](up_data_structs::PropertyKey).433/// Contains static property keys and values.434pub fn token_uri_key() -> up_data_structs::PropertyKey {434pub mod static_property {435 b"tokenURI"435 use evm_coder::{436 execution::{Result, Error},437 };438 use alloc::format;439440 const EXPECT_CONVERT_ERROR: &str = "length < limit";441442 /// Keys.443 pub mod key {444 use super::*;445446 /// Key "schemaName".447 pub fn schema_name() -> up_data_structs::PropertyKey {448 property_key_from_bytes(b"schemaName").expect(EXPECT_CONVERT_ERROR)449 }450451 /// Key "baseURI".452 pub fn base_uri() -> up_data_structs::PropertyKey {453 property_key_from_bytes(b"baseURI").expect(EXPECT_CONVERT_ERROR)454 }455456 /// Key "url".457 pub fn url() -> up_data_structs::PropertyKey {458 property_key_from_bytes(b"url").expect(EXPECT_CONVERT_ERROR)459 }460461 /// Key "suffix".462 pub fn suffix() -> up_data_structs::PropertyKey {463 property_key_from_bytes(b"suffix").expect(EXPECT_CONVERT_ERROR)464 }465 }466467 /// Values.468 pub mod value {469 use super::*;470471 /// Value "ERC721Metadata".472 pub const ERC721_METADATA: &[u8] = b"ERC721Metadata";473474 /// Value for [`ERC721_METADATA`].475 pub fn erc721() -> up_data_structs::PropertyValue {476 property_value_from_bytes(ERC721_METADATA).expect(EXPECT_CONVERT_ERROR)477 }478 }479480 /// Convert `byte` to [`PropertyKey`].481 pub fn property_key_from_bytes(bytes: &[u8]) -> Result<up_data_structs::PropertyKey> {436 .to_vec()482 bytes.to_vec().try_into().map_err(|_| {437 .try_into()483 Error::Revert(format!(484 "Property key is too long. Max length is {}.",485 up_data_structs::PropertyKey::bound()486 ))438 .expect("length < limit; qed")487 })439}488 }489490 /// Convert `bytes` to [`PropertyValue`].491 pub fn property_value_from_bytes(bytes: &[u8]) -> Result<up_data_structs::PropertyValue> {492 bytes.to_vec().try_into().map_err(|_| {493 Error::Revert(format!(494 "Property key is too long. Max length is {}.",495 up_data_structs::PropertyKey::bound()496 ))497 })498 }499}440500pallets/nonfungible/CHANGELOG.mddiffbeforeafterboth223All notable changes to this project will be documented in this file.3All notable changes to this project will be documented in this file.445## [0.1.2] - 2022-07-256### Changed7- New `token_uri` retrieval logic:89 If the collection has a `url` property and it is not empty, it is returned.10 Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.1112 If the property `baseURI` is empty or absent, return "" (empty string)13 otherwise, if property `suffix` present and is non-empty, return concatenation of baseURI and suffix14 otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).155## [0.1.1] - 2022-07-1416## [0.1.1] - 2022-07-1467### Added17### Added8189- Implementation of RPC method `token_owners`.19- Implementation of RPC method `token_owners`.10 For reasons of compatibility with this pallet, returns only one owner if token exists.20 For reasons of compatibility with this pallet, returns only one owner if token exists.11 This was an internal request to improve the web interface and support fractionalization event. 21 This was an internal request to improve the web interface and support fractionalization event. 22pallets/nonfungible/Cargo.tomldiffbeforeafterboth1[package]1[package]2name = "pallet-nonfungible"2name = "pallet-nonfungible"3version = "0.1.1"3version = "0.1.2"4license = "GPLv3"4license = "GPLv3"5edition = "2021"5edition = "2021"66pallets/nonfungible/src/erc.rsdiffbeforeafterboth33use pallet_evm_coder_substrate::dispatch_to_evm;33use pallet_evm_coder_substrate::dispatch_to_evm;34use sp_std::vec::Vec;34use sp_std::vec::Vec;35use pallet_common::{35use pallet_common::{36 erc::{CommonEvmHandler, PrecompileResult, CollectionCall, token_uri_key},36 erc::{37 CommonEvmHandler, PrecompileResult, CollectionCall,38 static_property::{key, value as property_value},39 },37 CollectionHandle, CollectionPropertyPermissions,40 CollectionHandle, CollectionPropertyPermissions,38};41};39use pallet_evm::{account::CrossAccountId, PrecompileHandle};42use pallet_evm::{account::CrossAccountId, PrecompileHandle};40use pallet_evm_coder_substrate::call;43use pallet_evm_coder_substrate::call;41use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};44use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};45use alloc::string::ToString;424643use crate::{47use crate::{44 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,48 AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,212 }216 }213217214 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.218 /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.215 /// @dev Throws if `tokenId` is not a valid NFT. URIs are defined in RFC219 ///216 /// 3986. The URI may point to a JSON file that conforms to the "ERC721220 /// @dev If the token has a `url` property and it is not empty, it is returned.217 /// Metadata JSON Schema".221 /// Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.222 /// If the collection property `baseURI` is empty or absent, return "" (empty string)223 /// otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix224 /// otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).225 ///218 /// @return token's const_metadata226 /// @return token's const_metadata219 #[solidity(rename_selector = "tokenURI")]227 #[solidity(rename_selector = "tokenURI")]220 fn token_uri(&self, token_id: uint256) -> Result<string> {228 fn token_uri(&self, token_id: uint256) -> Result<string> {221 let key = token_uri_key();229 let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;230222 if !has_token_permission::<T>(self.id, &key) {231 if let Ok(url) = get_token_property(self, token_id_u32, &key::url()) {232 if !url.is_empty() {233 return Ok(url);234 }235 } else if !is_erc721_metadata_compatible::<T>(self.id) {223 return Err("No tokenURI permission".into());236 return Err("tokenURI not set".into());224 }237 }225238226 self.consume_store_reads(1)?;227 let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;239 if let Some(base_uri) =228240 pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())241 {242 if !base_uri.is_empty() {229 let properties = <TokenProperties<T>>::try_get((self.id, token_id))243 let base_uri = string::from_utf8(base_uri.into_inner()).map_err(|e| {230 .map_err(|_| Error::Revert("Token properties not found".into()))?;244 Error::Revert(alloc::format!(245 "Can not convert value \"baseURI\" to string with error \"{}\"",246 e247 ))248 })?;231 if let Some(property) = properties.get(&key) {249 if let Ok(suffix) = get_token_property(self, token_id_u32, &key::suffix()) {250 if !suffix.is_empty() {232 return Ok(string::from_utf8_lossy(property).into());251 return Ok(base_uri + suffix.as_str());252 }233 }253 }254255 return Ok(base_uri + token_id.to_string().as_str());256 }257 }234258235 Err("Property tokenURI not found".into())259 Ok("".into())236 }260 }237}261}238262469 token_id: uint256,493 token_id: uint256,470 token_uri: string,494 token_uri: string,471 ) -> Result<bool> {495 ) -> Result<bool> {472 let key = token_uri_key();496 let key = key::url();473 let permission = get_token_permission::<T>(self.id, &key)?;497 let permission = get_token_permission::<T>(self.id, &key)?;474 if !permission.collection_admin {498 if !permission.collection_admin {475 return Err("Operation is not allowed".into());499 return Err("Operation is not allowed".into());520 }544 }521}545}546547fn get_token_property<T: Config>(548 collection: &CollectionHandle<T>,549 token_id: u32,550 key: &up_data_structs::PropertyKey,551) -> Result<string> {552 collection.consume_store_reads(1)?;553 let properties = <TokenProperties<T>>::try_get((collection.id, token_id))554 .map_err(|_| Error::Revert("Token properties not found".into()))?;555 if let Some(property) = properties.get(key) {556 return Ok(string::from_utf8_lossy(property).into());557 }558559 Err("Property tokenURI not found".into())560}561562fn is_erc721_metadata_compatible<T: Config>(collection_id: CollectionId) -> bool {563 if let Some(shema_name) =564 pallet_common::Pallet::<T>::get_collection_property(collection_id, &key::schema_name())565 {566 let shema_name = shema_name.into_inner();567 shema_name == property_value::ERC721_METADATA568 } else {569 false570 }571}522572523fn get_token_permission<T: Config>(573fn get_token_permission<T: Config>(524 collection_id: CollectionId,574 collection_id: CollectionId,528 .map_err(|_| Error::Revert("No permissions for collection".into()))?;578 .map_err(|_| Error::Revert("No permissions for collection".into()))?;529 let a = token_property_permissions579 let a = token_property_permissions530 .get(key)580 .get(key)531 .map(|p| p.clone())581 .map(Clone::clone)532 .ok_or_else(|| Error::Revert("No permission".into()))?;582 .ok_or_else(|| {583 let key = string::from_utf8(key.clone().into_inner()).unwrap_or_default();584 Error::Revert(alloc::format!("No permission for key {}", key))585 })?;533 Ok(a)586 Ok(a)534}587}535588656 to: address,709 to: address,657 tokens: Vec<(uint256, string)>,710 tokens: Vec<(uint256, string)>,658 ) -> Result<bool> {711 ) -> Result<bool> {659 let key = token_uri_key();712 let key = key::url();660 let caller = T::CrossAccountId::from_eth(caller);713 let caller = T::CrossAccountId::from_eth(caller);661 let to = T::CrossAccountId::from_eth(to);714 let to = T::CrossAccountId::from_eth(to);662 let mut expected_index = <TokensMinted<T>>::get(self.id)715 let mut expected_index = <TokensMinted<T>>::get(self.id)pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/CHANGELOG.mddiffbeforeafterboth10test(refungible-pallet): add tests for ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))10test(refungible-pallet): add tests for ERC-20 EVM API for RFT token pieces ([#413](https://github.com/UniqueNetwork/unique-chain/pull/413))111112## [v0.1.1] - 2022-07-1412## [v0.1.1] - 2022-07-1413### Added14- Support for properties for RFT collections and tokens.131514### Other changes16### Other changes1517pallets/refungible/Changelog.mddiffbeforeafterbothno changes
pallets/refungible/src/erc.rsdiffbeforeafterboth25use crate::{Config, RefungibleHandle};25use crate::{Config, RefungibleHandle};262627#[solidity_interface(27#[solidity_interface(28 name = "UniqueRFT",28 name = "UniqueRefungible",29 is(via("CollectionHandle<T>", common_mut, Collection),)29 is(via("CollectionHandle<T>", common_mut, Collection),)30)]30)]31impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> {}31impl<T: Config> RefungibleHandle<T> where T::AccountId: From<[u8; 32]> {}323233// Not a tests, but code generators33// Not a tests, but code generators34generate_stubgen!(gen_impl, UniqueRFTCall<()>, true);34generate_stubgen!(gen_impl, UniqueRefungibleCall<()>, true);35generate_stubgen!(gen_iface, UniqueRFTCall<()>, false);35generate_stubgen!(gen_iface, UniqueRefungibleCall<()>, false);363637impl<T: Config> CommonEvmHandler for RefungibleHandle<T>37impl<T: Config> CommonEvmHandler for RefungibleHandle<T>38where38where43 self,43 self,44 handle: &mut impl PrecompileHandle,44 handle: &mut impl PrecompileHandle,45 ) -> Option<pallet_common::erc::PrecompileResult> {45 ) -> Option<pallet_common::erc::PrecompileResult> {46 call::<T, UniqueRFTCall<T>, _, _>(handle, self)46 call::<T, UniqueRefungibleCall<T>, _, _>(handle, self)47 }47 }48}48}4949pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterbothno changes
pallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth333334// Selector: 942e8b2234// Selector: 942e8b2235contract ERC20 is Dummy, ERC165, ERC20Events {35contract ERC20 is Dummy, ERC165, ERC20Events {36 // @return the name of the token.37 //36 // Selector: name() 06fdde0338 // Selector: name() 06fdde0337 function name() public view returns (string memory) {39 function name() public view returns (string memory) {38 require(false, stub_error);40 require(false, stub_error);39 dummy;41 dummy;40 return "";42 return "";41 }43 }424445 // @return the symbol of the token.46 //43 // Selector: symbol() 95d89b4147 // Selector: symbol() 95d89b4144 function symbol() public view returns (string memory) {48 function symbol() public view returns (string memory) {45 require(false, stub_error);49 require(false, stub_error);46 dummy;50 dummy;47 return "";51 return "";48 }52 }495354 // @dev Total number of tokens in existence55 //50 // Selector: totalSupply() 18160ddd56 // Selector: totalSupply() 18160ddd51 function totalSupply() public view returns (uint256) {57 function totalSupply() public view returns (uint256) {52 require(false, stub_error);58 require(false, stub_error);53 dummy;59 dummy;54 return 0;60 return 0;55 }61 }566263 // @dev Not supported64 //57 // Selector: decimals() 313ce56765 // Selector: decimals() 313ce56758 function decimals() public view returns (uint8) {66 function decimals() public view returns (uint8) {59 require(false, stub_error);67 require(false, stub_error);60 dummy;68 dummy;61 return 0;69 return 0;62 }70 }637172 // @dev Gets the balance of the specified address.73 // @param owner The address to query the balance of.74 // @return An uint256 representing the amount owned by the passed address.75 //64 // Selector: balanceOf(address) 70a0823176 // Selector: balanceOf(address) 70a0823165 function balanceOf(address owner) public view returns (uint256) {77 function balanceOf(address owner) public view returns (uint256) {66 require(false, stub_error);78 require(false, stub_error);69 return 0;81 return 0;70 }82 }718384 // @dev Transfer token for a specified address85 // @param to The address to transfer to.86 // @param amount The amount to be transferred.87 //72 // Selector: transfer(address,uint256) a9059cbb88 // Selector: transfer(address,uint256) a9059cbb73 function transfer(address to, uint256 amount) public returns (bool) {89 function transfer(address to, uint256 amount) public returns (bool) {74 require(false, stub_error);90 require(false, stub_error);78 return false;94 return false;79 }95 }809697 // @dev Transfer tokens from one address to another98 // @param from address The address which you want to send tokens from99 // @param to address The address which you want to transfer to100 // @param amount uint256 the amount of tokens to be transferred101 //81 // Selector: transferFrom(address,address,uint256) 23b872dd102 // Selector: transferFrom(address,address,uint256) 23b872dd82 function transferFrom(103 function transferFrom(83 address from,104 address from,92 return false;113 return false;93 }114 }94115116 // @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.117 // Beware that changing an allowance with this method brings the risk that someone may use both the old118 // and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this119 // race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:120 // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729121 // @param spender The address which will spend the funds.122 // @param amount The amount of tokens to be spent.123 //95 // Selector: approve(address,uint256) 095ea7b3124 // Selector: approve(address,uint256) 095ea7b396 function approve(address spender, uint256 amount) public returns (bool) {125 function approve(address spender, uint256 amount) public returns (bool) {97 require(false, stub_error);126 require(false, stub_error);101 return false;130 return false;102 }131 }103132133 // @dev Function to check the amount of tokens that an owner allowed to a spender.134 // @param owner address The address which owns the funds.135 // @param spender address The address which will spend the funds.136 // @return A uint256 specifying the amount of tokens still available for the spender.137 //104 // Selector: allowance(address,address) dd62ed3e138 // Selector: allowance(address,address) dd62ed3e105 function allowance(address owner, address spender)139 function allowance(address owner, address spender)106 public140 public117151118// Selector: ab8deb37152// Selector: ab8deb37119contract ERC20UniqueExtensions is Dummy, ERC165 {153contract ERC20UniqueExtensions is Dummy, ERC165 {154 // @dev Function that burns an amount of the token of a given account,155 // deducting from the sender's allowance for said account.156 // @param from The account whose tokens will be burnt.157 // @param amount The amount that will be burnt.158 //120 // Selector: burnFrom(address,uint256) 79cc6790159 // Selector: burnFrom(address,uint256) 79cc6790121 function burnFrom(address from, uint256 amount) public returns (bool) {160 function burnFrom(address from, uint256 amount) public returns (bool) {122 require(false, stub_error);161 require(false, stub_error);126 return false;165 return false;127 }166 }128167168 // @dev Function that changes total amount of the tokens.169 // Throws if `msg.sender` doesn't owns all of the tokens.170 // @param amount New total amount of the tokens.171 //129 // Selector: repartition(uint256) d2418ca7172 // Selector: repartition(uint256) d2418ca7130 function repartition(uint256 amount) public returns (bool) {173 function repartition(uint256 amount) public returns (bool) {131 require(false, stub_error);174 require(false, stub_error);pallets/unique/CHANGELOG.mddiffbeforeafterbothno changes
pallets/unique/Cargo.tomldiffbeforeafterboth9license = 'GPLv3'9license = 'GPLv3'10name = 'pallet-unique'10name = 'pallet-unique'11repository = 'https://github.com/UniqueNetwork/unique-chain'11repository = 'https://github.com/UniqueNetwork/unique-chain'12version = '0.1.0'12version = '0.1.1'131314[package.metadata.docs.rs]14[package.metadata.docs.rs]15targets = ['x86_64-unknown-linux-gnu']15targets = ['x86_64-unknown-linux-gnu']103evm-coder = { default-features = false, path = '../../crates/evm-coder' }103evm-coder = { default-features = false, path = '../../crates/evm-coder' }104pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }104pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }105pallet-nonfungible = { default-features = false, path = '../../pallets/nonfungible' }105pallet-nonfungible = { default-features = false, path = '../../pallets/nonfungible' }106pallet-refungible = { default-features = false, path = '../../pallets/refungible' }106107pallets/unique/src/eth/mod.rsdiffbeforeafterboth17//! Implementation of CollectionHelpers contract.17//! Implementation of CollectionHelpers contract.181819use core::marker::PhantomData;19use core::marker::PhantomData;20use evm_coder::{execution::*, generate_stubgen, solidity_interface, weight, types::*};20use evm_coder::{execution::*, generate_stubgen, solidity_interface, solidity, weight, types::*};21use ethereum as _;21use ethereum as _;22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, PrecompileHandle};23use pallet_evm::{OnMethodCall, PrecompileResult, account::CrossAccountId, PrecompileHandle};24use up_data_structs::{24use up_data_structs::{25 CreateCollectionData, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,25 CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData,26 MAX_COLLECTION_NAME_LENGTH,26 CollectionMode, PropertyValue,27};27};28use frame_support::traits::Get;28use frame_support::traits::Get;29use pallet_common::{29use pallet_common::{30 CollectionById,30 CollectionById,31 erc::{token_uri_key, CollectionHelpersEvents},31 erc::{32 static_property::{key, value as property_value},33 CollectionHelpersEvents,34 },35 dispatch::CollectionDispatch,32};36};33use crate::{SelfWeightOf, Config, weights::WeightInfo};37use crate::{SelfWeightOf, Config, weights::WeightInfo};343847 }51 }48}52}5354fn convert_data<T: Config>(55 caller: caller,56 name: string,57 description: string,58 token_prefix: string,59 base_uri: string,60) -> Result<(61 T::CrossAccountId,62 CollectionName,63 CollectionDescription,64 CollectionTokenPrefix,65 PropertyValue,66)> {67 let caller = T::CrossAccountId::from_eth(caller);68 let name = name69 .encode_utf16()70 .collect::<Vec<u16>>()71 .try_into()72 .map_err(|_| error_field_too_long(stringify!(name), CollectionName::bound()))?;73 let description = description74 .encode_utf16()75 .collect::<Vec<u16>>()76 .try_into()77 .map_err(|_| {78 error_field_too_long(stringify!(description), CollectionDescription::bound())79 })?;80 let token_prefix = token_prefix.into_bytes().try_into().map_err(|_| {81 error_field_too_long(stringify!(token_prefix), CollectionTokenPrefix::bound())82 })?;83 let base_uri_value = base_uri84 .into_bytes()85 .try_into()86 .map_err(|_| error_field_too_long(stringify!(token_prefix), PropertyValue::bound()))?;87 Ok((caller, name, description, token_prefix, base_uri_value))88}8990fn make_data<T: Config>(91 name: CollectionName,92 mode: CollectionMode,93 description: CollectionDescription,94 token_prefix: CollectionTokenPrefix,95 base_uri_value: PropertyValue,96 add_properties: bool,97) -> Result<CreateCollectionData<T::AccountId>> {98 let mut properties = up_data_structs::CollectionPropertiesVec::default();99 let mut token_property_permissions =100 up_data_structs::CollectionPropertiesPermissionsVec::default();101102 token_property_permissions103 .try_push(up_data_structs::PropertyKeyPermission {104 key: key::url(),105 permission: up_data_structs::PropertyPermission {106 mutable: false,107 collection_admin: true,108 token_owner: false,109 },110 })111 .map_err(|e| Error::Revert(format!("{:?}", e)))?;112113 if add_properties {114 token_property_permissions115 .try_push(up_data_structs::PropertyKeyPermission {116 key: key::suffix(),117 permission: up_data_structs::PropertyPermission {118 mutable: false,119 collection_admin: true,120 token_owner: false,121 },122 })123 .map_err(|e| Error::Revert(format!("{:?}", e)))?;124125 properties126 .try_push(up_data_structs::Property {127 key: key::schema_name(),128 value: property_value::erc721(),129 })130 .map_err(|e| Error::Revert(format!("{:?}", e)))?;131132 if !base_uri_value.is_empty() {133 properties134 .try_push(up_data_structs::Property {135 key: key::base_uri(),136 value: base_uri_value,137 })138 .map_err(|e| Error::Revert(format!("{:?}", e)))?;139 }140 }141142 let data = CreateCollectionData {143 name,144 mode,145 description,146 token_prefix,147 token_property_permissions,148 properties,149 ..Default::default()150 };151 Ok(data)152}4915350/// @title Contract, which allows users to operate with collections154/// @title Contract, which allows users to operate with collections51#[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))]155#[solidity_interface(name = "CollectionHelpers", events(CollectionHelpersEvents))]52impl<T: Config + pallet_nonfungible::Config> EvmCollectionHelpers<T> {156impl<T> EvmCollectionHelpers<T>157where158 T: Config + pallet_nonfungible::Config + pallet_refungible::Config,159{53 /// Create an NFT collection160 /// Create an NFT collection54 /// @param name Name of the collection161 /// @param name Name of the collection62 name: string,169 name: string,63 description: string,170 description: string,64 token_prefix: string,171 token_prefix: string,65 ) -> Result<address> {172 ) -> Result<address> {173 let (caller, name, description, token_prefix, _base_uri_value) =174 convert_data::<T>(caller, name, description, token_prefix, "".into())?;175 let data = make_data::<T>(176 name,177 CollectionMode::NFT,178 description,179 token_prefix,180 Default::default(),181 false,182 )?;183 let collection_id = T::CollectionDispatch::create(caller, data)184 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;185186 let address = pallet_common::eth::collection_id_to_address(collection_id);187 Ok(address)188 }18966 let caller = T::CrossAccountId::from_eth(caller);190 #[weight(<SelfWeightOf<T>>::create_collection())]191 #[solidity(rename_selector = "createERC721MetadataCompatibleCollection")]192 fn create_nonfungible_collection_with_properties(193 &mut self,194 caller: caller,67 let name = name195 name: string,68 .encode_utf16()196 description: string,69 .collect::<Vec<u16>>()197 token_prefix: string,70 .try_into()198 base_uri: string,71 .map_err(|_| error_feild_too_long(stringify!(name), MAX_COLLECTION_NAME_LENGTH))?;199 ) -> Result<address> {72 let description = description200 let (caller, name, description, token_prefix, base_uri_value) =73 .encode_utf16()74 .collect::<Vec<u16>>()201 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;75 .try_into()76 .map_err(|_| {77 error_feild_too_long(stringify!(description), MAX_COLLECTION_DESCRIPTION_LENGTH)78 })?;79 let token_prefix = token_prefix202 let data = make_data::<T>(80 .into_bytes()203 name,81 .try_into()204 CollectionMode::NFT,205 description,82 .map_err(|_| error_feild_too_long(stringify!(token_prefix), MAX_TOKEN_PREFIX_LENGTH))?;206 token_prefix,83207 base_uri_value,208 true,209 )?;84 let key = token_uri_key();210 let collection_id = T::CollectionDispatch::create(caller, data)85 let permission = up_data_structs::PropertyPermission {211 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;212213 let address = pallet_common::eth::collection_id_to_address(collection_id);214 Ok(address)215 }216217 #[weight(<SelfWeightOf<T>>::create_collection())]218 fn create_refungible_collection(219 &self,86 mutable: true,220 caller: caller,87 collection_admin: true,221 name: string,88 token_owner: false,222 description: string,223 token_prefix: string,224 ) -> Result<address> {225 let (caller, name, description, token_prefix, _base_uri) =89 };226 convert_data::<T>(caller, name, description, token_prefix, "".into())?;90 let mut token_property_permissions =227 let data = make_data::<T>(228 name,91 up_data_structs::CollectionPropertiesPermissionsVec::default();229 CollectionMode::ReFungible,92 token_property_permissions230 description,231 token_prefix,232 Default::default(),233 false,234 )?;93 .try_push(up_data_structs::PropertyKeyPermission { key, permission })235 let collection_id = T::CollectionDispatch::create(caller, data)94 .map_err(|e| Error::Revert(format!("{:?}", e)))?;236 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;9523796 let data = CreateCollectionData {238 let address = pallet_common::eth::collection_id_to_address(collection_id);239 Ok(address)240 }241242 #[weight(<SelfWeightOf<T>>::create_collection())]243 #[solidity(rename_selector = "createERC721MetadataCompatibleRFTCollection")]244 fn create_refungible_collection_with_properties(245 &mut self,246 caller: caller,247 name: string,248 description: string,249 token_prefix: string,250 base_uri: string,251 ) -> Result<address> {97 name,252 let (caller, name, description, token_prefix, base_uri_value) =98 description,99 token_prefix,100 token_property_permissions,101 ..Default::default()253 convert_data::<T>(caller, name, description, token_prefix, base_uri)?;254 let data = make_data::<T>(255 name,256 CollectionMode::NFT,257 description,258 token_prefix,259 base_uri_value,260 true,102 };261 )?;103104 let collection_id =262 let collection_id = T::CollectionDispatch::create(caller, data)105 <pallet_nonfungible::Pallet<T>>::init_collection(caller.clone(), data, false)106 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;263 .map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;107264108 let address = pallet_common::eth::collection_id_to_address(collection_id);265 let address = pallet_common::eth::collection_id_to_address(collection_id);109 Ok(address)266 Ok(address)110 }267 }111268112 /// Check if a collection exists269 /// Check if a collection exists113 /// @param collection_address Address of the collection in question270 /// @param collection_address Address of the collection in question124281125/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]282/// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]126pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);283pub struct CollectionHelpersOnMethodCall<T: Config>(PhantomData<*const T>);127impl<T: Config + pallet_nonfungible::Config> OnMethodCall<T> for CollectionHelpersOnMethodCall<T> {284impl<T: Config + pallet_nonfungible::Config + pallet_refungible::Config> OnMethodCall<T>285 for CollectionHelpersOnMethodCall<T>286{128 fn is_reserved(contract: &sp_core::H160) -> bool {287 fn is_reserved(contract: &sp_core::H160) -> bool {152generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);311generate_stubgen!(collection_helper_impl, CollectionHelpersCall<()>, true);153generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);312generate_stubgen!(collection_helper_iface, CollectionHelpersCall<()>, false);154313155fn error_feild_too_long(feild: &str, bound: u32) -> Error {314fn error_field_too_long(feild: &str, bound: usize) -> Error {156 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))315 Error::Revert(format!("{} is too long. Max length is {}.", feild, bound))157}316}158317pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth29 );29 );30}30}313132// Selector: 20947cd032// Selector: c20653fc33contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {33contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {34 // Selector: createNonfungibleCollection(string,string,string) e34a684434 // Selector: createNonfungibleCollection(string,string,string) e34a684435 function createNonfungibleCollection(35 function createNonfungibleCollection(45 return 0x0000000000000000000000000000000000000000;45 return 0x0000000000000000000000000000000000000000;46 }46 }4748 // Selector: createERC721MetadataCompatibleCollection(string,string,string,string) a634a5f949 function createERC721MetadataCompatibleCollection(50 string memory name,51 string memory description,52 string memory tokenPrefix,53 string memory baseUri54 ) public returns (address) {55 require(false, stub_error);56 name;57 description;58 tokenPrefix;59 baseUri;60 dummy = 0;61 return 0x0000000000000000000000000000000000000000;62 }6364 // Selector: createRefungibleCollection(string,string,string) 44a68ad565 function createRefungibleCollection(66 string memory name,67 string memory description,68 string memory tokenPrefix69 ) public view returns (address) {70 require(false, stub_error);71 name;72 description;73 tokenPrefix;74 dummy;75 return 0x0000000000000000000000000000000000000000;76 }477748 // Selector: isCollectionExist(address) c3de149478 // Selector: isCollectionExist(address) c3de149449 function isCollectionExist(address collectionAddress)79 function isCollectionExist(address collectionAddress)pallets/unique/src/lib.rsdiffbeforeafterboth352352353 // =========353 // =========354354355 T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;355 let _id = T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;356356357 Ok(())357 Ok(())358 }358 }primitives/data-structs/CHANGELOG.mddiffbeforeafterbothno changes
primitives/data-structs/Cargo.tomldiffbeforeafterboth6license = 'GPLv3'6license = 'GPLv3'7homepage = "https://unique.network"7homepage = "https://unique.network"8repository = 'https://github.com/UniqueNetwork/unique-chain'8repository = 'https://github.com/UniqueNetwork/unique-chain'9version = '0.1.1'9version = '0.1.2'101011[dependencies]11[dependencies]12scale-info = { version = "2.0.1", default-features = false, features = [12scale-info = { version = "2.0.1", default-features = false, features = [primitives/data-structs/Changelog.mddiffbeforeafterbothno changes
primitives/data-structs/src/lib.rsdiffbeforeafterboth286 }286 }287}287}288289pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;290pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;291pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;288292289/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).293/// Collection parameters, used in storage (see [`RpcCollection`] for the RPC version).290#[struct_versioning::versioned(version = 2, upper)]294#[struct_versioning::versioned(version = 2, upper)]294 pub mode: CollectionMode,298 pub mode: CollectionMode,295 #[version(..2)]299 #[version(..2)]296 pub access: AccessMode,300 pub access: AccessMode,297 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,301 pub name: CollectionName,298 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,302 pub description: CollectionDescription,299 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,303 pub token_prefix: CollectionTokenPrefix,300304301 #[version(..2)]305 #[version(..2)]302 pub mint_mode: bool,306 pub mint_mode: bool,350 #[derivative(Default(value = "CollectionMode::NFT"))]354 #[derivative(Default(value = "CollectionMode::NFT"))]351 pub mode: CollectionMode,355 pub mode: CollectionMode,352 pub access: Option<AccessMode>,356 pub access: Option<AccessMode>,353 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,357 pub name: CollectionName,354 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,358 pub description: CollectionDescription,355 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,359 pub token_prefix: CollectionTokenPrefix,356 pub pending_sponsor: Option<AccountId>,360 pub pending_sponsor: Option<AccountId>,357 pub limits: Option<CollectionLimits>,361 pub limits: Option<CollectionLimits>,358 pub permissions: Option<CollectionPermissions>,362 pub permissions: Option<CollectionPermissions>,runtime/common/src/dispatch.rsdiffbeforeafterboth17use frame_support::{dispatch::DispatchResult, ensure};17use frame_support::{dispatch::DispatchResult, ensure};18use pallet_evm::{PrecompileHandle, PrecompileResult};18use pallet_evm::{PrecompileHandle, PrecompileResult};19use sp_core::H160;19use sp_core::H160;20use sp_runtime::DispatchError;20use sp_std::{borrow::ToOwned, vec::Vec};21use sp_std::{borrow::ToOwned, vec::Vec};21use pallet_common::{22use pallet_common::{22 CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,23 CollectionById, CollectionHandle, CommonCollectionOperations, erc::CommonEvmHandler,30};31};31use up_data_structs::{32use up_data_structs::{32 CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,33 CollectionMode, CreateCollectionData, MAX_DECIMAL_POINTS, mapping::TokenAddressMapping,34 CollectionId,33};35};343635pub enum CollectionDispatchT<T>37pub enum CollectionDispatchT<T>51 fn create(53 fn create(52 sender: T::CrossAccountId,54 sender: T::CrossAccountId,53 data: CreateCollectionData<T::AccountId>,55 data: CreateCollectionData<T::AccountId>,54 ) -> DispatchResult {56 ) -> Result<CollectionId, DispatchError> {55 let _id = match data.mode {57 let id = match data.mode {56 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,58 CollectionMode::NFT => <PalletNonfungible<T>>::init_collection(sender, data, false)?,57 CollectionMode::Fungible(decimal_points) => {59 CollectionMode::Fungible(decimal_points) => {58 // check params60 // check params64 }66 }65 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,67 CollectionMode::ReFungible => <PalletRefungible<T>>::init_collection(sender, data)?,66 };68 };67 Ok(())69 Ok(id)68 }70 }697170 fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {72 fn destroy(sender: T::CrossAccountId, collection: CollectionHandle<T>) -> DispatchResult {tests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth20 );20 );21}21}222223// Selector: 20947cd023// Selector: c20653fc24interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {24interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {25 // Selector: createNonfungibleCollection(string,string,string) e34a684425 // Selector: createNonfungibleCollection(string,string,string) e34a684426 function createNonfungibleCollection(26 function createNonfungibleCollection(29 string memory tokenPrefix29 string memory tokenPrefix30 ) external returns (address);30 ) external returns (address);3132 // Selector: createERC721MetadataCompatibleCollection(string,string,string,string) a634a5f933 function createERC721MetadataCompatibleCollection(34 string memory name,35 string memory description,36 string memory tokenPrefix,37 string memory baseUri38 ) external returns (address);3940 // Selector: createRefungibleCollection(string,string,string) 44a68ad541 function createRefungibleCollection(42 string memory name,43 string memory description,44 string memory tokenPrefix45 ) external view returns (address);314632 // Selector: isCollectionExist(address) c3de149447 // Selector: isCollectionExist(address) c3de149433 function isCollectionExist(address collectionAddress)48 function isCollectionExist(address collectionAddress)tests/src/eth/api/UniqueRFT.soldiffbeforeafterbothno changes
tests/src/eth/api/UniqueRefungible.soldiffbeforeafterbothno changes
tests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth242425// Selector: 942e8b2225// Selector: 942e8b2226interface ERC20 is Dummy, ERC165, ERC20Events {26interface ERC20 is Dummy, ERC165, ERC20Events {27 // @return the name of the token.28 //27 // Selector: name() 06fdde0329 // Selector: name() 06fdde0328 function name() external view returns (string memory);30 function name() external view returns (string memory);293132 // @return the symbol of the token.33 //30 // Selector: symbol() 95d89b4134 // Selector: symbol() 95d89b4131 function symbol() external view returns (string memory);35 function symbol() external view returns (string memory);323637 // @dev Total number of tokens in existence38 //33 // Selector: totalSupply() 18160ddd39 // Selector: totalSupply() 18160ddd34 function totalSupply() external view returns (uint256);40 function totalSupply() external view returns (uint256);354142 // @dev Not supported43 //36 // Selector: decimals() 313ce56744 // Selector: decimals() 313ce56737 function decimals() external view returns (uint8);45 function decimals() external view returns (uint8);384647 // @dev Gets the balance of the specified address.48 // @param owner The address to query the balance of.49 // @return An uint256 representing the amount owned by the passed address.50 //39 // Selector: balanceOf(address) 70a0823151 // Selector: balanceOf(address) 70a0823140 function balanceOf(address owner) external view returns (uint256);52 function balanceOf(address owner) external view returns (uint256);415354 // @dev Transfer token for a specified address55 // @param to The address to transfer to.56 // @param amount The amount to be transferred.57 //42 // Selector: transfer(address,uint256) a9059cbb58 // Selector: transfer(address,uint256) a9059cbb43 function transfer(address to, uint256 amount) external returns (bool);59 function transfer(address to, uint256 amount) external returns (bool);446061 // @dev Transfer tokens from one address to another62 // @param from address The address which you want to send tokens from63 // @param to address The address which you want to transfer to64 // @param amount uint256 the amount of tokens to be transferred65 //45 // Selector: transferFrom(address,address,uint256) 23b872dd66 // Selector: transferFrom(address,address,uint256) 23b872dd46 function transferFrom(67 function transferFrom(47 address from,68 address from,48 address to,69 address to,49 uint256 amount70 uint256 amount50 ) external returns (bool);71 ) external returns (bool);517273 // @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.74 // Beware that changing an allowance with this method brings the risk that someone may use both the old75 // and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this76 // race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:77 // https://github.com/ethereum/EIPs/issues/20#issuecomment-26352472978 // @param spender The address which will spend the funds.79 // @param amount The amount of tokens to be spent.80 //52 // Selector: approve(address,uint256) 095ea7b381 // Selector: approve(address,uint256) 095ea7b353 function approve(address spender, uint256 amount) external returns (bool);82 function approve(address spender, uint256 amount) external returns (bool);548384 // @dev Function to check the amount of tokens that an owner allowed to a spender.85 // @param owner address The address which owns the funds.86 // @param spender address The address which will spend the funds.87 // @return A uint256 specifying the amount of tokens still available for the spender.88 //55 // Selector: allowance(address,address) dd62ed3e89 // Selector: allowance(address,address) dd62ed3e56 function allowance(address owner, address spender)90 function allowance(address owner, address spender)57 external91 external619562// Selector: ab8deb3796// Selector: ab8deb3763interface ERC20UniqueExtensions is Dummy, ERC165 {97interface ERC20UniqueExtensions is Dummy, ERC165 {98 // @dev Function that burns an amount of the token of a given account,99 // deducting from the sender's allowance for said account.100 // @param from The account whose tokens will be burnt.101 // @param amount The amount that will be burnt.102 //64 // Selector: burnFrom(address,uint256) 79cc6790103 // Selector: burnFrom(address,uint256) 79cc679065 function burnFrom(address from, uint256 amount) external returns (bool);104 function burnFrom(address from, uint256 amount) external returns (bool);66105106 // @dev Function that changes total amount of the tokens.107 // Throws if `msg.sender` doesn't owns all of the tokens.108 // @param amount New total amount of the tokens.109 //67 // Selector: repartition(uint256) d2418ca7110 // Selector: repartition(uint256) d2418ca768 function repartition(uint256 amount) external returns (bool);111 function repartition(uint256 amount) external returns (bool);69}112}tests/src/eth/collectionHelpersAbi.jsondiffbeforeafterboth18 "name": "CollectionCreated",18 "name": "CollectionCreated",19 "type": "event"19 "type": "event"20 },20 },21 {22 "inputs": [23 { "internalType": "string", "name": "name", "type": "string" },24 { "internalType": "string", "name": "description", "type": "string" },25 { "internalType": "string", "name": "tokenPrefix", "type": "string" },26 { "internalType": "string", "name": "baseUri", "type": "string" }27 ],28 "name": "createERC721MetadataCompatibleCollection",29 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],30 "stateMutability": "nonpayable",31 "type": "function"32 },21 {33 {22 "inputs": [34 "inputs": [23 { "internalType": "string", "name": "name", "type": "string" },35 { "internalType": "string", "name": "name", "type": "string" },29 "stateMutability": "nonpayable",41 "stateMutability": "nonpayable",30 "type": "function"42 "type": "function"31 },43 },44 {45 "inputs": [46 { "internalType": "string", "name": "name", "type": "string" },47 { "internalType": "string", "name": "description", "type": "string" },48 { "internalType": "string", "name": "tokenPrefix", "type": "string" }49 ],50 "name": "createRefungibleCollection",51 "outputs": [{ "internalType": "address", "name": "", "type": "address" }],52 "stateMutability": "view",53 "type": "function"54 },32 {55 {33 "inputs": [56 "inputs": [34 {57 {tests/src/eth/createCollection.test.tsdiffbeforeafterbothno changes
tests/src/eth/createNFTCollection.test.tsdiffbeforeafterbothno changes
tests/src/eth/createRFTCollection.test.tsdiffbeforeafterbothno changes
tests/src/eth/nonFungible.test.tsdiffbeforeafterboth72 });72 });73});73});7475describe('Check ERC721 token URI for NFT', () => {76 itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {77 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);78 const helper = evmCollectionHelpers(web3, owner);79 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();80 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);81 const receiver = createEthAccount(web3);82 const contract = evmCollection(web3, owner, collectionIdAddress);83 84 const nextTokenId = await contract.methods.nextTokenId().call();85 expect(nextTokenId).to.be.equal('1');86 result = await contract.methods.mint(87 receiver,88 nextTokenId,89 ).send();9091 const events = normalizeEvents(result.events);92 const address = collectionIdToAddress(collectionId);9394 expect(events).to.be.deep.equal([95 {96 address,97 event: 'Transfer',98 args: {99 from: '0x0000000000000000000000000000000000000000',100 to: receiver,101 tokenId: nextTokenId,102 },103 },104 ]);105106 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');107 });108109 itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {110 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);111 const helper = evmCollectionHelpers(web3, owner);112 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();113 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);114 const receiver = createEthAccount(web3);115 const contract = evmCollection(web3, owner, collectionIdAddress);116 117 const nextTokenId = await contract.methods.nextTokenId().call();118 expect(nextTokenId).to.be.equal('1');119 result = await contract.methods.mint(120 receiver,121 nextTokenId,122 ).send();123 124 // Set URL125 await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();126 127 const events = normalizeEvents(result.events);128 const address = collectionIdToAddress(collectionId);129130 expect(events).to.be.deep.equal([131 {132 address,133 event: 'Transfer',134 args: {135 from: '0x0000000000000000000000000000000000000000',136 to: receiver,137 tokenId: nextTokenId,138 },139 },140 ]);141142 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');143 });144145 itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {146 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);147 const helper = evmCollectionHelpers(web3, owner);148 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();149 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);150 const receiver = createEthAccount(web3);151 const contract = evmCollection(web3, owner, collectionIdAddress);152 153 const nextTokenId = await contract.methods.nextTokenId().call();154 expect(nextTokenId).to.be.equal('1');155 result = await contract.methods.mint(156 receiver,157 nextTokenId,158 ).send();159 160 const events = normalizeEvents(result.events);161 const address = collectionIdToAddress(collectionId);162163 expect(events).to.be.deep.equal([164 {165 address,166 event: 'Transfer',167 args: {168 from: '0x0000000000000000000000000000000000000000',169 to: receiver,170 tokenId: nextTokenId,171 },172 },173 ]);174175 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);176 });177178 itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {179 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);180 const helper = evmCollectionHelpers(web3, owner);181 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();182 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);183 const receiver = createEthAccount(web3);184 const contract = evmCollection(web3, owner, collectionIdAddress);185 186 const nextTokenId = await contract.methods.nextTokenId().call();187 expect(nextTokenId).to.be.equal('1');188 result = await contract.methods.mint(189 receiver,190 nextTokenId,191 ).send();192 193 // Set suffix194 const suffix = '/some/suffix';195 await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();196197 const events = normalizeEvents(result.events);198 const address = collectionIdToAddress(collectionId);199200 expect(events).to.be.deep.equal([201 {202 address,203 event: 'Transfer',204 args: {205 from: '0x0000000000000000000000000000000000000000',206 to: receiver,207 tokenId: nextTokenId,208 },209 },210 ]);211212 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);213 });214});7421575describe('NFT: Plain calls', () => {216describe('NFT: Plain calls', () => {76 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {217 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';17import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';18import {createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';19import reFungibleTokenAbi from './reFungibleTokenAbi.json';19import reFungibleTokenAbi from './reFungibleTokenAbi.json';202021import chai from 'chai';21import chai from 'chai';73 });73 });74});74});7576// FIXME: Need erc721 for ReFubgible.77describe.skip('Check ERC721 token URI for ReFungible', () => {78 itWeb3('Empty tokenURI', async ({web3, api, privateKeyWrapper}) => {79 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);80 const helper = evmCollectionHelpers(web3, owner);81 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', '').send();82 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);83 const receiver = createEthAccount(web3);84 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});85 86 const nextTokenId = await contract.methods.nextTokenId().call();87 expect(nextTokenId).to.be.equal('1');88 result = await contract.methods.mint(89 receiver,90 nextTokenId,91 ).send();9293 const events = normalizeEvents(result.events);94 const address = collectionIdToAddress(collectionId);9596 expect(events).to.be.deep.equal([97 {98 address,99 event: 'Transfer',100 args: {101 from: '0x0000000000000000000000000000000000000000',102 to: receiver,103 tokenId: nextTokenId,104 },105 },106 ]);107108 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');109 });110111 itWeb3('TokenURI from url', async ({web3, api, privateKeyWrapper}) => {112 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);113 const helper = evmCollectionHelpers(web3, owner);114 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();115 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);116 const receiver = createEthAccount(web3);117 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});118 119 const nextTokenId = await contract.methods.nextTokenId().call();120 expect(nextTokenId).to.be.equal('1');121 result = await contract.methods.mint(122 receiver,123 nextTokenId,124 ).send();125 126 // Set URL127 await contract.methods.setProperty(nextTokenId, 'url', Buffer.from('Token URI')).send();128 129 const events = normalizeEvents(result.events);130 const address = collectionIdToAddress(collectionId);131132 expect(events).to.be.deep.equal([133 {134 address,135 event: 'Transfer',136 args: {137 from: '0x0000000000000000000000000000000000000000',138 to: receiver,139 tokenId: nextTokenId,140 },141 },142 ]);143144 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');145 });146147 itWeb3('TokenURI from baseURI + tokenId', async ({web3, api, privateKeyWrapper}) => {148 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);149 const helper = evmCollectionHelpers(web3, owner);150 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();151 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);152 const receiver = createEthAccount(web3);153 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});154 155 const nextTokenId = await contract.methods.nextTokenId().call();156 expect(nextTokenId).to.be.equal('1');157 result = await contract.methods.mint(158 receiver,159 nextTokenId,160 ).send();161 162 const events = normalizeEvents(result.events);163 const address = collectionIdToAddress(collectionId);164165 expect(events).to.be.deep.equal([166 {167 address,168 event: 'Transfer',169 args: {170 from: '0x0000000000000000000000000000000000000000',171 to: receiver,172 tokenId: nextTokenId,173 },174 },175 ]);176177 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);178 });179180 itWeb3('TokenURI from baseURI + suffix', async ({web3, api, privateKeyWrapper}) => {181 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);182 const helper = evmCollectionHelpers(web3, owner);183 let result = await helper.methods.createERC721MetadataCompatibleCollection('Mint collection', '1', '1', 'BaseURI_').send();184 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);185 const receiver = createEthAccount(web3);186 const contract = evmCollection(web3, owner, collectionIdAddress, {type: 'ReFungible'});187 188 const nextTokenId = await contract.methods.nextTokenId().call();189 expect(nextTokenId).to.be.equal('1');190 result = await contract.methods.mint(191 receiver,192 nextTokenId,193 ).send();194 195 // Set suffix196 const suffix = '/some/suffix';197 await contract.methods.setProperty(nextTokenId, 'suffix', Buffer.from(suffix)).send();198199 const events = normalizeEvents(result.events);200 const address = collectionIdToAddress(collectionId);201202 expect(events).to.be.deep.equal([203 {204 address,205 event: 'Transfer',206 args: {207 from: '0x0000000000000000000000000000000000000000',208 to: receiver,209 tokenId: nextTokenId,210 },211 },212 ]);213214 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);215 });216});7521776describe('Refungible: Plain calls', () => {218describe('Refungible: Plain calls', () => {77 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {219 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {tests/src/eth/refungibleAbi.jsondiffbeforeafterbothno changes
tests/src/eth/util/helpers.tsdiffbeforeafterboth25import Web3 from 'web3';25import Web3 from 'web3';26import config from '../../config';26import config from '../../config';27import getBalance from '../../substrate/get-balance';27import getBalance from '../../substrate/get-balance';28import privateKey from '../../substrate/privateKey';29import usingApi, {submitTransactionAsync} from '../../substrate/substrate-api';28import usingApi, {submitTransactionAsync} from '../../substrate/substrate-api';30import waitNewBlocks from '../../substrate/wait-new-blocks';29import waitNewBlocks from '../../substrate/wait-new-blocks';31import {CrossAccountId, getDetailedCollectionInfo, getGenericResult, UNIQUE} from '../../util/helpers';30import {CollectionMode, CrossAccountId, getDetailedCollectionInfo, getGenericResult, UNIQUE} from '../../util/helpers';32import collectionHelpersAbi from '../collectionHelpersAbi.json';31import collectionHelpersAbi from '../collectionHelpersAbi.json';32import fungibleAbi from '../fungibleAbi.json';33import nonFungibleAbi from '../nonFungibleAbi.json';33import nonFungibleAbi from '../nonFungibleAbi.json';34import refungibleAbi from '../refungibleAbi.json';34import contractHelpersAbi from './contractHelpersAbi.json';35import contractHelpersAbi from './contractHelpersAbi.json';353636export const GAS_ARGS = {gas: 2500000};37export const GAS_ARGS = {gas: 2500000};307 * @param caller - eth address308 * @param caller - eth address308 * @returns 309 * @returns 309 */310 */310export function evmCollection(web3: Web3, caller: string, collection: string) {311export function evmCollection(web3: Web3, caller: string, collection: string, mode: CollectionMode = {type: 'NFT'}) {312 let abi;313 switch (mode.type) {314 case 'Fungible':315 abi = fungibleAbi;316 break;317 318 case 'NFT':319 abi = nonFungibleAbi;320 break;321 322 case 'ReFungible':323 abi = refungibleAbi;324 break;325326 default:327 throw 'Bad collection mode';328 }311 return new web3.eth.Contract(nonFungibleAbi as any, collection, {from: caller, ...GAS_ARGS});329 const contract = new web3.eth.Contract(abi as any, collection, {from: caller, ...GAS_ARGS});330 return contract;312}331}313332314/**333/**