difftreelog
feat(bench) added fee benchmarks for erc721 functions
in: master
3 files changed
tests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth1import {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';121313const 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());9899 console.log('\n ERC721 ops fees');100 console.table(await ERC721CalculateFeeGas(helper, privateKey), ['fee', 'gas', 'substrate']);9710198 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 network99 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 });307308 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 }312297 await collection.setTokenPropertyPermissions(donor, permissions);313 await collection.setTokenPropertyPermissions(donor, permissions);298314578 return Number((value * 1000n) / nominal) / 1000;594 return Number((value * 1000n) / nominal) / 1000;579}595}580596597interface IFeeGas {598 fee: number | bigint,599 gas: number | bigint,600 substrate?: number,601}602interface IFunctionFee {603 [name: string]: IFeeGas604}605606async function ERC721CalculateFeeGas(607 helper: EthUniqueHelper,608 privateKey: (seed: string) => Promise<IKeyringPair>,609610): 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 );624625 const evmContract = await helper.ethNativeContract.collection(626 helper.ethAddress.fromCollectionId(collection.collectionId),627 'nft',628 ethSigner,629 true,630 );631632 res['mint'] =633 await helper.arrange.calculcateFeeGas(634 {Ethereum: ethSigner},635 () => evmContract.methods.mint(ethSigner).send(),636 );637638 res['mintCross'] =639 await helper.arrange.calculcateFeeGas(640 {Ethereum: ethSigner},641 () => evmContract.methods.mintCross(crossSigner, []).send(),642 );643644 res['mintWithTokenURI'] =645 await helper.arrange.calculcateFeeGas(646 {Ethereum: ethSigner},647 () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),648 );649650 res['setProperties'] =651 await helper.arrange.calculcateFeeGas(652 {Ethereum: ethSigner},653 () => evmContract.methods.setProperties(1, PROPERTIES.slice(0,1)).send(),654 );655656 res['deleteProperties'] =657 await helper.arrange.calculcateFeeGas(658 {Ethereum: ethSigner},659 () => evmContract.methods.deleteProperties(1, [PROPERTIES[0].key]).send(),660 );661662 res['transfer'] =663 await helper.arrange.calculcateFeeGas(664 {Ethereum: ethSigner},665 () => evmContract.methods.transfer(ethReceiver, 1).send(),666 );667668 res['transferCross'] =669 await helper.arrange.calculcateFeeGas(670 {Ethereum: ethReceiver},671 () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),672 );673674 res['transferFrom'] =675 await helper.arrange.calculcateFeeGas(676 {Ethereum: ethSigner},677 () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),678 );679680 res['transferFromCross'] =681 await helper.arrange.calculcateFeeGas(682 {Ethereum: ethReceiver},683 () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),684 );685686 res['burn'] =687 await helper.arrange.calculcateFeeGas(688 {Ethereum: ethSigner},689 () => evmContract.methods.burn(1).send(),690 );691692 res['approveCross'] =693 await helper.arrange.calculcateFeeGas(694 {Ethereum: ethSigner},695 () => evmContract.methods.approveCross(crossReceiver, 2).send(),696 );697698 res['burnFromCross'] =699 await helper.arrange.calculcateFeeGas(700 {Ethereum: ethReceiver},701 () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),702 );703704 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 );715716 res['setCollectionSponsorCross'] =717 await helper.arrange.calculcateFeeGas(718 {Ethereum: ethSigner},719 () => evmContract.methods.setCollectionSponsorCross(crossReceiver).send(),720 );721722 res['confirmCollectionSponsorship'] =723 await helper.arrange.calculcateFeeGas(724 {Ethereum: ethReceiver},725 () => evmContract.methods.confirmCollectionSponsorship().send({from: ethReceiver}),726 );727728 res['removeCollectionSponsor'] =729 await helper.arrange.calculcateFeeGas(730 {Ethereum: ethSigner},731 () => evmContract.methods.removeCollectionSponsor().send(),732 );733734 res['setCollectionProperties'] =735 await helper.arrange.calculcateFeeGas(736 {Ethereum: ethSigner},737 () => evmContract.methods.setCollectionProperties(PROPERTIES.slice(0, 1)).send(),738 );739740741742 res['deleteCollectionProperties'] =743 await helper.arrange.calculcateFeeGas(744 {Ethereum: ethSigner},745 () => evmContract.methods.deleteCollectionProperties(PROPERTIES.slice(0,1).map(p => p.key)).send(),746 );747748 res['setCollectionLimit'] =749 await helper.arrange.calculcateFeeGas(750 {Ethereum: ethSigner},751 () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),752 );753754 const {collectionAddress} = await helper.eth.createCollection('nft', ethSigner, 'A', 'B', 'C');755 const collectionWithEthOwner = await helper.ethNativeContract.collection(collectionAddress, 'nft', ethSigner, true);756757758 res['addCollectionAdminCross'] =759 await helper.arrange.calculcateFeeGas(760 {Ethereum: ethSigner},761 () => collectionWithEthOwner.methods.addCollectionAdminCross(crossReceiver).send(),762 );763764 res['removeCollectionAdminCross'] =765 await helper.arrange.calculcateFeeGas(766 {Ethereum: ethSigner},767 () => collectionWithEthOwner.methods.removeCollectionAdminCross(crossReceiver).send(),768 );769770 res['setCollectionNesting'] =771 await helper.arrange.calculcateFeeGas(772 {Ethereum: ethSigner},773 () => evmContract.methods.setCollectionNesting(true).send(),774 );775776 res['setCollectionNesting[]'] =777 await helper.arrange.calculcateFeeGas(778 {Ethereum: ethSigner},779 () => evmContract.methods.setCollectionNesting(true, [collectionAddress]).send(),780 );781782 res['setCollectionAcces'] =783 await helper.arrange.calculcateFeeGas(784 {Ethereum: ethSigner},785 () => evmContract.methods.setCollectionAccess(SponsoringMode.Allowlisted).send(),786 );787788 res['addToCollectionAllowListCross'] =789 await helper.arrange.calculcateFeeGas(790 {Ethereum: ethSigner},791 () => evmContract.methods.addToCollectionAllowListCross(crossReceiver).send(),792 );793794 res['removeFromCollectionAllowListCross'] =795 await helper.arrange.calculcateFeeGas(796 {Ethereum: ethSigner},797 () => evmContract.methods.removeFromCollectionAllowListCross(crossReceiver).send(),798 );799800 res['setCollectionMintMode'] =801 await helper.arrange.calculcateFeeGas(802 {Ethereum: ethSigner},803 () => evmContract.methods.setCollectionMintMode(true).send(),804 );805806 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}tests/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 {
tests/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;