git.delta.rocks / unique-network / refs/commits / 386b66a0b7e2

difftreelog

test fix for new ouroboros behavior

Yaroslav Bolyukin2022-05-11parent: #2934957.patch.diff
in: master

4 files changed

modifiedcrates/struct-versioning/src/lib.rsdiffbeforeafterboth
--- a/crates/struct-versioning/src/lib.rs
+++ b/crates/struct-versioning/src/lib.rs
@@ -199,7 +199,7 @@
 	let mut out = Vec::new();
 	for version in attr.first_version..=attr.current_version {
 		let name = if version == attr.current_version {
-			input.ident.clone()	
+			input.ident.clone()
 		} else {
 			format_ident!("{}Version{}", &input.ident, version)
 		};
modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
before · tests/src/nesting/unnest.test.ts
1import {expect} from 'chai';2import {tokenIdToAddress} from '../eth/util/helpers';3import privateKey from '../substrate/privateKey';4import usingApi, {executeTransaction} from '../substrate/substrate-api';5import {6  createCollectionExpectSuccess,7  createItemExpectFailure, 8  createItemExpectSuccess,9  getTokenOwner, 10  getTopmostTokenOwner, 11  normalizeAccountId, 12  setCollectionLimitsExpectSuccess, 13  transferExpectFailure, 14  transferExpectSuccess, 15} from '../util/helpers';16import {IKeyringPair} from '@polkadot/types/types';1718let alice: IKeyringPair;19let bob: IKeyringPair;2021describe('Integration Test: Unnesting', () => {22  before(async () => {23    alice = privateKey('//Alice');24    bob = privateKey('//Bob');25  });2627  it('Allows the owner to successfully unnest a token', async () => {28    await usingApi(async api => {29      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});30      await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});31      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');32      const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken)};3334      // Create a nested token35      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);3637      // Unnest38      await expect(executeTransaction(39        api, 40        alice, 41        api.tx.unique.transferFrom(normalizeAccountId(targetAddress), normalizeAccountId(alice), collection, nestedToken, 1),42      )).to.not.be.rejected;43      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Substrate: alice.address});4445      // Nest and burn46      await transferExpectSuccess(collection, nestedToken, alice, targetAddress);47      await expect(executeTransaction(48        api, 49        alice, 50        api.tx.unique.burnFrom(collection, normalizeAccountId(alice.address), nestedToken, 1),51      )).to.not.be.rejected;52      await expect(getTokenOwner(api, collection, nestedToken)).to.be.rejected; // 'owner == null'53    });54  });5556  // todo refungible-fungible test just in case57});5859describe('Negative Test: Unnesting', () => {60  before(async () => {61    alice = privateKey('//Alice');62    bob = privateKey('//Bob');63  });64  65  it('Disallows a non-owner to unnest/burn a token', async () => {66    await usingApi(async api => {67      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});68      await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});69      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');70      const targetAddress = {Ethereum: tokenIdToAddress(collection, targetToken)};7172      // Create a nested token73      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', targetAddress);7475      // Try to unnest76      await expect(executeTransaction(77        api, 78        bob, 79        api.tx.unique.transferFrom(normalizeAccountId(targetAddress), normalizeAccountId(bob), collection, nestedToken, 1),80      )).to.be.rejectedWith(/^common\.ApprovedValueTooLow$/);81      //await transferFromExpectSuccess(collection, nestedToken, bob, targetAddress, {Substrate: bob.address});82      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});8384      // Try to burn85      await expect(executeTransaction(86        api, 87        bob, 88        api.tx.unique.burnFrom(collection, normalizeAccountId(bob.address), nestedToken, 1),89      )).to.not.be.rejectedWith(/^common\.ApprovedValueTooLow$/);90      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});91    });92  });93  94  it('Disallows excessive token nesting', async () => {95    await usingApi(async api => {96      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});97      await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});98      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');99100      // Create a nested token matryoshka101      const nestedToken1 = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});102      const nestedToken2 = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, nestedToken1)});103      // The nesting depth is limited by 2104      await createItemExpectFailure(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, nestedToken2)});105106      expect(await getTopmostTokenOwner(api, collection, nestedToken2)).to.be.deep.equal({Substrate: alice.address});107    });108  });109110  // todo another test for creating excessive depth matryoshka with Ethereum, move this one to nest ^111  112  // Recursive nesting113  it('Prevents Ouroboros-nested operations', async () => { 114    await usingApi(async api => {115      const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}});116      await setCollectionLimitsExpectSuccess(alice, collection, {nestingRule: 'Owner'});117      const targetToken = await createItemExpectSuccess(alice, collection, 'NFT');118119      // Create a nested token ouroboros120      const nestedToken = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: tokenIdToAddress(collection, targetToken)});121      await transferExpectSuccess(collection, targetToken, alice, {Ethereum: tokenIdToAddress(collection, nestedToken)});122123      expect(await getTokenOwner(api, collection, nestedToken)).to.be.deep.equal({Ethereum: tokenIdToAddress(collection, targetToken).toLowerCase()});124125      // Make sure the ouroboros is detected126      await expect(getTopmostTokenOwner(api, collection, nestedToken)).to.be.rejected; // With(/^common\.DepthLimit$/);127      // todo transferFrom, must exit with Ouroboros error128    });129  });130});
modifiedtests/src/pallet-presence.test.tsdiffbeforeafterboth
--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -30,6 +30,7 @@
   'timestamp',
   'transactionpayment',
   'treasury',
+  'structure',
   'system',
   'vesting',
   'parachainsystem',
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -17,15 +17,15 @@
 import '../interfaces/augment-api-rpc';
 import '../interfaces/augment-api-query';
 import {ApiPromise, Keyring} from '@polkadot/api';
-import type {AccountId, EventRecord} from '@polkadot/types/interfaces';
-import {IKeyringPair} from '@polkadot/types/types';
+import type {AccountId, EventRecord, Event} from '@polkadot/types/interfaces';
+import {AnyTuple, IEvent, IKeyringPair} from '@polkadot/types/types';
 import {evmToAddress} from '@polkadot/util-crypto';
 import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import {alicesPublicKey} from '../accounts';
 import privateKey from '../substrate/privateKey';
-import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';
+import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';
 import {hexToStr, strToUTF16, utf16ToStr} from './util';
 import {UpDataStructsRpcCollection} from '@polkadot/types/lookup';
 
@@ -105,7 +105,6 @@
 }
 
 interface TransferResult {
-  success: boolean;
   collectionId: number;
   itemId: number;
   sender?: CrossAccountId;
@@ -168,6 +167,12 @@
   return result;
 }
 
+export function getEvent<T extends Event>(events: EventRecord[], check: (event: IEvent<AnyTuple>) => event is T): T | undefined {
+  const event = events.find(r => check(r.event));
+  if (!event) return;
+  return event.event as T;
+}
+
 export function getGenericResult(events: EventRecord[]): GenericResult {
   const result: GenericResult = {
     success: false,
@@ -225,27 +230,20 @@
   return result;
 }
 
-export function getTransferResult(events: EventRecord[]): TransferResult {
-  const result: TransferResult = {
-    success: false,
-    collectionId: 0,
-    itemId: 0,
-    value: 0n,
-  };
-
-  events.forEach(({event: {data, method, section}}) => {
-    if (method === 'ExtrinsicSuccess') {
-      result.success = true;
-    } else if (section === 'common' && method === 'Transfer') {
-      result.collectionId = +data[0].toString();
-      result.itemId = +data[1].toString();
-      result.sender = normalizeAccountId(data[2].toJSON() as any);
-      result.recipient = normalizeAccountId(data[3].toJSON() as any);
-      result.value = BigInt(data[4].toString());
+export function getTransferResult(api: ApiPromise, events: EventRecord[]): TransferResult {
+  for (const {event} of events) {
+    if (api.events.common.Transfer.is(event)) {
+      const [collection, token, sender, recipient, value] = event.data;
+      return {
+        collectionId: collection.toNumber(),
+        itemId: token.toNumber(),
+        sender: normalizeAccountId(sender.toJSON() as any),
+        recipient: normalizeAccountId(recipient.toJSON() as any),
+        value: value.toBigInt(),
+      };
     }
-  });
-
-  return result;
+  }
+  throw new Error('no transfer event');
 }
 
 interface Nft {
@@ -300,9 +298,9 @@
     }
 
     const tx = api.tx.unique.createCollectionEx({
-      name: strToUTF16(name), 
-      description: strToUTF16(description), 
-      tokenPrefix: strToUTF16(tokenPrefix), 
+      name: strToUTF16(name),
+      description: strToUTF16(description),
+      tokenPrefix: strToUTF16(tokenPrefix),
       mode: modeprm as any,
       schemaVersion: schemaVersion,
     });
@@ -912,15 +910,15 @@
       balanceBefore = await getBalance(api, collectionId, to, tokenId);
     }
     const transferTx = api.tx.unique.transfer(to, collectionId, tokenId, value);
-    const events = await submitTransactionAsync(sender, transferTx);
-    const result = getTransferResult(events);
-    // tslint:disable-next-line:no-unused-expression
-    expect(result.success).to.be.true;
+    const events = await executeTransaction(api, sender, transferTx);
+
+    const result = getTransferResult(api, events);
     expect(result.collectionId).to.be.equal(collectionId);
     expect(result.itemId).to.be.equal(tokenId);
     expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));
     expect(result.recipient).to.be.deep.equal(to);
     expect(result.value).to.be.equal(BigInt(value));
+
     if (type === 'NFT') {
       expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);
     }