git.delta.rocks / unique-network / refs/commits / 44da5f88ce12

difftreelog

source

tests/src/benchmarks/mintFeeBench/feeBench.ts11.4 KiBsourcehistory
1import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';2import {readFile} from 'fs/promises';3import {ContractImports} from '../../eth/util/playgrounds/types';4import {5  ICrossAccountId,6  ITokenPropertyPermission,7} from '../../util/playgrounds/types';8import {IKeyringPair} from '@polkadot/types/types';9import {UniqueNFTCollection} from '../../util/playgrounds/unique';10import {Contract} from 'web3-eth-contract';11import {createObjectCsvWriter} from 'csv-writer';1213const CONTRACT_IMPORT: ContractImports[] = [14  {15    fsPath: `${__dirname}/../../eth/api/CollectionHelpers.sol`,16    solPath: 'eth/api/CollectionHelpers.sol',17  },18  {19    fsPath: `${__dirname}/../../eth/api/ContractHelpers.sol`,20    solPath: 'eth/api/ContractHelpers.sol',21  },22  {23    fsPath: `${__dirname}/../../eth/api/UniqueRefungibleToken.sol`,24    solPath: 'eth/api/UniqueRefungibleToken.sol',25  },26  {27    fsPath: `${__dirname}/../../eth/api/UniqueRefungible.sol`,28    solPath: 'eth/api/UniqueRefungible.sol',29  },30  {31    fsPath: `${__dirname}/../../eth/api/UniqueNFT.sol`,32    solPath: 'eth/api/UniqueNFT.sol',33  },34];3536const PROPERTIES = Array(40)37  .fill(0)38  .map((_, i) => {39    return {40      key: `key_${i}`,41      value: Uint8Array.from(Buffer.from(`value_${i}`)),42    };43  });4445const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => {46  return {47    key: p.key,48    permission: {49      tokenOwner: true,50      collectionAdmin: true,51      mutable: true,52    },53  };54});5556interface IBenchmarkResultForProp {57	propertiesNumber: number;58	substrateFee: number;59	ethFee: number;60	ethBulkFee: number;61	evmProxyContractFee: number;62	evmProxyContractBulkFee: number;63}6465const main = async () => {66  const csvWriter = createObjectCsvWriter({67    path: 'properties.csv',68    header: [69      'propertiesNumber',70      'substrateFee',71      'ethFee',72      'ethBulkFee',73      'evmProxyContractFee',74      'evmProxyContractBulkFee',75    ],76  });7778  await usingEthPlaygrounds(async (helper, privateKey) => {79    const CONTRACT_SOURCE = (80      await readFile(`${__dirname}/proxyContract.sol`)81    ).toString();8283    const donor = await privateKey('//Alice'); // Seed from account with balance on this network84    const myAccount = await privateKey('//Bob'); // replace with account from polkadot extension85    const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);8687    const contract = await helper.ethContract.deployByCode(88      ethSigner,89      'ProxyMint',90      CONTRACT_SOURCE,91      CONTRACT_IMPORT,92    );9394    const fees = await benchMintFee(helper, privateKey, contract);95    console.log(fees);9697    const result: IBenchmarkResultForProp[] = [];9899    for (let i = 1; i <= 20; i++) {100      result.push(await benchMintWithProperties(helper, privateKey, contract, {101        propertiesNumber: i,102      }));103    }104105    await csvWriter.writeRecords(result);106107    console.table(result);108  });109};110111main()112  .then(() => process.exit(0))113  .catch((e) => {114    console.log(e);115    process.exit(1);116  });117118async function createCollectionForBenchmarks(119  helper: EthUniqueHelper,120  privateKey: (seed: string) => Promise<IKeyringPair>,121  ethSigner: string,122  proxyContract: string,123  permissions: ITokenPropertyPermission[],124) {125  const donor = await privateKey('//Alice');126127  const collection = await helper.nft.mintCollection(donor, {128    name: 'test mintToSubstrate',129    description: 'EVMHelpers',130    tokenPrefix: 'ap',131    tokenPropertyPermissions: [132      {133        key: 'url',134        permission: {135          tokenOwner: true,136          collectionAdmin: true,137          mutable: true,138        },139      },140    ],141    limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},142    permissions: {mintMode: true},143  });144145  await collection.addToAllowList(donor, {146    Ethereum: helper.address.substrateToEth(donor.address),147  });148  await collection.addToAllowList(donor, {Substrate: donor.address});149  await collection.addAdmin(donor, {Ethereum: ethSigner});150  await collection.addAdmin(donor, {151    Ethereum: helper.address.substrateToEth(donor.address),152  });153  await collection.addToAllowList(donor, {Ethereum: proxyContract});154  await collection.addAdmin(donor, {Ethereum: proxyContract});155  await collection.setTokenPropertyPermissions(donor, permissions);156157  return collection;158}159160async function benchMintFee(161  helper: EthUniqueHelper,162  privateKey: (seed: string) => Promise<IKeyringPair>,163  proxyContract: Contract,164): Promise<{165	substrateFee: number;166	ethFee: number;167	evmProxyContractFee: number;168}> {169  const donor = await privateKey('//Alice');170  const substrateReceiver = await privateKey('//Bob');171  const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);172173  const nominal = helper.balance.getOneTokenNominal();174175  await helper.eth.transferBalanceFromSubstrate(176    donor,177    proxyContract.options.address,178    100n,179  );180181  const collection = await createCollectionForBenchmarks(182    helper,183    privateKey,184    ethSigner,185    proxyContract.options.address,186    PERMISSIONS,187  );188189  const substrateFee = await helper.arrange.calculcateFee(190    {Substrate: donor.address},191    () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),192  );193194  const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);195  const collectionContract = helper.ethNativeContract.collection(196    collectionEthAddress,197    'nft',198  );199200  const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);201202  const encodedCall = collectionContract.methods203    .mint(receiverEthAddress)204    .encodeABI();205206  const ethFee = await helper.arrange.calculcateFee(207    {Substrate: donor.address},208    async () => {209      await helper.eth.sendEVM(210        donor,211        collectionContract.options.address,212        encodedCall,213        '0',214      );215    },216  );217218  const evmProxyContractFee = await helper.arrange.calculcateFee(219    {Ethereum: ethSigner},220    async () => {221      await proxyContract.methods222        .mintToSubstrate(223          helper.ethAddress.fromCollectionId(collection.collectionId),224          substrateReceiver.addressRaw,225        )226        .send({from: ethSigner});227    },228  );229230  return {231    substrateFee: convertToTokens(substrateFee, nominal),232    ethFee: convertToTokens(ethFee, nominal),233    evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),234  };235}236237async function benchMintWithProperties(238  helper: EthUniqueHelper,239  privateKey: (seed: string) => Promise<IKeyringPair>,240  proxyContract: Contract,241  setup: { propertiesNumber: number },242): Promise<IBenchmarkResultForProp> {243  const donor = await privateKey('//Alice'); // Seed from account with balance on this network244  const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);245246  const susbstrateReceiver = await privateKey('//Bob');247  const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);248249  const nominal = helper.balance.getOneTokenNominal();250251  const substrateFee = await calculateFeeNftMintWithProperties(252    helper,253    privateKey,254    {Substrate: donor.address},255    ethSigner,256    proxyContract.options.address,257    async (collection) => {258      await collection.mintToken(259        donor,260        {Substrate: susbstrateReceiver.address},261        PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {262          return {key: p.key, value: Buffer.from(p.value).toString()};263        }),264      );265    },266  );267268  const ethFee = await calculateFeeNftMintWithProperties(269    helper,270    privateKey,271    {Substrate: donor.address},272    ethSigner,273    proxyContract.options.address,274    async (collection) => {275      const evmContract = helper.ethNativeContract.collection(276        helper.ethAddress.fromCollectionId(collection.collectionId),277        'nft',278      );279280      const subTokenId = await evmContract.methods.nextTokenId().call();281282      let encodedCall = evmContract.methods283        .mint(receiverEthAddress)284        .encodeABI();285286      await helper.eth.sendEVM(287        donor,288        evmContract.options.address,289        encodedCall,290        '0',291      );292293      for (const val of PROPERTIES.slice(0, setup.propertiesNumber)) {294        encodedCall = await evmContract.methods295          .setProperty(subTokenId, val.key, Buffer.from(val.value))296          .encodeABI();297298        await helper.eth.sendEVM(299          donor,300          evmContract.options.address,301          encodedCall,302          '0',303        );304      }305    },306  );307308  const ethBulkFee = await calculateFeeNftMintWithProperties(309    helper,310    privateKey,311    {Substrate: donor.address},312    ethSigner,313    proxyContract.options.address,314    async (collection) => {315      const evmContract = helper.ethNativeContract.collection(316        helper.ethAddress.fromCollectionId(collection.collectionId),317        'nft',318      );319320      const subTokenId = await evmContract.methods.nextTokenId().call();321322      let encodedCall = evmContract.methods323        .mint(receiverEthAddress)324        .encodeABI();325326      await helper.eth.sendEVM(327        donor,328        evmContract.options.address,329        encodedCall,330        '0',331      );332333      encodedCall = await evmContract.methods334        .setProperties(335          subTokenId,336          PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {337            return {field_0: p.key, field_1: p.value};338          }),339        )340        .encodeABI();341342      await helper.eth.sendEVM(343        donor,344        evmContract.options.address,345        encodedCall,346        '0',347      );348    },349  );350351  const proxyContractFee = await calculateFeeNftMintWithProperties(352    helper,353    privateKey,354    {Ethereum: ethSigner},355    ethSigner,356    proxyContract.options.address,357    async (collection) => {358      await proxyContract.methods359        .mintToSubstrateWithProperty(360          helper.ethAddress.fromCollectionId(collection.collectionId),361          susbstrateReceiver.addressRaw,362          PROPERTIES.slice(0, setup.propertiesNumber),363        )364        .send({from: ethSigner});365    },366  );367368  const proxyContractBulkFee = await calculateFeeNftMintWithProperties(369    helper,370    privateKey,371    {Ethereum: ethSigner},372    ethSigner,373    proxyContract.options.address,374    async (collection) => {375      await proxyContract.methods376        .mintToSubstrateBulkProperty(377          helper.ethAddress.fromCollectionId(collection.collectionId),378          susbstrateReceiver.addressRaw,379          PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {380            return {field_0: p.key, field_1: p.value};381          }),382        )383        .send({from: ethSigner, gas: 25_000_000});384    },385  );386387  return {388    propertiesNumber: setup.propertiesNumber,389    substrateFee: convertToTokens(substrateFee, nominal),390    ethFee: convertToTokens(ethFee, nominal),391    ethBulkFee: convertToTokens(ethBulkFee, nominal),392    evmProxyContractFee: convertToTokens(proxyContractFee, nominal),393    evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),394  };395}396397async function calculateFeeNftMintWithProperties(398  helper: EthUniqueHelper,399  privateKey: (seed: string) => Promise<IKeyringPair>,400  payer: ICrossAccountId,401  ethSigner: string,402  proxyContractAddress: string,403  calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,404): Promise<bigint> {405  const collection = await createCollectionForBenchmarks(406    helper,407    privateKey,408    ethSigner,409    proxyContractAddress,410    PERMISSIONS,411  );412  return helper.arrange.calculcateFee(payer, async () => {413    await calculatedCall(collection);414  });415}416function convertToTokens(value: bigint, nominal: bigint): number {417  return Number((value * 1000n) / nominal) / 1000;418}