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
1import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';1import {EthUniqueHelper, SponsoringMode, usingEthPlaygrounds} from '../../eth/util';
2import {readFile} from 'fs/promises';2import {readFile} from 'fs/promises';
3import {ContractImports, TokenPermissionField} from '../../eth/util/playgrounds/types';3import {CollectionLimitField, ContractImports, TokenPermissionField} from '../../eth/util/playgrounds/types';
4import {4import {
5 ICrossAccountId,5 ICrossAccountId,
6 ITokenPropertyPermission,6 ITokenPropertyPermission,
9import {UniqueNFTCollection} from '../../util/playgrounds/unique';9import {UniqueNFTCollection} from '../../util/playgrounds/unique';
10import {Contract} from 'web3-eth-contract';10import {Contract} from 'web3-eth-contract';
11import {createObjectCsvWriter} from 'csv-writer';11import {createObjectCsvWriter} from 'csv-writer';
12import {FeeGas} from '../../eth/util/playgrounds/unique.dev';
1213
13const CONTRACT_IMPORT: ContractImports[] = [14const CONTRACT_IMPORT: ContractImports[] = [
14 {15 {
95 const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.bin`)).toString();96 const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.bin`)).toString();
96 const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.abi`)).toString());97 const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.abi`)).toString());
98
99 console.log('\n ERC721 ops fees');
100 console.table(await ERC721CalculateFeeGas(helper, privateKey), ['fee', 'gas', 'substrate']);
97101
98 const donor = await privateKey('//Alice'); // Seed from account with balance on this network102 const donor = await privateKey('//Alice'); // Seed from account with balance on this network
99 const [substrateReceiver] = await helper.arrange.createAccounts([10n], donor);103 const [substrateReceiver] = await helper.arrange.createAccounts([10n], donor);
261 helper: EthUniqueHelper,265 helper: EthUniqueHelper,
262 privateKey: (seed: string) => Promise<IKeyringPair>,266 privateKey: (seed: string) => Promise<IKeyringPair>,
263 ethSigner: string,267 ethSigner: string,
264 proxyContract: string,268 proxyContract: string | null,
265 permissions: ITokenPropertyPermission[],269 permissions: ITokenPropertyPermission[],
266) {270) {
267 const donor = await privateKey('//Alice');271 const donor = await privateKey('//Alice');
279 mutable: true,283 mutable: true,
280 },284 },
281 },285 },
286 {
287 key: 'URI',
288 permission: {
289 tokenOwner: true,
290 collectionAdmin: true,
291 mutable: true,
292 },
293 },
282 ],294 ],
283 limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},295 limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},
284 permissions: {mintMode: true},296 permissions: {mintMode: true},
293 Ethereum: helper.address.substrateToEth(donor.address),305 Ethereum: helper.address.substrateToEth(donor.address),
294 });306 });
307
308 if (proxyContract) {
295 await collection.addToAllowList(donor, {Ethereum: proxyContract});309 await collection.addToAllowList(donor, {Ethereum: proxyContract});
296 await collection.addAdmin(donor, {Ethereum: proxyContract});310 await collection.addAdmin(donor, {Ethereum: proxyContract});
311 }
312
297 await collection.setTokenPropertyPermissions(donor, permissions);313 await collection.setTokenPropertyPermissions(donor, permissions);
298314
578 return Number((value * 1000n) / nominal) / 1000;594 return Number((value * 1000n) / nominal) / 1000;
579}595}
580596
597interface IFeeGas {
598 fee: number | bigint,
599 gas: number | bigint,
600 substrate?: number,
601}
602interface IFunctionFee {
603 [name: string]: IFeeGas
604}
605
606async function ERC721CalculateFeeGas(
607 helper: EthUniqueHelper,
608 privateKey: (seed: string) => Promise<IKeyringPair>,
609
610): Promise<IFunctionFee> {
611 const res: IFunctionFee = {};
612 const donor = await privateKey('//Alice');
613 const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);
614 const ethReceiver = await helper.eth.createAccountWithBalance(donor, 10n);
615 const crossSigner = helper.ethCrossAccount.fromAddress(ethSigner);
616 const crossReceiver = helper.ethCrossAccount.fromAddress(ethReceiver);
617 const collection = await createCollectionForBenchmarks(
618 helper,
619 privateKey,
620 ethSigner,
621 null,
622 PERMISSIONS,
623 );
624
625 const evmContract = await helper.ethNativeContract.collection(
626 helper.ethAddress.fromCollectionId(collection.collectionId),
627 'nft',
628 ethSigner,
629 true,
630 );
631
632 res['mint'] =
633 await helper.arrange.calculcateFeeGas(
634 {Ethereum: ethSigner},
635 () => evmContract.methods.mint(ethSigner).send(),
636 );
637
638 res['mintCross'] =
639 await helper.arrange.calculcateFeeGas(
640 {Ethereum: ethSigner},
641 () => evmContract.methods.mintCross(crossSigner, []).send(),
642 );
643
644 res['mintWithTokenURI'] =
645 await helper.arrange.calculcateFeeGas(
646 {Ethereum: ethSigner},
647 () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),
648 );
649
650 res['setProperties'] =
651 await helper.arrange.calculcateFeeGas(
652 {Ethereum: ethSigner},
653 () => evmContract.methods.setProperties(1, PROPERTIES.slice(0,1)).send(),
654 );
655
656 res['deleteProperties'] =
657 await helper.arrange.calculcateFeeGas(
658 {Ethereum: ethSigner},
659 () => evmContract.methods.deleteProperties(1, [PROPERTIES[0].key]).send(),
660 );
661
662 res['transfer'] =
663 await helper.arrange.calculcateFeeGas(
664 {Ethereum: ethSigner},
665 () => evmContract.methods.transfer(ethReceiver, 1).send(),
666 );
667
668 res['transferCross'] =
669 await helper.arrange.calculcateFeeGas(
670 {Ethereum: ethReceiver},
671 () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
672 );
673
674 res['transferFrom'] =
675 await helper.arrange.calculcateFeeGas(
676 {Ethereum: ethSigner},
677 () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
678 );
679
680 res['transferFromCross'] =
681 await helper.arrange.calculcateFeeGas(
682 {Ethereum: ethReceiver},
683 () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
684 );
685
686 res['burn'] =
687 await helper.arrange.calculcateFeeGas(
688 {Ethereum: ethSigner},
689 () => evmContract.methods.burn(1).send(),
690 );
691
692 res['approveCross'] =
693 await helper.arrange.calculcateFeeGas(
694 {Ethereum: ethSigner},
695 () => evmContract.methods.approveCross(crossReceiver, 2).send(),
696 );
697
698 res['burnFromCross'] =
699 await helper.arrange.calculcateFeeGas(
700 {Ethereum: ethReceiver},
701 () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),
702 );
703
704 res['setTokenPropertyPermissions'] =
705 await helper.arrange.calculcateFeeGas(
706 {Ethereum: ethSigner},
707 () => evmContract.methods.setTokenPropertyPermissions([
708 ['url', [
709 [TokenPermissionField.Mutable, true],
710 [TokenPermissionField.TokenOwner, true],
711 [TokenPermissionField.CollectionAdmin, true]],
712 ],
713 ]).send(),
714 );
715
716 res['setCollectionSponsorCross'] =
717 await helper.arrange.calculcateFeeGas(
718 {Ethereum: ethSigner},
719 () => evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),
720 );
721
722 res['confirmCollectionSponsorship'] =
723 await helper.arrange.calculcateFeeGas(
724 {Ethereum: ethReceiver},
725 () => evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),
726 );
727
728 res['removeCollectionSponsor'] =
729 await helper.arrange.calculcateFeeGas(
730 {Ethereum: ethSigner},
731 () => evmContract.methods.removeCollectionSponsor().send(),
732 );
733
734 res['setCollectionProperties'] =
735 await helper.arrange.calculcateFeeGas(
736 {Ethereum: ethSigner},
737 () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),
738 );
739
740
741
742 res['deleteCollectionProperties'] =
743 await helper.arrange.calculcateFeeGas(
744 {Ethereum: ethSigner},
745 () => evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),
746 );
747
748 res['setCollectionLimit'] =
749 await helper.arrange.calculcateFeeGas(
750 {Ethereum: ethSigner},
751 () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
752 );
753
754 const {collectionAddress} = await helper.eth.createCollection('nft', ethSigner, 'A', 'B', 'C');
755 const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);
756
757
758 res['addCollectionAdminCross'] =
759 await helper.arrange.calculcateFeeGas(
760 {Ethereum: ethSigner},
761 () => collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),
762 );
763
764 res['removeCollectionAdminCross'] =
765 await helper.arrange.calculcateFeeGas(
766 {Ethereum: ethSigner},
767 () => collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),
768 );
769
770 res['setCollectionNesting'] =
771 await helper.arrange.calculcateFeeGas(
772 {Ethereum: ethSigner},
773 () => evmContract.methods.setCollectionNesting(true).send(),
774 );
775
776 res['setCollectionNesting[]'] =
777 await helper.arrange.calculcateFeeGas(
778 {Ethereum: ethSigner},
779 () => evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),
780 );
781
782 res['setCollectionAcces'] =
783 await helper.arrange.calculcateFeeGas(
784 {Ethereum: ethSigner},
785 () => evmContract.methods.setCollectionAccess(SponsoringMode.Allowlisted).send(),
786 );
787
788 res['addToCollectionAllowListCross'] =
789 await helper.arrange.calculcateFeeGas(
790 {Ethereum: ethSigner},
791 () => evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),
792 );
793
794 res['removeFromCollectionAllowListCross'] =
795 await helper.arrange.calculcateFeeGas(
796 {Ethereum: ethSigner},
797 () => evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),
798 );
799
800 res['setCollectionMintMode'] =
801 await helper.arrange.calculcateFeeGas(
802 {Ethereum: ethSigner},
803 () => evmContract.methods.setCollectionMintMode(true).send(),
804 );
805
806 res['changeCollectionOwnerCross'] =
807 await helper.arrange.calculcateFeeGas(
808 {Ethereum: ethSigner},
809 () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
810 );
811 for (const name in res) {
812 res[name] = {fee: res[name].fee, gas: res[name].gas};
813 }
814 return res;
815}
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/eth/util/playgrounds/unique.dev.ts
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -16,7 +16,7 @@
 import {evmToAddress} from '@polkadot/util-crypto';
 import {IKeyringPair} from '@polkadot/types/types';
 
-import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
+import {ArrangeGroup, DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
 
 import {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types';
 
@@ -461,6 +461,41 @@
   }
 }
 
+export class FeeGas {
+  fee: number | bigint = 0n;
+
+  gas: number | bigint = 0n;
+
+  public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
+    const instance = new FeeGas();
+    instance.fee = instance.convertToTokens(fee);
+    instance.gas = await instance.convertToGas(fee, helper);
+    return instance;
+  }
+
+  private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
+    const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
+    return fee / gasPrice;
+  }
+
+  private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
+    return Number((value * 1000n) / nominal) / 1000;
+  }
+}
+
+class EthArrangeGroup extends ArrangeGroup {
+  helper: EthUniqueHelper;
+
+  constructor(helper: EthUniqueHelper) {
+    super(helper);
+    this.helper = helper;
+  }
+
+  async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
+    const fee = await this.calculcateFee(payer, promise);
+    return await FeeGas.build(this.helper, fee);
+  }
+}
 export class EthUniqueHelper extends DevUniqueHelper {
   web3: Web3 | null = null;
   web3Provider: WebsocketProvider | null = null;
@@ -471,7 +506,7 @@
   ethNativeContract: NativeContractGroup;
   ethContract: ContractGroup;
   ethProperty: EthPropertyGroup;
-
+  arrange: EthArrangeGroup;
   constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
     options.helperBase = options.helperBase ?? EthUniqueHelper;
 
@@ -482,6 +517,8 @@
     this.ethNativeContract = new NativeContractGroup(this);
     this.ethContract = new ContractGroup(this);
     this.ethProperty = new EthPropertyGroup(this);
+    this.arrange = new EthArrangeGroup(this);
+    super.arrange = this.arrange;
   }
 
   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;