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

difftreelog

Merge pull request #539 from UniqueNetwork/test/move-to-playgrounds

ut-akuznetsov2022-08-25parents: #34aa637 #7079d71.patch.diff
in: master
Test/move to playgrounds

3 files changed

addedtests/src/util/playgrounds/types.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/util/playgrounds/types.ts
@@ -0,0 +1,130 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import {IKeyringPair} from '@polkadot/types/types';
+
+export interface IChainEvent {
+  data: any;
+  method: string;
+  section: string;
+}
+
+export interface ITransactionResult {
+    status: 'Fail' | 'Success';
+    result: {
+        events: {
+          event: IChainEvent
+        }[];
+    },
+    moduleError?: string;
+}
+
+export interface ILogger {
+  log: (msg: any, level?: string) => void;
+  level: {
+    ERROR: 'ERROR';
+    WARNING: 'WARNING';
+    INFO: 'INFO';
+    [key: string]: string;
+  }
+}
+
+export interface IUniqueHelperLog {
+  executedAt: number;
+  executionTime: number;
+  type: 'extrinsic' | 'rpc';
+  status: 'Fail' | 'Success';
+  call: string;
+  params: any[];
+  moduleError?: string;
+  events?: any;
+}
+
+export interface IApiListeners {
+  connected?: (...args: any[]) => any;
+  disconnected?: (...args: any[]) => any;
+  error?: (...args: any[]) => any;
+  ready?: (...args: any[]) => any; 
+  decorated?: (...args: any[]) => any;
+}
+
+export interface ICrossAccountId {
+  Substrate?: TSubstrateAccount;
+  Ethereum?: TEthereumAccount;
+}
+
+export interface ICrossAccountIdLower {
+  substrate?: TSubstrateAccount;
+  ethereum?: TEthereumAccount;
+}
+
+export interface ICollectionLimits {
+  accountTokenOwnershipLimit?: number | null;
+  sponsoredDataSize?: number | null;
+  sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;
+  tokenLimit?: number | null;
+  sponsorTransferTimeout?: number | null;
+  sponsorApproveTimeout?: number | null;
+  ownerCanTransfer?: boolean | null;
+  ownerCanDestroy?: boolean | null;
+  transfersEnabled?: boolean | null;
+}
+
+export interface INestingPermissions {
+  tokenOwner?: boolean;
+  collectionAdmin?: boolean;
+  restricted?: number[] | null;
+}
+
+export interface ICollectionPermissions {
+  access?: 'Normal' | 'AllowList';
+  mintMode?: boolean;
+  nesting?: INestingPermissions;
+}
+
+export interface IProperty {
+  key: string;
+  value: string;
+}
+
+export interface ITokenPropertyPermission {
+  key: string;
+  permission: {
+    mutable: boolean;
+    tokenOwner: boolean;
+    collectionAdmin: boolean;
+  }
+}
+
+export interface IToken {
+  collectionId: number;
+  tokenId: number;
+}
+
+export interface ICollectionCreationOptions {
+  name: string | number[];
+  description: string | number[];
+  tokenPrefix: string | number[];
+  mode?: {
+    nft?: null;
+    refungible?: null;
+    fungible?: number;
+  }
+  permissions?: ICollectionPermissions;
+  properties?: IProperty[];
+  tokenPropertyPermissions?: ITokenPropertyPermission[];
+  limits?: ICollectionLimits;
+  pendingSponsor?: TSubstrateAccount;
+}
+
+export interface IChainProperties {
+  ss58Format: number;
+  tokenDecimals: number[];
+  tokenSymbol: string[]
+}
+
+export type TSubstrateAccount = string;
+export type TEthereumAccount = string;
+export type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
+export type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
+export type TSigner = IKeyringPair; // | 'string'
\ No newline at end of file
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -3,9 +3,10 @@
 
 import {mnemonicGenerate} from '@polkadot/util-crypto';
 import {UniqueHelper} from './unique';
-import {IKeyringPair} from '@polkadot/types/types';
 import {ApiPromise, WsProvider} from '@polkadot/api';
 import * as defs from '../../interfaces/definitions';
+import {TSigner} from './types';
+import {IKeyringPair} from '@polkadot/types/types';
 
 
 export class DevUniqueHelper extends UniqueHelper {
@@ -73,7 +74,7 @@
     let nonce = await this.helper.chain.getNonce(donor.address);
     const tokenNominal = this.helper.balance.getOneTokenNominal();
     const transactions = [];
-    const accounts = [];
+    const accounts: IKeyringPair[] = [];
     for (const balance of balances) {
       const recepient = this.helper.util.fromSeed(mnemonicGenerate());
       accounts.push(recepient);
@@ -84,7 +85,52 @@
       }
     }
 
-    await Promise.all(transactions);
+    await Promise.all(transactions).catch(e => {});
+    
+    //#region TODO remove this region, when nonce problem will be solved
+    const checkBalances = async () => {
+      let isSuccess = true;
+      for (let i = 0; i < balances.length; i++) {
+        const balance = await this.helper.balance.getSubstrate(accounts[i].address);
+        if (balance !== balances[i] * tokenNominal) {
+          isSuccess = false;
+          break;
+        }
+      }
+      return isSuccess;
+    };
+
+    let accountsCreated = false;
+    // checkBalances retry up to 5 blocks
+    for (let index = 0; index < 5; index++) {
+      console.log(await this.helper.chain.getLatestBlockNumber());
+      accountsCreated = await checkBalances();
+      if(accountsCreated) break;
+      await this.waitNewBlocks(1);
+    }
+
+    if (!accountsCreated) throw Error('Accounts generation failed');
+    //#endregion
+
     return accounts;
   };
+
+  /**
+   * Wait for specified bnumber of blocks
+   * @param blocksCount number of blocks to wait
+   * @returns 
+   */
+  async waitNewBlocks(blocksCount = 1): Promise<void> {
+    const promise = new Promise<void>(async (resolve) => {
+      const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {
+        if (blocksCount > 0) {
+          blocksCount--;
+        } else {
+          unsubscribe();
+          resolve();
+        }
+      });
+    });
+    return promise;
+  }
 }
\ No newline at end of file
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
77
8import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';8import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';
9import {ApiInterfaceEvents} from '@polkadot/api/types';9import {ApiInterfaceEvents} from '@polkadot/api/types';
10import {IKeyringPair} from '@polkadot/types/types';
11import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto';
1211import {IKeyringPair} from '@polkadot/types/types';
12import {IApiListeners, IChainEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, TUniqueNetworks} from './types';
1313
14const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {14const crossAccountIdFromLower = (lowerAddress: ICrossAccountIdLower): ICrossAccountId => {
15 const address = {} as ICrossAccountId;15 const address = {} as ICrossAccountId;
45};45};
46
47
48interface IChainEvent {
49 data: any;
50 method: string;
51 section: string;
52}
53
54interface ITransactionResult {
55 status: 'Fail' | 'Success';
56 result: {
57 events: {
58 event: IChainEvent
59 }[];
60 },
61 moduleError?: string;
62}
63
64interface ILogger {
65 log: (msg: any, level?: string) => void;
66 level: {
67 ERROR: 'ERROR';
68 WARNING: 'WARNING';
69 INFO: 'INFO';
70 [key: string]: string;
71 }
72}
73
74interface IUniqueHelperLog {
75 executedAt: number;
76 executionTime: number;
77 type: 'extrinsic' | 'rpc';
78 status: 'Fail' | 'Success';
79 call: string;
80 params: any[];
81 moduleError?: string;
82 events?: any;
83}
84
85interface IApiListeners {
86 connected?: (...args: any[]) => any;
87 disconnected?: (...args: any[]) => any;
88 error?: (...args: any[]) => any;
89 ready?: (...args: any[]) => any;
90 decorated?: (...args: any[]) => any;
91}
92
93interface ICrossAccountId {
94 Substrate?: TSubstrateAccount;
95 Ethereum?: TEthereumAccount;
96}
97
98interface ICrossAccountIdLower {
99 substrate?: TSubstrateAccount;
100 ethereum?: TEthereumAccount;
101}
102
103interface ICollectionLimits {
104 accountTokenOwnershipLimit?: number | null;
105 sponsoredDataSize?: number | null;
106 sponsoredDataRateLimit?: {blocks: number} | {sponsoringDisabled: null} | null;
107 tokenLimit?: number | null;
108 sponsorTransferTimeout?: number | null;
109 sponsorApproveTimeout?: number | null;
110 ownerCanTransfer?: boolean | null;
111 ownerCanDestroy?: boolean | null;
112 transfersEnabled?: boolean | null;
113}
114
115interface INestingPermissions {
116 tokenOwner?: boolean;
117 collectionAdmin?: boolean;
118 restricted?: number[] | null;
119}
120
121interface ICollectionPermissions {
122 access?: 'Normal' | 'AllowList';
123 mintMode?: boolean;
124 nesting?: INestingPermissions;
125}
126
127interface IProperty {
128 key: string;
129 value: string;
130}
131
132interface ITokenPropertyPermission {
133 key: string;
134 permission: {
135 mutable: boolean;
136 tokenOwner: boolean;
137 collectionAdmin: boolean;
138 }
139}
140
141interface IToken {
142 collectionId: number;
143 tokenId: number;
144}
145
146interface ICollectionCreationOptions {
147 name: string | number[];
148 description: string | number[];
149 tokenPrefix: string | number[];
150 mode?: {
151 nft?: null;
152 refungible?: null;
153 fungible?: number;
154 }
155 permissions?: ICollectionPermissions;
156 properties?: IProperty[];
157 tokenPropertyPermissions?: ITokenPropertyPermission[];
158 limits?: ICollectionLimits;
159 pendingSponsor?: TSubstrateAccount;
160}
161
162interface IChainProperties {
163 ss58Format: number;
164 tokenDecimals: number[];
165 tokenSymbol: string[]
166}
167
168type TSubstrateAccount = string;
169type TEthereumAccount = string;
170type TApiAllowedListeners = 'connected' | 'disconnected' | 'error' | 'ready' | 'decorated';
171type TUniqueNetworks = 'opal' | 'quartz' | 'unique';
172type TSigner = IKeyringPair; // | 'string'
17346
174class UniqueUtil {47class UniqueUtil {
175 static transactionStatus = {48 static transactionStatus = {
651 return normalized;524 return normalized;
652 }525 }
526
527 /**
528 * Get the normalized addresses added to the collection allow-list.
529 * @param collectionId ID of collection
530 * @example await getAllowList(1)
531 * @returns array of allow-listed addresses
532 */
533 async getAllowList(collectionId: number): Promise<ICrossAccountId[]> {
534 const normalized = [];
535 const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();
536 for (const address of allowListed) {
537 if (address.Substrate) normalized.push({Substrate: this.helper.address.normalizeSubstrate(address.Substrate)});
538 else normalized.push(address);
539 }
540 return normalized;
541 }
653542
654 /**543 /**
655 * Get the effective limits of the collection instead of null for default values544 * Get the effective limits of the collection instead of null for default values
794 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded', label);683 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded', label);
795 }684 }
685
686 /**
687 * Adds an address to allow list
688 * @param signer keyring of signer
689 * @param collectionId ID of collection
690 * @param addressObj address to add to the allow list
691 * @param label extra label for log
692 * @returns ```true``` if extrinsic success, otherwise ```false```
693 */
694 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId, label?: string): Promise<boolean> {
695 if(typeof label === 'undefined') label = `collection #${collectionId}`;
696 const result = await this.helper.executeExtrinsic(
697 signer,
698 'api.tx.unique.addToAllowList', [collectionId, addressObj],
699 true, `Unable to add address to allow list for ${label}`,
700 );
701
702 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');
703 }
796704
797 /**705 /**
798 * Removes a collection administrator.706 * Removes a collection administrator.
2119 return await this.helper.collection.getAdmins(this.collectionId);2027 return await this.helper.collection.getAdmins(this.collectionId);
2120 }2028 }
2029
2030 async getAllowList() {
2031 return await this.helper.collection.getAllowList(this.collectionId);
2032 }
21212033
2122 async getEffectiveLimits() {2034 async getEffectiveLimits() {
2123 return await this.helper.collection.getEffectiveLimits(this.collectionId);2035 return await this.helper.collection.getEffectiveLimits(this.collectionId);
2143 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj, label);2055 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj, label);
2144 }2056 }
2057
2058 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId, label?: string) {
2059 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj, label);
2060 }
21452061
2146 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) {2062 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId, label?: string) {
2147 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj, label);2063 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj, label);