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

difftreelog

source

tests/src/benchmarks/mintFee/benchmark.ts29.9 KiBsourcehistory
1import {EthUniqueHelper, SponsoringMode, usingEthPlaygrounds} from '../../eth/util';2import {readFile} from 'fs/promises';3import {CollectionLimitField, ContractImports, TokenPermissionField} 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 SUBS_PROPERTIES = Array(40)46  .fill(0)47  .map((_, i) => {48    return {49      key: `key_${i}`,50      value: `value_${i}`,51    };52  });5354const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => {55  return {56    key: p.key,57    permission: {58      tokenOwner: true,59      collectionAdmin: true,60      mutable: true,61    },62  };63});6465interface IBenchmarkResultForProp {66	propertiesNumber: number;67	substrateFee: number;68	ethFee: number;69	ethBulkFee: number;70  ethMintCrossFee: number;71	evmProxyContractFee: number;72	evmProxyContractBulkFee: number;73}74interface IBenchmarkCollection {75  createFee: number,76  mintFee: number,77  transferFee: number,78}79const main = async () => {80  const benchmarks = [81    'substrateFee',82    'ethFee',83    'ethBulkFee',84    'ethMintCrossFee',85    'evmProxyContractFee',86    'evmProxyContractBulkFee',87  ];88  const headers = [89    'propertiesNumber',90    ...benchmarks,91  ];929394  const csvWriter = createObjectCsvWriter({95    path: 'properties.csv',96    header: headers,97  });9899  await usingEthPlaygrounds(async (helper, privateKey) => {100    const NOMINAL = helper.balance.getOneTokenNominal();101    const CONTRACT_SOURCE = (102      await readFile(`${__dirname}/proxyContract.sol`)103    ).toString();104    const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.bin`)).toString();105    const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.abi`)).toString());106107    console.log('\n ERC721 ops fees');108    console.table(await ERC721CalculateFeeGas(helper, privateKey), ['fee', 'gas', 'substrate']);109110    const donor = await privateKey('//Alice'); // Seed from account with balance on this network111    const [substrateReceiver] = await helper.arrange.createAccounts([10n], donor);112113    const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);114    const ethReceiver = await helper.eth.createAccountWithBalance(donor, 5n);115116    let susbtrateCollection: UniqueNFTCollection | null;117    const createCollectionSubstrateFee = convertToTokens(118      await helper.arrange.calculcateFee({Substrate: donor.address}, async () => {119        susbtrateCollection = await helper.nft.mintCollection(donor, {tokenPropertyPermissions: [120          {121            key: 'url',122            permission: {123              tokenOwner: true,124              collectionAdmin: true,125              mutable: true,126            },127          },128        ]});129      }),130      NOMINAL,131    );132133    const susbstrateMintFee = convertToTokens(134      await helper.arrange.calculcateFee(135        {Substrate: donor.address},136        () => susbtrateCollection!.mintToken(donor, {Substrate: substrateReceiver.address}, [{key: 'url', value: 'test'}]),137      ),138      NOMINAL,139    );140    const susbstrateTransferFee = convertToTokens(141      await helper.arrange.calculcateFee(142        {Substrate: substrateReceiver.address},143        () => susbtrateCollection!.transferToken(substrateReceiver, 1, {Substrate: donor.address}),144      ),145      NOMINAL,146    );147    const substrateFee: IBenchmarkCollection = {148      createFee: createCollectionSubstrateFee,149      mintFee: susbstrateMintFee,150      transferFee: susbstrateTransferFee,151    };152153    const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);154155    let ethContract: Contract | null = null;156157    const createCollectionEthFee = convertToTokens(158      await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {159        const result = await helperContract.methods.createNFTCollection('a', 'b', 'c').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())});160        ethContract = await helper.ethNativeContract.collection(helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId), 'nft', ethSigner);161      }),162      NOMINAL,163    );164165    await ethContract!.methods.setTokenPropertyPermissions([166      ['url', [167        [TokenPermissionField.Mutable, true],168        [TokenPermissionField.TokenOwner, true],169        [TokenPermissionField.CollectionAdmin, true]],170      ],171    ]).send({from: ethSigner});172173    const ethMintFee = convertToTokens(await helper.arrange.calculcateFee(174      {Ethereum: ethSigner},175      () => ethContract!.methods.mintCross(176        helper.ethCrossAccount.fromAddress(ethReceiver),177        [{key: 'url', value: Buffer.from('test')}],178      )179        .send({from: ethSigner}),180    ), NOMINAL);181182    const ethTransferFee = convertToTokens(await helper.arrange.calculcateFee(183      {Ethereum: ethReceiver},184      () => ethContract!.methods.transferFrom(ethReceiver, ethSigner, 1)185        .send({from: ethReceiver}),186    ), NOMINAL);187188    const ethFee: IBenchmarkCollection = {189      createFee: createCollectionEthFee,190      mintFee: ethMintFee,191      transferFee: ethTransferFee,192    };193194    let zeppelelinContract: Contract | null = null;195196    const zeppelinDeployFee = convertToTokens(197      await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {198        zeppelelinContract = await helper.ethContract.deployByAbi(199          ethSigner,200          ZEPPELIN_ABI,201          ZEPPELIN_OBJECT,202        );203      }),204      NOMINAL,205    );206207    const zeppelinMintFee = convertToTokens(await helper.arrange.calculcateFee(208      {Ethereum: ethSigner},209      () => zeppelelinContract!.methods.safeMint(ethReceiver, 'test').send({from: ethSigner}),210    ), NOMINAL);211212213    const zeppelinTransferFee = convertToTokens(await helper.arrange.calculcateFee(214      {Ethereum: ethReceiver},215      () => zeppelelinContract!.methods.safeTransferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),216    ), NOMINAL);217218    const zeppelinFee: IBenchmarkCollection = {219      createFee: zeppelinDeployFee,220      mintFee: zeppelinMintFee,221      transferFee: zeppelinTransferFee,222    };223224    console.log('collection ops fees');225    const results = {substrate: substrateFee, eth: ethFee, zeppelin: zeppelinFee};226    console.table(results);227228    const contract = await helper.ethContract.deployByCode(229      ethSigner,230      'ProxyMint',231      CONTRACT_SOURCE,232      CONTRACT_IMPORT,233    );234235    const fees = await benchMintFee(helper, privateKey, contract);236    console.log('Minting without properties');237    console.table(fees);238239    const result: IBenchmarkResultForProp[] = [];240    const csvResult: IBenchmarkResultForProp[] = [];241242    for (let i = 1; i <= 20; i++) {243      const benchResult = await benchMintWithProperties(helper, privateKey, contract, {244        propertiesNumber: i,245      }) as any;246247      csvResult.push(benchResult);248249      const minFee = Math.min(...(benchmarks.map(x => benchResult[x])));250      for(const key of benchmarks) {251        const keyPercent = Math.round((benchResult[key] / minFee) * 100);252        benchResult[key] = `${benchResult[key]} (${keyPercent}%)`;253      }254255      result.push(benchResult);256    }257258    await csvWriter.writeRecords(csvResult);259260    console.log('Minting with properties');261    console.table(result, headers);262  });263};264265main()266  .then(() => process.exit(0))267  .catch((e) => {268    console.log(e);269    process.exit(1);270  });271272async function createCollectionForBenchmarks(273  helper: EthUniqueHelper,274  privateKey: (seed: string) => Promise<IKeyringPair>,275  ethSigner: string,276  proxyContract: string | null,277  permissions: ITokenPropertyPermission[],278) {279  const donor = await privateKey('//Alice');280281  const collection = await helper.nft.mintCollection(donor, {282    name: 'test mintToSubstrate',283    description: 'EVMHelpers',284    tokenPrefix: 'ap',285    tokenPropertyPermissions: [286      {287        key: 'url',288        permission: {289          tokenOwner: true,290          collectionAdmin: true,291          mutable: true,292        },293      },294      {295        key: 'URI',296        permission: {297          tokenOwner: true,298          collectionAdmin: true,299          mutable: true,300        },301      },302    ],303    limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},304    permissions: {mintMode: true},305  });306307  await collection.addToAllowList(donor, {308    Ethereum: helper.address.substrateToEth(donor.address),309  });310  await collection.addToAllowList(donor, {Substrate: donor.address});311  await collection.addAdmin(donor, {Ethereum: ethSigner});312  await collection.addAdmin(donor, {313    Ethereum: helper.address.substrateToEth(donor.address),314  });315316  if (proxyContract) {317    await collection.addToAllowList(donor, {Ethereum: proxyContract});318    await collection.addAdmin(donor, {Ethereum: proxyContract});319  }320321  await collection.setTokenPropertyPermissions(donor, permissions);322323  return collection;324}325326async function benchMintFee(327  helper: EthUniqueHelper,328  privateKey: (seed: string) => Promise<IKeyringPair>,329  proxyContract: Contract,330): Promise<{331	substrateFee: number;332	ethFee: number;333	evmProxyContractFee: number;334}> {335  const donor = await privateKey('//Alice');336  const substrateReceiver = await privateKey('//Bob');337  const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);338339  const nominal = helper.balance.getOneTokenNominal();340341  await helper.eth.transferBalanceFromSubstrate(342    donor,343    proxyContract.options.address,344    100n,345  );346347  const collection = await createCollectionForBenchmarks(348    helper,349    privateKey,350    ethSigner,351    proxyContract.options.address,352    PERMISSIONS,353  );354355  const substrateFee = await helper.arrange.calculcateFee(356    {Substrate: donor.address},357    () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),358  );359360  const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);361  const collectionContract = await helper.ethNativeContract.collection(362    collectionEthAddress,363    'nft',364  );365366  const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);367368  const encodedCall = collectionContract.methods369    .mint(receiverEthAddress)370    .encodeABI();371372  const ethFee = await helper.arrange.calculcateFee(373    {Substrate: donor.address},374    async () => {375      await helper.eth.sendEVM(376        donor,377        collectionContract.options.address,378        encodedCall,379        '0',380      );381    },382  );383384  const evmProxyContractFee = await helper.arrange.calculcateFee(385    {Ethereum: ethSigner},386    async () => {387      await proxyContract.methods388        .mintToSubstrate(389          helper.ethAddress.fromCollectionId(collection.collectionId),390          substrateReceiver.addressRaw,391        )392        .send({from: ethSigner});393    },394  );395396  return {397    substrateFee: convertToTokens(substrateFee, nominal),398    ethFee: convertToTokens(ethFee, nominal),399    evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),400  };401}402403async function benchMintWithProperties(404  helper: EthUniqueHelper,405  privateKey: (seed: string) => Promise<IKeyringPair>,406  proxyContract: Contract,407  setup: { propertiesNumber: number },408): Promise<IBenchmarkResultForProp> {409  const donor = await privateKey('//Alice'); // Seed from account with balance on this network410  const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);411412  const susbstrateReceiver = await privateKey('//Bob');413  const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);414415  const nominal = helper.balance.getOneTokenNominal();416417  const substrateFee = await calculateFeeNftMintWithProperties(418    helper,419    privateKey,420    {Substrate: donor.address},421    ethSigner,422    proxyContract.options.address,423    async (collection) => {424      await collection.mintToken(425        donor,426        {Substrate: susbstrateReceiver.address},427        PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {428          return {key: p.key, value: Buffer.from(p.value).toString()};429        }),430      );431    },432  );433434  const ethFee = await calculateFeeNftMintWithProperties(435    helper,436    privateKey,437    {Substrate: donor.address},438    ethSigner,439    proxyContract.options.address,440    async (collection) => {441      const evmContract = await helper.ethNativeContract.collection(442        helper.ethAddress.fromCollectionId(collection.collectionId),443        'nft',444        undefined,445        true,446      );447448      const subTokenId = await evmContract.methods.nextTokenId().call();449450      let encodedCall = evmContract.methods451        .mint(receiverEthAddress)452        .encodeABI();453454      await helper.eth.sendEVM(455        donor,456        evmContract.options.address,457        encodedCall,458        '0',459      );460461      for (const val of PROPERTIES.slice(0, setup.propertiesNumber)) {462        encodedCall = await evmContract.methods463          .setProperty(subTokenId, val.key, Buffer.from(val.value))464          .encodeABI();465466        await helper.eth.sendEVM(467          donor,468          evmContract.options.address,469          encodedCall,470          '0',471        );472      }473    },474  );475476  const ethBulkFee = await calculateFeeNftMintWithProperties(477    helper,478    privateKey,479    {Substrate: donor.address},480    ethSigner,481    proxyContract.options.address,482    async (collection) => {483      const evmContract = await helper.ethNativeContract.collection(484        helper.ethAddress.fromCollectionId(collection.collectionId),485        'nft',486      );487488      const subTokenId = await evmContract.methods.nextTokenId().call();489490      let encodedCall = evmContract.methods491        .mint(receiverEthAddress)492        .encodeABI();493494      await helper.eth.sendEVM(495        donor,496        evmContract.options.address,497        encodedCall,498        '0',499      );500501      encodedCall = await evmContract.methods502        .setProperties(503          subTokenId,504          PROPERTIES.slice(0, setup.propertiesNumber),505        )506        .encodeABI();507508      await helper.eth.sendEVM(509        donor,510        evmContract.options.address,511        encodedCall,512        '0',513      );514    },515  );516517  const ethMintCrossFee = await calculateFeeNftMintWithProperties(518    helper,519    privateKey,520    {Ethereum: ethSigner},521    ethSigner,522    proxyContract.options.address,523    async (collection) => {524      const evmContract = await helper.ethNativeContract.collection(525        helper.ethAddress.fromCollectionId(collection.collectionId),526        'nft',527      );528529      await evmContract.methods.mintCross(530        helper.ethCrossAccount.fromAddress(receiverEthAddress),531        PROPERTIES.slice(0, setup.propertiesNumber),532      )533        .send({from: ethSigner});534    },535  );536537  const proxyContractFee = await calculateFeeNftMintWithProperties(538    helper,539    privateKey,540    {Ethereum: ethSigner},541    ethSigner,542    proxyContract.options.address,543    async (collection) => {544      await proxyContract.methods545        .mintToSubstrateWithProperty(546          helper.ethAddress.fromCollectionId(collection.collectionId),547          susbstrateReceiver.addressRaw,548          PROPERTIES.slice(0, setup.propertiesNumber),549        )550        .send({from: ethSigner});551    },552  );553554  const proxyContractBulkFee = await calculateFeeNftMintWithProperties(555    helper,556    privateKey,557    {Ethereum: ethSigner},558    ethSigner,559    proxyContract.options.address,560    async (collection) => {561      await proxyContract.methods562        .mintToSubstrateBulkProperty(563          helper.ethAddress.fromCollectionId(collection.collectionId),564          susbstrateReceiver.addressRaw,565          PROPERTIES.slice(0, setup.propertiesNumber),566        )567        .send({from: ethSigner, gas: 25_000_000});568    },569  );570571  return {572    propertiesNumber: setup.propertiesNumber,573    substrateFee: convertToTokens(substrateFee, nominal),574    ethFee: convertToTokens(ethFee, nominal),575    ethBulkFee: convertToTokens(ethBulkFee, nominal),576    ethMintCrossFee: convertToTokens(ethMintCrossFee, nominal),577    evmProxyContractFee: convertToTokens(proxyContractFee, nominal),578    evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),579  };580}581582async function calculateFeeNftMintWithProperties(583  helper: EthUniqueHelper,584  privateKey: (seed: string) => Promise<IKeyringPair>,585  payer: ICrossAccountId,586  ethSigner: string,587  proxyContractAddress: string,588  calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,589): Promise<bigint> {590  const collection = await createCollectionForBenchmarks(591    helper,592    privateKey,593    ethSigner,594    proxyContractAddress,595    PERMISSIONS,596  );597  return helper.arrange.calculcateFee(payer, async () => {598    await calculatedCall(collection);599  });600}601function convertToTokens(value: bigint, nominal = 1000_000_000_000_000_000n): number {602  return Number((value * 1000n) / nominal) / 1000;603}604605interface IFeeGas {606  fee: number | bigint,607  gas: number | bigint,608  substrate?: number,609}610interface IFunctionFee {611  [name: string]: IFeeGas612}613614async function ERC721CalculateFeeGas(615  helper: EthUniqueHelper,616  privateKey: (seed: string) => Promise<IKeyringPair>,617618): Promise<IFunctionFee> {619  const res: IFunctionFee = {};620  const donor = await privateKey('//Alice');621  const [subReceiver] = await helper.arrange.createAccounts([10n], donor);622  const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);623  const ethReceiver = await helper.eth.createAccountWithBalance(donor, 10n);624  const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);625  const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);626  const collection = await createCollectionForBenchmarks(627    helper,628    privateKey,629    ethSigner,630    null,631    PERMISSIONS,632  );633634  const evmContract = await helper.ethNativeContract.collection(635    helper.ethAddress.fromCollectionId(collection.collectionId),636    'nft',637    ethSigner,638    true,639  );640641  res['mint'] =642    await helper.arrange.calculcateFeeGas(643      {Ethereum: ethSigner},644      () => evmContract.methods.mint(ethSigner).send(),645    );646647  res['mintCross'] =648    await helper.arrange.calculcateFeeGas(649      {Ethereum: ethSigner},650      () => evmContract.methods.mintCross(crossSigner, []).send(),651    );652653  res['mint'].substrate = convertToTokens((await helper.arrange.calculcateFee(654    {Substrate: donor.address},655    () => collection.mintToken(656      donor,657      {Substrate: donor.address},658    ),659  )));660661  res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(662    {Substrate: donor.address},663    () => collection.mintMultipleTokens(donor, [{664      owner: {Substrate: donor.address},665    }]),666  )));667668  res['mintWithTokenURI'] =669    await helper.arrange.calculcateFeeGas(670      {Ethereum: ethSigner},671      () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),672    );673674  res['mintWithTokenURI'].substrate = convertToTokens((await helper.arrange.calculcateFee(675    {Substrate: donor.address},676    () => collection.mintToken(677      donor,678      {Ethereum: ethSigner},679      [{key: 'URI', value: 'Test URI'}],680    ),681  )));682683  res['setProperties'] =684    await helper.arrange.calculcateFeeGas(685      {Ethereum: ethSigner},686      () => evmContract.methods.setProperties(1, PROPERTIES.slice(0,1)).send(),687    );688689  res['deleteProperties'] =690    await helper.arrange.calculcateFeeGas(691      {Ethereum: ethSigner},692      () => evmContract.methods.deleteProperties(1, [PROPERTIES[0].key]).send(),693    );694695  res['setProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(696    {Substrate: donor.address},697    () => collection.setTokenProperties(698      donor,699      1,700      SUBS_PROPERTIES.slice(0, 1),701    ),702  )));703704  res['deleteProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(705    {Substrate: donor.address},706    () => collection.deleteTokenProperties(707      donor,708      1,709      SUBS_PROPERTIES.slice(0, 1)710        .map(p => p.key),711    ),712  )));713714  res['transfer'] =715    await helper.arrange.calculcateFeeGas(716      {Ethereum: ethSigner},717      () => evmContract.methods.transfer(ethReceiver, 1).send(),718    );719720  res['transferCross'] =721    await helper.arrange.calculcateFeeGas(722      {Ethereum: ethReceiver},723      () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),724    );725726  res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(727    {Substrate: donor.address},728    () => collection.transferToken(729      donor,730      3,731      {Substrate: subReceiver.address},732    ),733  )));734  await collection.approveToken(subReceiver, 3, {Substrate: donor.address});735736  res['transferFrom'] =737    await helper.arrange.calculcateFeeGas(738      {Ethereum: ethSigner},739      () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),740    );741742  res['transferFromCross'] =743    await helper.arrange.calculcateFeeGas(744      {Ethereum: ethReceiver},745      () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),746    );747748  res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(749    {Substrate: donor.address},750    () => collection.transferTokenFrom(donor, 3, {Substrate: subReceiver.address}, {Substrate: donor.address}),751  )));752753  res['burn'] =754    await helper.arrange.calculcateFeeGas(755      {Ethereum: ethSigner},756      () => evmContract.methods.burn(1).send(),757    );758759  res['burn'].substrate = convertToTokens((await helper.arrange.calculcateFee(760    {Substrate: donor.address},761    () => collection.burnToken(donor, 3),762  )));763764765  res['approveCross'] =766    await helper.arrange.calculcateFeeGas(767      {Ethereum: ethSigner},768      () => evmContract.methods.approveCross(crossReceiver, 2).send(),769    );770771  res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(772    {Substrate: donor.address},773    () => collection.approveToken(donor, 4, {Substrate: subReceiver.address}),774  )));775776  res['burnFromCross'] =777    await helper.arrange.calculcateFeeGas(778      {Ethereum: ethReceiver},779      () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),780    );781782  res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(783    {Substrate: subReceiver.address},784    () => collection.burnTokenFrom(subReceiver, 4, {Substrate: donor.address}),785  )));786787  res['setTokenPropertyPermissions'] =788    await helper.arrange.calculcateFeeGas(789      {Ethereum: ethSigner},790      () =>  evmContract.methods.setTokenPropertyPermissions([791        ['url', [792          [TokenPermissionField.Mutable, true],793          [TokenPermissionField.TokenOwner, true],794          [TokenPermissionField.CollectionAdmin, true]],795        ],796      ]).send(),797    );798799  res['setTokenPropertyPermissions'].substrate = convertToTokens((await helper.arrange.calculcateFee(800    {Substrate: donor.address},801    () => collection.setTokenPropertyPermissions(donor, [{key: 'url', permission: {802      tokenOwner: true,803      collectionAdmin: true,804      mutable: true,805    }}]),806  )));807808  res['setCollectionSponsorCross'] =809    await helper.arrange.calculcateFeeGas(810      {Ethereum: ethSigner},811      () =>  evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),812    );813814  res['confirmCollectionSponsorship'] =815    await helper.arrange.calculcateFeeGas(816      {Ethereum: ethReceiver},817      () =>  evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),818    );819820  res['removeCollectionSponsor'] =821    await helper.arrange.calculcateFeeGas(822      {Ethereum: ethSigner},823      () =>  evmContract.methods.removeCollectionSponsor().send(),824    );825826  res['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(827    {Substrate: donor.address},828    () => collection.setSponsor(donor, subReceiver.address),829  )));830831  res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(832    {Substrate: subReceiver.address},833    () => collection.confirmSponsorship(subReceiver),834  )));835836  res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(837    {Substrate: donor.address},838    () => collection.removeSponsor(donor),839  )));840841  res['setCollectionProperties'] =842    await helper.arrange.calculcateFeeGas(843      {Ethereum: ethSigner},844      () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),845    );846847  res['deleteCollectionProperties'] =848    await helper.arrange.calculcateFeeGas(849      {Ethereum: ethSigner},850      () =>  evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),851    );852  res['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(853    {Substrate: donor.address},854    () => collection.setProperties(donor, PROPERTIES.slice(0, 1)855      .map(p => { return {key: p.key, value: p.value.toString()}; })),856  )));857858  res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(859    {Substrate: donor.address},860    () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)861      .map(p => p.key)),862  )));863864  res['setCollectionLimit'] =865    await helper.arrange.calculcateFeeGas(866      {Ethereum: ethSigner},867      () =>  evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),868    );869870  res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(871    {Substrate: donor.address},872    () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),873  )));874875  const {collectionAddress} = await helper.eth.createCollection('nft', ethSigner, 'A', 'B', 'C');876  const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);877878879  res['addCollectionAdminCross'] =880    await helper.arrange.calculcateFeeGas(881      {Ethereum: ethSigner},882      () =>  collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),883    );884885  res['removeCollectionAdminCross'] =886    await helper.arrange.calculcateFeeGas(887      {Ethereum: ethSigner},888      () =>  collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),889    );890891  res['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(892    {Substrate: donor.address},893    () => collection.addAdmin(donor, {Ethereum: ethReceiver}),894  )));895896  res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(897    {Substrate: donor.address},898    () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),899  )));900901  res['setCollectionNesting'] =902    await helper.arrange.calculcateFeeGas(903      {Ethereum: ethSigner},904      () =>  evmContract.methods.setCollectionNesting(true).send(),905    );906907  res['setCollectionNesting[]'] =908    await helper.arrange.calculcateFeeGas(909      {Ethereum: ethSigner},910      () =>  evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),911    );912913  res['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(914    {Substrate: donor.address},915    () => collection.disableNesting(donor),916  )));917918  res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(919    {Substrate: donor.address},920    () => collection.setPermissions(921      donor,922      {923        nesting: {924          tokenOwner: true,925          restricted: [collection.collectionId],926        },927      },928    ),929  )));930931  res['setCollectionAccess'] =932    await helper.arrange.calculcateFeeGas(933      {Ethereum: ethSigner},934      () =>  evmContract.methods.setCollectionAccess(1).send(),935    );936937  res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(938    {Substrate: donor.address},939    () => collection.setPermissions(donor, {access: 'AllowList'}),940  )));941942  res['addToCollectionAllowListCross'] =943    await helper.arrange.calculcateFeeGas(944      {Ethereum: ethSigner},945      () =>  evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),946    );947948  res['removeFromCollectionAllowListCross'] =949    await helper.arrange.calculcateFeeGas(950      {Ethereum: ethSigner},951      () =>  evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),952    );953954  res['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(955    {Substrate: donor.address},956    () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),957  )));958959  res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(960    {Substrate: donor.address},961    () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),962  )));963964  res['setCollectionMintMode'] =965    await helper.arrange.calculcateFeeGas(966      {Ethereum: ethSigner},967      () =>  evmContract.methods.setCollectionMintMode(true).send(),968    );969970  res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(971    {Substrate: donor.address},972    () => collection.setPermissions(donor, {mintMode: false}),973  )));974975  res['changeCollectionOwnerCross'] =976    await helper.arrange.calculcateFeeGas(977      {Ethereum: ethSigner},978      () =>  collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),979    );980981  res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(982    {Substrate: donor.address},983    () => collection.changeOwner(donor, subReceiver.address),984  )));985986  return res;987}