1234import {mnemonicGenerate} from '@polkadot/util-crypto';5import {UniqueHelper} from './unique';6import {ApiPromise, WsProvider} from '@polkadot/api';7import * as defs from '../../interfaces/definitions';8import {IKeyringPair} from '@polkadot/types/types';91011export class DevUniqueHelper extends UniqueHelper {12 131415 arrange: ArrangeGroup;1617 constructor(logger: { log: (msg: any, level: any) => void, level: any }) {18 super(logger);19 this.arrange = new ArrangeGroup(this);20 }2122 async connect(wsEndpoint: string, listeners?: any): Promise<void> {23 const wsProvider = new WsProvider(wsEndpoint);24 this.api = new ApiPromise({25 provider: wsProvider,26 signedExtensions: {27 ContractHelpers: {28 extrinsic: {},29 payload: {},30 },31 FakeTransactionFinalizer: {32 extrinsic: {},33 payload: {},34 },35 },36 rpc: {37 unique: defs.unique.rpc,38 rmrk: defs.rmrk.rpc,39 eth: {40 feeHistory: {41 description: 'Dummy',42 params: [],43 type: 'u8',44 },45 maxPriorityFeePerGas: {46 description: 'Dummy',47 params: [],48 type: 'u8',49 },50 },51 },52 });53 await this.api.isReadyOrError;54 this.network = await UniqueHelper.detectNetwork(this.api);55 }56}5758class ArrangeGroup {59 helper: UniqueHelper;6061 constructor(helper: UniqueHelper) {62 this.helper = helper;63 }6465 66676869707172 createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {73 let nonce = await this.helper.chain.getNonce(donor.address);74 const tokenNominal = this.helper.balance.getOneTokenNominal();75 const transactions = [];76 const accounts: IKeyringPair[] = [];77 for (const balance of balances) {78 const recepient = this.helper.util.fromSeed(mnemonicGenerate());79 accounts.push(recepient);80 if (balance !== 0n) {81 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);82 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));83 nonce++;84 }85 }8687 await Promise.all(transactions).catch(e => {});88 89 90 const checkBalances = async () => {91 let isSuccess = true;92 for (let i = 0; i < balances.length; i++) {93 const balance = await this.helper.balance.getSubstrate(accounts[i].address);94 if (balance !== balances[i] * tokenNominal) {95 isSuccess = false;96 break;97 }98 }99 return isSuccess;100 };101102 let accountsCreated = false;103 104 for (let index = 0; index < 5; index++) {105 accountsCreated = await checkBalances();106 if(accountsCreated) break;107 await this.waitNewBlocks(1);108 }109110 if (!accountsCreated) throw Error('Accounts generation failed');111 112113 return accounts;114 };115116 117 createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {118 let transactions: any = [];119 const accounts: IKeyringPair[] = [];120121 const createAsManyAsCan = async () => {122 let nonce = await this.helper.chain.getNonce(donor.address);123 const tokenNominal = this.helper.balance.getOneTokenNominal();124 for (let i = 0; i < accountsToCreate; i++) {125 if (i === 500) { 126 await Promise.allSettled(transactions); 127 transactions = []; 128 nonce = await this.helper.chain.getNonce(donor.address); 129 }130 const recepient = this.helper.util.fromSeed(mnemonicGenerate());131 accounts.push(recepient);132 if (withBalance !== 0n) {133 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, withBalance * tokenNominal]);134 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));135 nonce++;136 }137 }138 139 const fullfilledAccounts = [];140 await Promise.allSettled(transactions);141 for (const account of accounts) {142 const accountBalance = await this.helper.balance.getSubstrate(account.address);143 if (accountBalance === withBalance * tokenNominal) {144 fullfilledAccounts.push(account);145 }146 }147 return fullfilledAccounts;148 };149150 151 const crowd: IKeyringPair[] = [];152 153 for (let index = 0; index < 5 && accountsToCreate !== 0; index++) {154 const asManyAsCan = await createAsManyAsCan();155 crowd.push(...asManyAsCan);156 accountsToCreate -= asManyAsCan.length;157 }158159 if (accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);160161 return crowd;162 };163164 isDevNode = async () => {165 const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));166 const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));167 const findCreationDate = async (block: any) => {168 const humanBlock = block.toHuman();169 let date;170 humanBlock.block.extrinsics.forEach((ext: any) => {171 if(ext.method.section === 'timestamp') {172 date = Number(ext.method.args.now.replaceAll(',', ''));173 }174 });175 return date;176 };177 const block1date = await findCreationDate(block1);178 const block2date = await findCreationDate(block2);179 if(block2date! - block1date! < 9000) return true;180 };181182 183184185186187 async waitNewBlocks(blocksCount = 1): Promise<void> {188 const promise = new Promise<void>(async (resolve) => {189 const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {190 if (blocksCount > 0) {191 blocksCount--;192 } else {193 unsubscribe();194 resolve();195 }196 });197 });198 return promise;199 }200}