--- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -64,6 +64,15 @@ #[indexed] collection_id: address, }, + + /// The token has been changed. + TokenChanged { + /// Collection ID. + #[indexed] + collection_id: address, + /// Token ID. + token_id: uint256, + }, } /// Does not always represent a full collection, for RFT it is either --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -108,11 +108,11 @@ use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_common::{ Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle, - eth::collection_id_to_address, + eth::collection_id_to_address, erc::CollectionHelpersEvents, }; use pallet_structure::{Pallet as PalletStructure, Error as StructureError}; use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; -use sp_core::H160; +use sp_core::{H160, Get}; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome}; use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap}; use core::ops::Deref; @@ -673,6 +673,14 @@ )); } } + + >::deposit_log( + CollectionHelpersEvents::TokenChanged { + collection_id: collection_id_to_address(collection.id), + token_id: token_id.into(), + } + .to_log(T::ContractAddress::get()), + ); } Ok(()) --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -102,11 +102,11 @@ use pallet_evm_coder_substrate::WithRecorder; use pallet_common::{ CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address, - Event as CommonEvent, Pallet as PalletCommon, + Event as CommonEvent, Pallet as PalletCommon, erc::CollectionHelpersEvents, }; use pallet_structure::Pallet as PalletStructure; use scale_info::TypeInfo; -use sp_core::H160; +use sp_core::{Get, H160}; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome}; use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap}; use up_data_structs::{ @@ -649,6 +649,14 @@ )); } } + + >::deposit_log( + CollectionHelpersEvents::TokenChanged { + collection_id: collection_id_to_address(collection.id), + token_id: token_id.into(), + } + .to_log(T::ContractAddress::get()), + ); } Ok(()) --- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol +++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol @@ -22,6 +22,7 @@ event CollectionCreated(address indexed owner, address indexed collectionId); event CollectionDestroyed(address indexed collectionId); event CollectionChanged(address indexed collectionId); + event TokenChanged(address indexed collectionId, uint256 tokenId); } /// @title Contract, which allows users to operate with collections --- a/tests/src/eth/abi/collectionHelpers.json +++ b/tests/src/eth/abi/collectionHelpers.json @@ -45,6 +45,25 @@ "type": "event" }, { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "collectionId", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "TokenChanged", + "type": "event" + }, + { "inputs": [ { "internalType": "uint32", "name": "collectionId", "type": "uint32" } ], --- a/tests/src/eth/api/CollectionHelpers.sol +++ b/tests/src/eth/api/CollectionHelpers.sol @@ -17,6 +17,7 @@ event CollectionCreated(address indexed owner, address indexed collectionId); event CollectionDestroyed(address indexed collectionId); event CollectionChanged(address indexed collectionId); + event TokenChanged(address indexed collectionId, uint256 tokenId); } /// @title Contract, which allows users to operate with collections --- a/tests/src/eth/events.test.ts +++ b/tests/src/eth/events.test.ts @@ -354,5 +354,48 @@ } unsubscribe(); }); - + + itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollecion('createNFTCollection', owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); + const result = await collection.methods.mint(owner).send({from: owner}); + const tokenId = result.events.Transfer.returnValues.tokenId; + await collection.methods.setTokenPropertyPermission('A', true, true, true).send({from: owner}); + + + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]); + { + await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner}); + expect(ethEvents).to.be.like([ + { + event: 'TokenChanged', + returnValues: { + collectionId: collectionAddress + } + } + ]); + expect(subEvents).to.be.like([{method: 'TokenPropertySet'}]); + ethEvents.pop(); + subEvents.pop(); + } + { + await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner}); + expect(ethEvents).to.be.like([ + { + event: 'TokenChanged', + returnValues: { + collectionId: collectionAddress + } + } + ]); + expect(subEvents).to.be.like([{method: 'TokenPropertyDeleted'}]); + } + unsubscribe(); + }); }); \ No newline at end of file