From 73c74cbad5e3a48974e0d1d1071c49817f749890 Mon Sep 17 00:00:00 2001 From: PraetorP Date: Mon, 24 Oct 2022 21:43:48 +0000 Subject: [PATCH] added `destroyCollection`method to `CollectionHelpers` --- --- a/Cargo.lock +++ b/Cargo.lock @@ -6799,7 +6799,7 @@ [[package]] name = "pallet-unique" -version = "0.2.0" +version = "0.2.1" dependencies = [ "ethereum", "evm-coder", --- a/pallets/unique/CHANGELOG.md +++ b/pallets/unique/CHANGELOG.md @@ -4,33 +4,40 @@ +## [v0.2.1] 2022-10-10 + +### Changes + +- Addded **CollectionHelpers** method `destroyCollection`. + ## [v0.2.0] 2022-09-13 ### Changes -- Change **collectionHelper** method `createRefungibleCollection` to `createRFTCollection`, +- Change **collectionHelper** method `createRefungibleCollection` to `createRFTCollection`, + ## [v0.1.4] 2022-09-05 ### Added -- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic. +- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic. ## [v0.1.3] 2022-08-16 ### Other changes -- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a +- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a -- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 +- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 -- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31 +- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31 Every extrinsic now runs in transaction implicitly, and `#[transactional]` on pallet dispatchable is now meaningless Upstream-Change: https://github.com/paritytech/substrate/issues/10806 -- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975 +- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975 New methods allows to call `remove_prefix` with limit multiple times in the same block @@ -39,12 +46,12 @@ Upstream-Change: https://github.com/paritytech/substrate/pull/11490 -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b +- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b ## [v0.1.1] - 2022-07-25 ### Added -- Method for creating `ERC721Metadata` compatible NFT collection. -- Method for creating `ERC721Metadata` compatible ReFungible collection. -- Method for creating ReFungible collection. +- Method for creating `ERC721Metadata` compatible NFT collection. +- Method for creating `ERC721Metadata` compatible ReFungible collection. +- Method for creating ReFungible collection. --- a/pallets/unique/Cargo.toml +++ b/pallets/unique/Cargo.toml @@ -9,7 +9,7 @@ license = 'GPLv3' name = 'pallet-unique' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = "0.2.0" +version = "0.2.1" [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] --- a/pallets/unique/src/eth/mod.rs +++ b/pallets/unique/src/eth/mod.rs @@ -19,7 +19,9 @@ use core::marker::PhantomData; use ethereum as _; use evm_coder::{execution::*, generate_stubgen, solidity_interface, solidity, weight, types::*}; -use frame_support::traits::Get; +use frame_support::{traits::Get, storage::StorageNMap}; + +use crate::sp_api_hidden_includes_decl_storage::hidden_include::StorageDoubleMap; use pallet_common::{ CollectionById, dispatch::CollectionDispatch, @@ -37,7 +39,10 @@ CollectionMode, PropertyValue, CollectionFlags, }; -use crate::{Config, SelfWeightOf, weights::WeightInfo}; +use crate::{ + Config, SelfWeightOf, weights::WeightInfo, NftTransferBasket, FungibleTransferBasket, + ReFungibleTransferBasket, NftApproveBasket, FungibleApproveBasket, RefungibleApproveBasket, +}; use sp_std::vec::Vec; use alloc::format; @@ -296,6 +301,33 @@ Ok(()) } + #[weight(>::destroy_collection())] + #[solidity(rename_selector = "destroyCollection")] + fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let collection_id = pallet_common::eth::map_eth_to_id(&collection_address) + .ok_or("Invalid collection address format".into()) + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; + let collection = >::try_get(collection_id) + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; + collection + .check_is_internal() + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; + + T::CollectionDispatch::destroy(caller, collection) + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::)?; + + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix((collection_id,), u32::MAX, None); + + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix((collection_id,), u32::MAX, None); + + Ok(()) + } + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? --- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol +++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol @@ -23,7 +23,7 @@ } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0x58918631 +/// @dev the ERC-165 identifier for this interface is 0x0edfb42e contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection @@ -85,6 +85,14 @@ dummy = 0; } + /// @dev EVM selector for this function is: 0x564e321f, + /// or in textual repr: destroyCollection(address) + function destroyCollection(address collectionAddress) public { + require(false, stub_error); + collectionAddress; + dummy = 0; + } + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? --- a/tests/src/eth/api/CollectionHelpers.sol +++ b/tests/src/eth/api/CollectionHelpers.sol @@ -18,7 +18,7 @@ } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0x58918631 +/// @dev the ERC-165 identifier for this interface is 0x0edfb42e interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection @@ -54,6 +54,10 @@ /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string) function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external; + /// @dev EVM selector for this function is: 0x564e321f, + /// or in textual repr: destroyCollection(address) + function destroyCollection(address collectionAddress) external; + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? --- a/tests/src/eth/collectionHelpersAbi.json +++ b/tests/src/eth/collectionHelpersAbi.json @@ -55,6 +55,19 @@ "type": "address" } ], + "name": "destroyCollection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "collectionAddress", + "type": "address" + } + ], "name": "isCollectionExist", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", --- a/tests/src/eth/createRFTCollection.test.ts +++ b/tests/src/eth/createRFTCollection.test.ts @@ -263,4 +263,18 @@ .setCollectionLimit('badLimit', 'true') .call()).to.be.rejectedWith('unknown boolean limit "badLimit"'); }); + + itEth('destroyCollection test', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); + const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); + + await expect(collectionHelper.methods + .destroyCollection(collectionAddress) + .send({from: owner})).to.be.fulfilled; + + expect(await collectionHelper.methods + .isCollectionExist(collectionAddress) + .call()).to.be.false; + }); }); --- /dev/null +++ b/tests/src/eth/destroyCollection.test.ts @@ -0,0 +1,76 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {Pallets, requirePalletsOrSkip} from '../util'; +import {expect, itEth, usingEthPlaygrounds} from './util'; + + +describe('Destroy Collection from EVM', () => { + let donor: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.ReFungible, Pallets.NFT]); + donor = await privateKey('//Alice'); + }); + }); + + + itEth('(!negative test!) RFT', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const signer = await helper.eth.createAccountWithBalance(donor); + + const unexistedCollection = helper.ethAddress.fromCollectionId(1000000); + + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); + const collectionHelper = helper.ethNativeContract.collectionHelpers(signer); + + await expect(collectionHelper.methods + .destroyCollection(collectionAddress) + .send({from: signer})).to.be.rejected; + + await expect(collectionHelper.methods + .destroyCollection(unexistedCollection) + .send({from: signer})).to.be.rejected; + + expect(await collectionHelper.methods + .isCollectionExist(unexistedCollection) + .call()).to.be.false; + }); + + itEth('(!negative test!) NFT', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const signer = await helper.eth.createAccountWithBalance(donor); + + const unexistedCollection = helper.ethAddress.fromCollectionId(1000000); + + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); + const collectionHelper = helper.ethNativeContract.collectionHelpers(signer); + + await expect(collectionHelper.methods + .destroyCollection(collectionAddress) + .send({from: signer})).to.be.rejected; + + await expect(collectionHelper.methods + .destroyCollection(unexistedCollection) + .send({from: signer})).to.be.rejected; + + expect(await collectionHelper.methods + .isCollectionExist(unexistedCollection) + .call()).to.be.false; + }); +}); -- gitstuff