difftreelog
feat Add `collection_admins` method to eth collection.
in: master
19 files changed
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -580,7 +580,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
fn collection_owner(&self) -> Result<(address, uint256)> {
Ok(convert_cross_account_to_tuple::<T>(
@@ -616,13 +616,16 @@
// .map_err(dispatch_to_evm::<T>)
// }
- // TODO: need implement AbiWriter for &Vec<T>
- // fn collection_admins(&self) -> Result<Vec<(address, uint256)>> {
- // let result = pallet_common::IsAdmin::<T>::iter_prefix((self.id,))
- // .map(|(admin, _)| pallet_common::eth::convert_cross_account_to_tuple::<T>(&admin))
- // .collect();
- // Ok(result)
- // }
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ fn collection_admins(&self) -> Result<Vec<(address, uint256)>> {
+ let result = crate::IsAdmin::<T>::iter_prefix((self.id,))
+ .map(|(admin, _)| crate::eth::convert_cross_account_to_tuple::<T>(&admin))
+ .collect();
+ Ok(result)
+ }
}
/// ### Note
pallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -18,7 +18,7 @@
}
/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x62e22290
+/// @dev the ERC-165 identifier for this interface is 0x3af103fb
contract Collection is Dummy, ERC165 {
/// Set collection property.
///
@@ -282,7 +282,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
/// @dev EVM selector for this function is: 0xdf727d3b,
/// or in textual repr: collectionOwner()
@@ -303,6 +303,18 @@
newOwner;
dummy = 0;
}
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() public view returns (Tuple6[] memory) {
+ require(false, stub_error);
+ dummy;
+ return new Tuple6[](0);
+ }
}
/// @dev the ERC-165 identifier for this interface is 0x63034ac5
pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -91,7 +91,7 @@
}
/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x62e22290
+/// @dev the ERC-165 identifier for this interface is 0x3af103fb
contract Collection is Dummy, ERC165 {
/// Set collection property.
///
@@ -355,7 +355,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
/// @dev EVM selector for this function is: 0xdf727d3b,
/// or in textual repr: collectionOwner()
@@ -376,6 +376,18 @@
newOwner;
dummy = 0;
}
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() public view returns (Tuple17[] memory) {
+ require(false, stub_error);
+ dummy;
+ return new Tuple17[](0);
+ }
}
/// @dev anonymous struct
pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -91,7 +91,7 @@
}
/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x62e22290
+/// @dev the ERC-165 identifier for this interface is 0x3af103fb
contract Collection is Dummy, ERC165 {
/// Set collection property.
///
@@ -355,7 +355,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
/// @dev EVM selector for this function is: 0xdf727d3b,
/// or in textual repr: collectionOwner()
@@ -376,6 +376,18 @@
newOwner;
dummy = 0;
}
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() public view returns (Tuple17[] memory) {
+ require(false, stub_error);
+ dummy;
+ return new Tuple17[](0);
+ }
}
/// @dev anonymous struct
pallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterbothbinary blob — no preview
pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -13,7 +13,7 @@
}
/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x62e22290
+/// @dev the ERC-165 identifier for this interface is 0x3af103fb
interface Collection is Dummy, ERC165 {
/// Set collection property.
///
@@ -184,7 +184,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
/// @dev EVM selector for this function is: 0xdf727d3b,
/// or in textual repr: collectionOwner()
@@ -197,6 +197,14 @@
/// @dev EVM selector for this function is: 0x4f53e226,
/// or in textual repr: changeCollectionOwner(address)
function changeCollectionOwner(address newOwner) external;
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() external view returns (Tuple6[] memory);
}
/// @dev the ERC-165 identifier for this interface is 0x63034ac5
tests/src/eth/api/UniqueNFT.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -62,7 +62,7 @@
}
/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x62e22290
+/// @dev the ERC-165 identifier for this interface is 0x3af103fb
interface Collection is Dummy, ERC165 {
/// Set collection property.
///
@@ -233,7 +233,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
/// @dev EVM selector for this function is: 0xdf727d3b,
/// or in textual repr: collectionOwner()
@@ -246,6 +246,14 @@
/// @dev EVM selector for this function is: 0x4f53e226,
/// or in textual repr: changeCollectionOwner(address)
function changeCollectionOwner(address newOwner) external;
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() external view returns (Tuple17[] memory);
}
/// @dev anonymous struct
tests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -62,7 +62,7 @@
}
/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x62e22290
+/// @dev the ERC-165 identifier for this interface is 0x3af103fb
interface Collection is Dummy, ERC165 {
/// Set collection property.
///
@@ -233,7 +233,7 @@
/// Get collection owner.
///
- /// @return Tuble with sponsor address and his substrate mirror.
+ /// @return Tuple with sponsor address and his substrate mirror.
/// If address is canonical then substrate mirror is zero and vice versa.
/// @dev EVM selector for this function is: 0xdf727d3b,
/// or in textual repr: collectionOwner()
@@ -246,6 +246,14 @@
/// @dev EVM selector for this function is: 0x4f53e226,
/// or in textual repr: changeCollectionOwner(address)
function changeCollectionOwner(address newOwner) external;
+
+ /// Get collection administrators
+ ///
+ /// @return Vector of tuples with admins address and his substrate mirror.
+ /// If address is canonical then substrate mirror is zero and vice versa.
+ /// @dev EVM selector for this function is: 0x5813216b,
+ /// or in textual repr: collectionAdmins()
+ function collectionAdmins() external view returns (Tuple17[] memory);
}
/// @dev anonymous struct
tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.3// Unique Network is free software: you can redistribute it and/or modify4// it under the terms of the GNU General Public License as published by5// the Free Software Foundation, either version 3 of the License, or6// (at your option) any later version.7//8// Unique Network is distributed in the hope that it will be useful,9// but WITHOUT ANY WARRANTY; without even the implied warranty of10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11// GNU General Public License for more details.1213// You should have received a copy of the GNU General Public License14// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1516import {IKeyringPair} from '@polkadot/types/types';17import {usingEthPlaygrounds, itEth, expect, EthUniqueHelper} from './util';1819async function recordEthFee(helper: EthUniqueHelper, userAddress: string, call: () => Promise<any>) {20 const before = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));21 await call();22 await helper.wait.newBlocks(1);23 const after = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));2425 expect(after < before).to.be.true;2627 return before - after;28}2930describe('Add collection admins', () => {31 let donor: IKeyringPair;3233 before(async function() {34 await usingEthPlaygrounds(async (_helper, privateKey) => {35 donor = await privateKey({filename: __filename});36 });37 });3839 itEth('Add admin by owner', async ({helper}) => {40 const owner = await helper.eth.createAccountWithBalance(donor);41 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');42 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);4344 const newAdmin = helper.eth.createAccount();4546 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();47 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);48 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())49 .to.be.eq(newAdmin.toLocaleLowerCase());50 });5152 itEth.skip('Add substrate admin by owner', async ({helper}) => {53 const owner = await helper.eth.createAccountWithBalance(donor);54 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');55 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);5657 const [newAdmin] = await helper.arrange.createAccounts([10n], donor);58 await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send();5960 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);61 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())62 .to.be.eq(newAdmin.address.toLocaleLowerCase());63 });6465 itEth('Verify owner or admin', async ({helper}) => {66 const owner = await helper.eth.createAccountWithBalance(donor);67 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');6869 const newAdmin = helper.eth.createAccount();70 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);71 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.false;72 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();73 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true;74 });7576 itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => {77 const owner = await helper.eth.createAccountWithBalance(donor);78 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');7980 const admin = await helper.eth.createAccountWithBalance(donor);81 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);82 await collectionEvm.methods.addCollectionAdmin(admin).send();8384 const user = helper.eth.createAccount();85 await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin}))86 .to.be.rejectedWith('NoPermission');8788 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);89 expect(adminList.length).to.be.eq(1);90 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())91 .to.be.eq(admin.toLocaleLowerCase());92 });9394 itEth('(!negative tests!) Add admin by USER is not allowed', async ({helper}) => {95 const owner = await helper.eth.createAccountWithBalance(donor);96 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');9798 const notAdmin = await helper.eth.createAccountWithBalance(donor);99 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);100101 const user = helper.eth.createAccount();102 await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin}))103 .to.be.rejectedWith('NoPermission');104105 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);106 expect(adminList.length).to.be.eq(0);107 });108109 itEth.skip('(!negative tests!) Add substrate admin by ADMIN is not allowed', async ({helper}) => {110 const owner = await helper.eth.createAccountWithBalance(donor);111 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');112113 const admin = await helper.eth.createAccountWithBalance(donor);114 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);115 await collectionEvm.methods.addCollectionAdmin(admin).send();116117 const [notAdmin] = await helper.arrange.createAccounts([10n], donor);118 await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin.addressRaw).call({from: admin}))119 .to.be.rejectedWith('NoPermission');120121 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);122 expect(adminList.length).to.be.eq(1);123 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())124 .to.be.eq(admin.toLocaleLowerCase());125 });126127 itEth.skip('(!negative tests!) Add substrate admin by USER is not allowed', async ({helper}) => {128 const owner = await helper.eth.createAccountWithBalance(donor);129 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');130131 const notAdmin0 = await helper.eth.createAccountWithBalance(donor);132 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);133 const [notAdmin1] = await helper.arrange.createAccounts([10n], donor);134 await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin1.addressRaw).call({from: notAdmin0}))135 .to.be.rejectedWith('NoPermission');136137 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);138 expect(adminList.length).to.be.eq(0);139 });140});141142describe('Remove collection admins', () => {143 let donor: IKeyringPair;144145 before(async function() {146 await usingEthPlaygrounds(async (_helper, privateKey) => {147 donor = await privateKey({filename: __filename});148 });149 });150151 itEth('Remove admin by owner', async ({helper}) => {152 const owner = await helper.eth.createAccountWithBalance(donor);153 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');154155 const newAdmin = helper.eth.createAccount();156 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);157 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();158159 {160 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);161 expect(adminList.length).to.be.eq(1);162 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())163 .to.be.eq(newAdmin.toLocaleLowerCase());164 }165166 await collectionEvm.methods.removeCollectionAdmin(newAdmin).send();167 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);168 expect(adminList.length).to.be.eq(0);169 });170171 itEth.skip('Remove substrate admin by owner', async ({helper}) => {172 const owner = await helper.eth.createAccountWithBalance(donor);173 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');174175 const [newAdmin] = await helper.arrange.createAccounts([10n], donor);176 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);177 await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send();178 {179 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);180 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())181 .to.be.eq(newAdmin.address.toLocaleLowerCase());182 }183184 await collectionEvm.methods.removeCollectionAdminSubstrate(newAdmin.addressRaw).send();185 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);186 expect(adminList.length).to.be.eq(0);187 });188189 itEth('(!negative tests!) Remove admin by ADMIN is not allowed', async ({helper}) => {190 const owner = await helper.eth.createAccountWithBalance(donor);191 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');192193 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);194195 const admin0 = await helper.eth.createAccountWithBalance(donor);196 await collectionEvm.methods.addCollectionAdmin(admin0).send();197 const admin1 = await helper.eth.createAccountWithBalance(donor);198 await collectionEvm.methods.addCollectionAdmin(admin1).send();199200 await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0}))201 .to.be.rejectedWith('NoPermission');202 {203 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);204 expect(adminList.length).to.be.eq(2);205 expect(adminList.toString().toLocaleLowerCase())206 .to.be.deep.contains(admin0.toLocaleLowerCase())207 .to.be.deep.contains(admin1.toLocaleLowerCase());208 }209 });210211 itEth('(!negative tests!) Remove admin by USER is not allowed', async ({helper}) => {212 const owner = await helper.eth.createAccountWithBalance(donor);213 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');214215 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);216217 const admin = await helper.eth.createAccountWithBalance(donor);218 await collectionEvm.methods.addCollectionAdmin(admin).send();219 const notAdmin = helper.eth.createAccount();220221 await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin}))222 .to.be.rejectedWith('NoPermission');223 {224 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);225 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())226 .to.be.eq(admin.toLocaleLowerCase());227 expect(adminList.length).to.be.eq(1);228 }229 });230231 itEth.skip('(!negative tests!) Remove substrate admin by ADMIN is not allowed', async ({helper}) => {232 const owner = await helper.eth.createAccountWithBalance(donor);233 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');234235 const [adminSub] = await helper.arrange.createAccounts([10n], donor);236 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);237 await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send();238 const adminEth = await helper.eth.createAccountWithBalance(donor);239 await collectionEvm.methods.addCollectionAdmin(adminEth).send();240241 await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: adminEth}))242 .to.be.rejectedWith('NoPermission');243244 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);245 expect(adminList.length).to.be.eq(2);246 expect(adminList.toString().toLocaleLowerCase())247 .to.be.deep.contains(adminSub.address.toLocaleLowerCase())248 .to.be.deep.contains(adminEth.toLocaleLowerCase());249 });250251 itEth.skip('(!negative tests!) Remove substrate admin by USER is not allowed', async ({helper}) => {252 const owner = await helper.eth.createAccountWithBalance(donor);253 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');254255 const [adminSub] = await helper.arrange.createAccounts([10n], donor);256 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);257 await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send();258 const notAdminEth = await helper.eth.createAccountWithBalance(donor);259260 await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: notAdminEth}))261 .to.be.rejectedWith('NoPermission');262263 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);264 expect(adminList.length).to.be.eq(1);265 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())266 .to.be.eq(adminSub.address.toLocaleLowerCase());267 });268});269270describe('Change owner tests', () => {271 let donor: IKeyringPair;272273 before(async function() {274 await usingEthPlaygrounds(async (_helper, privateKey) => {275 donor = await privateKey({filename: __filename});276 });277 });278279 itEth('Change owner', async ({helper}) => {280 const owner = await helper.eth.createAccountWithBalance(donor);281 const newOwner = await helper.eth.createAccountWithBalance(donor);282 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');283 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);284285 await collectionEvm.methods.changeCollectionOwner(newOwner).send();286287 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;288 expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.true;289 });290291 itEth('change owner call fee', async ({helper}) => {292 const owner = await helper.eth.createAccountWithBalance(donor);293 const newOwner = await helper.eth.createAccountWithBalance(donor);294 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');295 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);296 const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.changeCollectionOwner(newOwner).send());297 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));298 expect(cost > 0);299 });300301 itEth('(!negative tests!) call setOwner by non owner', async ({helper}) => {302 const owner = await helper.eth.createAccountWithBalance(donor);303 const newOwner = await helper.eth.createAccountWithBalance(donor);304 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');305 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);306307 await expect(collectionEvm.methods.changeCollectionOwner(newOwner).send({from: newOwner})).to.be.rejected;308 expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.false;309 });310});311312describe('Change substrate owner tests', () => {313 let donor: IKeyringPair;314315 before(async function() {316 await usingEthPlaygrounds(async (_helper, privateKey) => {317 donor = await privateKey({filename: __filename});318 });319 });320321 itEth.skip('Change owner', async ({helper}) => {322 const owner = await helper.eth.createAccountWithBalance(donor);323 const [newOwner] = await helper.arrange.createAccounts([10n], donor);324 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');325 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);326327 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.true;328 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false;329330 await collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send();331332 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;333 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.true;334 });335336 itEth.skip('change owner call fee', async ({helper}) => {337 const owner = await helper.eth.createAccountWithBalance(donor);338 const [newOwner] = await helper.arrange.createAccounts([10n], donor);339 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');340 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);341342 const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send());343 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));344 expect(cost > 0);345 });346347 itEth.skip('(!negative tests!) call setOwner by non owner', async ({helper}) => {348 const owner = await helper.eth.createAccountWithBalance(donor);349 const otherReceiver = await helper.eth.createAccountWithBalance(donor);350 const [newOwner] = await helper.arrange.createAccounts([10n], donor);351 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');352 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);353354 await expect(collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send({from: otherReceiver})).to.be.rejected;355 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false;356 });357});1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.3// Unique Network is free software: you can redistribute it and/or modify4// it under the terms of the GNU General Public License as published by5// the Free Software Foundation, either version 3 of the License, or6// (at your option) any later version.7//8// Unique Network is distributed in the hope that it will be useful,9// but WITHOUT ANY WARRANTY; without even the implied warranty of10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11// GNU General Public License for more details.1213// You should have received a copy of the GNU General Public License14// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1516import {IKeyringPair} from '@polkadot/types/types';17import {IEthCrossAccountId} from '../util/playgrounds/types';18import {usingEthPlaygrounds, itEth, expect, EthUniqueHelper} from './util';1920async function recordEthFee(helper: EthUniqueHelper, userAddress: string, call: () => Promise<any>) {21 const before = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));22 await call();23 await helper.wait.newBlocks(1);24 const after = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));2526 expect(after < before).to.be.true;2728 return before - after;29}3031describe('Add collection admins', () => {32 let donor: IKeyringPair;3334 before(async function() {35 await usingEthPlaygrounds(async (_helper, privateKey) => {36 donor = await privateKey({filename: __filename});37 });38 });3940 itEth('Add admin by owner', async ({helper}) => {41 const owner = await helper.eth.createAccountWithBalance(donor);42 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');43 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);4445 const newAdmin = helper.eth.createAccount();4647 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();48 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);49 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())50 .to.be.eq(newAdmin.toLocaleLowerCase());51 });5253 itEth.skip('Add substrate admin by owner', async ({helper}) => {54 const owner = await helper.eth.createAccountWithBalance(donor);55 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');56 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);5758 const [newAdmin] = await helper.arrange.createAccounts([10n], donor);59 await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send();6061 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);62 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())63 .to.be.eq(newAdmin.address.toLocaleLowerCase());64 });6566 itEth('Verify owner or admin', async ({helper}) => {67 const owner = await helper.eth.createAccountWithBalance(donor);68 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');6970 const newAdmin = helper.eth.createAccount();71 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);72 73 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.false;74 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();75 expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true;76 });77 78 itEth.skip('Check adminlist', async ({helper}) => {79 const owner = await helper.eth.createAccountWithBalance(donor);80 81 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');82 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);83 84 const admin1 = helper.eth.createAccount();85 const [admin2] = await helper.arrange.createAccounts([10n], donor);86 await collectionEvm.methods.addCollectionAdmin(admin1).send();87 await collectionEvm.methods.addCollectionAdminSubstrate(admin2.addressRaw).send();8889 const adminListRpc = await helper.collection.getAdmins(collectionId);90 let adminListEth = await collectionEvm.methods.collectionAdmins().call();91 adminListEth = adminListEth.map((element: IEthCrossAccountId) => {92 return helper.address.convertCrossAccountFromEthCrossAcoount(element);93 });94 expect(adminListRpc).to.be.like(adminListEth);95 }); 96 97 itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => {98 const owner = await helper.eth.createAccountWithBalance(donor);99 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');100101 const admin = await helper.eth.createAccountWithBalance(donor);102 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);103 await collectionEvm.methods.addCollectionAdmin(admin).send();104105 const user = helper.eth.createAccount();106 await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin}))107 .to.be.rejectedWith('NoPermission');108109 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);110 expect(adminList.length).to.be.eq(1);111 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())112 .to.be.eq(admin.toLocaleLowerCase());113 });114115 itEth('(!negative tests!) Add admin by USER is not allowed', async ({helper}) => {116 const owner = await helper.eth.createAccountWithBalance(donor);117 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');118119 const notAdmin = await helper.eth.createAccountWithBalance(donor);120 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);121122 const user = helper.eth.createAccount();123 await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin}))124 .to.be.rejectedWith('NoPermission');125126 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);127 expect(adminList.length).to.be.eq(0);128 });129130 itEth.skip('(!negative tests!) Add substrate admin by ADMIN is not allowed', async ({helper}) => {131 const owner = await helper.eth.createAccountWithBalance(donor);132 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');133134 const admin = await helper.eth.createAccountWithBalance(donor);135 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);136 await collectionEvm.methods.addCollectionAdmin(admin).send();137138 const [notAdmin] = await helper.arrange.createAccounts([10n], donor);139 await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin.addressRaw).call({from: admin}))140 .to.be.rejectedWith('NoPermission');141142 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);143 expect(adminList.length).to.be.eq(1);144 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())145 .to.be.eq(admin.toLocaleLowerCase());146 });147148 itEth.skip('(!negative tests!) Add substrate admin by USER is not allowed', async ({helper}) => {149 const owner = await helper.eth.createAccountWithBalance(donor);150 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');151152 const notAdmin0 = await helper.eth.createAccountWithBalance(donor);153 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);154 const [notAdmin1] = await helper.arrange.createAccounts([10n], donor);155 await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin1.addressRaw).call({from: notAdmin0}))156 .to.be.rejectedWith('NoPermission');157158 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);159 expect(adminList.length).to.be.eq(0);160 });161});162163describe('Remove collection admins', () => {164 let donor: IKeyringPair;165166 before(async function() {167 await usingEthPlaygrounds(async (_helper, privateKey) => {168 donor = await privateKey({filename: __filename});169 });170 });171172 itEth('Remove admin by owner', async ({helper}) => {173 const owner = await helper.eth.createAccountWithBalance(donor);174 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');175176 const newAdmin = helper.eth.createAccount();177 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);178 await collectionEvm.methods.addCollectionAdmin(newAdmin).send();179180 {181 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);182 expect(adminList.length).to.be.eq(1);183 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())184 .to.be.eq(newAdmin.toLocaleLowerCase());185 }186187 await collectionEvm.methods.removeCollectionAdmin(newAdmin).send();188 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);189 expect(adminList.length).to.be.eq(0);190 });191192 itEth.skip('Remove substrate admin by owner', async ({helper}) => {193 const owner = await helper.eth.createAccountWithBalance(donor);194 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');195196 const [newAdmin] = await helper.arrange.createAccounts([10n], donor);197 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);198 await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send();199 {200 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);201 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())202 .to.be.eq(newAdmin.address.toLocaleLowerCase());203 }204205 await collectionEvm.methods.removeCollectionAdminSubstrate(newAdmin.addressRaw).send();206 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);207 expect(adminList.length).to.be.eq(0);208 });209210 itEth('(!negative tests!) Remove admin by ADMIN is not allowed', async ({helper}) => {211 const owner = await helper.eth.createAccountWithBalance(donor);212 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');213214 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);215216 const admin0 = await helper.eth.createAccountWithBalance(donor);217 await collectionEvm.methods.addCollectionAdmin(admin0).send();218 const admin1 = await helper.eth.createAccountWithBalance(donor);219 await collectionEvm.methods.addCollectionAdmin(admin1).send();220221 await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0}))222 .to.be.rejectedWith('NoPermission');223 {224 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);225 expect(adminList.length).to.be.eq(2);226 expect(adminList.toString().toLocaleLowerCase())227 .to.be.deep.contains(admin0.toLocaleLowerCase())228 .to.be.deep.contains(admin1.toLocaleLowerCase());229 }230 });231232 itEth('(!negative tests!) Remove admin by USER is not allowed', async ({helper}) => {233 const owner = await helper.eth.createAccountWithBalance(donor);234 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');235236 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);237238 const admin = await helper.eth.createAccountWithBalance(donor);239 await collectionEvm.methods.addCollectionAdmin(admin).send();240 const notAdmin = helper.eth.createAccount();241242 await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin}))243 .to.be.rejectedWith('NoPermission');244 {245 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);246 expect(adminList[0].asEthereum.toString().toLocaleLowerCase())247 .to.be.eq(admin.toLocaleLowerCase());248 expect(adminList.length).to.be.eq(1);249 }250 });251252 itEth.skip('(!negative tests!) Remove substrate admin by ADMIN is not allowed', async ({helper}) => {253 const owner = await helper.eth.createAccountWithBalance(donor);254 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');255256 const [adminSub] = await helper.arrange.createAccounts([10n], donor);257 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);258 await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send();259 const adminEth = await helper.eth.createAccountWithBalance(donor);260 await collectionEvm.methods.addCollectionAdmin(adminEth).send();261262 await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: adminEth}))263 .to.be.rejectedWith('NoPermission');264265 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);266 expect(adminList.length).to.be.eq(2);267 expect(adminList.toString().toLocaleLowerCase())268 .to.be.deep.contains(adminSub.address.toLocaleLowerCase())269 .to.be.deep.contains(adminEth.toLocaleLowerCase());270 });271272 itEth.skip('(!negative tests!) Remove substrate admin by USER is not allowed', async ({helper}) => {273 const owner = await helper.eth.createAccountWithBalance(donor);274 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');275276 const [adminSub] = await helper.arrange.createAccounts([10n], donor);277 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);278 await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send();279 const notAdminEth = await helper.eth.createAccountWithBalance(donor);280281 await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: notAdminEth}))282 .to.be.rejectedWith('NoPermission');283284 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);285 expect(adminList.length).to.be.eq(1);286 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())287 .to.be.eq(adminSub.address.toLocaleLowerCase());288 });289});290291describe('Change owner tests', () => {292 let donor: IKeyringPair;293294 before(async function() {295 await usingEthPlaygrounds(async (_helper, privateKey) => {296 donor = await privateKey({filename: __filename});297 });298 });299300 itEth('Change owner', async ({helper}) => {301 const owner = await helper.eth.createAccountWithBalance(donor);302 const newOwner = await helper.eth.createAccountWithBalance(donor);303 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');304 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);305306 await collectionEvm.methods.changeCollectionOwner(newOwner).send();307308 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;309 expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.true;310 });311312 itEth('change owner call fee', async ({helper}) => {313 const owner = await helper.eth.createAccountWithBalance(donor);314 const newOwner = await helper.eth.createAccountWithBalance(donor);315 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');316 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);317 const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.changeCollectionOwner(newOwner).send());318 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));319 expect(cost > 0);320 });321322 itEth('(!negative tests!) call setOwner by non owner', async ({helper}) => {323 const owner = await helper.eth.createAccountWithBalance(donor);324 const newOwner = await helper.eth.createAccountWithBalance(donor);325 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');326 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);327328 await expect(collectionEvm.methods.changeCollectionOwner(newOwner).send({from: newOwner})).to.be.rejected;329 expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.false;330 });331});332333describe('Change substrate owner tests', () => {334 let donor: IKeyringPair;335336 before(async function() {337 await usingEthPlaygrounds(async (_helper, privateKey) => {338 donor = await privateKey({filename: __filename});339 });340 });341342 itEth.skip('Change owner', async ({helper}) => {343 const owner = await helper.eth.createAccountWithBalance(donor);344 const [newOwner] = await helper.arrange.createAccounts([10n], donor);345 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');346 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);347348 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.true;349 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false;350351 await collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send();352353 expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false;354 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.true;355 });356357 itEth.skip('change owner call fee', async ({helper}) => {358 const owner = await helper.eth.createAccountWithBalance(donor);359 const [newOwner] = await helper.arrange.createAccounts([10n], donor);360 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');361 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);362363 const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send());364 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));365 expect(cost > 0);366 });367368 itEth.skip('(!negative tests!) call setOwner by non owner', async ({helper}) => {369 const owner = await helper.eth.createAccountWithBalance(donor);370 const otherReceiver = await helper.eth.createAccountWithBalance(donor);371 const [newOwner] = await helper.arrange.createAccounts([10n], donor);372 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');373 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);374375 await expect(collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send({from: otherReceiver})).to.be.rejected;376 expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false;377 });378});tests/src/eth/fungibleAbi.jsondiffbeforeafterboth--- a/tests/src/eth/fungibleAbi.json
+++ b/tests/src/eth/fungibleAbi.json
@@ -126,6 +126,23 @@
},
{
"inputs": [],
+ "name": "collectionAdmins",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "field_0", "type": "address" },
+ { "internalType": "uint256", "name": "field_1", "type": "uint256" }
+ ],
+ "internalType": "struct Tuple6[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
"name": "collectionOwner",
"outputs": [
{
tests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -156,6 +156,23 @@
},
{
"inputs": [],
+ "name": "collectionAdmins",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "field_0", "type": "address" },
+ { "internalType": "uint256", "name": "field_1", "type": "uint256" }
+ ],
+ "internalType": "struct Tuple17[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
"name": "collectionOwner",
"outputs": [
{
tests/src/eth/reFungibleAbi.jsondiffbeforeafterboth--- a/tests/src/eth/reFungibleAbi.json
+++ b/tests/src/eth/reFungibleAbi.json
@@ -156,6 +156,23 @@
},
{
"inputs": [],
+ "name": "collectionAdmins",
+ "outputs": [
+ {
+ "components": [
+ { "internalType": "address", "name": "field_0", "type": "address" },
+ { "internalType": "uint256", "name": "field_1", "type": "uint256" }
+ ],
+ "internalType": "struct Tuple17[]",
+ "name": "",
+ "type": "tuple[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
"name": "collectionOwner",
"outputs": [
{
tests/src/util/playgrounds/types.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/types.ts
+++ b/tests/src/util/playgrounds/types.ts
@@ -70,6 +70,13 @@
ethereum?: TEthereumAccount;
}
+export interface IEthCrossAccountId {
+ 0: TEthereumAccount;
+ 1: TSubstrateAccount;
+ field_0: TEthereumAccount;
+ field_1: TSubstrateAccount;
+}
+
export interface ICollectionLimits {
accountTokenOwnershipLimit?: number | null;
sponsoredDataSize?: number | null;
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -7,9 +7,11 @@
import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';
import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';
-import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
+import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';
import {IKeyringPair} from '@polkadot/types/types';
-import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISchedulerOptions, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, IForeignAssetMetadata, TNetworks, MoonbeamAssetInfo, DemocracyStandardAccountVote, AcalaAssetMetadata} from './types';
+import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISchedulerOptions, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, IForeignAssetMetadata, TNetworks, MoonbeamAssetInfo, DemocracyStandardAccountVote, AcalaAssetMetadata, IEthCrossAccountId} from './types';
+import {hexToU8a} from '@polkadot/util/hex';
+import {u8aConcat} from '@polkadot/util/u8a';
export class CrossAccountId implements ICrossAccountId {
Substrate?: TSubstrateAccount;
@@ -2309,6 +2311,73 @@
return siblingPrefix + encodedParaId + suffix;
}
+
+ /**
+ * Encode key to substrate address
+ * @param key key for encoding address
+ * @param ss58Format prefix for encoding to the address of the corresponding network
+ * @returns encoded substrate address
+ */
+ encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {
+ const u8a :Uint8Array = typeof key === 'string'
+ ? hexToU8a(key)
+ : typeof key === 'bigint'
+ ? hexToU8a(key.toString(16))
+ : key;
+
+ if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {
+ throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);
+ }
+
+ const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];
+ if (!allowedDecodedLengths.includes(u8a.length)) {
+ throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);
+ }
+
+ const u8aPrefix = ss58Format < 64
+ ? new Uint8Array([ss58Format])
+ : new Uint8Array([
+ ((ss58Format & 0xfc) >> 2) | 0x40,
+ (ss58Format >> 8) | ((ss58Format & 0x03) << 6),
+ ]);
+
+ const input = u8aConcat(u8aPrefix, u8a);
+
+ return base58Encode(u8aConcat(
+ input,
+ blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),
+ ));
+ }
+
+ /**
+ * Restore substrate address from bigint representation
+ * @param number decimal representation of substrate address
+ * @returns substrate address
+ */
+ restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {
+ if (this.helper.api === null) {
+ throw 'Not connected';
+ }
+ const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();
+ if (res === undefined || res === null) {
+ throw 'Restore address error';
+ }
+ return res.toString();
+ }
+
+ /**
+ * Convert etherium cross account id to substrate cross account id
+ * @param ethCrossAccount etherium cross account
+ * @returns substrate cross account id
+ */
+ convertCrossAccountFromEthCrossAcoount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {
+ if (ethCrossAccount.field_1 === '0') {
+ return {Ethereum: ethCrossAccount.field_0.toLocaleLowerCase()};
+ }
+
+ const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.field_1));
+ return {Substrate: ss58};
+ }
}
class StakingGroup extends HelperGroup<UniqueHelper> {