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

difftreelog

feat(bench) added fee benchmarks for erc721 functions

PraetorP2023-01-25parent: #8dd063b.patch.diff
in: master

3 files changed

modifiedtests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/benchmark.ts
+++ b/tests/src/benchmarks/mintFee/benchmark.ts
@@ -1,6 +1,6 @@
-import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
+import {EthUniqueHelper, SponsoringMode, usingEthPlaygrounds} from '../../eth/util';
 import {readFile} from 'fs/promises';
-import {ContractImports, TokenPermissionField} from '../../eth/util/playgrounds/types';
+import {CollectionLimitField, ContractImports, TokenPermissionField} from '../../eth/util/playgrounds/types';
 import {
   ICrossAccountId,
   ITokenPropertyPermission,
@@ -9,6 +9,7 @@
 import {UniqueNFTCollection} from '../../util/playgrounds/unique';
 import {Contract} from 'web3-eth-contract';
 import {createObjectCsvWriter} from 'csv-writer';
+import {FeeGas} from '../../eth/util/playgrounds/unique.dev';
 
 const CONTRACT_IMPORT: ContractImports[] = [
   {
@@ -95,6 +96,9 @@
     const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.bin`)).toString();
     const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.abi`)).toString());
 
+    console.log('\n ERC721 ops fees');
+    console.table(await ERC721CalculateFeeGas(helper, privateKey), ['fee', 'gas', 'substrate']);
+
     const donor = await privateKey('//Alice'); // Seed from account with balance on this network
     const [substrateReceiver] = await helper.arrange.createAccounts([10n], donor);
 
@@ -261,7 +265,7 @@
   helper: EthUniqueHelper,
   privateKey: (seed: string) => Promise<IKeyringPair>,
   ethSigner: string,
-  proxyContract: string,
+  proxyContract: string | null,
   permissions: ITokenPropertyPermission[],
 ) {
   const donor = await privateKey('//Alice');
@@ -279,6 +283,14 @@
           mutable: true,
         },
       },
+      {
+        key: 'URI',
+        permission: {
+          tokenOwner: true,
+          collectionAdmin: true,
+          mutable: true,
+        },
+      },
     ],
     limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},
     permissions: {mintMode: true},
@@ -292,8 +304,12 @@
   await collection.addAdmin(donor, {
     Ethereum: helper.address.substrateToEth(donor.address),
   });
-  await collection.addToAllowList(donor, {Ethereum: proxyContract});
-  await collection.addAdmin(donor, {Ethereum: proxyContract});
+
+  if (proxyContract) {
+    await collection.addToAllowList(donor, {Ethereum: proxyContract});
+    await collection.addAdmin(donor, {Ethereum: proxyContract});
+  }
+
   await collection.setTokenPropertyPermissions(donor, permissions);
 
   return collection;
@@ -577,3 +593,223 @@
 function convertToTokens(value: bigint, nominal: bigint): number {
   return Number((value * 1000n) / nominal) / 1000;
 }
+
+interface IFeeGas {
+  fee: number | bigint,
+  gas: number | bigint,
+  substrate?: number,
+}
+interface IFunctionFee {
+  [name: string]: IFeeGas
+}
+
+async function ERC721CalculateFeeGas(
+  helper: EthUniqueHelper,
+  privateKey: (seed: string) => Promise<IKeyringPair>,
+
+): Promise<IFunctionFee> {
+  const res: IFunctionFee = {};
+  const donor = await privateKey('//Alice');
+  const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);
+  const ethReceiver = await helper.eth.createAccountWithBalance(donor, 10n);
+  const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);
+  const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);
+  const collection = await createCollectionForBenchmarks(
+    helper,
+    privateKey,
+    ethSigner,
+    null,
+    PERMISSIONS,
+  );
+
+  const evmContract = await helper.ethNativeContract.collection(
+    helper.ethAddress.fromCollectionId(collection.collectionId),
+    'nft',
+    ethSigner,
+    true,
+  );
+
+  res['mint'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.mint(ethSigner).send(),
+    );
+
+  res['mintCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.mintCross(crossSigner, []).send(),
+    );
+
+  res['mintWithTokenURI'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),
+    );
+
+  res['setProperties'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.setProperties(1, PROPERTIES.slice(0,1)).send(),
+    );
+
+  res['deleteProperties'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.deleteProperties(1, [PROPERTIES[0].key]).send(),
+    );
+
+  res['transfer'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.transfer(ethReceiver, 1).send(),
+    );
+
+  res['transferCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethReceiver},
+      () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
+    );
+
+  res['transferFrom'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
+    );
+
+  res['transferFromCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethReceiver},
+      () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
+    );
+
+  res['burn'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.burn(1).send(),
+    );
+
+  res['approveCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.approveCross(crossReceiver, 2).send(),
+    );
+
+  res['burnFromCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethReceiver},
+      () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),
+    );
+
+  res['setTokenPropertyPermissions'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setTokenPropertyPermissions([
+        ['url', [
+          [TokenPermissionField.Mutable, true],
+          [TokenPermissionField.TokenOwner, true],
+          [TokenPermissionField.CollectionAdmin, true]],
+        ],
+      ]).send(),
+    );
+
+  res['setCollectionSponsorCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),
+    );
+
+  res['confirmCollectionSponsorship'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethReceiver},
+      () =>  evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),
+    );
+
+  res['removeCollectionSponsor'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.removeCollectionSponsor().send(),
+    );
+
+  res['setCollectionProperties'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),
+    );
+
+
+
+  res['deleteCollectionProperties'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),
+    );
+
+  res['setCollectionLimit'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
+    );
+
+  const {collectionAddress} = await helper.eth.createCollection('nft', ethSigner, 'A', 'B', 'C');
+  const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);
+
+
+  res['addCollectionAdminCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),
+    );
+
+  res['removeCollectionAdminCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),
+    );
+
+  res['setCollectionNesting'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setCollectionNesting(true).send(),
+    );
+
+  res['setCollectionNesting[]'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),
+    );
+
+  res['setCollectionAcces'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setCollectionAccess(SponsoringMode.Allowlisted).send(),
+    );
+
+  res['addToCollectionAllowListCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),
+    );
+
+  res['removeFromCollectionAllowListCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),
+    );
+
+  res['setCollectionMintMode'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  evmContract.methods.setCollectionMintMode(true).send(),
+    );
+
+  res['changeCollectionOwnerCross'] =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () =>  collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
+    );
+  for (const name in res) {
+    res[name] = {fee: res[name].fee, gas: res[name].gas};
+  }
+  return res;
+}
\ No newline at end of file
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
16import {evmToAddress} from '@polkadot/util-crypto';16import {evmToAddress} from '@polkadot/util-crypto';
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
1818
19import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';19import {ArrangeGroup, DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
2020
21import {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types';21import {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types';
2222
461 }461 }
462}462}
463463
464export class FeeGas {
465 fee: number | bigint = 0n;
466
467 gas: number | bigint = 0n;
468
469 public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
470 const instance = new FeeGas();
471 instance.fee = instance.convertToTokens(fee);
472 instance.gas = await instance.convertToGas(fee, helper);
473 return instance;
474 }
475
476 private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
477 const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
478 return fee / gasPrice;
479 }
480
481 private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
482 return Number((value * 1000n) / nominal) / 1000;
483 }
484}
485
486class EthArrangeGroup extends ArrangeGroup {
487 helper: EthUniqueHelper;
488
489 constructor(helper: EthUniqueHelper) {
490 super(helper);
491 this.helper = helper;
492 }
493
494 async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
495 const fee = await this.calculcateFee(payer, promise);
496 return await FeeGas.build(this.helper, fee);
497 }
498}
464export class EthUniqueHelper extends DevUniqueHelper {499export class EthUniqueHelper extends DevUniqueHelper {
465 web3: Web3 | null = null;500 web3: Web3 | null = null;
466 web3Provider: WebsocketProvider | null = null;501 web3Provider: WebsocketProvider | null = null;
471 ethNativeContract: NativeContractGroup;506 ethNativeContract: NativeContractGroup;
472 ethContract: ContractGroup;507 ethContract: ContractGroup;
473 ethProperty: EthPropertyGroup;508 ethProperty: EthPropertyGroup;
474509 arrange: EthArrangeGroup;
475 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {510 constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
476 options.helperBase = options.helperBase ?? EthUniqueHelper;511 options.helperBase = options.helperBase ?? EthUniqueHelper;
477512
482 this.ethNativeContract = new NativeContractGroup(this);517 this.ethNativeContract = new NativeContractGroup(this);
483 this.ethContract = new ContractGroup(this);518 this.ethContract = new ContractGroup(this);
484 this.ethProperty = new EthPropertyGroup(this);519 this.ethProperty = new EthPropertyGroup(this);
520 this.arrange = new EthArrangeGroup(this);
521 super.arrange = this.arrange;
485 }522 }
486523
487 getWeb3(): Web3 {524 getWeb3(): Web3 {
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -187,7 +187,7 @@
 
 export class DevKaruraHelper extends DevAcalaHelper {}
 
-class ArrangeGroup {
+export class ArrangeGroup {
   helper: DevUniqueHelper;
 
   scheduledIdSlider = 0;