difftreelog
refactor changed arch of bechmarks
in: master
added export to `csv` ops fees
6 files changed
tests/.gitignorediffbeforeafterboth--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,2 +1,4 @@
/node_modules/
properties.csv
+erc721.csv
+erc20.csv
\ No newline at end of file
tests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth--- a/tests/src/benchmarks/mintFee/benchmark.ts
+++ /dev/null
@@ -1,1323 +0,0 @@
-import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
-import {readFile} from 'fs/promises';
-import {CollectionLimitField, ContractImports, TokenPermissionField} from '../../eth/util/playgrounds/types';
-import {
- ICrossAccountId,
- ITokenPropertyPermission,
- TCollectionMode,
-} from '../../util/playgrounds/types';
-import {IKeyringPair} from '@polkadot/types/types';
-import {UniqueFTCollection, UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';
-import {Contract} from 'web3-eth-contract';
-import {createObjectCsvWriter} from 'csv-writer';
-import {FunctionFeeVM, IFunctionFee} from './types';
-
-const CONTRACT_IMPORT: ContractImports[] = [
- {
- fsPath: `${__dirname}/../../eth/api/CollectionHelpers.sol`,
- solPath: 'eth/api/CollectionHelpers.sol',
- },
- {
- fsPath: `${__dirname}/../../eth/api/ContractHelpers.sol`,
- solPath: 'eth/api/ContractHelpers.sol',
- },
- {
- fsPath: `${__dirname}/../../eth/api/UniqueRefungibleToken.sol`,
- solPath: 'eth/api/UniqueRefungibleToken.sol',
- },
- {
- fsPath: `${__dirname}/../../eth/api/UniqueRefungible.sol`,
- solPath: 'eth/api/UniqueRefungible.sol',
- },
- {
- fsPath: `${__dirname}/../../eth/api/UniqueNFT.sol`,
- solPath: 'eth/api/UniqueNFT.sol',
- },
-];
-
-const PROPERTIES = Array(40)
- .fill(0)
- .map((_, i) => {
- return {
- key: `key_${i}`,
- value: Uint8Array.from(Buffer.from(`value_${i}`)),
- };
- });
-
-const SUBS_PROPERTIES = Array(40)
- .fill(0)
- .map((_, i) => {
- return {
- key: `key_${i}`,
- value: `value_${i}`,
- };
- });
-
-const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => {
- return {
- key: p.key,
- permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
- };
-});
-
-interface IBenchmarkResultForProp {
- propertiesNumber: number;
- substrateFee: number;
- ethFee: number;
- ethBulkFee: number;
- ethMintCrossFee: number;
- evmProxyContractFee: number;
- evmProxyContractBulkFee: number;
-}
-
-const main = async () => {
- const benchmarks = [
- 'substrateFee',
- 'ethFee',
- 'ethBulkFee',
- 'ethMintCrossFee',
- 'evmProxyContractFee',
- 'evmProxyContractBulkFee',
- ];
- const headers = [
- 'propertiesNumber',
- ...benchmarks,
- ];
-
-
- const csvWriter = createObjectCsvWriter({
- path: 'properties.csv',
- header: headers,
- });
-
- await usingEthPlaygrounds(async (helper, privateKey) => {
- const NOMINAL = helper.balance.getOneTokenNominal();
- const CONTRACT_SOURCE = (
- await readFile(`${__dirname}/proxyContract.sol`)
- ).toString();
-
- console.log('\n ERC20 ops fees');
- console.table(FunctionFeeVM.fromModel(await erc20CalculateFeeGas(helper, privateKey)));
-
- console.log('\n ERC721 ops fees');
- const erc721 = await erc721CalculateFeeGas(helper, privateKey);
- console.table(FunctionFeeVM.fromModel(erc721));
-
- const donor = await privateKey('//Alice'); // Seed from account with balance on this network
- const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);
-
- const contract = await helper.ethContract.deployByCode(
- ethSigner,
- 'ProxyMint',
- CONTRACT_SOURCE,
- CONTRACT_IMPORT,
- );
-
- const fees = await benchMintFee(helper, privateKey, contract);
- console.log('Minting without properties');
- console.table(fees);
-
- const result: IBenchmarkResultForProp[] = [];
- const csvResult: IBenchmarkResultForProp[] = [];
-
- for (let i = 1; i <= 20; i++) {
- const benchResult = await benchMintWithProperties(helper, privateKey, contract, {
- propertiesNumber: i,
- }) as any;
-
- csvResult.push(benchResult);
-
- const minFee = Math.min(...(benchmarks.map(x => benchResult[x])));
- for(const key of benchmarks) {
- const keyPercent = Math.round((benchResult[key] / minFee) * 100);
- benchResult[key] = `${benchResult[key]} (${keyPercent}%)`;
- }
-
- result.push(benchResult);
- }
-
- await csvWriter.writeRecords(csvResult);
-
- console.log('Minting with properties');
- console.table(result, headers);
- });
-};
-
-main()
- .then(() => process.exit(0))
- .catch((e) => {
- console.log(e);
- process.exit(1);
- });
-
-async function createCollectionForBenchmarks(
- mode : TCollectionMode,
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- ethSigner: string,
- proxyContract: string | null,
- permissions: ITokenPropertyPermission[],
-) {
- const donor = await privateKey('//Alice');
-
- const collection = await helper[mode].mintCollection(donor, {
- name: 'test mintToSubstrate',
- description: 'EVMHelpers',
- tokenPrefix: mode,
- ...(mode != 'ft' ? {
- tokenPropertyPermissions: [
- {
- key: 'url',
- permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
- },
- {
- key: 'URI',
- permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- },
- },
- ],
- } : {}),
- limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},
- permissions: {mintMode: true},
- });
-
- await collection.addToAllowList(donor, {
- Ethereum: helper.address.substrateToEth(donor.address),
- });
- await collection.addToAllowList(donor, {Substrate: donor.address});
- await collection.addAdmin(donor, {Ethereum: ethSigner});
- await collection.addAdmin(donor, {
- Ethereum: helper.address.substrateToEth(donor.address),
- });
-
- if (proxyContract) {
- await collection.addToAllowList(donor, {Ethereum: proxyContract});
- await collection.addAdmin(donor, {Ethereum: proxyContract});
- }
- if (collection instanceof UniqueNFTCollection || collection instanceof UniqueRFTCollection)
- await collection.setTokenPropertyPermissions(donor, permissions);
-
- return collection;
-}
-
-async function benchMintFee(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- proxyContract: Contract,
-): Promise<{
- substrateFee: number;
- ethFee: number;
- evmProxyContractFee: number;
-}> {
- const donor = await privateKey('//Alice');
- const substrateReceiver = await privateKey('//Bob');
- const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);
-
- const nominal = helper.balance.getOneTokenNominal();
-
- await helper.eth.transferBalanceFromSubstrate(
- donor,
- proxyContract.options.address,
- 100n,
- );
-
- const collection = (await createCollectionForBenchmarks(
- 'nft',
- helper,
- privateKey,
- ethSigner,
- proxyContract.options.address,
- PERMISSIONS,
- )) as UniqueNFTCollection;
-
- const substrateFee = await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),
- );
-
- const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionContract = await helper.ethNativeContract.collection(
- collectionEthAddress,
- 'nft',
- );
-
- const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);
-
- const encodedCall = collectionContract.methods
- .mint(receiverEthAddress)
- .encodeABI();
-
- const ethFee = await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- async () => {
- await helper.eth.sendEVM(
- donor,
- collectionContract.options.address,
- encodedCall,
- '0',
- );
- },
- );
-
- const evmProxyContractFee = await helper.arrange.calculcateFee(
- {Ethereum: ethSigner},
- async () => {
- await proxyContract.methods
- .mintToSubstrate(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- substrateReceiver.addressRaw,
- )
- .send({from: ethSigner});
- },
- );
-
- return {
- substrateFee: convertToTokens(substrateFee, nominal),
- ethFee: convertToTokens(ethFee, nominal),
- evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),
- };
-}
-
-async function benchMintWithProperties(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- proxyContract: Contract,
- setup: { propertiesNumber: number },
-): Promise<IBenchmarkResultForProp> {
- const donor = await privateKey('//Alice'); // Seed from account with balance on this network
- const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);
-
- const susbstrateReceiver = await privateKey('//Bob');
- const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);
-
- const nominal = helper.balance.getOneTokenNominal();
-
- const substrateFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Substrate: donor.address},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- await collection.mintToken(
- donor,
- {Substrate: susbstrateReceiver.address},
- PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {
- return {key: p.key, value: Buffer.from(p.value).toString()};
- }),
- );
- },
- );
-
- const ethFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Substrate: donor.address},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- undefined,
- true,
- );
-
- const subTokenId = await evmContract.methods.nextTokenId().call();
-
- let encodedCall = evmContract.methods
- .mint(receiverEthAddress)
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
-
- for (const val of PROPERTIES.slice(0, setup.propertiesNumber)) {
- encodedCall = await evmContract.methods
- .setProperty(subTokenId, val.key, Buffer.from(val.value))
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
- }
- },
- );
-
- const ethBulkFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Substrate: donor.address},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- );
-
- const subTokenId = await evmContract.methods.nextTokenId().call();
-
- let encodedCall = evmContract.methods
- .mint(receiverEthAddress)
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
-
- encodedCall = await evmContract.methods
- .setProperties(
- subTokenId,
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
- },
- );
-
- const ethMintCrossFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Ethereum: ethSigner},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- );
-
- await evmContract.methods.mintCross(
- helper.ethCrossAccount.fromAddress(receiverEthAddress),
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .send({from: ethSigner});
- },
- );
-
- const proxyContractFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Ethereum: ethSigner},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- await proxyContract.methods
- .mintToSubstrateWithProperty(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- susbstrateReceiver.addressRaw,
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .send({from: ethSigner});
- },
- );
-
- const proxyContractBulkFee = await calculateFeeNftMintWithProperties(
- helper,
- privateKey,
- {Ethereum: ethSigner},
- ethSigner,
- proxyContract.options.address,
- async (collection) => {
- await proxyContract.methods
- .mintToSubstrateBulkProperty(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- susbstrateReceiver.addressRaw,
- PROPERTIES.slice(0, setup.propertiesNumber),
- )
- .send({from: ethSigner, gas: 25_000_000});
- },
- );
-
- return {
- propertiesNumber: setup.propertiesNumber,
- substrateFee: convertToTokens(substrateFee, nominal),
- ethFee: convertToTokens(ethFee, nominal),
- ethBulkFee: convertToTokens(ethBulkFee, nominal),
- ethMintCrossFee: convertToTokens(ethMintCrossFee, nominal),
- evmProxyContractFee: convertToTokens(proxyContractFee, nominal),
- evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),
- };
-}
-
-async function calculateFeeNftMintWithProperties(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- payer: ICrossAccountId,
- ethSigner: string,
- proxyContractAddress: string,
- calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,
-): Promise<bigint> {
- const collection = (await createCollectionForBenchmarks(
- 'nft',
- helper,
- privateKey,
- ethSigner,
- proxyContractAddress,
- PERMISSIONS,
- )) as UniqueNFTCollection;
- return helper.arrange.calculcateFee(payer, async () => {
- await calculatedCall(collection);
- });
-}
-
-function convertToTokens(value: bigint, nominal = 1000_000_000_000_000_000n): number {
- return Number((value * 1000n) / nominal) / 1000;
-}
-
-async function erc721CalculateFeeGas(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
-
-): Promise<IFunctionFee> {
- const res: IFunctionFee = {};
- const donor = await privateKey('//Alice');
- const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
- 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(
- 'nft',
- helper,
- privateKey,
- ethSigner,
- null,
- PERMISSIONS,
- )) as UniqueNFTCollection;
-
- const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
- let zeppelelinContract: Contract | null = null;
- const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/ERC721/bin/ZeppelinContract.bin`)).toString();
- const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/ERC721/bin/ZeppelinContract.abi`)).toString());
-
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'nft',
- ethSigner,
- true,
- );
-
- res['createCollection'] = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => helperContract.methods.createNFTCollection('test','test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
- );
-
- res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.nft.mintCollection(
- donor,
- {name: 'test', description: 'test', tokenPrefix: 'test'},
- ),
- )));
-
- res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- async () => {
- zeppelelinContract = await helper.ethContract.deployByAbi(
- ethSigner,
- ZEPPELIN_ABI,
- ZEPPELIN_OBJECT,
- );
- },
- );
-
- res['mint'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mint(ethSigner).send(),
- );
-
- res['mint'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.safeMint(ethSigner, 'test').send({from: ethSigner}),
- );
-
- res['mintCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintCross(crossSigner, []).send(),
- );
-
- res['mint'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(
- donor,
- {Substrate: donor.address},
- ),
- )));
-
- res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintMultipleTokens(donor, [{
- owner: {Substrate: donor.address},
- }]),
- )));
-
- res['mintWithTokenURI'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),
- );
-
- res['mintWithTokenURI'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(
- donor,
- {Ethereum: ethSigner},
- [{key: 'URI', value: 'Test URI'}],
- ),
- )));
-
- 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['setProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setTokenProperties(
- donor,
- 1,
- SUBS_PROPERTIES.slice(0, 1),
- ),
- )));
-
- res['deleteProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.deleteTokenProperties(
- donor,
- 1,
- SUBS_PROPERTIES.slice(0, 1)
- .map(p => p.key),
- ),
- )));
-
- res['transfer'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transfer(ethReceiver, 1).send(),
- );
-
- res['safeTransferFrom*'] = {
- zeppelin:
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.safeTransferFrom(ethSigner, ethReceiver, 0).send({from: ethSigner}),
- ),
- };
-
- res['transferCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
- );
-
- res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transferToken(
- donor,
- 3,
- {Substrate: subReceiver.address},
- ),
- )));
- await collection.approveToken(subReceiver, 3, {Substrate: donor.address});
-
- res['transferFrom*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
- );
-
- res['transferFrom*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
- );
-
-
- res['transferFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
- );
-
- res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transferTokenFrom(donor, 3, {Substrate: subReceiver.address}, {Substrate: donor.address}),
- )));
-
- res['burn'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.burn(1).send(),
- );
-
- res['burn'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.burnToken(donor, 3),
- )));
-
- res['approve*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approve(ethReceiver, 2).send(),
- );
-
- res['approve*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.approve(ethReceiver, 0).send({from: ethSigner}),
- );
-
- res['approveCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approveCross(crossReceiver, 2).send(),
- );
-
- res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.approveToken(donor, 4, {Substrate: subReceiver.address}),
- )));
-
- res['setApprovalForAll*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setApprovalForAll(ethReceiver, true).send(),
- );
-
- res['setApprovalForAll*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.setApprovalForAll(ethReceiver, true).send({from: ethSigner}),
- );
-
- res['setApprovalForAll*'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.nft.setAllowanceForAll(donor, collection.collectionId, {Substrate: subReceiver.address}, true),
- )));
-
- res['burnFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),
- );
-
- res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.burnTokenFrom(subReceiver, 4, {Substrate: donor.address}),
- )));
-
- res['setTokenPropertyPermissions'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setTokenPropertyPermissions([
- ['url', [
- [TokenPermissionField.Mutable, true],
- [TokenPermissionField.TokenOwner, true],
- [TokenPermissionField.CollectionAdmin, true]],
- ],
- ]).send(),
- );
-
- res['setTokenPropertyPermissions'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setTokenPropertyPermissions(donor, [{key: 'url', permission: {
- tokenOwner: true,
- collectionAdmin: true,
- mutable: true,
- }}]),
- )));
-
- 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['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setSponsor(donor, subReceiver.address),
- )));
-
- res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.confirmSponsorship(subReceiver),
- )));
-
- res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeSponsor(donor),
- )));
-
- 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['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => { return {key: p.key, value: p.value.toString()}; })),
- )));
-
- res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => p.key)),
- )));
-
- res['setCollectionLimit'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
- );
-
- res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
- )));
-
- 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['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- 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['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.disableNesting(donor),
- )));
-
- res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(
- donor,
- {
- nesting: {
- tokenOwner: true,
- restricted: [collection.collectionId],
- },
- },
- ),
- )));
-
- res['setCollectionAccess'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionAccess(1).send(),
- );
-
- res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {access: 'AllowList'}),
- )));
-
- 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['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['setCollectionMintMode'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionMintMode(true).send(),
- );
-
- res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {mintMode: false}),
- )));
-
- res['changeCollectionOwnerCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
- );
-
- res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.changeOwner(donor, subReceiver.address),
- )));
-
- return res;
-}
-
-async function erc20CalculateFeeGas(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
-
-): Promise<IFunctionFee> {
- const res: IFunctionFee = {};
- const donor = await privateKey('//Alice');
- const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
- 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(
- 'ft',
- helper,
- privateKey,
- ethSigner,
- null,
- PERMISSIONS,
- )) as UniqueFTCollection;
-
- const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
- let zeppelelinContract: Contract | null = null;
- const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/ERC20/bin/ZeppelinContract.bin`)).toString();
- const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/ERC20/bin/ZeppelinContract.abi`)).toString());
-
- const evmContract = await helper.ethNativeContract.collection(
- helper.ethAddress.fromCollectionId(collection.collectionId),
- 'ft',
- ethSigner,
- true,
- );
-
- res['createCollection'] = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => helperContract.methods.createFTCollection('test', 18,'test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
- );
-
- res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.ft.mintCollection(
- donor,
- {name: 'test', description: 'test', tokenPrefix: 'test'},
- 18,
- ),
- )));
-
- res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- async () => {
- zeppelelinContract = await helper.ethContract.deployByAbi(
- ethSigner,
- ZEPPELIN_ABI,
- ZEPPELIN_OBJECT,
- );
- },
- );
-
- res['mint'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mint(ethSigner, 1).send(),
- );
-
- res['mint'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.mint(ethSigner, 1).send(),
- );
-
- res['mintCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintCross(crossSigner, 1).send(),
- );
-
- res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mint(
- donor,
- 10n,
- {Substrate: donor.address},
- ),
- )));
-
- res['mintBulk'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.mintBulk([{to: ethSigner, amount: 1}]).send(),
- );
-
- res['mintBulk'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => helper.executeExtrinsic(donor, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
- Fungible: new Map([
- [JSON.stringify({Ethereum: ethSigner}), 1],
-
- ]),
- }], true),
- )));
-
- res['transfer*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transfer(ethReceiver, 1).send(),
- );
-
- res['transfer*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.transfer(ethReceiver, 1).send(),
- );
-
- res['transferCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
- );
-
- res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transfer(
- donor,
- {Substrate: subReceiver.address},
- 1n,
- ),
- )));
- await collection.approveTokens(subReceiver, {Substrate: donor.address}, 1n);
-
- res['transferFrom*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
- );
-
- res['transferFrom*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
- );
-
- res['transferFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
- );
-
- res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.transferFrom(donor, {Substrate: subReceiver.address}, {Substrate: donor.address}, 1n),
- )));
-
-
- res['burnTokens'] = {fee: 0n, gas: 0n};
- res['burnTokens'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.burnTokens(donor, 1n),
- )));
-
-
- res['approve*'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approve(ethReceiver, 2).send(),
- );
-
- res['approve*'].zeppelin =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => zeppelelinContract!.methods.approve(ethReceiver, 0).send(),
- );
-
- res['approveCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.approveCross(crossReceiver, 2).send(),
- );
-
- res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.approveTokens(donor, {Substrate: subReceiver.address}, 1n),
- )));
-
- res['burnFromCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethReceiver},
- () => evmContract.methods.burnFromCross(crossSigner, 1).send({from:ethReceiver}),
- );
-
- res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.burnTokensFrom(subReceiver, {Substrate: donor.address}, 1n),
- )));
-
- 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['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setSponsor(donor, subReceiver.address),
- )));
-
- res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: subReceiver.address},
- () => collection.confirmSponsorship(subReceiver),
- )));
-
- res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeSponsor(donor),
- )));
-
- 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['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => { return {key: p.key, value: p.value.toString()}; })),
- )));
-
- res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
- .map(p => p.key)),
- )));
-
- res['setCollectionLimit'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
- );
-
- res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
- )));
-
- 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['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
- )));
-
- 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['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.disableNesting(donor),
- )));
-
- res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(
- donor,
- {
- nesting: {
- tokenOwner: true,
- restricted: [collection.collectionId],
- },
- },
- ),
- )));
-
- res['setCollectionAccess'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionAccess(1).send(),
- );
-
- res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {access: 'AllowList'}),
- )));
-
- 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['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
- )));
-
- res['setCollectionMintMode'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => evmContract.methods.setCollectionMintMode(true).send(),
- );
-
- res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.setPermissions(donor, {mintMode: false}),
- )));
-
- res['changeCollectionOwnerCross'] =
- await helper.arrange.calculcateFeeGas(
- {Ethereum: ethSigner},
- () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
- );
-
- res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.changeOwner(donor, subReceiver.address),
- )));
-
- return res;
-}
\ No newline at end of file
tests/src/benchmarks/mintFee/common.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/mintFee/common.ts
@@ -0,0 +1,118 @@
+import {EthUniqueHelper} from '../../eth/util';
+import {ITokenPropertyPermission, TCollectionMode} from '../../util/playgrounds/types';
+import {UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';
+import {IKeyringPair} from '@polkadot/types/types';
+import {ContractImports} from '../../eth/util/playgrounds/types';
+
+export const CONTRACT_IMPORT: ContractImports[] = [
+ {
+ fsPath: `${__dirname}/../../eth/api/CollectionHelpers.sol`,
+ solPath: 'eth/api/CollectionHelpers.sol',
+ },
+ {
+ fsPath: `${__dirname}/../../eth/api/ContractHelpers.sol`,
+ solPath: 'eth/api/ContractHelpers.sol',
+ },
+ {
+ fsPath: `${__dirname}/../../eth/api/UniqueRefungibleToken.sol`,
+ solPath: 'eth/api/UniqueRefungibleToken.sol',
+ },
+ {
+ fsPath: `${__dirname}/../../eth/api/UniqueRefungible.sol`,
+ solPath: 'eth/api/UniqueRefungible.sol',
+ },
+ {
+ fsPath: `${__dirname}/../../eth/api/UniqueNFT.sol`,
+ solPath: 'eth/api/UniqueNFT.sol',
+ },
+];
+
+export const PROPERTIES = Array(40)
+ .fill(0)
+ .map((_, i) => {
+ return {
+ key: `key_${i}`,
+ value: Uint8Array.from(Buffer.from(`value_${i}`)),
+ };
+ });
+
+export const SUBS_PROPERTIES = Array(40)
+ .fill(0)
+ .map((_, i) => {
+ return {
+ key: `key_${i}`,
+ value: `value_${i}`,
+ };
+ });
+
+export const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => {
+ return {
+ key: p.key,
+ permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+ };
+});
+
+export function convertToTokens(value: bigint, nominal = 1000_000_000_000_000_000n): number {
+ return Number((value * 1000n) / nominal) / 1000;
+}
+
+export async function createCollectionForBenchmarks(
+ mode : TCollectionMode,
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+ ethSigner: string,
+ proxyContract: string | null,
+ permissions: ITokenPropertyPermission[],
+) {
+ const donor = await privateKey('//Alice');
+
+ const collection = await helper[mode].mintCollection(donor, {
+ name: 'test mintToSubstrate',
+ description: 'EVMHelpers',
+ tokenPrefix: mode,
+ ...(mode != 'ft' ? {
+ tokenPropertyPermissions: [
+ {
+ key: 'url',
+ permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+ },
+ {
+ key: 'URI',
+ permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ },
+ },
+ ],
+ } : {}),
+ limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0},
+ permissions: {mintMode: true},
+ });
+
+ await collection.addToAllowList(donor, {
+ Ethereum: helper.address.substrateToEth(donor.address),
+ });
+ await collection.addToAllowList(donor, {Substrate: donor.address});
+ await collection.addAdmin(donor, {Ethereum: ethSigner});
+ await collection.addAdmin(donor, {
+ Ethereum: helper.address.substrateToEth(donor.address),
+ });
+
+ if (proxyContract) {
+ await collection.addToAllowList(donor, {Ethereum: proxyContract});
+ await collection.addAdmin(donor, {Ethereum: proxyContract});
+ }
+ if (collection instanceof UniqueNFTCollection || collection instanceof UniqueRFTCollection)
+ await collection.setTokenPropertyPermissions(donor, permissions);
+
+ return collection;
+}
\ No newline at end of file
tests/src/benchmarks/mintFee/mintFee.tsdiffbeforeafterboth1import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';2import {readFile} from 'fs/promises';3import {4 ICrossAccountId,5} from '../../util/playgrounds/types';6import {IKeyringPair} from '@polkadot/types/types';7import {UniqueNFTCollection} from '../../util/playgrounds/unique';8import {Contract} from 'web3-eth-contract';9import {createObjectCsvWriter} from 'csv-writer';10import {CONTRACT_IMPORT, convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from './common';11121314interface IBenchmarkResultForProp {15 propertiesNumber: number;16 substrateFee: number;17 ethFee: number;18 ethBulkFee: number;19 ethMintCrossFee: number;20 evmProxyContractFee: number;21 evmProxyContractBulkFee: number;22}2324const main = async () => {25 const benchmarks = [26 'substrateFee',27 'ethFee',28 'ethBulkFee',29 'ethMintCrossFee',30 'evmProxyContractFee',31 'evmProxyContractBulkFee',32 ];33 const headers = [34 'propertiesNumber',35 ...benchmarks,36 ];373839 const csvWriter = createObjectCsvWriter({40 path: 'properties.csv',41 header: headers,42 });4344 await usingEthPlaygrounds(async (helper, privateKey) => {45 const CONTRACT_SOURCE = (46 await readFile(`${__dirname}/proxyContract.sol`)47 ).toString();4849 const donor = await privateKey('//Alice'); // Seed from account with balance on this network50 const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);5152 const contract = await helper.ethContract.deployByCode(53 ethSigner,54 'ProxyMint',55 CONTRACT_SOURCE,56 CONTRACT_IMPORT,57 );5859 const fees = await benchMintFee(helper, privateKey, contract);60 console.log('Minting without properties');61 console.table(fees);6263 const result: IBenchmarkResultForProp[] = [];64 const csvResult: IBenchmarkResultForProp[] = [];6566 for (let i = 1; i <= 20; i++) {67 const benchResult = await benchMintWithProperties(helper, privateKey, contract, {68 propertiesNumber: i,69 }) as any;7071 csvResult.push(benchResult);7273 const minFee = Math.min(...(benchmarks.map(x => benchResult[x])));74 for(const key of benchmarks) {75 const keyPercent = Math.round((benchResult[key] / minFee) * 100);76 benchResult[key] = `${benchResult[key]} (${keyPercent}%)`;77 }7879 result.push(benchResult);80 }8182 await csvWriter.writeRecords(csvResult);8384 console.log('Minting with properties');85 console.table(result, headers);86 });87};8889main()90 .then(() => process.exit(0))91 .catch((e) => {92 console.log(e);93 process.exit(1);94 });95969798async function benchMintFee(99 helper: EthUniqueHelper,100 privateKey: (seed: string) => Promise<IKeyringPair>,101 proxyContract: Contract,102): Promise<{103 substrateFee: number;104 ethFee: number;105 evmProxyContractFee: number;106}> {107 const donor = await privateKey('//Alice');108 const substrateReceiver = await privateKey('//Bob');109 const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);110111 const nominal = helper.balance.getOneTokenNominal();112113 await helper.eth.transferBalanceFromSubstrate(114 donor,115 proxyContract.options.address,116 100n,117 );118119 const collection = (await createCollectionForBenchmarks(120 'nft',121 helper,122 privateKey,123 ethSigner,124 proxyContract.options.address,125 PERMISSIONS,126 )) as UniqueNFTCollection;127128 const substrateFee = await helper.arrange.calculcateFee(129 {Substrate: donor.address},130 () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),131 );132133 const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);134 const collectionContract = await helper.ethNativeContract.collection(135 collectionEthAddress,136 'nft',137 );138139 const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address);140141 const encodedCall = collectionContract.methods142 .mint(receiverEthAddress)143 .encodeABI();144145 const ethFee = await helper.arrange.calculcateFee(146 {Substrate: donor.address},147 async () => {148 await helper.eth.sendEVM(149 donor,150 collectionContract.options.address,151 encodedCall,152 '0',153 );154 },155 );156157 const evmProxyContractFee = await helper.arrange.calculcateFee(158 {Ethereum: ethSigner},159 async () => {160 await proxyContract.methods161 .mintToSubstrate(162 helper.ethAddress.fromCollectionId(collection.collectionId),163 substrateReceiver.addressRaw,164 )165 .send({from: ethSigner});166 },167 );168169 return {170 substrateFee: convertToTokens(substrateFee, nominal),171 ethFee: convertToTokens(ethFee, nominal),172 evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal),173 };174}175176async function benchMintWithProperties(177 helper: EthUniqueHelper,178 privateKey: (seed: string) => Promise<IKeyringPair>,179 proxyContract: Contract,180 setup: { propertiesNumber: number },181): Promise<IBenchmarkResultForProp> {182 const donor = await privateKey('//Alice'); // Seed from account with balance on this network183 const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);184185 const susbstrateReceiver = await privateKey('//Bob');186 const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address);187188 const nominal = helper.balance.getOneTokenNominal();189190 const substrateFee = await calculateFeeNftMintWithProperties(191 helper,192 privateKey,193 {Substrate: donor.address},194 ethSigner,195 proxyContract.options.address,196 async (collection) => {197 await collection.mintToken(198 donor,199 {Substrate: susbstrateReceiver.address},200 PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {201 return {key: p.key, value: Buffer.from(p.value).toString()};202 }),203 );204 },205 );206207 const ethFee = await calculateFeeNftMintWithProperties(208 helper,209 privateKey,210 {Substrate: donor.address},211 ethSigner,212 proxyContract.options.address,213 async (collection) => {214 const evmContract = await helper.ethNativeContract.collection(215 helper.ethAddress.fromCollectionId(collection.collectionId),216 'nft',217 undefined,218 true,219 );220221 const subTokenId = await evmContract.methods.nextTokenId().call();222223 let encodedCall = evmContract.methods224 .mint(receiverEthAddress)225 .encodeABI();226227 await helper.eth.sendEVM(228 donor,229 evmContract.options.address,230 encodedCall,231 '0',232 );233234 for (const val of PROPERTIES.slice(0, setup.propertiesNumber)) {235 encodedCall = await evmContract.methods236 .setProperty(subTokenId, val.key, Buffer.from(val.value))237 .encodeABI();238239 await helper.eth.sendEVM(240 donor,241 evmContract.options.address,242 encodedCall,243 '0',244 );245 }246 },247 );248249 const ethBulkFee = await calculateFeeNftMintWithProperties(250 helper,251 privateKey,252 {Substrate: donor.address},253 ethSigner,254 proxyContract.options.address,255 async (collection) => {256 const evmContract = await helper.ethNativeContract.collection(257 helper.ethAddress.fromCollectionId(collection.collectionId),258 'nft',259 );260261 const subTokenId = await evmContract.methods.nextTokenId().call();262263 let encodedCall = evmContract.methods264 .mint(receiverEthAddress)265 .encodeABI();266267 await helper.eth.sendEVM(268 donor,269 evmContract.options.address,270 encodedCall,271 '0',272 );273274 encodedCall = await evmContract.methods275 .setProperties(276 subTokenId,277 PROPERTIES.slice(0, setup.propertiesNumber),278 )279 .encodeABI();280281 await helper.eth.sendEVM(282 donor,283 evmContract.options.address,284 encodedCall,285 '0',286 );287 },288 );289290 const ethMintCrossFee = await calculateFeeNftMintWithProperties(291 helper,292 privateKey,293 {Ethereum: ethSigner},294 ethSigner,295 proxyContract.options.address,296 async (collection) => {297 const evmContract = await helper.ethNativeContract.collection(298 helper.ethAddress.fromCollectionId(collection.collectionId),299 'nft',300 );301302 await evmContract.methods.mintCross(303 helper.ethCrossAccount.fromAddress(receiverEthAddress),304 PROPERTIES.slice(0, setup.propertiesNumber),305 )306 .send({from: ethSigner});307 },308 );309310 const proxyContractFee = await calculateFeeNftMintWithProperties(311 helper,312 privateKey,313 {Ethereum: ethSigner},314 ethSigner,315 proxyContract.options.address,316 async (collection) => {317 await proxyContract.methods318 .mintToSubstrateWithProperty(319 helper.ethAddress.fromCollectionId(collection.collectionId),320 susbstrateReceiver.addressRaw,321 PROPERTIES.slice(0, setup.propertiesNumber),322 )323 .send({from: ethSigner});324 },325 );326327 const proxyContractBulkFee = await calculateFeeNftMintWithProperties(328 helper,329 privateKey,330 {Ethereum: ethSigner},331 ethSigner,332 proxyContract.options.address,333 async (collection) => {334 await proxyContract.methods335 .mintToSubstrateBulkProperty(336 helper.ethAddress.fromCollectionId(collection.collectionId),337 susbstrateReceiver.addressRaw,338 PROPERTIES.slice(0, setup.propertiesNumber),339 )340 .send({from: ethSigner, gas: 25_000_000});341 },342 );343344 return {345 propertiesNumber: setup.propertiesNumber,346 substrateFee: convertToTokens(substrateFee, nominal),347 ethFee: convertToTokens(ethFee, nominal),348 ethBulkFee: convertToTokens(ethBulkFee, nominal),349 ethMintCrossFee: convertToTokens(ethMintCrossFee, nominal),350 evmProxyContractFee: convertToTokens(proxyContractFee, nominal),351 evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal),352 };353}354355async function calculateFeeNftMintWithProperties(356 helper: EthUniqueHelper,357 privateKey: (seed: string) => Promise<IKeyringPair>,358 payer: ICrossAccountId,359 ethSigner: string,360 proxyContractAddress: string,361 calculatedCall: (collection: UniqueNFTCollection) => Promise<any>,362): Promise<bigint> {363 const collection = (await createCollectionForBenchmarks(364 'nft',365 helper,366 privateKey,367 ethSigner,368 proxyContractAddress,369 PERMISSIONS,370 )) as UniqueNFTCollection;371 return helper.arrange.calculcateFee(payer, async () => {372 await calculatedCall(collection);373 });374}375376377tests/src/benchmarks/mintFee/opsFee.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/mintFee/opsFee.ts
@@ -0,0 +1,881 @@
+import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
+import {readFile} from 'fs/promises';
+import {CollectionLimitField, TokenPermissionField} from '../../eth/util/playgrounds/types';
+import {IKeyringPair} from '@polkadot/types/types';
+import {UniqueFTCollection, UniqueNFTCollection} from '../../util/playgrounds/unique';
+import {Contract} from 'web3-eth-contract';
+import {createObjectCsvWriter} from 'csv-writer';
+import {FunctionFeeVM, IFunctionFee} from './types';
+import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES, SUBS_PROPERTIES} from './common';
+
+
+
+const main = async () => {
+
+ const headers = [
+ 'function',
+ 'ethFee',
+ 'ethGas',
+ 'substrate',
+ 'zeppelinFee',
+ 'zeppelinGas',
+ ];
+
+ const csvWriter20 = createObjectCsvWriter({
+ path: 'erc20.csv',
+ header: headers,
+ });
+
+ const csvWriter721 = createObjectCsvWriter({
+ path: 'erc721.csv',
+ header: headers,
+ });
+
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ console.log('\n ERC20 ops fees');
+ const erc20 = FunctionFeeVM.fromModel(await erc20CalculateFeeGas(helper, privateKey));
+ console.table(erc20);
+ await csvWriter20.writeRecords(FunctionFeeVM.toCsv(erc20));
+
+ console.log('\n ERC721 ops fees');
+ const erc721 = FunctionFeeVM.fromModel(await erc721CalculateFeeGas(helper, privateKey));
+ console.table(erc721);
+
+ await csvWriter721.writeRecords(FunctionFeeVM.toCsv(erc721));
+ });
+};
+
+main()
+ .then(() => process.exit(0))
+ .catch((e) => {
+ console.log(e);
+ process.exit(1);
+ });
+
+async function erc721CalculateFeeGas(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+): Promise<IFunctionFee> {
+ const res: IFunctionFee = {};
+ const donor = await privateKey('//Alice');
+ const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
+ 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(
+ 'nft',
+ helper,
+ privateKey,
+ ethSigner,
+ null,
+ PERMISSIONS,
+ )) as UniqueNFTCollection;
+
+ const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
+ let zeppelelinContract: Contract | null = null;
+ const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/ERC721/bin/ZeppelinContract.bin`)).toString();
+ const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/ERC721/bin/ZeppelinContract.abi`)).toString());
+
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'nft',
+ ethSigner,
+ true,
+ );
+
+ res['createCollection'] = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => helperContract.methods.createNFTCollection('test','test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
+ );
+
+ res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.nft.mintCollection(
+ donor,
+ {name: 'test', description: 'test', tokenPrefix: 'test'},
+ ),
+ )));
+
+ res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ async () => {
+ zeppelelinContract = await helper.ethContract.deployByAbi(
+ ethSigner,
+ ZEPPELIN_ABI,
+ ZEPPELIN_OBJECT,
+ );
+ },
+ );
+
+ res['mint'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mint(ethSigner).send(),
+ );
+
+ res['mint'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.safeMint(ethSigner, 'test').send({from: ethSigner}),
+ );
+
+ res['mintCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintCross(crossSigner, []).send(),
+ );
+
+ res['mint'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintToken(
+ donor,
+ {Substrate: donor.address},
+ ),
+ )));
+
+ res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintMultipleTokens(donor, [{
+ owner: {Substrate: donor.address},
+ }]),
+ )));
+
+ res['mintWithTokenURI'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintWithTokenURI(ethSigner, 'Test URI').send(),
+ );
+
+ res['mintWithTokenURI'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintToken(
+ donor,
+ {Ethereum: ethSigner},
+ [{key: 'URI', value: 'Test URI'}],
+ ),
+ )));
+
+ 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['setProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setTokenProperties(
+ donor,
+ 1,
+ SUBS_PROPERTIES.slice(0, 1),
+ ),
+ )));
+
+ res['deleteProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.deleteTokenProperties(
+ donor,
+ 1,
+ SUBS_PROPERTIES.slice(0, 1)
+ .map(p => p.key),
+ ),
+ )));
+
+ res['transfer'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transfer(ethReceiver, 1).send(),
+ );
+
+ res['safeTransferFrom*'] = {
+ zeppelin:
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.safeTransferFrom(ethSigner, ethReceiver, 0).send({from: ethSigner}),
+ ),
+ };
+
+ res['transferCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
+ );
+
+ res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transferToken(
+ donor,
+ 3,
+ {Substrate: subReceiver.address},
+ ),
+ )));
+ await collection.approveToken(subReceiver, 3, {Substrate: donor.address});
+
+ res['transferFrom*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
+ );
+
+ res['transferFrom*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
+ );
+
+
+ res['transferFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
+ );
+
+ res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transferTokenFrom(donor, 3, {Substrate: subReceiver.address}, {Substrate: donor.address}),
+ )));
+
+ res['burn'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.burn(1).send(),
+ );
+
+ res['burn'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.burnToken(donor, 3),
+ )));
+
+ res['approve*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approve(ethReceiver, 2).send(),
+ );
+
+ res['approve*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.approve(ethReceiver, 0).send({from: ethSigner}),
+ );
+
+ res['approveCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approveCross(crossReceiver, 2).send(),
+ );
+
+ res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.approveToken(donor, 4, {Substrate: subReceiver.address}),
+ )));
+
+ res['setApprovalForAll*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setApprovalForAll(ethReceiver, true).send(),
+ );
+
+ res['setApprovalForAll*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.setApprovalForAll(ethReceiver, true).send({from: ethSigner}),
+ );
+
+ res['setApprovalForAll*'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.nft.setAllowanceForAll(donor, collection.collectionId, {Substrate: subReceiver.address}, true),
+ )));
+
+ res['burnFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.burnFromCross(crossSigner, 2).send({from:ethReceiver}),
+ );
+
+ res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.burnTokenFrom(subReceiver, 4, {Substrate: donor.address}),
+ )));
+
+ res['setTokenPropertyPermissions'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setTokenPropertyPermissions([
+ ['url', [
+ [TokenPermissionField.Mutable, true],
+ [TokenPermissionField.TokenOwner, true],
+ [TokenPermissionField.CollectionAdmin, true]],
+ ],
+ ]).send(),
+ );
+
+ res['setTokenPropertyPermissions'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setTokenPropertyPermissions(donor, [{key: 'url', permission: {
+ tokenOwner: true,
+ collectionAdmin: true,
+ mutable: true,
+ }}]),
+ )));
+
+ 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['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setSponsor(donor, subReceiver.address),
+ )));
+
+ res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.confirmSponsorship(subReceiver),
+ )));
+
+ res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeSponsor(donor),
+ )));
+
+ 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['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => { return {key: p.key, value: p.value.toString()}; })),
+ )));
+
+ res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => p.key)),
+ )));
+
+ res['setCollectionLimit'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
+ );
+
+ res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
+ )));
+
+ 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['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ 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['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.disableNesting(donor),
+ )));
+
+ res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(
+ donor,
+ {
+ nesting: {
+ tokenOwner: true,
+ restricted: [collection.collectionId],
+ },
+ },
+ ),
+ )));
+
+ res['setCollectionAccess'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionAccess(1).send(),
+ );
+
+ res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {access: 'AllowList'}),
+ )));
+
+ 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['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['setCollectionMintMode'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionMintMode(true).send(),
+ );
+
+ res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {mintMode: false}),
+ )));
+
+ res['changeCollectionOwnerCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
+ );
+
+ res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.changeOwner(donor, subReceiver.address),
+ )));
+
+ return res;
+}
+
+async function erc20CalculateFeeGas(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+
+): Promise<IFunctionFee> {
+ const res: IFunctionFee = {};
+ const donor = await privateKey('//Alice');
+ const [subReceiver] = await helper.arrange.createAccounts([10n], donor);
+ 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(
+ 'ft',
+ helper,
+ privateKey,
+ ethSigner,
+ null,
+ PERMISSIONS,
+ )) as UniqueFTCollection;
+
+ const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
+ let zeppelelinContract: Contract | null = null;
+ const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/ERC20/bin/ZeppelinContract.bin`)).toString();
+ const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/ERC20/bin/ZeppelinContract.abi`)).toString());
+
+ const evmContract = await helper.ethNativeContract.collection(
+ helper.ethAddress.fromCollectionId(collection.collectionId),
+ 'ft',
+ ethSigner,
+ true,
+ );
+
+ res['createCollection'] = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => helperContract.methods.createFTCollection('test', 18,'test','test').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())}),
+ );
+
+ res['createCollection'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.ft.mintCollection(
+ donor,
+ {name: 'test', description: 'test', tokenPrefix: 'test'},
+ 18,
+ ),
+ )));
+
+ res['createCollection'].zeppelin = await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ async () => {
+ zeppelelinContract = await helper.ethContract.deployByAbi(
+ ethSigner,
+ ZEPPELIN_ABI,
+ ZEPPELIN_OBJECT,
+ );
+ },
+ );
+
+ res['mint'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mint(ethSigner, 1).send(),
+ );
+
+ res['mint'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.mint(ethSigner, 1).send(),
+ );
+
+ res['mintCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintCross(crossSigner, 1).send(),
+ );
+
+ res['mintCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mint(
+ donor,
+ 10n,
+ {Substrate: donor.address},
+ ),
+ )));
+
+ res['mintBulk'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.mintBulk([{to: ethSigner, amount: 1}]).send(),
+ );
+
+ res['mintBulk'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => helper.executeExtrinsic(donor, 'api.tx.unique.createMultipleItemsEx',[collection.collectionId, {
+ Fungible: new Map([
+ [JSON.stringify({Ethereum: ethSigner}), 1],
+
+ ]),
+ }], true),
+ )));
+
+ res['transfer*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transfer(ethReceiver, 1).send(),
+ );
+
+ res['transfer*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.transfer(ethReceiver, 1).send(),
+ );
+
+ res['transferCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferCross(crossSigner, 1).send({from: ethReceiver}),
+ );
+
+ res['transferCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transfer(
+ donor,
+ {Substrate: subReceiver.address},
+ 1n,
+ ),
+ )));
+ await collection.approveTokens(subReceiver, {Substrate: donor.address}, 1n);
+
+ res['transferFrom*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.transferFrom(ethSigner, ethReceiver, 1).send(),
+ );
+
+ res['transferFrom*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
+ );
+
+ res['transferFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.transferFromCross(crossReceiver, crossSigner, 1).send({from:ethReceiver}),
+ );
+
+ res['transferFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.transferFrom(donor, {Substrate: subReceiver.address}, {Substrate: donor.address}, 1n),
+ )));
+
+
+ res['burnTokens'] = {fee: 0n, gas: 0n};
+ res['burnTokens'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.burnTokens(donor, 1n),
+ )));
+
+
+ res['approve*'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approve(ethReceiver, 2).send(),
+ );
+
+ res['approve*'].zeppelin =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => zeppelelinContract!.methods.approve(ethReceiver, 0).send(),
+ );
+
+ res['approveCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.approveCross(crossReceiver, 2).send(),
+ );
+
+ res['approveCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.approveTokens(donor, {Substrate: subReceiver.address}, 1n),
+ )));
+
+ res['burnFromCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethReceiver},
+ () => evmContract.methods.burnFromCross(crossSigner, 1).send({from:ethReceiver}),
+ );
+
+ res['burnFromCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.burnTokensFrom(subReceiver, {Substrate: donor.address}, 1n),
+ )));
+
+ 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['setCollectionSponsorCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setSponsor(donor, subReceiver.address),
+ )));
+
+ res['confirmCollectionSponsorship'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: subReceiver.address},
+ () => collection.confirmSponsorship(subReceiver),
+ )));
+
+ res['removeCollectionSponsor'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeSponsor(donor),
+ )));
+
+ 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['setCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => { return {key: p.key, value: p.value.toString()}; })),
+ )));
+
+ res['deleteCollectionProperties'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.deleteProperties(donor, PROPERTIES.slice(0, 1)
+ .map(p => p.key)),
+ )));
+
+ res['setCollectionLimit'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}).send(),
+ );
+
+ res['setCollectionLimit'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setLimits(donor, {accountTokenOwnershipLimit: 1000}),
+ )));
+
+ 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['addCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeCollectionAdminCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeAdmin(donor, {Ethereum: ethReceiver}),
+ )));
+
+ 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['setCollectionNesting'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.disableNesting(donor),
+ )));
+
+ res['setCollectionNesting[]'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(
+ donor,
+ {
+ nesting: {
+ tokenOwner: true,
+ restricted: [collection.collectionId],
+ },
+ },
+ ),
+ )));
+
+ res['setCollectionAccess'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionAccess(1).send(),
+ );
+
+ res['setCollectionAccess'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {access: 'AllowList'}),
+ )));
+
+ 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['addToCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.addToAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['removeFromCollectionAllowListCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.removeFromAllowList(donor, {Ethereum: ethReceiver}),
+ )));
+
+ res['setCollectionMintMode'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => evmContract.methods.setCollectionMintMode(true).send(),
+ );
+
+ res['setCollectionMintMode'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.setPermissions(donor, {mintMode: false}),
+ )));
+
+ res['changeCollectionOwnerCross'] =
+ await helper.arrange.calculcateFeeGas(
+ {Ethereum: ethSigner},
+ () => collectionWithEthOwner.methods.changeCollectionOwnerCross(crossReceiver).send(),
+ );
+
+ res['changeCollectionOwnerCross'].substrate = convertToTokens((await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.changeOwner(donor, subReceiver.address),
+ )));
+
+ return res;
+}
\ No newline at end of file
tests/src/benchmarks/mintFee/types.tsdiffbeforeafterboth--- a/tests/src/benchmarks/mintFee/types.ts
+++ b/tests/src/benchmarks/mintFee/types.ts
@@ -8,19 +8,38 @@
}
}
-export interface IFunctionFee {
- [name: string]: IFeeGas
+export interface IFeeGasCsv extends IFeeGasVm {
+ function: string,
}
-
-export abstract class FunctionFeeVM {
- [name: string]: {
+export interface IFeeGasVm{
ethFee?: number | bigint,
ethGas?: number | bigint,
substrate?: number,
zeppelinFee?: number | bigint,
zeppelinGas?: number | bigint
- };
+}
+export interface IFunctionFee {
+ [name: string]: IFeeGas
+}
+
+export abstract class FunctionFeeVM {
+ [name: string]: IFeeGasVm
+
+ static toCsv(model: FunctionFeeVM): IFeeGasCsv[]{
+ const res: IFeeGasCsv[] = [];
+ Object.keys(model).forEach(key => {
+ res.push({
+ function: key,
+ ethFee: model[key].ethFee,
+ ethGas: model[key].ethGas,
+ substrate: model[key].substrate,
+ zeppelinFee: model[key].zeppelinFee,
+ zeppelinGas: model[key].zeppelinGas,
+ });
+ });
+ return res;
+ }
static fromModel(model: IFunctionFee): FunctionFeeVM {
const res: FunctionFeeVM = {};