difftreelog
Style fixes
in: master
6 files changed
tests/.gitignorediffbeforeafterboth1/node_modules/1/node_modules/2properties.csv23tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -101,6 +101,7 @@
"testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",
"testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",
"testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",
+ "benchMintingFee": "ts-node src/benchmarks/mintFee/benchmark.ts",
"load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",
"loadTransfer": "ts-node src/transfer.nload.ts",
"polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
tests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/mintFee/benchmark.ts
@@ -0,0 +1,436 @@
+import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
+import {readFile} from 'fs/promises';
+import {ContractImports} from '../../eth/util/playgrounds/types';
+import {
+ ICrossAccountId,
+ ITokenPropertyPermission,
+} from '../../util/playgrounds/types';
+import {IKeyringPair} from '@polkadot/types/types';
+import {UniqueNFTCollection} from '../../util/playgrounds/unique';
+import {Contract} from 'web3-eth-contract';
+import {createObjectCsvWriter} from 'csv-writer';
+
+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 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;
+ evmProxyContractFee: number;
+ evmProxyContractBulkFee: number;
+}
+
+const main = async () => {
+ const benchmarks = [
+ 'substrateFee',
+ 'ethFee',
+ 'ethBulkFee',
+ 'evmProxyContractFee',
+ 'evmProxyContractBulkFee',
+ ];
+ const headers = [
+ 'propertiesNumber',
+ ...benchmarks,
+ ];
+
+
+ const csvWriter = createObjectCsvWriter({
+ path: 'properties.csv',
+ header: headers,
+ });
+
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ const CONTRACT_SOURCE = (
+ await readFile(`${__dirname}/proxyContract.sol`)
+ ).toString();
+
+ 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(
+ helper: EthUniqueHelper,
+ privateKey: (seed: string) => Promise<IKeyringPair>,
+ ethSigner: string,
+ proxyContract: string,
+ permissions: ITokenPropertyPermission[],
+) {
+ const donor = await privateKey('//Alice');
+
+ const collection = await helper.nft.mintCollection(donor, {
+ name: 'test mintToSubstrate',
+ description: 'EVMHelpers',
+ tokenPrefix: 'ap',
+ tokenPropertyPermissions: [
+ {
+ key: 'url',
+ 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),
+ });
+ await collection.addToAllowList(donor, {Ethereum: proxyContract});
+ await collection.addAdmin(donor, {Ethereum: proxyContract});
+ 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(
+ helper,
+ privateKey,
+ ethSigner,
+ proxyContract.options.address,
+ PERMISSIONS,
+ );
+
+ const substrateFee = await helper.arrange.calculcateFee(
+ {Substrate: donor.address},
+ () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),
+ );
+
+ const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+ const collectionContract = 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 = 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',
+ );
+
+ 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 = 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).map((p) => {
+ return {field_0: p.key, field_1: p.value};
+ }),
+ )
+ .encodeABI();
+
+ await helper.eth.sendEVM(
+ donor,
+ evmContract.options.address,
+ encodedCall,
+ '0',
+ );
+ },
+ );
+
+ 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).map((p) => {
+ return {field_0: p.key, field_1: p.value};
+ }),
+ )
+ .send({from: ethSigner, gas: 25_000_000});
+ },
+ );
+
+ return {
+ propertiesNumber: setup.propertiesNumber,
+ substrateFee: convertToTokens(substrateFee, nominal),
+ ethFee: convertToTokens(ethFee, nominal),
+ ethBulkFee: convertToTokens(ethBulkFee, 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(
+ helper,
+ privateKey,
+ ethSigner,
+ proxyContractAddress,
+ PERMISSIONS,
+ );
+ return helper.arrange.calculcateFee(payer, async () => {
+ await calculatedCall(collection);
+ });
+}
+function convertToTokens(value: bigint, nominal: bigint): number {
+ return Number((value * 1000n) / nominal) / 1000;
+}
tests/src/benchmarks/mintFee/proxyContract.soldiffbeforeafterboth--- /dev/null
+++ b/tests/src/benchmarks/mintFee/proxyContract.sol
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: Apache License
+pragma solidity >=0.8.0;
+import {CollectionHelpers} from "../../eth/api/CollectionHelpers.sol";
+import {ContractHelpers} from "../../eth/api/ContractHelpers.sol";
+import {UniqueRefungibleToken} from "../../eth/api/UniqueRefungibleToken.sol";
+import {UniqueRefungible, Collection, EthCrossAccount as RftCrossAccountId, Tuple20 as RftProperties} from "../../eth/api/UniqueRefungible.sol";
+import {UniqueNFT, EthCrossAccount as NftCrossAccountId, Tuple21 as NftProperty, TokenProperties} from "../../eth/api/UniqueNFT.sol";
+
+struct Property {
+ string key;
+ bytes value;
+}
+
+contract ProxyMint {
+ bytes32 constant REFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("ReFungible"));
+ bytes32 constant NONFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("NFT"));
+
+ modifier checkRestrictions(address _collection) {
+ Collection commonContract = Collection(_collection);
+ require(commonContract.isOwnerOrAdmin(msg.sender), "Only collection admin/owner can call this method");
+ _;
+ }
+
+ /// @dev This emits when a mint to a substrate address has been made.
+ event MintToSub(address _toEth, uint256 _toSub, address _collection, uint256 _tokenId);
+
+ function mintToSubstrate(address _collection, uint256 _substrateReceiver) external checkRestrictions(_collection) {
+ Collection commonContract = Collection(_collection);
+ bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
+ uint256 tokenId;
+
+ if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
+ UniqueRefungible rftCollection = UniqueRefungible(_collection);
+
+ tokenId = rftCollection.mint(address(this));
+
+ rftCollection.transferFromCross(
+ RftCrossAccountId(address(this), 0),
+ RftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
+ UniqueNFT nftCollection = UniqueNFT(_collection);
+ tokenId = nftCollection.mint(address(this));
+
+ nftCollection.transferFromCross(
+ NftCrossAccountId(address(this), 0),
+ NftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else {
+ revert("Wrong collection type. Works only with NFT or RFT");
+ }
+
+ emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
+ }
+
+ function mintToSubstrateWithProperty(
+ address _collection,
+ uint256 _substrateReceiver,
+ Property[] calldata properties
+ ) external checkRestrictions(_collection) {
+ uint256 propertiesLength = properties.length;
+ require(propertiesLength > 0, "Properies is empty");
+
+ Collection commonContract = Collection(_collection);
+ bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
+ uint256 tokenId;
+
+ if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
+ UniqueRefungible rftCollection = UniqueRefungible(_collection);
+ tokenId = rftCollection.nextTokenId();
+ rftCollection.mint(address(this));
+ for (uint256 i = 0; i < propertiesLength; ++i) {
+ rftCollection.setProperty(tokenId, properties[i].key, properties[i].value);
+ }
+ rftCollection.transferFromCross(
+ RftCrossAccountId(address(this), 0),
+ RftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
+ UniqueNFT nftCollection = UniqueNFT(_collection);
+ tokenId = nftCollection.mint(address(this));
+ for (uint256 i = 0; i < propertiesLength; ++i) {
+ nftCollection.setProperty(tokenId, properties[i].key, properties[i].value);
+ }
+ nftCollection.transferFromCross(
+ NftCrossAccountId(address(this), 0),
+ NftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else {
+ revert("Wrong collection type. Works only with NFT or RFT");
+ }
+
+ emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
+ }
+
+ function mintToSubstrateBulkProperty(
+ address _collection,
+ uint256 _substrateReceiver,
+ NftProperty[] calldata _properties
+ ) external checkRestrictions(_collection) {
+ uint256 propertiesLength = _properties.length;
+ require(propertiesLength > 0, "Properies is empty");
+
+ Collection commonContract = Collection(_collection);
+ bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
+ uint256 tokenId;
+
+ if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {} else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
+ UniqueNFT nftCollection = UniqueNFT(_collection);
+ tokenId = nftCollection.mint(address(this));
+
+ nftCollection.setProperties(tokenId, _properties);
+
+ nftCollection.transferFromCross(
+ NftCrossAccountId(address(this), 0),
+ NftCrossAccountId(address(0), _substrateReceiver),
+ tokenId
+ );
+ } else {
+ revert("Wrong collection type. Works only with NFT or RFT");
+ }
+
+ emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
+ }
+}
tests/src/benchmarks/mintFeeBench/feeBench.tsdiffbeforeafterboth--- a/tests/src/benchmarks/mintFeeBench/feeBench.ts
+++ /dev/null
@@ -1,418 +0,0 @@
-import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
-import {readFile} from 'fs/promises';
-import {ContractImports} from '../../eth/util/playgrounds/types';
-import {
- ICrossAccountId,
- ITokenPropertyPermission,
-} from '../../util/playgrounds/types';
-import {IKeyringPair} from '@polkadot/types/types';
-import {UniqueNFTCollection} from '../../util/playgrounds/unique';
-import {Contract} from 'web3-eth-contract';
-import {createObjectCsvWriter} from 'csv-writer';
-
-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 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;
- evmProxyContractFee: number;
- evmProxyContractBulkFee: number;
-}
-
-const main = async () => {
- const csvWriter = createObjectCsvWriter({
- path: 'properties.csv',
- header: [
- 'propertiesNumber',
- 'substrateFee',
- 'ethFee',
- 'ethBulkFee',
- 'evmProxyContractFee',
- 'evmProxyContractBulkFee',
- ],
- });
-
- await usingEthPlaygrounds(async (helper, privateKey) => {
- const CONTRACT_SOURCE = (
- await readFile(`${__dirname}/proxyContract.sol`)
- ).toString();
-
- const donor = await privateKey('//Alice'); // Seed from account with balance on this network
- const myAccount = await privateKey('//Bob'); // replace with account from polkadot extension
- 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(fees);
-
- const result: IBenchmarkResultForProp[] = [];
-
- for (let i = 1; i <= 20; i++) {
- result.push(await benchMintWithProperties(helper, privateKey, contract, {
- propertiesNumber: i,
- }));
- }
-
- await csvWriter.writeRecords(result);
-
- console.table(result);
- });
-};
-
-main()
- .then(() => process.exit(0))
- .catch((e) => {
- console.log(e);
- process.exit(1);
- });
-
-async function createCollectionForBenchmarks(
- helper: EthUniqueHelper,
- privateKey: (seed: string) => Promise<IKeyringPair>,
- ethSigner: string,
- proxyContract: string,
- permissions: ITokenPropertyPermission[],
-) {
- const donor = await privateKey('//Alice');
-
- const collection = await helper.nft.mintCollection(donor, {
- name: 'test mintToSubstrate',
- description: 'EVMHelpers',
- tokenPrefix: 'ap',
- tokenPropertyPermissions: [
- {
- key: 'url',
- 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),
- });
- await collection.addToAllowList(donor, {Ethereum: proxyContract});
- await collection.addAdmin(donor, {Ethereum: proxyContract});
- 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(
- helper,
- privateKey,
- ethSigner,
- proxyContract.options.address,
- PERMISSIONS,
- );
-
- const substrateFee = await helper.arrange.calculcateFee(
- {Substrate: donor.address},
- () => collection.mintToken(donor, {Substrate: substrateReceiver.address}),
- );
-
- const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
- const collectionContract = 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 = 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',
- );
-
- 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 = 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).map((p) => {
- return {field_0: p.key, field_1: p.value};
- }),
- )
- .encodeABI();
-
- await helper.eth.sendEVM(
- donor,
- evmContract.options.address,
- encodedCall,
- '0',
- );
- },
- );
-
- 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).map((p) => {
- return {field_0: p.key, field_1: p.value};
- }),
- )
- .send({from: ethSigner, gas: 25_000_000});
- },
- );
-
- return {
- propertiesNumber: setup.propertiesNumber,
- substrateFee: convertToTokens(substrateFee, nominal),
- ethFee: convertToTokens(ethFee, nominal),
- ethBulkFee: convertToTokens(ethBulkFee, 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(
- helper,
- privateKey,
- ethSigner,
- proxyContractAddress,
- PERMISSIONS,
- );
- return helper.arrange.calculcateFee(payer, async () => {
- await calculatedCall(collection);
- });
-}
-function convertToTokens(value: bigint, nominal: bigint): number {
- return Number((value * 1000n) / nominal) / 1000;
-}
tests/src/benchmarks/mintFeeBench/proxyContract.soldiffbeforeafterboth--- a/tests/src/benchmarks/mintFeeBench/proxyContract.sol
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: Apache License
-pragma solidity >=0.8.0;
-import {CollectionHelpers} from "../../eth/api/CollectionHelpers.sol";
-import {ContractHelpers} from "../../eth/api/ContractHelpers.sol";
-import {UniqueRefungibleToken} from "../../eth/api/UniqueRefungibleToken.sol";
-import {UniqueRefungible, Collection, EthCrossAccount as RftCrossAccountId, Tuple20 as RftProperties} from "../../eth/api/UniqueRefungible.sol";
-import {UniqueNFT, EthCrossAccount as NftCrossAccountId, Tuple21 as NftProperty, TokenProperties} from "../../eth/api/UniqueNFT.sol";
-
-struct Property {
- string key;
- bytes value;
-}
-
-contract ProxyMint {
- bytes32 constant REFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("ReFungible"));
- bytes32 constant NONFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("NFT"));
-
- modifier checkRestrictions(address _collection) {
- Collection commonContract = Collection(_collection);
- require(commonContract.isOwnerOrAdmin(msg.sender), "Only collection admin/owner can call this method");
- _;
- }
-
- /// @dev This emits when a mint to a substrate address has been made.
- event MintToSub(address _toEth, uint256 _toSub, address _collection, uint256 _tokenId);
-
- function mintToSubstrate(address _collection, uint256 _substrateReceiver) external checkRestrictions(_collection) {
- Collection commonContract = Collection(_collection);
- bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
- uint256 tokenId;
-
- if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
- UniqueRefungible rftCollection = UniqueRefungible(_collection);
-
- tokenId = rftCollection.mint(address(this));
-
- rftCollection.transferFromCross(
- RftCrossAccountId(address(this), 0),
- RftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
- UniqueNFT nftCollection = UniqueNFT(_collection);
- tokenId = nftCollection.mint(address(this));
-
- nftCollection.transferFromCross(
- NftCrossAccountId(address(this), 0),
- NftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else {
- revert("Wrong collection type. Works only with NFT or RFT");
- }
-
- emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
- }
-
- function mintToSubstrateWithProperty(
- address _collection,
- uint256 _substrateReceiver,
- Property[] calldata properties
- ) external checkRestrictions(_collection) {
- uint256 propertiesLength = properties.length;
- require(propertiesLength > 0, "Properies is empty");
-
- Collection commonContract = Collection(_collection);
- bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
- uint256 tokenId;
-
- if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
- UniqueRefungible rftCollection = UniqueRefungible(_collection);
- tokenId = rftCollection.nextTokenId();
- rftCollection.mint(address(this));
- for (uint256 i = 0; i < propertiesLength; ++i) {
- rftCollection.setProperty(tokenId, properties[i].key, properties[i].value);
- }
- rftCollection.transferFromCross(
- RftCrossAccountId(address(this), 0),
- RftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
- UniqueNFT nftCollection = UniqueNFT(_collection);
- tokenId = nftCollection.mint(address(this));
- for (uint256 i = 0; i < propertiesLength; ++i) {
- nftCollection.setProperty(tokenId, properties[i].key, properties[i].value);
- }
- nftCollection.transferFromCross(
- NftCrossAccountId(address(this), 0),
- NftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else {
- revert("Wrong collection type. Works only with NFT or RFT");
- }
-
- emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
- }
-
- function mintToSubstrateBulkProperty(
- address _collection,
- uint256 _substrateReceiver,
- NftProperty[] calldata _properties
- ) external checkRestrictions(_collection) {
- uint256 propertiesLength = _properties.length;
- require(propertiesLength > 0, "Properies is empty");
-
- Collection commonContract = Collection(_collection);
- bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType()));
- uint256 tokenId;
-
- if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {} else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
- UniqueNFT nftCollection = UniqueNFT(_collection);
- tokenId = nftCollection.mint(address(this));
-
- nftCollection.setProperties(tokenId, _properties);
-
- nftCollection.transferFromCross(
- NftCrossAccountId(address(this), 0),
- NftCrossAccountId(address(0), _substrateReceiver),
- tokenId
- );
- } else {
- revert("Wrong collection type. Works only with NFT or RFT");
- }
-
- emit MintToSub(address(0), _substrateReceiver, _collection, tokenId);
- }
-}