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 appPromotion: defs.appPromotion.rpc,39 rmrk: defs.rmrk.rpc,40 eth: {41 feeHistory: {42 description: 'Dummy',43 params: [],44 type: 'u8',45 },46 maxPriorityFeePerGas: {47 description: 'Dummy',48 params: [],49 type: 'u8',50 },51 },52 },53 });54 await this.api.isReadyOrError;55 this.network = await UniqueHelper.detectNetwork(this.api);56 }57}5859class ArrangeGroup {60 helper: UniqueHelper;6162 constructor(helper: UniqueHelper) {63 this.helper = helper;64 }6566 67686970717273 createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise<IKeyringPair[]> => {74 let nonce = await this.helper.chain.getNonce(donor.address);75 const tokenNominal = this.helper.balance.getOneTokenNominal();76 const transactions = [];77 const accounts: IKeyringPair[] = [];78 for (const balance of balances) {79 const recepient = this.helper.util.fromSeed(mnemonicGenerate());80 accounts.push(recepient);81 if (balance !== 0n) {82 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, balance * tokenNominal]);83 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));84 nonce++;85 }86 }8788 await Promise.all(transactions).catch(e => {});89 90 91 const checkBalances = async () => {92 let isSuccess = true;93 for (let i = 0; i < balances.length; i++) {94 const balance = await this.helper.balance.getSubstrate(accounts[i].address);95 if (balance !== balances[i] * tokenNominal) {96 isSuccess = false;97 break;98 }99 }100 return isSuccess;101 };102103 let accountsCreated = false;104 105 for (let index = 0; index < 5; index++) {106 accountsCreated = await checkBalances();107 if(accountsCreated) break;108 await this.waitNewBlocks(1);109 }110111 if (!accountsCreated) throw Error('Accounts generation failed');112 113114 return accounts;115 };116117 118 createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise<IKeyringPair[]> => {119 let transactions: any = [];120 const accounts: IKeyringPair[] = [];121122 const createAsManyAsCan = async () => {123 let nonce = await this.helper.chain.getNonce(donor.address);124 const tokenNominal = this.helper.balance.getOneTokenNominal();125 for (let i = 0; i < accountsToCreate; i++) {126 if (i === 500) { 127 await Promise.allSettled(transactions); 128 transactions = []; 129 nonce = await this.helper.chain.getNonce(donor.address); 130 }131 const recepient = this.helper.util.fromSeed(mnemonicGenerate());132 accounts.push(recepient);133 if (withBalance !== 0n) {134 const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recepient.address}, withBalance * tokenNominal]);135 transactions.push(this.helper.signTransaction(donor, tx, 'account generation', {nonce}));136 nonce++;137 }138 }139 140 const fullfilledAccounts = [];141 await Promise.allSettled(transactions);142 for (const account of accounts) {143 const accountBalance = await this.helper.balance.getSubstrate(account.address);144 if (accountBalance === withBalance * tokenNominal) {145 fullfilledAccounts.push(account);146 }147 }148 return fullfilledAccounts;149 };150151 152 const crowd: IKeyringPair[] = [];153 154 for (let index = 0; index < 5 && accountsToCreate !== 0; index++) {155 const asManyAsCan = await createAsManyAsCan();156 crowd.push(...asManyAsCan);157 accountsToCreate -= asManyAsCan.length;158 }159160 if (accountsToCreate !== 0) throw Error(`Crowd generation failed: ${accountsToCreate} accounts left`);161162 return crowd;163 };164165 isDevNode = async () => {166 const block1 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(1));167 const block2 = await this.helper.api?.rpc.chain.getBlock(await this.helper.api?.rpc.chain.getBlockHash(2));168 const findCreationDate = async (block: any) => {169 const humanBlock = block.toHuman();170 let date;171 humanBlock.block.extrinsics.forEach((ext: any) => {172 if(ext.method.section === 'timestamp') {173 date = Number(ext.method.args.now.replaceAll(',', ''));174 }175 });176 return date;177 };178 const block1date = await findCreationDate(block1);179 const block2date = await findCreationDate(block2);180 if(block2date! - block1date! < 9000) return true;181 };182183 184185186187188 async waitNewBlocks(blocksCount = 1): Promise<void> {189 const promise = new Promise<void>(async (resolve) => {190 const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {191 if (blocksCount > 0) {192 blocksCount--;193 } else {194 unsubscribe();195 resolve();196 }197 });198 });199 return promise;200 }201}