difftreelog
Add checks to mintCross tests
in: master
3 files changed
tests/src/eth/fungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/fungible.test.ts
+++ b/tests/src/eth/fungible.test.ts
@@ -79,23 +79,40 @@
expect(event.returnValues.value).to.equal('100');
});
+ [
+ 'substrate' as const,
+ 'ethereum' as const,
+ ].map(testCase => {
+ itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
+ // 1. Create receiver depending on the test case:
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverSub = owner;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(owner);
+
+ const ethOwner = await helper.eth.createAccountWithBalance(donor);
+ const collection = await helper.ft.mintCollection(alice);
+ await collection.addAdmin(alice, {Ethereum: ethOwner});
- itEth('Can perform mintCross()', async ({helper}) => {
- const receiverCross = helper.ethCrossAccount.fromKeyringPair(owner);
- const ethOwner = await helper.eth.createAccountWithBalance(donor);
- const collection = await helper.ft.mintCollection(alice);
- await collection.addAdmin(alice, {Ethereum: ethOwner});
-
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner);
+
+ // 2. Mint tokens:
+ const result = await collectionEvm.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, 100).send();
+
+ const event = result.events.Transfer;
+ expect(event.address).to.equal(collectionAddress);
+ expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(receiverSub.address));
+ expect(event.returnValues.value).to.equal('100');
- const result = await contract.methods.mintCross(receiverCross, 100).send();
-
- const event = result.events.Transfer;
- expect(event.address).to.equal(collectionAddress);
- expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.equal(helper.address.substrateToEth(owner.address));
- expect(event.returnValues.value).to.equal('100');
+ // 3. Get balance depending on the test case:
+ let balance;
+ if (testCase === 'ethereum') balance = await collection.getBalance({Ethereum: receiverEth});
+ else if (testCase === 'substrate') balance = await collection.getBalance({Substrate: receiverSub.address});
+ // 3.1 Check balance:
+ expect(balance).to.eq(100n);
+ });
});
itEth('Can perform mintBulk()', async ({helper}) => {
tests/src/eth/nonFungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -175,55 +175,82 @@
// expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);
});
- itEth('Can perform mintCross()', async ({helper}) => {
- const caller = await helper.eth.createAccountWithBalance(donor);
- const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);
- const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });
- const permissions: ITokenPropertyPermission[] = properties
- .map(p => {
- return {
- key: p.key, permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
- };
- });
+ // TODO combine all minting tests in one place
+ [
+ 'substrate' as const,
+ 'ethereum' as const,
+ ].map(testCase => {
+ itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
+ const collectionAdmin = await helper.eth.createAccountWithBalance(donor);
+
+ const receiverEth = helper.eth.createAccount();
+ const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+ const receiverSub = bob;
+ const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+
+ // const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);
+ const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });
+ const permissions: ITokenPropertyPermission[] = properties
+ .map(p => {
+ return {
+ key: p.key, permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+ };
+ });
- const collection = await helper.nft.mintCollection(minter, {
- tokenPrefix: 'ethp',
- tokenPropertyPermissions: permissions,
- });
- await collection.addAdmin(minter, {Ethereum: caller});
+ const collection = await helper.nft.mintCollection(minter, {
+ tokenPrefix: 'ethp',
+ tokenPropertyPermissions: permissions,
+ });
+ await collection.addAdmin(minter, {Ethereum: collectionAdmin});
- const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller, true);
- let expectedTokenId = await contract.methods.nextTokenId().call();
- let result = await contract.methods.mintCross(receiverCross, []).send();
- let tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal(expectedTokenId);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', collectionAdmin, true);
+ let expectedTokenId = await contract.methods.nextTokenId().call();
+ let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();
+ let tokenId = result.events.Transfer.returnValues.tokenId;
+ expect(tokenId).to.be.equal(expectedTokenId);
- let event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+ let event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
- expectedTokenId = await contract.methods.nextTokenId().call();
- result = await contract.methods.mintCross(receiverCross, properties).send();
- event = result.events.Transfer;
- expect(event.address).to.be.equal(collectionAddress);
- expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
- expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
+ expectedTokenId = await contract.methods.nextTokenId().call();
+ result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();
+ event = result.events.Transfer;
+ expect(event.address).to.be.equal(collectionAddress);
+ expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');
+ expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);
- tokenId = result.events.Transfer.returnValues.tokenId;
+ tokenId = result.events.Transfer.returnValues.tokenId;
- expect(tokenId).to.be.equal(expectedTokenId);
+ expect(tokenId).to.be.equal(expectedTokenId);
- expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
- .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));
+ expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties
+ .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));
+
+ expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))
+ .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});
+ });
+ });
+
+ itEth('Non-owner and non admin cannot mintCross', async ({helper}) => {
+ const nonOwner = await helper.eth.createAccountWithBalance(donor);
+ const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);
+
+ const collection = await helper.nft.mintCollection(minter);
+ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft');
+
+ await expect(collectionEvm.methods.mintCross(nonOwnerCross, []).call({from: nonOwner}))
+ .to.be.rejectedWith('PublicMintingNotAllowed');
});
//TODO: CORE-302 add eth methods
tests/src/eth/reFungible.test.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {Pallets, requirePalletsOrSkip} from '../util';18import {expect, itEth, usingEthPlaygrounds} from './util';19import {IKeyringPair} from '@polkadot/types/types';20import {ITokenPropertyPermission} from '../util/playgrounds/types';2122describe('Refungible: Information getting', () => {23 let donor: IKeyringPair;2425 before(async function() {26 await usingEthPlaygrounds(async (helper, privateKey) => {27 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);2829 donor = await privateKey({filename: __filename});30 });31 });3233 itEth('totalSupply', async ({helper}) => {34 const caller = await helper.eth.createAccountWithBalance(donor);35 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'TotalSupply', '6', '6');36 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);3738 await contract.methods.mint(caller).send();3940 const totalSupply = await contract.methods.totalSupply().call();41 expect(totalSupply).to.equal('1');42 });4344 itEth('balanceOf', async ({helper}) => {45 const caller = await helper.eth.createAccountWithBalance(donor);46 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'BalanceOf', '6', '6');47 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);4849 await contract.methods.mint(caller).send();50 await contract.methods.mint(caller).send();51 await contract.methods.mint(caller).send();5253 const balance = await contract.methods.balanceOf(caller).call();54 expect(balance).to.equal('3');55 });5657 itEth('ownerOf', async ({helper}) => {58 const caller = await helper.eth.createAccountWithBalance(donor);59 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf', '6', '6');60 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);6162 const result = await contract.methods.mint(caller).send();63 const tokenId = result.events.Transfer.returnValues.tokenId;6465 const owner = await contract.methods.ownerOf(tokenId).call();66 expect(owner).to.equal(caller);67 });6869 itEth('ownerOf after burn', async ({helper}) => {70 const caller = await helper.eth.createAccountWithBalance(donor);71 const receiver = helper.eth.createAccount();72 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf-AfterBurn', '6', '6');73 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);7475 const result = await contract.methods.mint(caller).send();76 const tokenId = result.events.Transfer.returnValues.tokenId;77 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);7879 await tokenContract.methods.repartition(2).send();80 await tokenContract.methods.transfer(receiver, 1).send();8182 await tokenContract.methods.burnFrom(caller, 1).send();8384 const owner = await contract.methods.ownerOf(tokenId).call();85 expect(owner).to.equal(receiver);86 });8788 itEth('ownerOf for partial ownership', async ({helper}) => {89 const caller = await helper.eth.createAccountWithBalance(donor);90 const receiver = helper.eth.createAccount();91 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6');92 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);9394 const result = await contract.methods.mint(caller).send();95 const tokenId = result.events.Transfer.returnValues.tokenId;96 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);9798 await tokenContract.methods.repartition(2).send();99 await tokenContract.methods.transfer(receiver, 1).send();100101 const owner = await contract.methods.ownerOf(tokenId).call();102 expect(owner).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');103 });104});105106describe('Refungible: Plain calls', () => {107 let donor: IKeyringPair;108 let minter: IKeyringPair;109 let bob: IKeyringPair;110 let charlie: IKeyringPair;111112 before(async function() {113 await usingEthPlaygrounds(async (helper, privateKey) => {114 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);115116 donor = await privateKey({filename: __filename});117 [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);118 });119 });120121 itEth('Can perform mint() & crossOwnerOf()', async ({helper}) => {122 const owner = await helper.eth.createAccountWithBalance(donor);123 const receiver = helper.eth.createAccount();124 const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', '');125 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);126127 const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send();128129 const event = result.events.Transfer;130 expect(event.address).to.equal(collectionAddress);131 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');132 expect(event.returnValues.to).to.equal(receiver);133 const tokenId = event.returnValues.tokenId;134 expect(tokenId).to.be.equal('1');135136 expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']);137 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');138 });139 140 [141 'substrate' as const,142 'ethereum' as const,143 ].map(testCase => {144 itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {145 const collectionAdmin = await helper.eth.createAccountWithBalance(donor);146147 const receiverEth = helper.eth.createAccount();148 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);149 const receiverSub = bob;150 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);151152 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });153 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true,154 collectionAdmin: true,155 mutable: true}}; });156 157 158 const collection = await helper.rft.mintCollection(minter, {159 tokenPrefix: 'ethp',160 tokenPropertyPermissions: permissions,161 });162 await collection.addAdmin(minter, {Ethereum: collectionAdmin});163 164 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);165 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', collectionAdmin, true);166 let expectedTokenId = await contract.methods.nextTokenId().call();167 let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();168 let tokenId = result.events.Transfer.returnValues.tokenId;169 expect(tokenId).to.be.equal(expectedTokenId);170171 let event = result.events.Transfer;172 expect(event.address).to.be.equal(collectionAddress);173 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');174 expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));175 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);176 177 expectedTokenId = await contract.methods.nextTokenId().call();178 result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();179 event = result.events.Transfer;180 expect(event.address).to.be.equal(collectionAddress);181 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');182 expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));183 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);184 185 tokenId = result.events.Transfer.returnValues.tokenId;186187 expect(tokenId).to.be.equal(expectedTokenId);188 189 expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties190 .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));191192 expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))193 .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});194 });195 });196197 itEth.skip('Can perform mintBulk()', async ({helper}) => {198 const owner = await helper.eth.createAccountWithBalance(donor);199 const receiver = helper.eth.createAccount();200 const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'MintBulky', '6', '6', '');201 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);202203 {204 const nextTokenId = await contract.methods.nextTokenId().call();205 expect(nextTokenId).to.be.equal('1');206 const result = await contract.methods.mintBulkWithTokenURI(207 receiver,208 [209 [nextTokenId, 'Test URI 0'],210 [+nextTokenId + 1, 'Test URI 1'],211 [+nextTokenId + 2, 'Test URI 2'],212 ],213 ).send();214215 const events = result.events.Transfer;216 for (let i = 0; i < 2; i++) {217 const event = events[i];218 expect(event.address).to.equal(collectionAddress);219 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');220 expect(event.returnValues.to).to.equal(receiver);221 expect(event.returnValues.tokenId).to.equal(String(+nextTokenId + i));222 }223224 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');225 expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');226 expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');227 }228 });229230 itEth('Can perform setApprovalForAll()', async ({helper}) => {231 const owner = await helper.eth.createAccountWithBalance(donor);232 const operator = helper.eth.createAccount();233234 const collection = await helper.rft.mintCollection(minter, {});235236 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);237 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner);238239 const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call();240 expect(approvedBefore).to.be.equal(false);241242 {243 const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner});244245 expect(result.events.ApprovalForAll).to.be.like({246 address: collectionAddress,247 event: 'ApprovalForAll',248 returnValues: {249 owner,250 operator,251 approved: true,252 },253 });254255 const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();256 expect(approvedAfter).to.be.equal(true);257 }258259 {260 const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner});261262 expect(result.events.ApprovalForAll).to.be.like({263 address: collectionAddress,264 event: 'ApprovalForAll',265 returnValues: {266 owner,267 operator,268 approved: false,269 },270 });271272 const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call();273 expect(approvedAfter).to.be.equal(false);274 }275 });276277 itEth('Can perform burn with ApprovalForAll', async ({helper}) => {278 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});279280 const owner = await helper.eth.createAccountWithBalance(donor);281 const operator = await helper.eth.createAccountWithBalance(donor, 100n);282283 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});284285 const address = helper.ethAddress.fromCollectionId(collection.collectionId);286 const contract = helper.ethNativeContract.collection(address, 'rft');287288 {289 await contract.methods.setApprovalForAll(operator, true).send({from: owner});290 const ownerCross = helper.ethCrossAccount.fromAddress(owner);291 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator});292 const events = result.events.Transfer;293294 expect(events).to.be.like({295 address,296 event: 'Transfer',297 returnValues: {298 from: owner,299 to: '0x0000000000000000000000000000000000000000',300 tokenId: token.tokenId.toString(),301 },302 });303 }304 });305306 itEth('Can perform burn with approve and approvalForAll', async ({helper}) => {307 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});308309 const owner = await helper.eth.createAccountWithBalance(donor);310 const operator = await helper.eth.createAccountWithBalance(donor, 100n);311312 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});313314 const address = helper.ethAddress.fromCollectionId(collection.collectionId);315 const contract = helper.ethNativeContract.collection(address, 'rft');316317 const rftToken = helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner);318319 {320 await rftToken.methods.approve(operator, 15n).send({from: owner});321 await contract.methods.setApprovalForAll(operator, true).send({from: owner});322 await rftToken.methods.burnFrom(owner, 10n).send({from: operator});323 const allowance = await rftToken.methods.allowance(owner, operator).call();324 expect(allowance).to.be.equal('5');325 }326 });327 328 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {329 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});330331 const owner = await helper.eth.createAccountWithBalance(donor);332 const operator = await helper.eth.createAccountWithBalance(donor);333 const receiver = charlie;334335 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});336337 const address = helper.ethAddress.fromCollectionId(collection.collectionId);338 const contract = helper.ethNativeContract.collection(address, 'rft');339340 {341 await contract.methods.setApprovalForAll(operator, true).send({from: owner});342 const ownerCross = helper.ethCrossAccount.fromAddress(owner);343 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);344 const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator});345 const event = result.events.Transfer;346 expect(event).to.be.like({347 address: helper.ethAddress.fromCollectionId(collection.collectionId),348 event: 'Transfer',349 returnValues: {350 from: owner,351 to: helper.address.substrateToEth(receiver.address),352 tokenId: token.tokenId.toString(),353 },354 });355 }356357 expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);358 });359360 itEth('Can perform burn()', async ({helper}) => {361 const caller = await helper.eth.createAccountWithBalance(donor);362 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6');363 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);364365 const result = await contract.methods.mint(caller).send();366 const tokenId = result.events.Transfer.returnValues.tokenId;367 {368 const result = await contract.methods.burn(tokenId).send();369 const event = result.events.Transfer;370 expect(event.address).to.equal(collectionAddress);371 expect(event.returnValues.from).to.equal(caller);372 expect(event.returnValues.to).to.equal('0x0000000000000000000000000000000000000000');373 expect(event.returnValues.tokenId).to.equal(tokenId.toString());374 }375 });376377 itEth('Can perform transferFrom()', async ({helper}) => {378 const caller = await helper.eth.createAccountWithBalance(donor);379 const receiver = helper.eth.createAccount();380 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6');381 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);382383 const result = await contract.methods.mint(caller).send();384 const tokenId = result.events.Transfer.returnValues.tokenId;385386 const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId);387388 const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller);389 await tokenContract.methods.repartition(15).send();390391 {392 const tokenEvents: any = [];393 tokenContract.events.allEvents((_: any, event: any) => {394 tokenEvents.push(event);395 });396 const result = await contract.methods.transferFrom(caller, receiver, tokenId).send();397 if (tokenEvents.length == 0) await helper.wait.newBlocks(1);398399 let event = result.events.Transfer;400 expect(event.address).to.equal(collectionAddress);401 expect(event.returnValues.from).to.equal(caller);402 expect(event.returnValues.to).to.equal(receiver);403 expect(event.returnValues.tokenId).to.equal(tokenId.toString());404405 event = tokenEvents[0];406 expect(event.address).to.equal(tokenAddress);407 expect(event.returnValues.from).to.equal(caller);408 expect(event.returnValues.to).to.equal(receiver);409 expect(event.returnValues.value).to.equal('15');410 }411412 {413 const balance = await contract.methods.balanceOf(receiver).call();414 expect(+balance).to.equal(1);415 }416417 {418 const balance = await contract.methods.balanceOf(caller).call();419 expect(+balance).to.equal(0);420 }421 });422423 // Soft-deprecated424 itEth('Can perform burnFrom()', async ({helper}) => {425 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});426427 const owner = await helper.eth.createAccountWithBalance(donor, 100n);428 const spender = await helper.eth.createAccountWithBalance(donor, 100n);429430 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});431432 const address = helper.ethAddress.fromCollectionId(collection.collectionId);433 const contract = helper.ethNativeContract.collection(address, 'rft', spender, true);434435 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);436 const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner);437 await tokenContract.methods.repartition(15).send();438 await tokenContract.methods.approve(spender, 15).send();439440 {441 const result = await contract.methods.burnFrom(owner, token.tokenId).send();442 const event = result.events.Transfer;443 expect(event).to.be.like({444 address: helper.ethAddress.fromCollectionId(collection.collectionId),445 event: 'Transfer',446 returnValues: {447 from: owner,448 to: '0x0000000000000000000000000000000000000000',449 tokenId: token.tokenId.toString(),450 },451 });452 }453454 expect(await collection.getTokenBalance(token.tokenId, {Ethereum: owner})).to.be.eq(0n);455 });456457 itEth('Can perform burnFromCross()', async ({helper}) => {458 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});459 460 const owner = bob;461 const spender = await helper.eth.createAccountWithBalance(donor, 100n);462463 const token = await collection.mintToken(minter, 100n, {Substrate: owner.address});464465 const address = helper.ethAddress.fromCollectionId(collection.collectionId);466 const contract = helper.ethNativeContract.collection(address, 'rft');467468 await token.repartition(owner, 15n);469 await token.approve(owner, {Ethereum: spender}, 15n);470471 {472 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);473 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});474 const event = result.events.Transfer;475 expect(event).to.be.like({476 address: helper.ethAddress.fromCollectionId(collection.collectionId),477 event: 'Transfer',478 returnValues: {479 from: helper.address.substrateToEth(owner.address),480 to: '0x0000000000000000000000000000000000000000',481 tokenId: token.tokenId.toString(),482 },483 });484 }485486 expect(await collection.getTokenBalance(token.tokenId, {Substrate: owner.address})).to.be.eq(0n);487 });488489 itEth('Can perform transferFromCross()', async ({helper}) => {490 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});491492 const owner = bob;493 const spender = await helper.eth.createAccountWithBalance(donor, 100n);494 const receiver = charlie;495496 const token = await collection.mintToken(minter, 100n, {Substrate: owner.address});497498 const address = helper.ethAddress.fromCollectionId(collection.collectionId);499 const contract = helper.ethNativeContract.collection(address, 'rft');500501 await token.repartition(owner, 15n);502 await token.approve(owner, {Ethereum: spender}, 15n);503504 {505 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);506 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);507 const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender});508 const event = result.events.Transfer;509 expect(event).to.be.like({510 address: helper.ethAddress.fromCollectionId(collection.collectionId),511 event: 'Transfer',512 returnValues: {513 from: helper.address.substrateToEth(owner.address),514 to: helper.address.substrateToEth(receiver.address),515 tokenId: token.tokenId.toString(),516 },517 });518 }519520 expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]);521 });522523 itEth('Can perform transfer()', async ({helper}) => {524 const caller = await helper.eth.createAccountWithBalance(donor);525 const receiver = helper.eth.createAccount();526 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6');527 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);528529 const result = await contract.methods.mint(caller).send();530 const tokenId = result.events.Transfer.returnValues.tokenId;531532 {533 const result = await contract.methods.transfer(receiver, tokenId).send();534535 const event = result.events.Transfer;536 expect(event.address).to.equal(collectionAddress);537 expect(event.returnValues.from).to.equal(caller);538 expect(event.returnValues.to).to.equal(receiver);539 expect(event.returnValues.tokenId).to.equal(tokenId.toString());540 }541542 {543 const balance = await contract.methods.balanceOf(caller).call();544 expect(+balance).to.equal(0);545 }546547 {548 const balance = await contract.methods.balanceOf(receiver).call();549 expect(+balance).to.equal(1);550 }551 });552 553 itEth('Can perform transferCross()', async ({helper}) => {554 const sender = await helper.eth.createAccountWithBalance(donor);555 const receiverEth = await helper.eth.createAccountWithBalance(donor);556 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);557 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);558559 const collection = await helper.rft.mintCollection(minter, {});560 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);561 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender);562563 const token = await collection.mintToken(minter, 50n, {Ethereum: sender});564565 {566 // Can transferCross to ethereum address:567 const result = await collectionEvm.methods.transferCross(receiverCrossEth, token.tokenId).send({from: sender});568 // Check events:569 const event = result.events.Transfer;570 expect(event.address).to.equal(collectionAddress);571 expect(event.returnValues.from).to.equal(sender);572 expect(event.returnValues.to).to.equal(receiverEth);573 expect(event.returnValues.tokenId).to.equal(token.tokenId.toString());574 // Sender's balance decreased:575 const senderBalance = await collectionEvm.methods.balanceOf(sender).call();576 expect(+senderBalance).to.equal(0);577 expect(await token.getBalance({Ethereum: sender})).to.eq(0n);578 // Receiver's balance increased:579 const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();580 expect(+receiverBalance).to.equal(1);581 expect(await token.getBalance({Ethereum: receiverEth})).to.eq(50n);582 }583 584 {585 // Can transferCross to substrate address:586 const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, token.tokenId).send({from: receiverEth});587 // Check events:588 const event = substrateResult.events.Transfer;589 expect(event.address).to.be.equal(collectionAddress);590 expect(event.returnValues.from).to.be.equal(receiverEth);591 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));592 expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);593 // Sender's balance decreased:594 const senderBalance = await collectionEvm.methods.balanceOf(receiverEth).call();595 expect(+senderBalance).to.equal(0);596 expect(await token.getBalance({Ethereum: receiverEth})).to.eq(0n);597 // Receiver's balance increased:598 const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});599 expect(receiverBalance).to.contain(token.tokenId);600 expect(await token.getBalance({Substrate: minter.address})).to.eq(50n);601 }602 });603604 ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {605 const sender = await helper.eth.createAccountWithBalance(donor);606 const tokenOwner = await helper.eth.createAccountWithBalance(donor);607 const receiverSub = minter;608 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);609610 const collection = await helper.rft.mintCollection(minter, {});611 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);612 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender);613614 await collection.mintToken(minter, 50n, {Ethereum: sender});615 const nonSendersToken = await collection.mintToken(minter, 50n, {Ethereum: tokenOwner});616617 // Cannot transferCross someone else's token:618 const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;619 await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;620 // Cannot transfer token if it does not exist:621 await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;622 }));623624 itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {625 const caller = await helper.eth.createAccountWithBalance(donor);626 const receiver = helper.eth.createAccount();627 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6');628 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);629630 const result = await contract.methods.mint(caller).send();631 const tokenId = result.events.Transfer.returnValues.tokenId;632633 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);634635 await tokenContract.methods.repartition(2).send();636 await tokenContract.methods.transfer(receiver, 1).send();637638 const events: any = [];639 contract.events.allEvents((_: any, event: any) => {640 events.push(event);641 });642643 await tokenContract.methods.transfer(receiver, 1).send();644 if (events.length == 0) await helper.wait.newBlocks(1);645 const event = events[0];646647 expect(event.address).to.equal(collectionAddress);648 expect(event.returnValues.from).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');649 expect(event.returnValues.to).to.equal(receiver);650 expect(event.returnValues.tokenId).to.equal(tokenId.toString());651 });652653 itEth('transfer event on transfer from full ownership to partial ownership', async ({helper}) => {654 const caller = await helper.eth.createAccountWithBalance(donor);655 const receiver = helper.eth.createAccount();656 const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6');657 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);658659 const result = await contract.methods.mint(caller).send();660 const tokenId = result.events.Transfer.returnValues.tokenId;661662 const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller);663664 await tokenContract.methods.repartition(2).send();665666 const events: any = [];667 contract.events.allEvents((_: any, event: any) => {668 events.push(event);669 });670671 await tokenContract.methods.transfer(receiver, 1).send();672 if (events.length == 0) await helper.wait.newBlocks(1);673 const event = events[0];674675 expect(event.address).to.equal(collectionAddress);676 expect(event.returnValues.from).to.equal(caller);677 expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF');678 expect(event.returnValues.tokenId).to.equal(tokenId.toString());679 });680});681682describe('RFT: Fees', () => {683 let donor: IKeyringPair;684685 before(async function() {686 await usingEthPlaygrounds(async (helper, privateKey) => {687 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);688689 donor = await privateKey({filename: __filename});690 });691 });692693 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {694 const caller = await helper.eth.createAccountWithBalance(donor);695 const receiver = helper.eth.createAccount();696 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6');697 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);698699 const result = await contract.methods.mint(caller).send();700 const tokenId = result.events.Transfer.returnValues.tokenId;701702 const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send());703 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));704 expect(cost > 0n);705 });706707 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {708 const caller = await helper.eth.createAccountWithBalance(donor);709 const receiver = helper.eth.createAccount();710 const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6');711 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);712713 const result = await contract.methods.mint(caller).send();714 const tokenId = result.events.Transfer.returnValues.tokenId;715716 const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send());717 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));718 expect(cost > 0n);719 });720});721722describe('Common metadata', () => {723 let donor: IKeyringPair;724 let alice: IKeyringPair;725726 before(async function() {727 await usingEthPlaygrounds(async (helper, privateKey) => {728 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);729730 donor = await privateKey({filename: __filename});731 [alice] = await helper.arrange.createAccounts([20n], donor);732 });733 });734735 itEth('Returns collection name', async ({helper}) => {736 const caller = helper.eth.createAccount();737 const tokenPropertyPermissions = [{738 key: 'URI',739 permission: {740 mutable: true,741 collectionAdmin: true,742 tokenOwner: false,743 },744 }];745 const collection = await helper.rft.mintCollection(746 alice,747 {748 name: 'Leviathan',749 tokenPrefix: '11',750 properties: [{key: 'ERC721Metadata', value: '1'}],751 tokenPropertyPermissions,752 },753 );754755 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller);756 const name = await contract.methods.name().call();757 expect(name).to.equal('Leviathan');758 });759760 itEth('Returns symbol name', async ({helper}) => {761 const caller = await helper.eth.createAccountWithBalance(donor);762 const tokenPropertyPermissions = [{763 key: 'URI',764 permission: {765 mutable: true,766 collectionAdmin: true,767 tokenOwner: false,768 },769 }];770 const {collectionId} = await helper.rft.mintCollection(771 alice,772 {773 name: 'Leviathan',774 tokenPrefix: '12',775 properties: [{key: 'ERC721Metadata', value: '1'}],776 tokenPropertyPermissions,777 },778 );779780 const contract = helper.ethNativeContract.collectionById(collectionId, 'rft', caller);781 const symbol = await contract.methods.symbol().call();782 expect(symbol).to.equal('12');783 });784});785786describe('Negative tests', () => {787 let donor: IKeyringPair;788 let minter: IKeyringPair;789 let alice: IKeyringPair;790791 before(async function() {792 await usingEthPlaygrounds(async (helper, privateKey) => {793 requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);794 795 donor = await privateKey({filename: __filename});796 [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor);797 });798 });799800 itEth('[negative] Cant perform burn without approval', async ({helper}) => {801 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});802803 const owner = await helper.eth.createAccountWithBalance(donor, 100n);804 const spender = await helper.eth.createAccountWithBalance(donor, 100n);805806 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});807808 const address = helper.ethAddress.fromCollectionId(collection.collectionId);809 const contract = helper.ethNativeContract.collection(address, 'rft');810811 const ownerCross = helper.ethCrossAccount.fromAddress(owner);812813 await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;814815 await contract.methods.setApprovalForAll(spender, true).send({from: owner});816 await contract.methods.setApprovalForAll(spender, false).send({from: owner});817818 await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected;819 });820821 itEth('[negative] Cant perform transfer without approval', async ({helper}) => {822 const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});823 const owner = await helper.eth.createAccountWithBalance(donor, 100n);824 const receiver = alice;825826 const spender = await helper.eth.createAccountWithBalance(donor, 100n);827828 const token = await collection.mintToken(minter, 100n, {Ethereum: owner});829830 const address = helper.ethAddress.fromCollectionId(collection.collectionId);831 const contract = helper.ethNativeContract.collection(address, 'rft');832833 const ownerCross = helper.ethCrossAccount.fromAddress(owner);834 const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);835 836 await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;837838 await contract.methods.setApprovalForAll(spender, true).send({from: owner});839 await contract.methods.setApprovalForAll(spender, false).send({from: owner});840 841 await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected;842 });843});