git.delta.rocks / unique-network / refs/commits / c07446fc926e

difftreelog

Merge pull request #745 from UniqueNetwork/tests/eth-helpers

ut-akuznetsov2022-12-05parents: #bf1349a #fc6fcf2.patch.diff
in: master

9 files changed

modifiedtests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth
239 const owner = await helper.eth.createAccountWithBalance(donor);239 const owner = await helper.eth.createAccountWithBalance(donor);
240 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');240 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
241241
242 const [newAdmin] = await helper.arrange.createAccounts([10n], donor);242 const [adminSub] = await helper.arrange.createAccounts([10n], donor);
243 const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
243 const newAdminCross = helper.ethCrossAccount.fromKeyringPair(newAdmin);244 const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
245 const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
246
244 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);247 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
245 await collectionEvm.methods.addCollectionAdminCross(newAdminCross).send();248 await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
249 await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
250
246 {251 {
247 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);252 const adminList = await helper.collection.getAdmins(collectionId);
248 expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())253 expect(adminList).to.deep.include({Substrate: adminSub.address});
249 .to.be.eq(newAdmin.address.toLocaleLowerCase());254 expect(adminList).to.deep.include({Ethereum: adminEth});
250 }255 }
251256
252 await collectionEvm.methods.removeCollectionAdminCross(newAdminCross).send();257 await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send();
258 await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send();
253 const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);259 const adminList = await helper.collection.getAdmins(collectionId);
254 expect(adminList.length).to.be.eq(0);260 expect(adminList.length).to.be.eq(0);
261
262 // Non admin cannot mint:
263 await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
264 await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected;
255 });265 });
256266
257 // Soft-deprecated267 // Soft-deprecated
395405
396 itEth('Change owner [cross]', async ({helper}) => {406 itEth('Change owner [cross]', async ({helper}) => {
397 const owner = await helper.eth.createAccountWithBalance(donor);407 const owner = await helper.eth.createAccountWithBalance(donor);
408 const ownerEth = await helper.eth.createAccountWithBalance(donor);
409 const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
398 const [newOwner] = await helper.arrange.createAccounts([10n], donor);410 const [ownerSub] = await helper.arrange.createAccounts([10n], donor);
399 const newOwnerCross = helper.ethCrossAccount.fromKeyringPair(newOwner);411 const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
412
400 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');413 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
401 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);414 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
402415
403 expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.false;416 expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.false;
404417
418 // Can set ethereum owner:
405 await collectionEvm.methods.changeCollectionOwnerCross(newOwnerCross).send();419 await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossEth).send({from: owner});
406
407 expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.true;420 expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossEth).call()).to.be.true;
421 expect(await helper.collection.getData(collectionId))
422 .to.have.property('normalizedOwner').that.is.eq(helper.address.ethToSubstrate(ownerEth));
423
424 // Can set Substrate owner:
425 await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossSub).send({from: ownerEth});
426 expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.true;
427 expect(await helper.collection.getData(collectionId))
428 .to.have.property('normalizedOwner').that.is.eq(helper.address.normalizeSubstrate(ownerSub.address));
408 });429 });
409430
410 itEth.skip('change owner call fee', async ({helper}) => {431 itEth.skip('change owner call fee', async ({helper}) => {
modifiedtests/src/eth/createFTCollection.test.tsdiffbeforeafterboth
144 144
145 itEth('destroyCollection', async ({helper}) => {145 itEth('destroyCollection', async ({helper}) => {
146 const owner = await helper.eth.createAccountWithBalance(donor);146 const owner = await helper.eth.createAccountWithBalance(donor);
147 const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');147 const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
148 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);148 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
149149
150 const result = await collectionHelper.methods150 const result = await collectionHelper.methods
166 expect(await collectionHelper.methods166 expect(await collectionHelper.methods
167 .isCollectionExist(collectionAddress)167 .isCollectionExist(collectionAddress)
168 .call()).to.be.false;168 .call()).to.be.false;
169 expect(await helper.collection.getData(collectionId)).to.be.null;
169 });170 });
170});171});
171172
214 }215 }
215 });216 });
216 217
217 itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {218 itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {
218 const owner = await helper.eth.createAccountWithBalance(donor);219 const owner = await helper.eth.createAccountWithBalance(donor);
219 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);220 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
221 const expects = [0n, 1n, 30n].map(async value => {
220 await expect(collectionHelper.methods222 await expect(collectionHelper.methods
221 .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')223 .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')
222 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');224 .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
225 });
226 await Promise.all(expects);
223 });227 });
224228
225 // Soft-deprecated229 // Soft-deprecated
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
308308
309 itEth('destroyCollection', async ({helper}) => {309 itEth('destroyCollection', async ({helper}) => {
310 const owner = await helper.eth.createAccountWithBalance(donor);310 const owner = await helper.eth.createAccountWithBalance(donor);
311 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');311 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
312 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);312 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
313313
314314
331 expect(await collectionHelper.methods331 expect(await collectionHelper.methods
332 .isCollectionExist(collectionAddress)332 .isCollectionExist(collectionAddress)
333 .call()).to.be.false;333 .call()).to.be.false;
334 expect(await helper.collection.getData(collectionId)).to.be.null;
334 });335 });
335});336});
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
340 340
341 itEth('destroyCollection', async ({helper}) => {341 itEth('destroyCollection', async ({helper}) => {
342 const owner = await helper.eth.createAccountWithBalance(donor);342 const owner = await helper.eth.createAccountWithBalance(donor);
343 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');343 const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
344 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);344 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
345 345
346 await expect(collectionHelper.methods346 await expect(collectionHelper.methods
350 expect(await collectionHelper.methods350 expect(await collectionHelper.methods
351 .isCollectionExist(collectionAddress)351 .isCollectionExist(collectionAddress)
352 .call()).to.be.false; 352 .call()).to.be.false;
353 expect(await helper.collection.getData(collectionId)).to.be.null;
353 });354 });
354});355});
355356
modifiedtests/src/eth/destroyCollection.test.tsdiffbeforeafterboth
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {Pallets, requirePalletsOrSkip} from '../util';18import {Pallets} from '../util';
19import {expect, itEth, usingEthPlaygrounds} from './util';19import {expect, itEth, usingEthPlaygrounds} from './util';
20
2120
22describe('Destroy Collection from EVM', () => {21describe('Destroy Collection from EVM', function() {
23 let donor: IKeyringPair;22 let donor: IKeyringPair;
23 const testCases = [
24 {method: 'createRFTCollection' as const, params: ['Limits', 'absolutely anything', 'OLF'], requiredPallets: [Pallets.ReFungible]},
25 {method: 'createNFTCollection' as const, params: ['Limits', 'absolutely anything', 'OLF'], requiredPallets: [Pallets.NFT]},
26 {method: 'createFTCollection' as const, params: ['Limits', 'absolutely anything', 'OLF', 18], requiredPallets: [Pallets.Fungible]},
27 ];
2428
25 before(async function() {29 before(async function() {
26 await usingEthPlaygrounds(async (helper, privateKey) => {30 await usingEthPlaygrounds(async (_, privateKey) => {
27 requirePalletsOrSkip(this, helper, [Pallets.ReFungible, Pallets.NFT]);
28 donor = await privateKey({filename: __filename});31 donor = await privateKey({filename: __filename});
29 });32 });
30 });33 });
3134
32 35 testCases.map((testCase) =>
33 itEth('(!negative test!) RFT', async ({helper}) => {36 itEth.ifWithPallets(`Cannot burn non-owned or non-existing collection ${testCase.method}`, testCase.requiredPallets, async ({helper}) => {
34 const owner = await helper.eth.createAccountWithBalance(donor);37 const owner = await helper.eth.createAccountWithBalance(donor);
35 const signer = await helper.eth.createAccountWithBalance(donor);38 const signer = await helper.eth.createAccountWithBalance(donor);
36 39
37 const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);40 const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
38 41
39 const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');42 const collectionHelpers = helper.ethNativeContract.collectionHelpers(signer);
40 const collectionHelper = helper.ethNativeContract.collectionHelpers(signer);43 const {collectionAddress} = await helper.eth.createCollecion(testCase.method, owner, ...testCase.params as [string, string, string, number?]);
41 44
45 // cannot burn collec
42 await expect(collectionHelper.methods46 await expect(collectionHelpers.methods
43 .destroyCollection(collectionAddress)47 .destroyCollection(collectionAddress)
44 .send({from: signer})).to.be.rejected;48 .send({from: signer})).to.be.rejected;
45 49
46 await expect(collectionHelper.methods50 await expect(collectionHelpers.methods
47 .destroyCollection(unexistedCollection)51 .destroyCollection(unexistedCollection)
48 .send({from: signer})).to.be.rejected;52 .send({from: signer})).to.be.rejected;
49 53
50 expect(await collectionHelper.methods54 expect(await collectionHelpers.methods
51 .isCollectionExist(unexistedCollection)55 .isCollectionExist(unexistedCollection)
52 .call()).to.be.false;56 .call()).to.be.false;
57
58 expect(await collectionHelpers.methods
59 .isCollectionExist(collectionAddress)
60 .call()).to.be.true;
53 });61 }));
54
55 itEth('(!negative test!) NFT', async ({helper}) => {
56 const owner = await helper.eth.createAccountWithBalance(donor);
57 const signer = await helper.eth.createAccountWithBalance(donor);
58
59 const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
60
61 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
62 const collectionHelper = helper.ethNativeContract.collectionHelpers(signer);
63
64 await expect(collectionHelper.methods
65 .destroyCollection(collectionAddress)
66 .send({from: signer})).to.be.rejected;
67
68 await expect(collectionHelper.methods
69 .destroyCollection(unexistedCollection)
70 .send({from: signer})).to.be.rejected;
71
72 expect(await collectionHelper.methods
73 .isCollectionExist(unexistedCollection)
74 .call()).to.be.false;
75 });
76});62});
7763
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
232 });232 });
233233
234 itEth('Can perform transferCross()', async ({helper}) => {234 itEth('Can perform transferCross()', async ({helper}) => {
235 const owner = await helper.eth.createAccountWithBalance(donor);235 const sender = await helper.eth.createAccountWithBalance(donor);
236 const receiver = await helper.eth.createAccountWithBalance(donor);236 const receiverEth = await helper.eth.createAccountWithBalance(donor);
237 const to = helper.ethCrossAccount.fromAddress(receiver);237 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
238 const toSubstrate = helper.ethCrossAccount.fromKeyringPair(donor);238 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(donor);
239 const collection = await helper.ft.mintCollection(alice);239 const collection = await helper.ft.mintCollection(alice);
240 await collection.mint(alice, 200n, {Ethereum: owner});240 await collection.mint(alice, 200n, {Ethereum: sender});
241241
242 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);242 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
243 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);243 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
244244
245 {245 {
246 // Can transferCross to ethereum address:
246 const result = await contract.methods.transferCross(to, 50).send({from: owner});247 const result = await collectionEvm.methods.transferCross(receiverCrossEth, 50).send({from: sender});
247 248 // Check events:
248 const event = result.events.Transfer;249 const event = result.events.Transfer;
249 expect(event.address).to.be.equal(collectionAddress);250 expect(event.address).to.be.equal(collectionAddress);
250 expect(event.returnValues.from).to.be.equal(owner);251 expect(event.returnValues.from).to.be.equal(sender);
251 expect(event.returnValues.to).to.be.equal(receiver);252 expect(event.returnValues.to).to.be.equal(receiverEth);
252 expect(event.returnValues.value).to.be.equal('50');253 expect(event.returnValues.value).to.be.equal('50');
254 // Sender's balance decreased:
255 const ownerBalance = await collectionEvm.methods.balanceOf(sender).call();
256 expect(+ownerBalance).to.equal(150);
257 // Receiver's balance increased:
258 const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
259 expect(+receiverBalance).to.equal(50);
253 }260 }
254261
255 {262 {
256 const balance = await contract.methods.balanceOf(owner).call();263 // Can transferCross to substrate address:
257 expect(+balance).to.equal(150);
258 }
259
260 {264 const result = await collectionEvm.methods.transferCross(receiverCrossSub, 50).send({from: sender});
261 const balance = await contract.methods.balanceOf(receiver).call();265 // Check events:
262 expect(+balance).to.equal(50);
263 }
264
265 {
266 const result = await contract.methods.transferCross(toSubstrate, 50).send({from: owner});
267
268 const event = result.events.Transfer;266 const event = result.events.Transfer;
269 expect(event.address).to.be.equal(collectionAddress);267 expect(event.address).to.be.equal(collectionAddress);
270 expect(event.returnValues.from).to.be.equal(owner);268 expect(event.returnValues.from).to.be.equal(sender);
271 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address));269 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address));
272 expect(event.returnValues.value).to.be.equal('50');270 expect(event.returnValues.value).to.be.equal('50');
273 }271 // Sender's balance decreased:
274
275 {
276 const balance = await collection.getBalance({Ethereum: owner});272 const senderBalance = await collection.getBalance({Ethereum: sender});
277 expect(balance).to.equal(100n);273 expect(senderBalance).to.equal(100n);
278 }274 // Receiver's balance increased:
279
280 {
281 const balance = await collection.getBalance({Substrate: donor.address});275 const balance = await collection.getBalance({Substrate: donor.address});
282 expect(balance).to.equal(50n);276 expect(balance).to.equal(50n);
283 }277 }
284
285 });278 });
286 279
280 itEth('Cannot transferCross() more than have', async ({helper}) => {
281 const sender = await helper.eth.createAccountWithBalance(donor);
282 const receiverEth = await helper.eth.createAccountWithBalance(donor);
283 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
284 const BALANCE = 200n;
285 const BALANCE_TO_TRANSFER = BALANCE + 100n;
286
287 const collection = await helper.ft.mintCollection(alice);
288 await collection.mint(alice, BALANCE, {Ethereum: sender});
289 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
290 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
291
292 await expect(collectionEvm.methods.transferCross(receiverCrossEth, BALANCE_TO_TRANSFER).send({from: sender})).to.be.rejected;
293 });
294
287 itEth('Can perform transfer()', async ({helper}) => {295 itEth('Can perform transfer()', async ({helper}) => {
288 const owner = await helper.eth.createAccountWithBalance(donor);296 const owner = await helper.eth.createAccountWithBalance(donor);
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
252 itEth('Can perform burnFromCross()', async ({helper}) => {252 itEth('Can perform burnFromCross()', async ({helper}) => {
253 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});253 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
254
255 const owner = bob;254 const ownerSub = bob;
255 const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
256 const spender = await helper.eth.createAccountWithBalance(donor, 100n);256 const ownerEth = await helper.eth.createAccountWithBalance(donor, 100n);
257 const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
258
259 const burnerEth = await helper.eth.createAccountWithBalance(donor, 100n);
260 const burnerCrossEth = helper.ethCrossAccount.fromAddress(burnerEth);
257261
258 const token = await collection.mintToken(minter, {Substrate: owner.address});262 const token1 = await collection.mintToken(minter, {Substrate: ownerSub.address});
263 const token2 = await collection.mintToken(minter, {Ethereum: ownerEth});
259264
260 const address = helper.ethAddress.fromCollectionId(collection.collectionId);265 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
261 const contract = helper.ethNativeContract.collection(address, 'nft');266 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft');
262267
263 {268 // Approve tokens from substrate and ethereum:
264 await token.approve(owner, {Ethereum: spender});269 await token1.approve(ownerSub, {Ethereum: burnerEth});
270 await collectionEvm.methods.approveCross(burnerCrossEth, token2.tokenId).send({from: ownerEth});
271
272 // can burnFromCross:
265 const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);273 const result1 = await collectionEvm.methods.burnFromCross(ownerCrossSub, token1.tokenId).send({from: burnerEth});
266 const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});274 const result2 = await collectionEvm.methods.burnFromCross(ownerCrossEth, token2.tokenId).send({from: burnerEth});
267 const events = result.events.Transfer;275 const events1 = result1.events.Transfer;
268276 const events2 = result2.events.Transfer;
277
278 // Check events for burnFromCross (substrate and ethereum):
279 [
269 expect(events).to.be.like({280 [events1, token1, helper.address.substrateToEth(ownerSub.address)],
281 [events2, token2, ownerEth],
282 ].map(burnData => {
283 expect(burnData[0]).to.be.like({
270 address,284 address: collectionAddress,
271 event: 'Transfer',285 event: 'Transfer',
272 returnValues: {286 returnValues: {
273 from: helper.address.substrateToEth(owner.address),287 from: burnData[2],
274 to: '0x0000000000000000000000000000000000000000',288 to: '0x0000000000000000000000000000000000000000',
275 tokenId: token.tokenId.toString(),289 tokenId: burnData[1].tokenId.toString(),
276 },290 },
277 });291 });
278 }292 });
293
294 expect(await token1.doesExist()).to.be.false;
295 expect(await token2.doesExist()).to.be.false;
279 });296 });
280297
281 itEth('Can perform approveCross()', async ({helper}) => {298 itEth('Can perform approveCross()', async ({helper}) => {
326 expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});343 expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
327 });344 });
345
346 itEth('Can reaffirm approved address', async ({helper}) => {
347 const owner = await helper.eth.createAccountWithBalance(donor, 100n);
348 const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
349 const [receiver1, receiver2] = await helper.arrange.createAccounts([100n, 100n], donor);
350 const receiver1Cross = helper.ethCrossAccount.fromKeyringPair(receiver1);
351 const receiver2Cross = helper.ethCrossAccount.fromKeyringPair(receiver2);
352 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
353 const token1 = await collection.mintToken(minter, {Ethereum: owner});
354 const token2 = await collection.mintToken(minter, {Ethereum: owner});
355 const collectionEvm = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
356
357 // Can approve and reaffirm approved address:
358 await collectionEvm.methods.approveCross(receiver1Cross, token1.tokenId).send({from: owner});
359 await collectionEvm.methods.approveCross(receiver2Cross, token1.tokenId).send({from: owner});
360
361 // receiver1 cannot transferFrom:
362 await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
363 // receiver2 can transferFrom:
364 await helper.nft.transferTokenFrom(receiver2, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver2.address});
365
366 // can set approved address to self address to remove approval:
367 await collectionEvm.methods.approveCross(receiver1Cross, token2.tokenId).send({from: owner});
368 await collectionEvm.methods.approveCross(ownerCrossEth, token2.tokenId).send({from: owner});
369
370 // receiver1 cannot transfer token anymore:
371 await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token2.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
372 });
328373
329 itEth('Can perform transferFrom()', async ({helper}) => {374 itEth('Can perform transferFrom()', async ({helper}) => {
330 const owner = await helper.eth.createAccountWithBalance(donor);375 const owner = await helper.eth.createAccountWithBalance(donor);
426 itEth('Can perform transferCross()', async ({helper}) => {471 itEth('Can perform transferCross()', async ({helper}) => {
427 const collection = await helper.nft.mintCollection(minter, {});472 const collection = await helper.nft.mintCollection(minter, {});
428 const owner = await helper.eth.createAccountWithBalance(donor);473 const owner = await helper.eth.createAccountWithBalance(donor);
429 const receiver = await helper.eth.createAccountWithBalance(donor);474 const receiverEth = await helper.eth.createAccountWithBalance(donor);
430 const to = helper.ethCrossAccount.fromAddress(receiver);475 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
431 const toSubstrate = helper.ethCrossAccount.fromKeyringPair(minter);476 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
432 477
433 const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});478 const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
434479
435 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);480 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
436 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);481 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
437482
438 {483 {
439 const result = await contract.methods.transferCross(to, tokenId).send({from: owner});484 // Can transferCross to ethereum address:
440485 const result = await collectionEvm.methods.transferCross(receiverCrossEth, tokenId).send({from: owner});
486 // Check events:
441 const event = result.events.Transfer;487 const event = result.events.Transfer;
442 expect(event.address).to.be.equal(collectionAddress);488 expect(event.address).to.be.equal(collectionAddress);
443 expect(event.returnValues.from).to.be.equal(owner);489 expect(event.returnValues.from).to.be.equal(owner);
444 expect(event.returnValues.to).to.be.equal(receiver);490 expect(event.returnValues.to).to.be.equal(receiverEth);
445 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);491 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
446 }492
447493 // owner has balance = 0:
448 {
449 const balance = await contract.methods.balanceOf(owner).call();494 const ownerBalance = await collectionEvm.methods.balanceOf(owner).call();
450 expect(+balance).to.equal(0);495 expect(+ownerBalance).to.equal(0);
451 }496 // receiver owns token:
452
453 {
454 const balance = await contract.methods.balanceOf(receiver).call();497 const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
455 expect(+balance).to.equal(1);498 expect(+receiverBalance).to.equal(1);
456 }
457
458 {
459 const substrateResult = await contract.methods.transferCross(toSubstrate, tokenId).send({from: receiver});499 expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
460 500 }
461501
502 {
503 // Can transferCross to substrate address:
504 const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, tokenId).send({from: receiverEth});
505 // Check events:
462 const event = substrateResult.events.Transfer;506 const event = substrateResult.events.Transfer;
463 expect(event.address).to.be.equal(collectionAddress);507 expect(event.address).to.be.equal(collectionAddress);
464 expect(event.returnValues.from).to.be.equal(receiver);508 expect(event.returnValues.from).to.be.equal(receiverEth);
465 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));509 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
466 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);510 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
467 }511
468512 // owner has balance = 0:
469 {
470 const balance = await contract.methods.balanceOf(receiver).call();513 const ownerBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
471 expect(+balance).to.equal(0);514 expect(+ownerBalance).to.equal(0);
472 }515 // receiver owns token:
473
474 {
475 const balance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});516 const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
476 expect(balance).to.be.contain(tokenId);517 expect(receiverBalance).to.contain(tokenId);
477 }518 }
478 });519 });
479});520});
480521
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
363 });363 });
364 364
365 itEth('Can perform transferCross()', async ({helper}) => {365 itEth('Can perform transferCross()', async ({helper}) => {
366 const caller = await helper.eth.createAccountWithBalance(donor);366 const sender = await helper.eth.createAccountWithBalance(donor);
367 const receiver = await helper.eth.createAccountWithBalance(donor);367 const receiverEth = await helper.eth.createAccountWithBalance(donor);
368 const to = helper.ethCrossAccount.fromAddress(receiver);368 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
369 const toSubstrate = helper.ethCrossAccount.fromKeyringPair(minter);369 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
370
370 const collection = await helper.rft.mintCollection(minter, {});371 const collection = await helper.rft.mintCollection(minter, {});
371 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);372 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
372 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);373 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
373374
374 const {tokenId} = await collection.mintToken(minter, 1n, {Ethereum: caller});375 const token = await collection.mintToken(minter, 50n, {Ethereum: sender});
375376
376 {377 {
378 // Can transferCross to ethereum address:
377 const result = await contract.methods.transferCross(to, tokenId).send({from: caller});379 const result = await collectionEvm.methods.transferCross(receiverCrossEth, token.tokenId).send({from: sender});
378380 // Check events:
379 const event = result.events.Transfer;381 const event = result.events.Transfer;
380 expect(event.address).to.equal(collectionAddress);382 expect(event.address).to.equal(collectionAddress);
381 expect(event.returnValues.from).to.equal(caller);383 expect(event.returnValues.from).to.equal(sender);
382 expect(event.returnValues.to).to.equal(receiver);384 expect(event.returnValues.to).to.equal(receiverEth);
383 expect(event.returnValues.tokenId).to.equal(tokenId.toString());385 expect(event.returnValues.tokenId).to.equal(token.tokenId.toString());
386 // Sender's balance decreased:
387 const senderBalance = await collectionEvm.methods.balanceOf(sender).call();
388 expect(+senderBalance).to.equal(0);
389 expect(await token.getBalance({Ethereum: sender})).to.eq(0n);
390 // Receiver's balance increased:
391 const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
392 expect(+receiverBalance).to.equal(1);
393 expect(await token.getBalance({Ethereum: receiverEth})).to.eq(50n);
384 }394 }
385395
386 {396 {
387 const balance = await contract.methods.balanceOf(caller).call();397 // Can transferCross to substrate address:
388 expect(+balance).to.equal(0);
389 }
390
391 {398 const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, token.tokenId).send({from: receiverEth});
392 const balance = await contract.methods.balanceOf(receiver).call();399 // Check events:
393 expect(+balance).to.equal(1);
394 }
395
396 {
397 const substrateResult = await contract.methods.transferCross(toSubstrate, tokenId).send({from: receiver});
398
399
400 const event = substrateResult.events.Transfer;400 const event = substrateResult.events.Transfer;
401 expect(event.address).to.be.equal(collectionAddress);401 expect(event.address).to.be.equal(collectionAddress);
402 expect(event.returnValues.from).to.be.equal(receiver);402 expect(event.returnValues.from).to.be.equal(receiverEth);
403 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));403 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
404 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);404 expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
405 }405 // Sender's balance decreased:
406
407 {
408 const balance = await contract.methods.balanceOf(receiver).call();406 const senderBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
409 expect(+balance).to.equal(0);407 expect(+senderBalance).to.equal(0);
410 }408 expect(await token.getBalance({Ethereum: receiverEth})).to.eq(0n);
411409 // Receiver's balance increased:
412 {
413 const balance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});410 const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
414 expect(balance).to.be.contain(tokenId);411 expect(receiverBalance).to.contain(token.tokenId);
415 }412 expect(await token.getBalance({Substrate: minter.address})).to.eq(50n);
413 }
416 });414 });
415
416 itEth.skip('Cannot transferCross with invalid params', async ({helper}) => {
417 const sender = await helper.eth.createAccountWithBalance(donor);
418 const tokenOwner = await helper.eth.createAccountWithBalance(donor);
419 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
420
421 const collection = await helper.rft.mintCollection(minter, {});
422 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
423 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
424
425 await collection.mintToken(minter, 50n, {Ethereum: sender});
426 const notSendersToken = await collection.mintToken(minter, 50n, {Ethereum: tokenOwner});
427 // Cannot transferCross someone else's token:
428 await expect(collectionEvm.methods.transferCross(receiverCrossSub, notSendersToken.tokenId).send({from: sender})).to.be.rejected;
429 // FIXME: (transaction successful): Cannot transfer token if it does not exist:
430 await expect(collectionEvm.methods.transferCross(receiverCrossSub, 999999).send({from: sender})).to.be.rejected;
431 });
417432
418 itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {433 itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
419 const caller = await helper.eth.createAccountWithBalance(donor);434 const caller = await helper.eth.createAccountWithBalance(donor);
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
186 return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);186 return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);
187 }187 }
188188
189 async createCollecion(functionName: string, signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {189 async createCollecion(functionName: 'createNFTCollection' | 'createRFTCollection' | 'createFTCollection', signer: string, name: string, description: string, tokenPrefix: string, decimals?: number): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
190 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();190 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
191 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);191 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
192192
193 const functionParams = functionName === 'createFTCollection' ? [name, decimals, description, tokenPrefix] : [name, description, tokenPrefix];
193 const result = await collectionHelper.methods[functionName](name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});194 const result = await collectionHelper.methods[functionName](...functionParams).send({value: Number(collectionCreationPrice)});
194195
195 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);196 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
196 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);197 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
217 return this.createCollecion('createRFTCollection', signer, name, description, tokenPrefix);218 return this.createCollecion('createRFTCollection', signer, name, description, tokenPrefix);
218 }219 }
219220
220 async createFungibleCollection(signer: string, name: string, decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> {221 createFungibleCollection(signer: string, name: string, decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> {
221 const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
222 const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
223
224 const result = await collectionHelper.methods.createFTCollection(name, decimals, description, tokenPrefix).send({value: Number(collectionCreationPrice)});222 return this.createCollecion('createFTCollection', signer, name, description, tokenPrefix, decimals);
225 const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
226 const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
227
228 const events = this.helper.eth.normalizeEvents(result.events);
229
230 return {collectionId, collectionAddress, events};
231 }223 }
232224
233 async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {225 async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {