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

difftreelog

Merge pull request #858 from UniqueNetwork/feature/erc721bench

Andy Smith2023-02-09parents: #5f3e0fd #c8529d8.patch.diff
in: master
Feature/erc721bench

72 files changed

modifiedtests/.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
deletedtests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/benchmark.ts
+++ /dev/null
@@ -1,579 +0,0 @@
-import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
-import {readFile} from 'fs/promises';
-import {ContractImports, TokenPermissionField} 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;
-  ethMintCrossFee: number;
-	evmProxyContractFee: number;
-	evmProxyContractBulkFee: number;
-}
-interface IBenchmarkCollection {
-  createFee: number,
-  mintFee: number,
-  transferFee: 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();
-    const ZEPPELIN_OBJECT = '0x' + (await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.bin`)).toString();
-    const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/openZeppelin/bin/ZeppelinContract.abi`)).toString());
-
-    const donor = await privateKey('//Alice'); // Seed from account with balance on this network
-    const [substrateReceiver] = await helper.arrange.createAccounts([10n], donor);
-
-    const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n);
-    const ethReceiver = await helper.eth.createAccountWithBalance(donor, 5n);
-
-    let susbtrateCollection: UniqueNFTCollection | null;
-    const createCollectionSubstrateFee = convertToTokens(
-      await helper.arrange.calculcateFee({Substrate: donor.address}, async () => {
-        susbtrateCollection = await helper.nft.mintCollection(donor, {tokenPropertyPermissions: [
-          {
-            key: 'url',
-            permission: {
-              tokenOwner: true,
-              collectionAdmin: true,
-              mutable: true,
-            },
-          },
-        ]});
-      }),
-      NOMINAL,
-    );
-
-    const susbstrateMintFee = convertToTokens(
-      await helper.arrange.calculcateFee(
-        {Substrate: donor.address},
-        () => susbtrateCollection!.mintToken(donor, {Substrate: substrateReceiver.address}, [{key: 'url', value: 'test'}]),
-      ),
-      NOMINAL,
-    );
-    const susbstrateTransferFee = convertToTokens(
-      await helper.arrange.calculcateFee(
-        {Substrate: substrateReceiver.address},
-        () => susbtrateCollection!.transferToken(substrateReceiver, 1, {Substrate: donor.address}),
-      ),
-      NOMINAL,
-    );
-    const substrateFee: IBenchmarkCollection = {
-      createFee: createCollectionSubstrateFee,
-      mintFee: susbstrateMintFee,
-      transferFee: susbstrateTransferFee,
-    };
-
-    const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
-
-    let ethContract: Contract | null = null;
-
-    const createCollectionEthFee = convertToTokens(
-      await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
-        const result = await helperContract.methods.createNFTCollection('a', 'b', 'c').send({from: ethSigner, value: Number(2n * helper.balance.getOneTokenNominal())});
-        ethContract = await helper.ethNativeContract.collection(helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId), 'nft', ethSigner);
-      }),
-      NOMINAL,
-    );
-
-    await ethContract!.methods.setTokenPropertyPermissions([
-      ['url', [
-        [TokenPermissionField.Mutable, true],
-        [TokenPermissionField.TokenOwner, true],
-        [TokenPermissionField.CollectionAdmin, true]],
-      ],
-    ]).send({from: ethSigner});
-
-    const ethMintFee = convertToTokens(await helper.arrange.calculcateFee(
-      {Ethereum: ethSigner},
-      () => ethContract!.methods.mintCross(
-        helper.ethCrossAccount.fromAddress(ethReceiver),
-        [{key: 'url', value: Buffer.from('test')}],
-      )
-        .send({from: ethSigner}),
-    ), NOMINAL);
-
-    const ethTransferFee = convertToTokens(await helper.arrange.calculcateFee(
-      {Ethereum: ethReceiver},
-      () => ethContract!.methods.transferFrom(ethReceiver, ethSigner, 1)
-        .send({from: ethReceiver}),
-    ), NOMINAL);
-
-    const ethFee: IBenchmarkCollection = {
-      createFee: createCollectionEthFee,
-      mintFee: ethMintFee,
-      transferFee: ethTransferFee,
-    };
-
-    let zeppelelinContract: Contract | null = null;
-
-    const zeppelinDeployFee = convertToTokens(
-      await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {
-        zeppelelinContract = await helper.ethContract.deployByAbi(
-          ethSigner,
-          ZEPPELIN_ABI,
-          ZEPPELIN_OBJECT,
-        );
-      }),
-      NOMINAL,
-    );
-
-    const zeppelinMintFee = convertToTokens(await helper.arrange.calculcateFee(
-      {Ethereum: ethSigner},
-      () => zeppelelinContract!.methods.safeMint(ethReceiver, 'test').send({from: ethSigner}),
-    ), NOMINAL);
-
-
-    const zeppelinTransferFee = convertToTokens(await helper.arrange.calculcateFee(
-      {Ethereum: ethReceiver},
-      () => zeppelelinContract!.methods.safeTransferFrom(ethReceiver, ethSigner, 0).send({from: ethReceiver}),
-    ), NOMINAL);
-
-    const zeppelinFee: IBenchmarkCollection = {
-      createFee: zeppelinDeployFee,
-      mintFee: zeppelinMintFee,
-      transferFee: zeppelinTransferFee,
-    };
-
-    console.log('collection ops fees');
-    const results = {substrate: substrateFee, eth: ethFee, zeppelin: zeppelinFee};
-    console.table(results);
-
-    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 = 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(
-    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;
-}
addedtests/src/benchmarks/mintFee/index.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/mintFee/index.ts
@@ -0,0 +1,399 @@
+import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util';
+import {readFile} from 'fs/promises';
+import {
+  ICrossAccountId,
+} 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';
+import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from '../utils/common';
+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',
+  },
+];
+
+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 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 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);
+  });
+}
+
+
+
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/README.mddiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# OpenZeppelin Contracts
-
-The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
-
-They are not meant to be edited.
-
-The originals can be found on [GitHub] and [npm].
-
-[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
-[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
-
-Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/access/Ownable.sol
+++ /dev/null
@@ -1,83 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../utils/Context.sol";
-
-/**
- * @dev Contract module which provides a basic access control mechanism, where
- * there is an account (an owner) that can be granted exclusive access to
- * specific functions.
- *
- * By default, the owner account will be the one that deploys the contract. This
- * can later be changed with {transferOwnership}.
- *
- * This module is used through inheritance. It will make available the modifier
- * `onlyOwner`, which can be applied to your functions to restrict their use to
- * the owner.
- */
-abstract contract Ownable is Context {
-    address private _owner;
-
-    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
-    /**
-     * @dev Initializes the contract setting the deployer as the initial owner.
-     */
-    constructor() {
-        _transferOwnership(_msgSender());
-    }
-
-    /**
-     * @dev Throws if called by any account other than the owner.
-     */
-    modifier onlyOwner() {
-        _checkOwner();
-        _;
-    }
-
-    /**
-     * @dev Returns the address of the current owner.
-     */
-    function owner() public view virtual returns (address) {
-        return _owner;
-    }
-
-    /**
-     * @dev Throws if the sender is not the owner.
-     */
-    function _checkOwner() internal view virtual {
-        require(owner() == _msgSender(), "Ownable: caller is not the owner");
-    }
-
-    /**
-     * @dev Leaves the contract without owner. It will not be possible to call
-     * `onlyOwner` functions anymore. Can only be called by the current owner.
-     *
-     * NOTE: Renouncing ownership will leave the contract without an owner,
-     * thereby removing any functionality that is only available to the owner.
-     */
-    function renounceOwnership() public virtual onlyOwner {
-        _transferOwnership(address(0));
-    }
-
-    /**
-     * @dev Transfers ownership of the contract to a new account (`newOwner`).
-     * Can only be called by the current owner.
-     */
-    function transferOwnership(address newOwner) public virtual onlyOwner {
-        require(newOwner != address(0), "Ownable: new owner is the zero address");
-        _transferOwnership(newOwner);
-    }
-
-    /**
-     * @dev Transfers ownership of the contract to a new account (`newOwner`).
-     * Internal function without access restriction.
-     */
-    function _transferOwnership(address newOwner) internal virtual {
-        address oldOwner = _owner;
-        _owner = newOwner;
-        emit OwnershipTransferred(oldOwner, newOwner);
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/ERC721.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/ERC721.sol
+++ /dev/null
@@ -1,503 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC721.sol";
-import "./IERC721Receiver.sol";
-import "./extensions/IERC721Metadata.sol";
-import "../../utils/Address.sol";
-import "../../utils/Context.sol";
-import "../../utils/Strings.sol";
-import "../../utils/introspection/ERC165.sol";
-
-/**
- * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
- * the Metadata extension, but not including the Enumerable extension, which is available separately as
- * {ERC721Enumerable}.
- */
-contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
-    using Address for address;
-    using Strings for uint256;
-
-    // Token name
-    string private _name;
-
-    // Token symbol
-    string private _symbol;
-
-    // Mapping from token ID to owner address
-    mapping(uint256 => address) private _owners;
-
-    // Mapping owner address to token count
-    mapping(address => uint256) private _balances;
-
-    // Mapping from token ID to approved address
-    mapping(uint256 => address) private _tokenApprovals;
-
-    // Mapping from owner to operator approvals
-    mapping(address => mapping(address => bool)) private _operatorApprovals;
-
-    /**
-     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
-     */
-    constructor(string memory name_, string memory symbol_) {
-        _name = name_;
-        _symbol = symbol_;
-    }
-
-    /**
-     * @dev See {IERC165-supportsInterface}.
-     */
-    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
-        return
-            interfaceId == type(IERC721).interfaceId ||
-            interfaceId == type(IERC721Metadata).interfaceId ||
-            super.supportsInterface(interfaceId);
-    }
-
-    /**
-     * @dev See {IERC721-balanceOf}.
-     */
-    function balanceOf(address owner) public view virtual override returns (uint256) {
-        require(owner != address(0), "ERC721: address zero is not a valid owner");
-        return _balances[owner];
-    }
-
-    /**
-     * @dev See {IERC721-ownerOf}.
-     */
-    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
-        address owner = _ownerOf(tokenId);
-        require(owner != address(0), "ERC721: invalid token ID");
-        return owner;
-    }
-
-    /**
-     * @dev See {IERC721Metadata-name}.
-     */
-    function name() public view virtual override returns (string memory) {
-        return _name;
-    }
-
-    /**
-     * @dev See {IERC721Metadata-symbol}.
-     */
-    function symbol() public view virtual override returns (string memory) {
-        return _symbol;
-    }
-
-    /**
-     * @dev See {IERC721Metadata-tokenURI}.
-     */
-    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
-        _requireMinted(tokenId);
-
-        string memory baseURI = _baseURI();
-        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
-    }
-
-    /**
-     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
-     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
-     * by default, can be overridden in child contracts.
-     */
-    function _baseURI() internal view virtual returns (string memory) {
-        return "";
-    }
-
-    /**
-     * @dev See {IERC721-approve}.
-     */
-    function approve(address to, uint256 tokenId) public virtual override {
-        address owner = ERC721.ownerOf(tokenId);
-        require(to != owner, "ERC721: approval to current owner");
-
-        require(
-            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
-            "ERC721: approve caller is not token owner or approved for all"
-        );
-
-        _approve(to, tokenId);
-    }
-
-    /**
-     * @dev See {IERC721-getApproved}.
-     */
-    function getApproved(uint256 tokenId) public view virtual override returns (address) {
-        _requireMinted(tokenId);
-
-        return _tokenApprovals[tokenId];
-    }
-
-    /**
-     * @dev See {IERC721-setApprovalForAll}.
-     */
-    function setApprovalForAll(address operator, bool approved) public virtual override {
-        _setApprovalForAll(_msgSender(), operator, approved);
-    }
-
-    /**
-     * @dev See {IERC721-isApprovedForAll}.
-     */
-    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
-        return _operatorApprovals[owner][operator];
-    }
-
-    /**
-     * @dev See {IERC721-transferFrom}.
-     */
-    function transferFrom(
-        address from,
-        address to,
-        uint256 tokenId
-    ) public virtual override {
-        //solhint-disable-next-line max-line-length
-        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
-
-        _transfer(from, to, tokenId);
-    }
-
-    /**
-     * @dev See {IERC721-safeTransferFrom}.
-     */
-    function safeTransferFrom(
-        address from,
-        address to,
-        uint256 tokenId
-    ) public virtual override {
-        safeTransferFrom(from, to, tokenId, "");
-    }
-
-    /**
-     * @dev See {IERC721-safeTransferFrom}.
-     */
-    function safeTransferFrom(
-        address from,
-        address to,
-        uint256 tokenId,
-        bytes memory data
-    ) public virtual override {
-        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
-        _safeTransfer(from, to, tokenId, data);
-    }
-
-    /**
-     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
-     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
-     *
-     * `data` is additional data, it has no specified format and it is sent in call to `to`.
-     *
-     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
-     * implement alternative mechanisms to perform token transfer, such as signature-based.
-     *
-     * Requirements:
-     *
-     * - `from` cannot be the zero address.
-     * - `to` cannot be the zero address.
-     * - `tokenId` token must exist and be owned by `from`.
-     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
-     *
-     * Emits a {Transfer} event.
-     */
-    function _safeTransfer(
-        address from,
-        address to,
-        uint256 tokenId,
-        bytes memory data
-    ) internal virtual {
-        _transfer(from, to, tokenId);
-        require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
-    }
-
-    /**
-     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
-     */
-    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
-        return _owners[tokenId];
-    }
-
-    /**
-     * @dev Returns whether `tokenId` exists.
-     *
-     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
-     *
-     * Tokens start existing when they are minted (`_mint`),
-     * and stop existing when they are burned (`_burn`).
-     */
-    function _exists(uint256 tokenId) internal view virtual returns (bool) {
-        return _ownerOf(tokenId) != address(0);
-    }
-
-    /**
-     * @dev Returns whether `spender` is allowed to manage `tokenId`.
-     *
-     * Requirements:
-     *
-     * - `tokenId` must exist.
-     */
-    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
-        address owner = ERC721.ownerOf(tokenId);
-        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
-    }
-
-    /**
-     * @dev Safely mints `tokenId` and transfers it to `to`.
-     *
-     * Requirements:
-     *
-     * - `tokenId` must not exist.
-     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
-     *
-     * Emits a {Transfer} event.
-     */
-    function _safeMint(address to, uint256 tokenId) internal virtual {
-        _safeMint(to, tokenId, "");
-    }
-
-    /**
-     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
-     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
-     */
-    function _safeMint(
-        address to,
-        uint256 tokenId,
-        bytes memory data
-    ) internal virtual {
-        _mint(to, tokenId);
-        require(
-            _checkOnERC721Received(address(0), to, tokenId, data),
-            "ERC721: transfer to non ERC721Receiver implementer"
-        );
-    }
-
-    /**
-     * @dev Mints `tokenId` and transfers it to `to`.
-     *
-     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
-     *
-     * Requirements:
-     *
-     * - `tokenId` must not exist.
-     * - `to` cannot be the zero address.
-     *
-     * Emits a {Transfer} event.
-     */
-    function _mint(address to, uint256 tokenId) internal virtual {
-        require(to != address(0), "ERC721: mint to the zero address");
-        require(!_exists(tokenId), "ERC721: token already minted");
-
-        _beforeTokenTransfer(address(0), to, tokenId, 1);
-
-        // Check that tokenId was not minted by `_beforeTokenTransfer` hook
-        require(!_exists(tokenId), "ERC721: token already minted");
-
-        unchecked {
-            // Will not overflow unless all 2**256 token ids are minted to the same owner.
-            // Given that tokens are minted one by one, it is impossible in practice that
-            // this ever happens. Might change if we allow batch minting.
-            // The ERC fails to describe this case.
-            _balances[to] += 1;
-        }
-
-        _owners[tokenId] = to;
-
-        emit Transfer(address(0), to, tokenId);
-
-        _afterTokenTransfer(address(0), to, tokenId, 1);
-    }
-
-    /**
-     * @dev Destroys `tokenId`.
-     * The approval is cleared when the token is burned.
-     * This is an internal function that does not check if the sender is authorized to operate on the token.
-     *
-     * Requirements:
-     *
-     * - `tokenId` must exist.
-     *
-     * Emits a {Transfer} event.
-     */
-    function _burn(uint256 tokenId) internal virtual {
-        address owner = ERC721.ownerOf(tokenId);
-
-        _beforeTokenTransfer(owner, address(0), tokenId, 1);
-
-        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
-        owner = ERC721.ownerOf(tokenId);
-
-        // Clear approvals
-        delete _tokenApprovals[tokenId];
-
-        unchecked {
-            // Cannot overflow, as that would require more tokens to be burned/transferred
-            // out than the owner initially received through minting and transferring in.
-            _balances[owner] -= 1;
-        }
-        delete _owners[tokenId];
-
-        emit Transfer(owner, address(0), tokenId);
-
-        _afterTokenTransfer(owner, address(0), tokenId, 1);
-    }
-
-    /**
-     * @dev Transfers `tokenId` from `from` to `to`.
-     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
-     *
-     * Requirements:
-     *
-     * - `to` cannot be the zero address.
-     * - `tokenId` token must be owned by `from`.
-     *
-     * Emits a {Transfer} event.
-     */
-    function _transfer(
-        address from,
-        address to,
-        uint256 tokenId
-    ) internal virtual {
-        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
-        require(to != address(0), "ERC721: transfer to the zero address");
-
-        _beforeTokenTransfer(from, to, tokenId, 1);
-
-        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
-        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
-
-        // Clear approvals from the previous owner
-        delete _tokenApprovals[tokenId];
-
-        unchecked {
-            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
-            // `from`'s balance is the number of token held, which is at least one before the current
-            // transfer.
-            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
-            // all 2**256 token ids to be minted, which in practice is impossible.
-            _balances[from] -= 1;
-            _balances[to] += 1;
-        }
-        _owners[tokenId] = to;
-
-        emit Transfer(from, to, tokenId);
-
-        _afterTokenTransfer(from, to, tokenId, 1);
-    }
-
-    /**
-     * @dev Approve `to` to operate on `tokenId`
-     *
-     * Emits an {Approval} event.
-     */
-    function _approve(address to, uint256 tokenId) internal virtual {
-        _tokenApprovals[tokenId] = to;
-        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
-    }
-
-    /**
-     * @dev Approve `operator` to operate on all of `owner` tokens
-     *
-     * Emits an {ApprovalForAll} event.
-     */
-    function _setApprovalForAll(
-        address owner,
-        address operator,
-        bool approved
-    ) internal virtual {
-        require(owner != operator, "ERC721: approve to caller");
-        _operatorApprovals[owner][operator] = approved;
-        emit ApprovalForAll(owner, operator, approved);
-    }
-
-    /**
-     * @dev Reverts if the `tokenId` has not been minted yet.
-     */
-    function _requireMinted(uint256 tokenId) internal view virtual {
-        require(_exists(tokenId), "ERC721: invalid token ID");
-    }
-
-    /**
-     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
-     * The call is not executed if the target address is not a contract.
-     *
-     * @param from address representing the previous owner of the given token ID
-     * @param to target address that will receive the tokens
-     * @param tokenId uint256 ID of the token to be transferred
-     * @param data bytes optional data to send along with the call
-     * @return bool whether the call correctly returned the expected magic value
-     */
-    function _checkOnERC721Received(
-        address from,
-        address to,
-        uint256 tokenId,
-        bytes memory data
-    ) private returns (bool) {
-        if (to.isContract()) {
-            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
-                return retval == IERC721Receiver.onERC721Received.selector;
-            } catch (bytes memory reason) {
-                if (reason.length == 0) {
-                    revert("ERC721: transfer to non ERC721Receiver implementer");
-                } else {
-                    /// @solidity memory-safe-assembly
-                    assembly {
-                        revert(add(32, reason), mload(reason))
-                    }
-                }
-            }
-        } else {
-            return true;
-        }
-    }
-
-    /**
-     * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
-     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
-     *
-     * Calling conditions:
-     *
-     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
-     * - When `from` is zero, the tokens will be minted for `to`.
-     * - When `to` is zero, ``from``'s tokens will be burned.
-     * - `from` and `to` are never both zero.
-     * - `batchSize` is non-zero.
-     *
-     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
-     */
-    function _beforeTokenTransfer(
-        address from,
-        address to,
-        uint256, /* firstTokenId */
-        uint256 batchSize
-    ) internal virtual {
-        if (batchSize > 1) {
-            if (from != address(0)) {
-                _balances[from] -= batchSize;
-            }
-            if (to != address(0)) {
-                _balances[to] += batchSize;
-            }
-        }
-    }
-
-    /**
-     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
-     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
-     *
-     * Calling conditions:
-     *
-     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
-     * - When `from` is zero, the tokens were minted for `to`.
-     * - When `to` is zero, ``from``'s tokens were burned.
-     * - `from` and `to` are never both zero.
-     * - `batchSize` is non-zero.
-     *
-     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
-     */
-    function _afterTokenTransfer(
-        address from,
-        address to,
-        uint256 firstTokenId,
-        uint256 batchSize
-    ) internal virtual {}
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/IERC721.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/IERC721.sol
+++ /dev/null
@@ -1,145 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
-
-pragma solidity ^0.8.0;
-
-import "../../utils/introspection/IERC165.sol";
-
-/**
- * @dev Required interface of an ERC721 compliant contract.
- */
-interface IERC721 is IERC165 {
-    /**
-     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
-     */
-    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
-
-    /**
-     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
-     */
-    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
-
-    /**
-     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
-     */
-    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-
-    /**
-     * @dev Returns the number of tokens in ``owner``'s account.
-     */
-    function balanceOf(address owner) external view returns (uint256 balance);
-
-    /**
-     * @dev Returns the owner of the `tokenId` token.
-     *
-     * Requirements:
-     *
-     * - `tokenId` must exist.
-     */
-    function ownerOf(uint256 tokenId) external view returns (address owner);
-
-    /**
-     * @dev Safely transfers `tokenId` token from `from` to `to`.
-     *
-     * Requirements:
-     *
-     * - `from` cannot be the zero address.
-     * - `to` cannot be the zero address.
-     * - `tokenId` token must exist and be owned by `from`.
-     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
-     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
-     *
-     * Emits a {Transfer} event.
-     */
-    function safeTransferFrom(
-        address from,
-        address to,
-        uint256 tokenId,
-        bytes calldata data
-    ) external;
-
-    /**
-     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
-     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
-     *
-     * Requirements:
-     *
-     * - `from` cannot be the zero address.
-     * - `to` cannot be the zero address.
-     * - `tokenId` token must exist and be owned by `from`.
-     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
-     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
-     *
-     * Emits a {Transfer} event.
-     */
-    function safeTransferFrom(
-        address from,
-        address to,
-        uint256 tokenId
-    ) external;
-
-    /**
-     * @dev Transfers `tokenId` token from `from` to `to`.
-     *
-     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
-     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
-     * understand this adds an external call which potentially creates a reentrancy vulnerability.
-     *
-     * Requirements:
-     *
-     * - `from` cannot be the zero address.
-     * - `to` cannot be the zero address.
-     * - `tokenId` token must be owned by `from`.
-     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
-     *
-     * Emits a {Transfer} event.
-     */
-    function transferFrom(
-        address from,
-        address to,
-        uint256 tokenId
-    ) external;
-
-    /**
-     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
-     * The approval is cleared when the token is transferred.
-     *
-     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
-     *
-     * Requirements:
-     *
-     * - The caller must own the token or be an approved operator.
-     * - `tokenId` must exist.
-     *
-     * Emits an {Approval} event.
-     */
-    function approve(address to, uint256 tokenId) external;
-
-    /**
-     * @dev Approve or remove `operator` as an operator for the caller.
-     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
-     *
-     * Requirements:
-     *
-     * - The `operator` cannot be the caller.
-     *
-     * Emits an {ApprovalForAll} event.
-     */
-    function setApprovalForAll(address operator, bool _approved) external;
-
-    /**
-     * @dev Returns the account approved for `tokenId` token.
-     *
-     * Requirements:
-     *
-     * - `tokenId` must exist.
-     */
-    function getApproved(uint256 tokenId) external view returns (address operator);
-
-    /**
-     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
-     *
-     * See {setApprovalForAll}
-     */
-    function isApprovedForAll(address owner, address operator) external view returns (bool);
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/IERC721Receiver.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @title ERC721 token receiver interface
- * @dev Interface for any contract that wants to support safeTransfers
- * from ERC721 asset contracts.
- */
-interface IERC721Receiver {
-    /**
-     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
-     * by `operator` from `from`, this function is called.
-     *
-     * It must return its Solidity selector to confirm the token transfer.
-     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
-     *
-     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
-     */
-    function onERC721Received(
-        address operator,
-        address from,
-        uint256 tokenId,
-        bytes calldata data
-    ) external returns (bytes4);
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC721.sol";
-import "../../../utils/Context.sol";
-
-/**
- * @title ERC721 Burnable Token
- * @dev ERC721 Token that can be burned (destroyed).
- */
-abstract contract ERC721Burnable is Context, ERC721 {
-    /**
-     * @dev Burns `tokenId`. See {ERC721-_burn}.
-     *
-     * Requirements:
-     *
-     * - The caller must own `tokenId` or be an approved operator.
-     */
-    function burn(uint256 tokenId) public virtual {
-        //solhint-disable-next-line max-line-length
-        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
-        _burn(tokenId);
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
+++ /dev/null
@@ -1,159 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC721.sol";
-import "./IERC721Enumerable.sol";
-
-/**
- * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
- * enumerability of all the token ids in the contract as well as all token ids owned by each
- * account.
- */
-abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
-    // Mapping from owner to list of owned token IDs
-    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
-
-    // Mapping from token ID to index of the owner tokens list
-    mapping(uint256 => uint256) private _ownedTokensIndex;
-
-    // Array with all token ids, used for enumeration
-    uint256[] private _allTokens;
-
-    // Mapping from token id to position in the allTokens array
-    mapping(uint256 => uint256) private _allTokensIndex;
-
-    /**
-     * @dev See {IERC165-supportsInterface}.
-     */
-    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
-        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
-    }
-
-    /**
-     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
-     */
-    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
-        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
-        return _ownedTokens[owner][index];
-    }
-
-    /**
-     * @dev See {IERC721Enumerable-totalSupply}.
-     */
-    function totalSupply() public view virtual override returns (uint256) {
-        return _allTokens.length;
-    }
-
-    /**
-     * @dev See {IERC721Enumerable-tokenByIndex}.
-     */
-    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
-        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
-        return _allTokens[index];
-    }
-
-    /**
-     * @dev See {ERC721-_beforeTokenTransfer}.
-     */
-    function _beforeTokenTransfer(
-        address from,
-        address to,
-        uint256 firstTokenId,
-        uint256 batchSize
-    ) internal virtual override {
-        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
-
-        if (batchSize > 1) {
-            // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
-            revert("ERC721Enumerable: consecutive transfers not supported");
-        }
-
-        uint256 tokenId = firstTokenId;
-
-        if (from == address(0)) {
-            _addTokenToAllTokensEnumeration(tokenId);
-        } else if (from != to) {
-            _removeTokenFromOwnerEnumeration(from, tokenId);
-        }
-        if (to == address(0)) {
-            _removeTokenFromAllTokensEnumeration(tokenId);
-        } else if (to != from) {
-            _addTokenToOwnerEnumeration(to, tokenId);
-        }
-    }
-
-    /**
-     * @dev Private function to add a token to this extension's ownership-tracking data structures.
-     * @param to address representing the new owner of the given token ID
-     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
-     */
-    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
-        uint256 length = ERC721.balanceOf(to);
-        _ownedTokens[to][length] = tokenId;
-        _ownedTokensIndex[tokenId] = length;
-    }
-
-    /**
-     * @dev Private function to add a token to this extension's token tracking data structures.
-     * @param tokenId uint256 ID of the token to be added to the tokens list
-     */
-    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
-        _allTokensIndex[tokenId] = _allTokens.length;
-        _allTokens.push(tokenId);
-    }
-
-    /**
-     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
-     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
-     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
-     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
-     * @param from address representing the previous owner of the given token ID
-     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
-     */
-    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
-        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
-        // then delete the last slot (swap and pop).
-
-        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
-        uint256 tokenIndex = _ownedTokensIndex[tokenId];
-
-        // When the token to delete is the last token, the swap operation is unnecessary
-        if (tokenIndex != lastTokenIndex) {
-            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
-
-            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
-            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
-        }
-
-        // This also deletes the contents at the last position of the array
-        delete _ownedTokensIndex[tokenId];
-        delete _ownedTokens[from][lastTokenIndex];
-    }
-
-    /**
-     * @dev Private function to remove a token from this extension's token tracking data structures.
-     * This has O(1) time complexity, but alters the order of the _allTokens array.
-     * @param tokenId uint256 ID of the token to be removed from the tokens list
-     */
-    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
-        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
-        // then delete the last slot (swap and pop).
-
-        uint256 lastTokenIndex = _allTokens.length - 1;
-        uint256 tokenIndex = _allTokensIndex[tokenId];
-
-        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
-        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
-        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
-        uint256 lastTokenId = _allTokens[lastTokenIndex];
-
-        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
-        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
-
-        // This also deletes the contents at the last position of the array
-        delete _allTokensIndex[tokenId];
-        _allTokens.pop();
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol)
-
-pragma solidity ^0.8.0;
-
-import "../ERC721.sol";
-
-/**
- * @dev ERC721 token with storage based token URI management.
- */
-abstract contract ERC721URIStorage is ERC721 {
-    using Strings for uint256;
-
-    // Optional mapping for token URIs
-    mapping(uint256 => string) private _tokenURIs;
-
-    /**
-     * @dev See {IERC721Metadata-tokenURI}.
-     */
-    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
-        _requireMinted(tokenId);
-
-        string memory _tokenURI = _tokenURIs[tokenId];
-        string memory base = _baseURI();
-
-        // If there is no base URI, return the token URI.
-        if (bytes(base).length == 0) {
-            return _tokenURI;
-        }
-        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
-        if (bytes(_tokenURI).length > 0) {
-            return string(abi.encodePacked(base, _tokenURI));
-        }
-
-        return super.tokenURI(tokenId);
-    }
-
-    /**
-     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
-     *
-     * Requirements:
-     *
-     * - `tokenId` must exist.
-     */
-    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
-        require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
-        _tokenURIs[tokenId] = _tokenURI;
-    }
-
-    /**
-     * @dev See {ERC721-_burn}. This override additionally checks to see if a
-     * token-specific URI was set for the token, and if so, it deletes the token URI from
-     * the storage mapping.
-     */
-    function _burn(uint256 tokenId) internal virtual override {
-        super._burn(tokenId);
-
-        if (bytes(_tokenURIs[tokenId]).length != 0) {
-            delete _tokenURIs[tokenId];
-        }
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
-
-pragma solidity ^0.8.0;
-
-import "../IERC721.sol";
-
-/**
- * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
- * @dev See https://eips.ethereum.org/EIPS/eip-721
- */
-interface IERC721Enumerable is IERC721 {
-    /**
-     * @dev Returns the total amount of tokens stored by the contract.
-     */
-    function totalSupply() external view returns (uint256);
-
-    /**
-     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
-     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
-     */
-    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
-
-    /**
-     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
-     * Use along with {totalSupply} to enumerate all tokens.
-     */
-    function tokenByIndex(uint256 index) external view returns (uint256);
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
-
-pragma solidity ^0.8.0;
-
-import "../IERC721.sol";
-
-/**
- * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
- * @dev See https://eips.ethereum.org/EIPS/eip-721
- */
-interface IERC721Metadata is IERC721 {
-    /**
-     * @dev Returns the token collection name.
-     */
-    function name() external view returns (string memory);
-
-    /**
-     * @dev Returns the token collection symbol.
-     */
-    function symbol() external view returns (string memory);
-
-    /**
-     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
-     */
-    function tokenURI(uint256 tokenId) external view returns (string memory);
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Address.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Address.sol
+++ /dev/null
@@ -1,244 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
-
-pragma solidity ^0.8.1;
-
-/**
- * @dev Collection of functions related to the address type
- */
-library Address {
-    /**
-     * @dev Returns true if `account` is a contract.
-     *
-     * [IMPORTANT]
-     * ====
-     * It is unsafe to assume that an address for which this function returns
-     * false is an externally-owned account (EOA) and not a contract.
-     *
-     * Among others, `isContract` will return false for the following
-     * types of addresses:
-     *
-     *  - an externally-owned account
-     *  - a contract in construction
-     *  - an address where a contract will be created
-     *  - an address where a contract lived, but was destroyed
-     * ====
-     *
-     * [IMPORTANT]
-     * ====
-     * You shouldn't rely on `isContract` to protect against flash loan attacks!
-     *
-     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
-     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
-     * constructor.
-     * ====
-     */
-    function isContract(address account) internal view returns (bool) {
-        // This method relies on extcodesize/address.code.length, which returns 0
-        // for contracts in construction, since the code is only stored at the end
-        // of the constructor execution.
-
-        return account.code.length > 0;
-    }
-
-    /**
-     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
-     * `recipient`, forwarding all available gas and reverting on errors.
-     *
-     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
-     * of certain opcodes, possibly making contracts go over the 2300 gas limit
-     * imposed by `transfer`, making them unable to receive funds via
-     * `transfer`. {sendValue} removes this limitation.
-     *
-     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
-     *
-     * IMPORTANT: because control is transferred to `recipient`, care must be
-     * taken to not create reentrancy vulnerabilities. Consider using
-     * {ReentrancyGuard} or the
-     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
-     */
-    function sendValue(address payable recipient, uint256 amount) internal {
-        require(address(this).balance >= amount, "Address: insufficient balance");
-
-        (bool success, ) = recipient.call{value: amount}("");
-        require(success, "Address: unable to send value, recipient may have reverted");
-    }
-
-    /**
-     * @dev Performs a Solidity function call using a low level `call`. A
-     * plain `call` is an unsafe replacement for a function call: use this
-     * function instead.
-     *
-     * If `target` reverts with a revert reason, it is bubbled up by this
-     * function (like regular Solidity function calls).
-     *
-     * Returns the raw returned data. To convert to the expected return value,
-     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
-     *
-     * Requirements:
-     *
-     * - `target` must be a contract.
-     * - calling `target` with `data` must not revert.
-     *
-     * _Available since v3.1._
-     */
-    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
-        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
-     * `errorMessage` as a fallback revert reason when `target` reverts.
-     *
-     * _Available since v3.1._
-     */
-    function functionCall(
-        address target,
-        bytes memory data,
-        string memory errorMessage
-    ) internal returns (bytes memory) {
-        return functionCallWithValue(target, data, 0, errorMessage);
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
-     * but also transferring `value` wei to `target`.
-     *
-     * Requirements:
-     *
-     * - the calling contract must have an ETH balance of at least `value`.
-     * - the called Solidity function must be `payable`.
-     *
-     * _Available since v3.1._
-     */
-    function functionCallWithValue(
-        address target,
-        bytes memory data,
-        uint256 value
-    ) internal returns (bytes memory) {
-        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
-     * with `errorMessage` as a fallback revert reason when `target` reverts.
-     *
-     * _Available since v3.1._
-     */
-    function functionCallWithValue(
-        address target,
-        bytes memory data,
-        uint256 value,
-        string memory errorMessage
-    ) internal returns (bytes memory) {
-        require(address(this).balance >= value, "Address: insufficient balance for call");
-        (bool success, bytes memory returndata) = target.call{value: value}(data);
-        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
-     * but performing a static call.
-     *
-     * _Available since v3.3._
-     */
-    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
-        return functionStaticCall(target, data, "Address: low-level static call failed");
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
-     * but performing a static call.
-     *
-     * _Available since v3.3._
-     */
-    function functionStaticCall(
-        address target,
-        bytes memory data,
-        string memory errorMessage
-    ) internal view returns (bytes memory) {
-        (bool success, bytes memory returndata) = target.staticcall(data);
-        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
-     * but performing a delegate call.
-     *
-     * _Available since v3.4._
-     */
-    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
-        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
-    }
-
-    /**
-     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
-     * but performing a delegate call.
-     *
-     * _Available since v3.4._
-     */
-    function functionDelegateCall(
-        address target,
-        bytes memory data,
-        string memory errorMessage
-    ) internal returns (bytes memory) {
-        (bool success, bytes memory returndata) = target.delegatecall(data);
-        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
-    }
-
-    /**
-     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
-     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
-     *
-     * _Available since v4.8._
-     */
-    function verifyCallResultFromTarget(
-        address target,
-        bool success,
-        bytes memory returndata,
-        string memory errorMessage
-    ) internal view returns (bytes memory) {
-        if (success) {
-            if (returndata.length == 0) {
-                // only check isContract if the call was successful and the return data is empty
-                // otherwise we already know that it was a contract
-                require(isContract(target), "Address: call to non-contract");
-            }
-            return returndata;
-        } else {
-            _revert(returndata, errorMessage);
-        }
-    }
-
-    /**
-     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
-     * revert reason or using the provided one.
-     *
-     * _Available since v4.3._
-     */
-    function verifyCallResult(
-        bool success,
-        bytes memory returndata,
-        string memory errorMessage
-    ) internal pure returns (bytes memory) {
-        if (success) {
-            return returndata;
-        } else {
-            _revert(returndata, errorMessage);
-        }
-    }
-
-    function _revert(bytes memory returndata, string memory errorMessage) private pure {
-        // Look for revert reason and bubble it up if present
-        if (returndata.length > 0) {
-            // The easiest way to bubble the revert reason is using memory via assembly
-            /// @solidity memory-safe-assembly
-            assembly {
-                let returndata_size := mload(returndata)
-                revert(add(32, returndata), returndata_size)
-            }
-        } else {
-            revert(errorMessage);
-        }
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Context.sol
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Provides information about the current execution context, including the
- * sender of the transaction and its data. While these are generally available
- * via msg.sender and msg.data, they should not be accessed in such a direct
- * manner, since when dealing with meta-transactions the account sending and
- * paying for execution may not be the actual sender (as far as an application
- * is concerned).
- *
- * This contract is only required for intermediate, library-like contracts.
- */
-abstract contract Context {
-    function _msgSender() internal view virtual returns (address) {
-        return msg.sender;
-    }
-
-    function _msgData() internal view virtual returns (bytes calldata) {
-        return msg.data;
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Counters.sol
+++ /dev/null
@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @title Counters
- * @author Matt Condon (@shrugs)
- * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
- * of elements in a mapping, issuing ERC721 ids, or counting request ids.
- *
- * Include with `using Counters for Counters.Counter;`
- */
-library Counters {
-    struct Counter {
-        // This variable should never be directly accessed by users of the library: interactions must be restricted to
-        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
-        // this feature: see https://github.com/ethereum/solidity/issues/4637
-        uint256 _value; // default: 0
-    }
-
-    function current(Counter storage counter) internal view returns (uint256) {
-        return counter._value;
-    }
-
-    function increment(Counter storage counter) internal {
-        unchecked {
-            counter._value += 1;
-        }
-    }
-
-    function decrement(Counter storage counter) internal {
-        uint256 value = counter._value;
-        require(value > 0, "Counter: decrement overflow");
-        unchecked {
-            counter._value = value - 1;
-        }
-    }
-
-    function reset(Counter storage counter) internal {
-        counter._value = 0;
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/Strings.sol
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
-
-pragma solidity ^0.8.0;
-
-import "./math/Math.sol";
-
-/**
- * @dev String operations.
- */
-library Strings {
-    bytes16 private constant _SYMBOLS = "0123456789abcdef";
-    uint8 private constant _ADDRESS_LENGTH = 20;
-
-    /**
-     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
-     */
-    function toString(uint256 value) internal pure returns (string memory) {
-        unchecked {
-            uint256 length = Math.log10(value) + 1;
-            string memory buffer = new string(length);
-            uint256 ptr;
-            /// @solidity memory-safe-assembly
-            assembly {
-                ptr := add(buffer, add(32, length))
-            }
-            while (true) {
-                ptr--;
-                /// @solidity memory-safe-assembly
-                assembly {
-                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
-                }
-                value /= 10;
-                if (value == 0) break;
-            }
-            return buffer;
-        }
-    }
-
-    /**
-     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
-     */
-    function toHexString(uint256 value) internal pure returns (string memory) {
-        unchecked {
-            return toHexString(value, Math.log256(value) + 1);
-        }
-    }
-
-    /**
-     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
-     */
-    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
-        bytes memory buffer = new bytes(2 * length + 2);
-        buffer[0] = "0";
-        buffer[1] = "x";
-        for (uint256 i = 2 * length + 1; i > 1; --i) {
-            buffer[i] = _SYMBOLS[value & 0xf];
-            value >>= 4;
-        }
-        require(value == 0, "Strings: hex length insufficient");
-        return string(buffer);
-    }
-
-    /**
-     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
-     */
-    function toHexString(address addr) internal pure returns (string memory) {
-        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/introspection/ERC165.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/introspection/ERC165.sol
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC165.sol";
-
-/**
- * @dev Implementation of the {IERC165} interface.
- *
- * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
- * for the additional interface id that will be supported. For example:
- *
- * ```solidity
- * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
- *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
- * }
- * ```
- *
- * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
- */
-abstract contract ERC165 is IERC165 {
-    /**
-     * @dev See {IERC165-supportsInterface}.
-     */
-    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
-        return interfaceId == type(IERC165).interfaceId;
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/introspection/IERC165.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/introspection/IERC165.sol
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Interface of the ERC165 standard, as defined in the
- * https://eips.ethereum.org/EIPS/eip-165[EIP].
- *
- * Implementers can declare support of contract interfaces, which can then be
- * queried by others ({ERC165Checker}).
- *
- * For an implementation, see {ERC165}.
- */
-interface IERC165 {
-    /**
-     * @dev Returns true if this contract implements the interface defined by
-     * `interfaceId`. See the corresponding
-     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
-     * to learn more about how these ids are created.
-     *
-     * This function call must use less than 30 000 gas.
-     */
-    function supportsInterface(bytes4 interfaceId) external view returns (bool);
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/@openzeppelin/contracts/utils/math/Math.sol
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
-
-pragma solidity ^0.8.0;
-
-/**
- * @dev Standard math utilities missing in the Solidity language.
- */
-library Math {
-    enum Rounding {
-        Down, // Toward negative infinity
-        Up, // Toward infinity
-        Zero // Toward zero
-    }
-
-    /**
-     * @dev Returns the largest of two numbers.
-     */
-    function max(uint256 a, uint256 b) internal pure returns (uint256) {
-        return a > b ? a : b;
-    }
-
-    /**
-     * @dev Returns the smallest of two numbers.
-     */
-    function min(uint256 a, uint256 b) internal pure returns (uint256) {
-        return a < b ? a : b;
-    }
-
-    /**
-     * @dev Returns the average of two numbers. The result is rounded towards
-     * zero.
-     */
-    function average(uint256 a, uint256 b) internal pure returns (uint256) {
-        // (a + b) / 2 can overflow.
-        return (a & b) + (a ^ b) / 2;
-    }
-
-    /**
-     * @dev Returns the ceiling of the division of two numbers.
-     *
-     * This differs from standard division with `/` in that it rounds up instead
-     * of rounding down.
-     */
-    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
-        // (a + b - 1) / b can overflow on addition, so we distribute.
-        return a == 0 ? 0 : (a - 1) / b + 1;
-    }
-
-    /**
-     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
-     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
-     * with further edits by Uniswap Labs also under MIT license.
-     */
-    function mulDiv(
-        uint256 x,
-        uint256 y,
-        uint256 denominator
-    ) internal pure returns (uint256 result) {
-        unchecked {
-            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
-            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
-            // variables such that product = prod1 * 2^256 + prod0.
-            uint256 prod0; // Least significant 256 bits of the product
-            uint256 prod1; // Most significant 256 bits of the product
-            assembly {
-                let mm := mulmod(x, y, not(0))
-                prod0 := mul(x, y)
-                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
-            }
-
-            // Handle non-overflow cases, 256 by 256 division.
-            if (prod1 == 0) {
-                return prod0 / denominator;
-            }
-
-            // Make sure the result is less than 2^256. Also prevents denominator == 0.
-            require(denominator > prod1);
-
-            ///////////////////////////////////////////////
-            // 512 by 256 division.
-            ///////////////////////////////////////////////
-
-            // Make division exact by subtracting the remainder from [prod1 prod0].
-            uint256 remainder;
-            assembly {
-                // Compute remainder using mulmod.
-                remainder := mulmod(x, y, denominator)
-
-                // Subtract 256 bit number from 512 bit number.
-                prod1 := sub(prod1, gt(remainder, prod0))
-                prod0 := sub(prod0, remainder)
-            }
-
-            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
-            // See https://cs.stackexchange.com/q/138556/92363.
-
-            // Does not overflow because the denominator cannot be zero at this stage in the function.
-            uint256 twos = denominator & (~denominator + 1);
-            assembly {
-                // Divide denominator by twos.
-                denominator := div(denominator, twos)
-
-                // Divide [prod1 prod0] by twos.
-                prod0 := div(prod0, twos)
-
-                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
-                twos := add(div(sub(0, twos), twos), 1)
-            }
-
-            // Shift in bits from prod1 into prod0.
-            prod0 |= prod1 * twos;
-
-            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
-            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
-            // four bits. That is, denominator * inv = 1 mod 2^4.
-            uint256 inverse = (3 * denominator) ^ 2;
-
-            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
-            // in modular arithmetic, doubling the correct bits in each step.
-            inverse *= 2 - denominator * inverse; // inverse mod 2^8
-            inverse *= 2 - denominator * inverse; // inverse mod 2^16
-            inverse *= 2 - denominator * inverse; // inverse mod 2^32
-            inverse *= 2 - denominator * inverse; // inverse mod 2^64
-            inverse *= 2 - denominator * inverse; // inverse mod 2^128
-            inverse *= 2 - denominator * inverse; // inverse mod 2^256
-
-            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
-            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
-            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
-            // is no longer required.
-            result = prod0 * inverse;
-            return result;
-        }
-    }
-
-    /**
-     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
-     */
-    function mulDiv(
-        uint256 x,
-        uint256 y,
-        uint256 denominator,
-        Rounding rounding
-    ) internal pure returns (uint256) {
-        uint256 result = mulDiv(x, y, denominator);
-        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
-            result += 1;
-        }
-        return result;
-    }
-
-    /**
-     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
-     *
-     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
-     */
-    function sqrt(uint256 a) internal pure returns (uint256) {
-        if (a == 0) {
-            return 0;
-        }
-
-        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
-        //
-        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
-        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
-        //
-        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
-        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
-        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
-        //
-        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
-        uint256 result = 1 << (log2(a) >> 1);
-
-        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
-        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
-        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
-        // into the expected uint128 result.
-        unchecked {
-            result = (result + a / result) >> 1;
-            result = (result + a / result) >> 1;
-            result = (result + a / result) >> 1;
-            result = (result + a / result) >> 1;
-            result = (result + a / result) >> 1;
-            result = (result + a / result) >> 1;
-            result = (result + a / result) >> 1;
-            return min(result, a / result);
-        }
-    }
-
-    /**
-     * @notice Calculates sqrt(a), following the selected rounding direction.
-     */
-    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
-        unchecked {
-            uint256 result = sqrt(a);
-            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
-        }
-    }
-
-    /**
-     * @dev Return the log in base 2, rounded down, of a positive value.
-     * Returns 0 if given 0.
-     */
-    function log2(uint256 value) internal pure returns (uint256) {
-        uint256 result = 0;
-        unchecked {
-            if (value >> 128 > 0) {
-                value >>= 128;
-                result += 128;
-            }
-            if (value >> 64 > 0) {
-                value >>= 64;
-                result += 64;
-            }
-            if (value >> 32 > 0) {
-                value >>= 32;
-                result += 32;
-            }
-            if (value >> 16 > 0) {
-                value >>= 16;
-                result += 16;
-            }
-            if (value >> 8 > 0) {
-                value >>= 8;
-                result += 8;
-            }
-            if (value >> 4 > 0) {
-                value >>= 4;
-                result += 4;
-            }
-            if (value >> 2 > 0) {
-                value >>= 2;
-                result += 2;
-            }
-            if (value >> 1 > 0) {
-                result += 1;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
-     * Returns 0 if given 0.
-     */
-    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
-        unchecked {
-            uint256 result = log2(value);
-            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
-        }
-    }
-
-    /**
-     * @dev Return the log in base 10, rounded down, of a positive value.
-     * Returns 0 if given 0.
-     */
-    function log10(uint256 value) internal pure returns (uint256) {
-        uint256 result = 0;
-        unchecked {
-            if (value >= 10**64) {
-                value /= 10**64;
-                result += 64;
-            }
-            if (value >= 10**32) {
-                value /= 10**32;
-                result += 32;
-            }
-            if (value >= 10**16) {
-                value /= 10**16;
-                result += 16;
-            }
-            if (value >= 10**8) {
-                value /= 10**8;
-                result += 8;
-            }
-            if (value >= 10**4) {
-                value /= 10**4;
-                result += 4;
-            }
-            if (value >= 10**2) {
-                value /= 10**2;
-                result += 2;
-            }
-            if (value >= 10**1) {
-                result += 1;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
-     * Returns 0 if given 0.
-     */
-    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
-        unchecked {
-            uint256 result = log10(value);
-            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
-        }
-    }
-
-    /**
-     * @dev Return the log in base 256, rounded down, of a positive value.
-     * Returns 0 if given 0.
-     *
-     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
-     */
-    function log256(uint256 value) internal pure returns (uint256) {
-        uint256 result = 0;
-        unchecked {
-            if (value >> 128 > 0) {
-                value >>= 128;
-                result += 16;
-            }
-            if (value >> 64 > 0) {
-                value >>= 64;
-                result += 8;
-            }
-            if (value >> 32 > 0) {
-                value >>= 32;
-                result += 4;
-            }
-            if (value >> 16 > 0) {
-                value >>= 16;
-                result += 2;
-            }
-            if (value >> 8 > 0) {
-                result += 1;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
-     * Returns 0 if given 0.
-     */
-    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
-        unchecked {
-            uint256 result = log256(value);
-            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
-        }
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/ZeppelinContract.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/ZeppelinContract.sol
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.9;
-
-import "./@openzeppelin/contracts/token/ERC721/ERC721.sol";
-import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
-import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
-import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
-import "./@openzeppelin/contracts/access/Ownable.sol";
-import "./@openzeppelin/contracts/utils/Counters.sol";
-
-contract ZeppelinContract is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Burnable, Ownable {
-    using Counters for Counters.Counter;
-
-    Counters.Counter private _tokenIdCounter;
-
-    constructor() ERC721("ZeppelinContract", "UNQ") {}
-
-    function _baseURI() internal pure override returns (string memory) {
-        return "test";
-    }
-
-    function safeMint(address to, string memory uri) public onlyOwner {
-        uint256 tokenId = _tokenIdCounter.current();
-        _tokenIdCounter.increment();
-        _safeMint(to, tokenId);
-        _setTokenURI(tokenId, uri);
-    }
-
-    // The following functions are overrides required by Solidity.
-
-    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
-        internal
-        override(ERC721, ERC721Enumerable)
-    {
-        super._beforeTokenTransfer(from, to, tokenId, batchSize);
-    }
-
-    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
-        super._burn(tokenId);
-    }
-
-    function tokenURI(uint256 tokenId)
-        public
-        view
-        override(ERC721, ERC721URIStorage)
-        returns (string memory)
-    {
-        return super.tokenURI(tokenId);
-    }
-
-    function supportsInterface(bytes4 interfaceId)
-        public
-        view
-        override(ERC721, ERC721Enumerable)
-        returns (bool)
-    {
-        return super.supportsInterface(interfaceId);
-    }
-}
deletedtests/src/benchmarks/mintFee/openZeppelin/bin/ZeppelinContract.abidiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/bin/ZeppelinContract.abi
+++ /dev/null
@@ -1 +0,0 @@
-[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"string","name":"uri","type":"string"}],"name":"safeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
deletedtests/src/benchmarks/mintFee/openZeppelin/bin/ZeppelinContract.bindiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/openZeppelin/bin/ZeppelinContract.bin
+++ /dev/null
@@ -1 +0,0 @@
-60806040523480156200001157600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b815250816000908162000068919062000195565b50600162000077828262000195565b505050620000946200008e6200009a60201b60201c565b6200009e565b62000261565b3390565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200011b57607f821691505b6020821081036200013c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019057600081815260208120601f850160051c810160208610156200016b5750805b601f850160051c820191505b818110156200018c5782815560010162000177565b5050505b505050565b81516001600160401b03811115620001b157620001b1620000f0565b620001c981620001c2845462000106565b8462000142565b602080601f831160018114620002015760008415620001e85750858301515b600019600386901b1c1916600185901b1785556200018c565b600085815260208120601f198616915b82811015620002325788860151825594840194600190910190840162000211565b5085821015620002515787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611f0d80620002716000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80636352211e116100b8578063a22cb4651161007c578063a22cb46514610271578063b88d4fde14610284578063c87b56dd14610297578063d204c45e146102aa578063e985e9c5146102bd578063f2fde38b146102f957600080fd5b80636352211e1461022a57806370a082311461023d578063715018a6146102505780638da5cb5b1461025857806395d89b411461026957600080fd5b806323b872dd116100ff57806323b872dd146101cb5780632f745c59146101de57806342842e0e146101f157806342966c68146102045780634f6ccce71461021757600080fd5b806301ffc9a71461013c57806306fdde0314610164578063081812fc14610179578063095ea7b3146101a457806318160ddd146101b9575b600080fd5b61014f61014a3660046118ab565b61030c565b60405190151581526020015b60405180910390f35b61016c61031d565b60405161015b9190611918565b61018c61018736600461192b565b6103af565b6040516001600160a01b03909116815260200161015b565b6101b76101b2366004611960565b6103d6565b005b6008545b60405190815260200161015b565b6101b76101d936600461198a565b6104f0565b6101bd6101ec366004611960565b610522565b6101b76101ff36600461198a565b6105b8565b6101b761021236600461192b565b6105d3565b6101bd61022536600461192b565b610604565b61018c61023836600461192b565b610697565b6101bd61024b3660046119c6565b6106f7565b6101b761077d565b600b546001600160a01b031661018c565b61016c610791565b6101b761027f3660046119e1565b6107a0565b6101b7610292366004611aa9565b6107af565b61016c6102a536600461192b565b6107e7565b6101b76102b8366004611b25565b6107f2565b61014f6102cb366004611b87565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6101b76103073660046119c6565b610829565b60006103178261089f565b92915050565b60606000805461032c90611bba565b80601f016020809104026020016040519081016040528092919081815260200182805461035890611bba565b80156103a55780601f1061037a576101008083540402835291602001916103a5565b820191906000526020600020905b81548152906001019060200180831161038857829003601f168201915b5050505050905090565b60006103ba826108c4565b506000908152600460205260409020546001600160a01b031690565b60006103e182610697565b9050806001600160a01b0316836001600160a01b0316036104535760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061046f575061046f81336102cb565b6104e15760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161044a565b6104eb8383610923565b505050565b6104fb335b82610991565b6105175760405162461bcd60e51b815260040161044a90611bf4565b6104eb838383610a10565b600061052d836106f7565b821061058f5760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b606482015260840161044a565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6104eb838383604051806020016040528060008152506107af565b6105dc336104f5565b6105f85760405162461bcd60e51b815260040161044a90611bf4565b61060181610b81565b50565b600061060f60085490565b82106106725760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b606482015260840161044a565b6008828154811061068557610685611c41565b90600052602060002001549050919050565b6000818152600260205260408120546001600160a01b0316806103175760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b60006001600160a01b0382166107615760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161044a565b506001600160a01b031660009081526003602052604090205490565b610785610b8a565b61078f6000610be4565b565b60606001805461032c90611bba565b6107ab338383610c36565b5050565b6107b93383610991565b6107d55760405162461bcd60e51b815260040161044a90611bf4565b6107e184848484610d04565b50505050565b606061031782610d37565b6107fa610b8a565b6000610805600c5490565b9050610815600c80546001019055565b61081f8382610e4b565b6104eb8183610e65565b610831610b8a565b6001600160a01b0381166108965760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161044a565b61060181610be4565b60006001600160e01b0319821663780e9d6360e01b1480610317575061031782610ef8565b6000818152600260205260409020546001600160a01b03166106015760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061095882610697565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061099d83610697565b9050806001600160a01b0316846001600160a01b031614806109e457506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80610a085750836001600160a01b03166109fd846103af565b6001600160a01b0316145b949350505050565b826001600160a01b0316610a2382610697565b6001600160a01b031614610a495760405162461bcd60e51b815260040161044a90611c57565b6001600160a01b038216610aab5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161044a565b610ab88383836001610f48565b826001600160a01b0316610acb82610697565b6001600160a01b031614610af15760405162461bcd60e51b815260040161044a90611c57565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61060181610f54565b600b546001600160a01b0316331461078f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161044a565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b031603610c975760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161044a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b610d0f848484610a10565b610d1b84848484610f94565b6107e15760405162461bcd60e51b815260040161044a90611c9c565b6060610d42826108c4565b6000828152600a602052604081208054610d5b90611bba565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8790611bba565b8015610dd45780601f10610da957610100808354040283529160200191610dd4565b820191906000526020600020905b815481529060010190602001808311610db757829003601f168201915b505050505090506000610dfe6040805180820190915260048152631d195cdd60e21b602082015290565b90508051600003610e10575092915050565b815115610e42578082604051602001610e2a929190611cee565b60405160208183030381529060405292505050919050565b610a0884611095565b6107ab828260405180602001604052806000815250611115565b6000828152600260205260409020546001600160a01b0316610ee05760405162461bcd60e51b815260206004820152602e60248201527f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b606482015260840161044a565b6000828152600a602052604090206104eb8282611d6b565b60006001600160e01b031982166380ac58cd60e01b1480610f2957506001600160e01b03198216635b5e139f60e01b145b8061031757506301ffc9a760e01b6001600160e01b0319831614610317565b6107e184848484611148565b610f5d81611288565b6000818152600a602052604090208054610f7690611bba565b159050610601576000818152600a6020526040812061060191611847565b60006001600160a01b0384163b1561108a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610fd8903390899088908890600401611e2b565b6020604051808303816000875af1925050508015611013575060408051601f3d908101601f1916820190925261101091810190611e68565b60015b611070573d808015611041576040519150601f19603f3d011682016040523d82523d6000602084013e611046565b606091505b5080516000036110685760405162461bcd60e51b815260040161044a90611c9c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610a08565b506001949350505050565b60606110a0826108c4565b60006110c36040805180820190915260048152631d195cdd60e21b602082015290565b905060008151116110e3576040518060200160405280600081525061110e565b806110ed8461132b565b6040516020016110fe929190611cee565b6040516020818303038152906040525b9392505050565b61111f83836113be565b61112c6000848484610f94565b6104eb5760405162461bcd60e51b815260040161044a90611c9c565b61115484848484611557565b60018111156111c35760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b606482015260840161044a565b816001600160a01b03851661121f5761121a81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611242565b836001600160a01b0316856001600160a01b0316146112425761124285826115df565b6001600160a01b03841661125e576112598161167c565b611281565b846001600160a01b0316846001600160a01b03161461128157611281848261172b565b5050505050565b600061129382610697565b90506112a3816000846001610f48565b6112ac82610697565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b606060006113388361176f565b600101905060008167ffffffffffffffff81111561135857611358611a1d565b6040519080825280601f01601f191660200182016040528015611382576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461138c57509392505050565b6001600160a01b0382166114145760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161044a565b6000818152600260205260409020546001600160a01b0316156114795760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b611487600083836001610f48565b6000818152600260205260409020546001600160a01b0316156114ec5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60018111156107e1576001600160a01b0384161561159d576001600160a01b03841660009081526003602052604081208054839290611597908490611e9b565b90915550505b6001600160a01b038316156107e1576001600160a01b038316600090815260036020526040812080548392906115d4908490611eae565b909155505050505050565b600060016115ec846106f7565b6115f69190611e9b565b600083815260076020526040902054909150808214611649576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b60085460009061168e90600190611e9b565b600083815260096020526040812054600880549394509092849081106116b6576116b6611c41565b9060005260206000200154905080600883815481106116d7576116d7611c41565b600091825260208083209091019290925582815260099091526040808220849055858252812055600880548061170f5761170f611ec1565b6001900381819060005260206000200160009055905550505050565b6000611736836106f7565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106117ae5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106117da576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106117f857662386f26fc10000830492506010015b6305f5e1008310611810576305f5e100830492506008015b612710831061182457612710830492506004015b60648310611836576064830492506002015b600a83106103175760010192915050565b50805461185390611bba565b6000825580601f10611863575050565b601f01602090049060005260206000209081019061060191905b80821115611891576000815560010161187d565b5090565b6001600160e01b03198116811461060157600080fd5b6000602082840312156118bd57600080fd5b813561110e81611895565b60005b838110156118e35781810151838201526020016118cb565b50506000910152565b600081518084526119048160208601602086016118c8565b601f01601f19169290920160200192915050565b60208152600061110e60208301846118ec565b60006020828403121561193d57600080fd5b5035919050565b80356001600160a01b038116811461195b57600080fd5b919050565b6000806040838503121561197357600080fd5b61197c83611944565b946020939093013593505050565b60008060006060848603121561199f57600080fd5b6119a884611944565b92506119b660208501611944565b9150604084013590509250925092565b6000602082840312156119d857600080fd5b61110e82611944565b600080604083850312156119f457600080fd5b6119fd83611944565b915060208301358015158114611a1257600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611a4e57611a4e611a1d565b604051601f8501601f19908116603f01168101908282118183101715611a7657611a76611a1d565b81604052809350858152868686011115611a8f57600080fd5b858560208301376000602087830101525050509392505050565b60008060008060808587031215611abf57600080fd5b611ac885611944565b9350611ad660208601611944565b925060408501359150606085013567ffffffffffffffff811115611af957600080fd5b8501601f81018713611b0a57600080fd5b611b1987823560208401611a33565b91505092959194509250565b60008060408385031215611b3857600080fd5b611b4183611944565b9150602083013567ffffffffffffffff811115611b5d57600080fd5b8301601f81018513611b6e57600080fd5b611b7d85823560208401611a33565b9150509250929050565b60008060408385031215611b9a57600080fd5b611ba383611944565b9150611bb160208401611944565b90509250929050565b600181811c90821680611bce57607f821691505b602082108103611bee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60008351611d008184602088016118c8565b835190830190611d148183602088016118c8565b01949350505050565b601f8211156104eb57600081815260208120601f850160051c81016020861015611d445750805b601f850160051c820191505b81811015611d6357828155600101611d50565b505050505050565b815167ffffffffffffffff811115611d8557611d85611a1d565b611d9981611d938454611bba565b84611d1d565b602080601f831160018114611dce5760008415611db65750858301515b600019600386901b1c1916600185901b178555611d63565b600085815260208120601f198616915b82811015611dfd57888601518255948401946001909101908401611dde565b5085821015611e1b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611e5e908301846118ec565b9695505050505050565b600060208284031215611e7a57600080fd5b815161110e81611895565b634e487b7160e01b600052601160045260246000fd5b8181038181111561031757610317611e85565b8082018082111561031757610317611e85565b634e487b7160e01b600052603160045260246000fdfea26469706673582212207960bc65d7484ab1502ccdc352c91f0fb91535a525cf99e1b6392e242548279a64736f6c63430008110033
\ No newline at end of file
addedtests/src/benchmarks/opsFee/index.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/opsFee/index.ts
@@ -0,0 +1,888 @@
+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 '../utils/types';
+import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES, SUBS_PROPERTIES} from '../utils/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}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.bin`)).toString();
+  const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/../utils/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, '').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['mintWithTokenURI'].zeppelin =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => zeppelelinContract!.methods.safeMint(ethSigner, 'Test URI').send({from: ethSigner}),
+    );
+
+  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}/../utils/openZeppelin/ERC20/bin/ZeppelinContract.bin`)).toString();
+  const ZEPPELIN_ABI = JSON.parse((await readFile(`${__dirname}/../utils/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(),
+    );
+
+  await zeppelelinContract!.methods.approve(ethSigner, 10).send({from: ethReceiver});
+
+  res['transferFrom*'].zeppelin =
+    await helper.arrange.calculcateFeeGas(
+      {Ethereum: ethSigner},
+      () => zeppelelinContract!.methods.transferFrom(ethReceiver, ethSigner, 1).send({from: ethSigner}),
+    );
+
+  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, 10).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
addedtests/src/benchmarks/utils/common.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/common.ts
@@ -0,0 +1,95 @@
+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 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
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/README.mddiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/README.md
@@ -0,0 +1,12 @@
+# OpenZeppelin Contracts
+
+The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
+
+They are not meant to be edited.
+
+The originals can be found on [GitHub] and [npm].
+
+[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
+[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
+
+Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/access/Ownable.sol
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../utils/Context.sol";
+
+/**
+ * @dev Contract module which provides a basic access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership}.
+ *
+ * This module is used through inheritance. It will make available the modifier
+ * `onlyOwner`, which can be applied to your functions to restrict their use to
+ * the owner.
+ */
+abstract contract Ownable is Context {
+    address private _owner;
+
+    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
+
+    /**
+     * @dev Initializes the contract setting the deployer as the initial owner.
+     */
+    constructor() {
+        _transferOwnership(_msgSender());
+    }
+
+    /**
+     * @dev Throws if called by any account other than the owner.
+     */
+    modifier onlyOwner() {
+        _checkOwner();
+        _;
+    }
+
+    /**
+     * @dev Returns the address of the current owner.
+     */
+    function owner() public view virtual returns (address) {
+        return _owner;
+    }
+
+    /**
+     * @dev Throws if the sender is not the owner.
+     */
+    function _checkOwner() internal view virtual {
+        require(owner() == _msgSender(), "Ownable: caller is not the owner");
+    }
+
+    /**
+     * @dev Leaves the contract without owner. It will not be possible to call
+     * `onlyOwner` functions anymore. Can only be called by the current owner.
+     *
+     * NOTE: Renouncing ownership will leave the contract without an owner,
+     * thereby removing any functionality that is only available to the owner.
+     */
+    function renounceOwnership() public virtual onlyOwner {
+        _transferOwnership(address(0));
+    }
+
+    /**
+     * @dev Transfers ownership of the contract to a new account (`newOwner`).
+     * Can only be called by the current owner.
+     */
+    function transferOwnership(address newOwner) public virtual onlyOwner {
+        require(newOwner != address(0), "Ownable: new owner is the zero address");
+        _transferOwnership(newOwner);
+    }
+
+    /**
+     * @dev Transfers ownership of the contract to a new account (`newOwner`).
+     * Internal function without access restriction.
+     */
+    function _transferOwnership(address newOwner) internal virtual {
+        address oldOwner = _owner;
+        _owner = newOwner;
+        emit OwnershipTransferred(oldOwner, newOwner);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/governance/utils/IVotes.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/governance/utils/IVotes.sol
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
+ *
+ * _Available since v4.5._
+ */
+interface IVotes {
+    /**
+     * @dev Emitted when an account changes their delegate.
+     */
+    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
+
+    /**
+     * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
+     */
+    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
+
+    /**
+     * @dev Returns the current amount of votes that `account` has.
+     */
+    function getVotes(address account) external view returns (uint256);
+
+    /**
+     * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
+     */
+    function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
+
+    /**
+     * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
+     *
+     * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
+     * Votes that have not been delegated are still part of total supply, even though they would not participate in a
+     * vote.
+     */
+    function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
+
+    /**
+     * @dev Returns the delegate that `account` has chosen.
+     */
+    function delegates(address account) external view returns (address);
+
+    /**
+     * @dev Delegates votes from the sender to `delegatee`.
+     */
+    function delegate(address delegatee) external;
+
+    /**
+     * @dev Delegates votes from signer to `delegatee`.
+     */
+    function delegateBySig(
+        address delegatee,
+        uint256 nonce,
+        uint256 expiry,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) external;
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC3156 FlashBorrower, as defined in
+ * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
+ *
+ * _Available since v4.1._
+ */
+interface IERC3156FlashBorrower {
+    /**
+     * @dev Receive a flash loan.
+     * @param initiator The initiator of the loan.
+     * @param token The loan currency.
+     * @param amount The amount of tokens lent.
+     * @param fee The additional amount of tokens to repay.
+     * @param data Arbitrary data structure, intended to contain user-defined parameters.
+     * @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan"
+     */
+    function onFlashLoan(
+        address initiator,
+        address token,
+        uint256 amount,
+        uint256 fee,
+        bytes calldata data
+    ) external returns (bytes32);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashLender.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC3156FlashBorrower.sol";
+
+/**
+ * @dev Interface of the ERC3156 FlashLender, as defined in
+ * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
+ *
+ * _Available since v4.1._
+ */
+interface IERC3156FlashLender {
+    /**
+     * @dev The amount of currency available to be lended.
+     * @param token The loan currency.
+     * @return The amount of `token` that can be borrowed.
+     */
+    function maxFlashLoan(address token) external view returns (uint256);
+
+    /**
+     * @dev The fee to be charged for a given loan.
+     * @param token The loan currency.
+     * @param amount The amount of tokens lent.
+     * @return The amount of `token` to be charged for the loan, on top of the returned principal.
+     */
+    function flashFee(address token, uint256 amount) external view returns (uint256);
+
+    /**
+     * @dev Initiate a flash loan.
+     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
+     * @param token The loan currency.
+     * @param amount The amount of tokens lent.
+     * @param data Arbitrary data structure, intended to contain user-defined parameters.
+     */
+    function flashLoan(
+        IERC3156FlashBorrower receiver,
+        address token,
+        uint256 amount,
+        bytes calldata data
+    ) external returns (bool);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/security/Pausable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/security/Pausable.sol
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../utils/Context.sol";
+
+/**
+ * @dev Contract module which allows children to implement an emergency stop
+ * mechanism that can be triggered by an authorized account.
+ *
+ * This module is used through inheritance. It will make available the
+ * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
+ * the functions of your contract. Note that they will not be pausable by
+ * simply including this module, only once the modifiers are put in place.
+ */
+abstract contract Pausable is Context {
+    /**
+     * @dev Emitted when the pause is triggered by `account`.
+     */
+    event Paused(address account);
+
+    /**
+     * @dev Emitted when the pause is lifted by `account`.
+     */
+    event Unpaused(address account);
+
+    bool private _paused;
+
+    /**
+     * @dev Initializes the contract in unpaused state.
+     */
+    constructor() {
+        _paused = false;
+    }
+
+    /**
+     * @dev Modifier to make a function callable only when the contract is not paused.
+     *
+     * Requirements:
+     *
+     * - The contract must not be paused.
+     */
+    modifier whenNotPaused() {
+        _requireNotPaused();
+        _;
+    }
+
+    /**
+     * @dev Modifier to make a function callable only when the contract is paused.
+     *
+     * Requirements:
+     *
+     * - The contract must be paused.
+     */
+    modifier whenPaused() {
+        _requirePaused();
+        _;
+    }
+
+    /**
+     * @dev Returns true if the contract is paused, and false otherwise.
+     */
+    function paused() public view virtual returns (bool) {
+        return _paused;
+    }
+
+    /**
+     * @dev Throws if the contract is paused.
+     */
+    function _requireNotPaused() internal view virtual {
+        require(!paused(), "Pausable: paused");
+    }
+
+    /**
+     * @dev Throws if the contract is not paused.
+     */
+    function _requirePaused() internal view virtual {
+        require(paused(), "Pausable: not paused");
+    }
+
+    /**
+     * @dev Triggers stopped state.
+     *
+     * Requirements:
+     *
+     * - The contract must not be paused.
+     */
+    function _pause() internal virtual whenNotPaused {
+        _paused = true;
+        emit Paused(_msgSender());
+    }
+
+    /**
+     * @dev Returns to normal state.
+     *
+     * Requirements:
+     *
+     * - The contract must be paused.
+     */
+    function _unpause() internal virtual whenPaused {
+        _paused = false;
+        emit Unpaused(_msgSender());
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/ERC20.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/ERC20.sol
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC20.sol";
+import "./extensions/IERC20Metadata.sol";
+import "../../utils/Context.sol";
+
+/**
+ * @dev Implementation of the {IERC20} interface.
+ *
+ * This implementation is agnostic to the way tokens are created. This means
+ * that a supply mechanism has to be added in a derived contract using {_mint}.
+ * For a generic mechanism see {ERC20PresetMinterPauser}.
+ *
+ * TIP: For a detailed writeup see our guide
+ * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
+ * to implement supply mechanisms].
+ *
+ * We have followed general OpenZeppelin Contracts guidelines: functions revert
+ * instead returning `false` on failure. This behavior is nonetheless
+ * conventional and does not conflict with the expectations of ERC20
+ * applications.
+ *
+ * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
+ * This allows applications to reconstruct the allowance for all accounts just
+ * by listening to said events. Other implementations of the EIP may not emit
+ * these events, as it isn't required by the specification.
+ *
+ * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
+ * functions have been added to mitigate the well-known issues around setting
+ * allowances. See {IERC20-approve}.
+ */
+contract ERC20 is Context, IERC20, IERC20Metadata {
+    mapping(address => uint256) private _balances;
+
+    mapping(address => mapping(address => uint256)) private _allowances;
+
+    uint256 private _totalSupply;
+
+    string private _name;
+    string private _symbol;
+
+    /**
+     * @dev Sets the values for {name} and {symbol}.
+     *
+     * The default value of {decimals} is 18. To select a different value for
+     * {decimals} you should overload it.
+     *
+     * All two of these values are immutable: they can only be set once during
+     * construction.
+     */
+    constructor(string memory name_, string memory symbol_) {
+        _name = name_;
+        _symbol = symbol_;
+    }
+
+    /**
+     * @dev Returns the name of the token.
+     */
+    function name() public view virtual override returns (string memory) {
+        return _name;
+    }
+
+    /**
+     * @dev Returns the symbol of the token, usually a shorter version of the
+     * name.
+     */
+    function symbol() public view virtual override returns (string memory) {
+        return _symbol;
+    }
+
+    /**
+     * @dev Returns the number of decimals used to get its user representation.
+     * For example, if `decimals` equals `2`, a balance of `505` tokens should
+     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
+     *
+     * Tokens usually opt for a value of 18, imitating the relationship between
+     * Ether and Wei. This is the value {ERC20} uses, unless this function is
+     * overridden;
+     *
+     * NOTE: This information is only used for _display_ purposes: it in
+     * no way affects any of the arithmetic of the contract, including
+     * {IERC20-balanceOf} and {IERC20-transfer}.
+     */
+    function decimals() public view virtual override returns (uint8) {
+        return 18;
+    }
+
+    /**
+     * @dev See {IERC20-totalSupply}.
+     */
+    function totalSupply() public view virtual override returns (uint256) {
+        return _totalSupply;
+    }
+
+    /**
+     * @dev See {IERC20-balanceOf}.
+     */
+    function balanceOf(address account) public view virtual override returns (uint256) {
+        return _balances[account];
+    }
+
+    /**
+     * @dev See {IERC20-transfer}.
+     *
+     * Requirements:
+     *
+     * - `to` cannot be the zero address.
+     * - the caller must have a balance of at least `amount`.
+     */
+    function transfer(address to, uint256 amount) public virtual override returns (bool) {
+        address owner = _msgSender();
+        _transfer(owner, to, amount);
+        return true;
+    }
+
+    /**
+     * @dev See {IERC20-allowance}.
+     */
+    function allowance(address owner, address spender) public view virtual override returns (uint256) {
+        return _allowances[owner][spender];
+    }
+
+    /**
+     * @dev See {IERC20-approve}.
+     *
+     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
+     * `transferFrom`. This is semantically equivalent to an infinite approval.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     */
+    function approve(address spender, uint256 amount) public virtual override returns (bool) {
+        address owner = _msgSender();
+        _approve(owner, spender, amount);
+        return true;
+    }
+
+    /**
+     * @dev See {IERC20-transferFrom}.
+     *
+     * Emits an {Approval} event indicating the updated allowance. This is not
+     * required by the EIP. See the note at the beginning of {ERC20}.
+     *
+     * NOTE: Does not update the allowance if the current allowance
+     * is the maximum `uint256`.
+     *
+     * Requirements:
+     *
+     * - `from` and `to` cannot be the zero address.
+     * - `from` must have a balance of at least `amount`.
+     * - the caller must have allowance for ``from``'s tokens of at least
+     * `amount`.
+     */
+    function transferFrom(
+        address from,
+        address to,
+        uint256 amount
+    ) public virtual override returns (bool) {
+        address spender = _msgSender();
+        _spendAllowance(from, spender, amount);
+        _transfer(from, to, amount);
+        return true;
+    }
+
+    /**
+     * @dev Atomically increases the allowance granted to `spender` by the caller.
+     *
+     * This is an alternative to {approve} that can be used as a mitigation for
+     * problems described in {IERC20-approve}.
+     *
+     * Emits an {Approval} event indicating the updated allowance.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     */
+    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
+        address owner = _msgSender();
+        _approve(owner, spender, allowance(owner, spender) + addedValue);
+        return true;
+    }
+
+    /**
+     * @dev Atomically decreases the allowance granted to `spender` by the caller.
+     *
+     * This is an alternative to {approve} that can be used as a mitigation for
+     * problems described in {IERC20-approve}.
+     *
+     * Emits an {Approval} event indicating the updated allowance.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     * - `spender` must have allowance for the caller of at least
+     * `subtractedValue`.
+     */
+    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
+        address owner = _msgSender();
+        uint256 currentAllowance = allowance(owner, spender);
+        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
+        unchecked {
+            _approve(owner, spender, currentAllowance - subtractedValue);
+        }
+
+        return true;
+    }
+
+    /**
+     * @dev Moves `amount` of tokens from `from` to `to`.
+     *
+     * This internal function is equivalent to {transfer}, and can be used to
+     * e.g. implement automatic token fees, slashing mechanisms, etc.
+     *
+     * Emits a {Transfer} event.
+     *
+     * Requirements:
+     *
+     * - `from` cannot be the zero address.
+     * - `to` cannot be the zero address.
+     * - `from` must have a balance of at least `amount`.
+     */
+    function _transfer(
+        address from,
+        address to,
+        uint256 amount
+    ) internal virtual {
+        require(from != address(0), "ERC20: transfer from the zero address");
+        require(to != address(0), "ERC20: transfer to the zero address");
+
+        _beforeTokenTransfer(from, to, amount);
+
+        uint256 fromBalance = _balances[from];
+        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
+        unchecked {
+            _balances[from] = fromBalance - amount;
+            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
+            // decrementing then incrementing.
+            _balances[to] += amount;
+        }
+
+        emit Transfer(from, to, amount);
+
+        _afterTokenTransfer(from, to, amount);
+    }
+
+    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
+     * the total supply.
+     *
+     * Emits a {Transfer} event with `from` set to the zero address.
+     *
+     * Requirements:
+     *
+     * - `account` cannot be the zero address.
+     */
+    function _mint(address account, uint256 amount) internal virtual {
+        require(account != address(0), "ERC20: mint to the zero address");
+
+        _beforeTokenTransfer(address(0), account, amount);
+
+        _totalSupply += amount;
+        unchecked {
+            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
+            _balances[account] += amount;
+        }
+        emit Transfer(address(0), account, amount);
+
+        _afterTokenTransfer(address(0), account, amount);
+    }
+
+    /**
+     * @dev Destroys `amount` tokens from `account`, reducing the
+     * total supply.
+     *
+     * Emits a {Transfer} event with `to` set to the zero address.
+     *
+     * Requirements:
+     *
+     * - `account` cannot be the zero address.
+     * - `account` must have at least `amount` tokens.
+     */
+    function _burn(address account, uint256 amount) internal virtual {
+        require(account != address(0), "ERC20: burn from the zero address");
+
+        _beforeTokenTransfer(account, address(0), amount);
+
+        uint256 accountBalance = _balances[account];
+        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
+        unchecked {
+            _balances[account] = accountBalance - amount;
+            // Overflow not possible: amount <= accountBalance <= totalSupply.
+            _totalSupply -= amount;
+        }
+
+        emit Transfer(account, address(0), amount);
+
+        _afterTokenTransfer(account, address(0), amount);
+    }
+
+    /**
+     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
+     *
+     * This internal function is equivalent to `approve`, and can be used to
+     * e.g. set automatic allowances for certain subsystems, etc.
+     *
+     * Emits an {Approval} event.
+     *
+     * Requirements:
+     *
+     * - `owner` cannot be the zero address.
+     * - `spender` cannot be the zero address.
+     */
+    function _approve(
+        address owner,
+        address spender,
+        uint256 amount
+    ) internal virtual {
+        require(owner != address(0), "ERC20: approve from the zero address");
+        require(spender != address(0), "ERC20: approve to the zero address");
+
+        _allowances[owner][spender] = amount;
+        emit Approval(owner, spender, amount);
+    }
+
+    /**
+     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
+     *
+     * Does not update the allowance amount in case of infinite allowance.
+     * Revert if not enough allowance is available.
+     *
+     * Might emit an {Approval} event.
+     */
+    function _spendAllowance(
+        address owner,
+        address spender,
+        uint256 amount
+    ) internal virtual {
+        uint256 currentAllowance = allowance(owner, spender);
+        if (currentAllowance != type(uint256).max) {
+            require(currentAllowance >= amount, "ERC20: insufficient allowance");
+            unchecked {
+                _approve(owner, spender, currentAllowance - amount);
+            }
+        }
+    }
+
+    /**
+     * @dev Hook that is called before any transfer of tokens. This includes
+     * minting and burning.
+     *
+     * Calling conditions:
+     *
+     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+     * will be transferred to `to`.
+     * - when `from` is zero, `amount` tokens will be minted for `to`.
+     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
+     * - `from` and `to` are never both zero.
+     *
+     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     */
+    function _beforeTokenTransfer(
+        address from,
+        address to,
+        uint256 amount
+    ) internal virtual {}
+
+    /**
+     * @dev Hook that is called after any transfer of tokens. This includes
+     * minting and burning.
+     *
+     * Calling conditions:
+     *
+     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+     * has been transferred to `to`.
+     * - when `from` is zero, `amount` tokens have been minted for `to`.
+     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
+     * - `from` and `to` are never both zero.
+     *
+     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     */
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 amount
+    ) internal virtual {}
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/IERC20.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/IERC20.sol
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+    /**
+     * @dev Emitted when `value` tokens are moved from one account (`from`) to
+     * another (`to`).
+     *
+     * Note that `value` may be zero.
+     */
+    event Transfer(address indexed from, address indexed to, uint256 value);
+
+    /**
+     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+     * a call to {approve}. `value` is the new allowance.
+     */
+    event Approval(address indexed owner, address indexed spender, uint256 value);
+
+    /**
+     * @dev Returns the amount of tokens in existence.
+     */
+    function totalSupply() external view returns (uint256);
+
+    /**
+     * @dev Returns the amount of tokens owned by `account`.
+     */
+    function balanceOf(address account) external view returns (uint256);
+
+    /**
+     * @dev Moves `amount` tokens from the caller's account to `to`.
+     *
+     * Returns a boolean value indicating whether the operation succeeded.
+     *
+     * Emits a {Transfer} event.
+     */
+    function transfer(address to, uint256 amount) external returns (bool);
+
+    /**
+     * @dev Returns the remaining number of tokens that `spender` will be
+     * allowed to spend on behalf of `owner` through {transferFrom}. This is
+     * zero by default.
+     *
+     * This value changes when {approve} or {transferFrom} are called.
+     */
+    function allowance(address owner, address spender) external view returns (uint256);
+
+    /**
+     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
+     *
+     * Returns a boolean value indicating whether the operation succeeded.
+     *
+     * IMPORTANT: Beware that changing an allowance with this method brings the risk
+     * that someone may use both the old and the new allowance by unfortunate
+     * transaction ordering. One possible solution to mitigate this race
+     * condition is to first reduce the spender's allowance to 0 and set the
+     * desired value afterwards:
+     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+     *
+     * Emits an {Approval} event.
+     */
+    function approve(address spender, uint256 amount) external returns (bool);
+
+    /**
+     * @dev Moves `amount` tokens from `from` to `to` using the
+     * allowance mechanism. `amount` is then deducted from the caller's
+     * allowance.
+     *
+     * Returns a boolean value indicating whether the operation succeeded.
+     *
+     * Emits a {Transfer} event.
+     */
+    function transferFrom(
+        address from,
+        address to,
+        uint256 amount
+    ) external returns (bool);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC20.sol";
+import "../../../utils/Context.sol";
+
+/**
+ * @dev Extension of {ERC20} that allows token holders to destroy both their own
+ * tokens and those that they have an allowance for, in a way that can be
+ * recognized off-chain (via event analysis).
+ */
+abstract contract ERC20Burnable is Context, ERC20 {
+    /**
+     * @dev Destroys `amount` tokens from the caller.
+     *
+     * See {ERC20-_burn}.
+     */
+    function burn(uint256 amount) public virtual {
+        _burn(_msgSender(), amount);
+    }
+
+    /**
+     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
+     * allowance.
+     *
+     * See {ERC20-_burn} and {ERC20-allowance}.
+     *
+     * Requirements:
+     *
+     * - the caller must have allowance for ``accounts``'s tokens of at least
+     * `amount`.
+     */
+    function burnFrom(address account, uint256 amount) public virtual {
+        _spendAllowance(account, _msgSender(), amount);
+        _burn(account, amount);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20FlashMint.sol)
+
+pragma solidity ^0.8.0;
+
+import "../../../interfaces/IERC3156FlashBorrower.sol";
+import "../../../interfaces/IERC3156FlashLender.sol";
+import "../ERC20.sol";
+
+/**
+ * @dev Implementation of the ERC3156 Flash loans extension, as defined in
+ * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
+ *
+ * Adds the {flashLoan} method, which provides flash loan support at the token
+ * level. By default there is no fee, but this can be changed by overriding {flashFee}.
+ *
+ * _Available since v4.1._
+ */
+abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
+    bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
+
+    /**
+     * @dev Returns the maximum amount of tokens available for loan.
+     * @param token The address of the token that is requested.
+     * @return The amount of token that can be loaned.
+     */
+    function maxFlashLoan(address token) public view virtual override returns (uint256) {
+        return token == address(this) ? type(uint256).max - ERC20.totalSupply() : 0;
+    }
+
+    /**
+     * @dev Returns the fee applied when doing flash loans. This function calls
+     * the {_flashFee} function which returns the fee applied when doing flash
+     * loans.
+     * @param token The token to be flash loaned.
+     * @param amount The amount of tokens to be loaned.
+     * @return The fees applied to the corresponding flash loan.
+     */
+    function flashFee(address token, uint256 amount) public view virtual override returns (uint256) {
+        require(token == address(this), "ERC20FlashMint: wrong token");
+        return _flashFee(token, amount);
+    }
+
+    /**
+     * @dev Returns the fee applied when doing flash loans. By default this
+     * implementation has 0 fees. This function can be overloaded to make
+     * the flash loan mechanism deflationary.
+     * @param token The token to be flash loaned.
+     * @param amount The amount of tokens to be loaned.
+     * @return The fees applied to the corresponding flash loan.
+     */
+    function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) {
+        // silence warning about unused variable without the addition of bytecode.
+        token;
+        amount;
+        return 0;
+    }
+
+    /**
+     * @dev Returns the receiver address of the flash fee. By default this
+     * implementation returns the address(0) which means the fee amount will be burnt.
+     * This function can be overloaded to change the fee receiver.
+     * @return The address for which the flash fee will be sent to.
+     */
+    function _flashFeeReceiver() internal view virtual returns (address) {
+        return address(0);
+    }
+
+    /**
+     * @dev Performs a flash loan. New tokens are minted and sent to the
+     * `receiver`, who is required to implement the {IERC3156FlashBorrower}
+     * interface. By the end of the flash loan, the receiver is expected to own
+     * amount + fee tokens and have them approved back to the token contract itself so
+     * they can be burned.
+     * @param receiver The receiver of the flash loan. Should implement the
+     * {IERC3156FlashBorrower-onFlashLoan} interface.
+     * @param token The token to be flash loaned. Only `address(this)` is
+     * supported.
+     * @param amount The amount of tokens to be loaned.
+     * @param data An arbitrary datafield that is passed to the receiver.
+     * @return `true` if the flash loan was successful.
+     */
+    // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount
+    // minted at the beginning is always recovered and burned at the end, or else the entire function will revert.
+    // slither-disable-next-line reentrancy-no-eth
+    function flashLoan(
+        IERC3156FlashBorrower receiver,
+        address token,
+        uint256 amount,
+        bytes calldata data
+    ) public virtual override returns (bool) {
+        require(amount <= maxFlashLoan(token), "ERC20FlashMint: amount exceeds maxFlashLoan");
+        uint256 fee = flashFee(token, amount);
+        _mint(address(receiver), amount);
+        require(
+            receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE,
+            "ERC20FlashMint: invalid return value"
+        );
+        address flashFeeReceiver = _flashFeeReceiver();
+        _spendAllowance(address(receiver), address(this), amount + fee);
+        if (fee == 0 || flashFeeReceiver == address(0)) {
+            _burn(address(receiver), amount + fee);
+        } else {
+            _burn(address(receiver), amount);
+            _transfer(address(receiver), flashFeeReceiver, fee);
+        }
+        return true;
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC20Votes.sol)
+
+pragma solidity ^0.8.0;
+
+import "./draft-ERC20Permit.sol";
+import "../../../utils/math/Math.sol";
+import "../../../governance/utils/IVotes.sol";
+import "../../../utils/math/SafeCast.sol";
+import "../../../utils/cryptography/ECDSA.sol";
+
+/**
+ * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
+ * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
+ *
+ * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
+ *
+ * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
+ * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
+ * power can be queried through the public accessors {getVotes} and {getPastVotes}.
+ *
+ * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
+ * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
+ *
+ * _Available since v4.2._
+ */
+abstract contract ERC20Votes is IVotes, ERC20Permit {
+    struct Checkpoint {
+        uint32 fromBlock;
+        uint224 votes;
+    }
+
+    bytes32 private constant _DELEGATION_TYPEHASH =
+        keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
+
+    mapping(address => address) private _delegates;
+    mapping(address => Checkpoint[]) private _checkpoints;
+    Checkpoint[] private _totalSupplyCheckpoints;
+
+    /**
+     * @dev Get the `pos`-th checkpoint for `account`.
+     */
+    function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
+        return _checkpoints[account][pos];
+    }
+
+    /**
+     * @dev Get number of checkpoints for `account`.
+     */
+    function numCheckpoints(address account) public view virtual returns (uint32) {
+        return SafeCast.toUint32(_checkpoints[account].length);
+    }
+
+    /**
+     * @dev Get the address `account` is currently delegating to.
+     */
+    function delegates(address account) public view virtual override returns (address) {
+        return _delegates[account];
+    }
+
+    /**
+     * @dev Gets the current votes balance for `account`
+     */
+    function getVotes(address account) public view virtual override returns (uint256) {
+        uint256 pos = _checkpoints[account].length;
+        return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
+    }
+
+    /**
+     * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
+     *
+     * Requirements:
+     *
+     * - `blockNumber` must have been already mined
+     */
+    function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
+        require(blockNumber < block.number, "ERC20Votes: block not yet mined");
+        return _checkpointsLookup(_checkpoints[account], blockNumber);
+    }
+
+    /**
+     * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
+     * It is but NOT the sum of all the delegated votes!
+     *
+     * Requirements:
+     *
+     * - `blockNumber` must have been already mined
+     */
+    function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
+        require(blockNumber < block.number, "ERC20Votes: block not yet mined");
+        return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
+    }
+
+    /**
+     * @dev Lookup a value in a list of (sorted) checkpoints.
+     */
+    function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
+        // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
+        //
+        // Initially we check if the block is recent to narrow the search range.
+        // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
+        // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
+        // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
+        // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
+        // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
+        // out of bounds (in which case we're looking too far in the past and the result is 0).
+        // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
+        // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
+        // the same.
+        uint256 length = ckpts.length;
+
+        uint256 low = 0;
+        uint256 high = length;
+
+        if (length > 5) {
+            uint256 mid = length - Math.sqrt(length);
+            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
+                high = mid;
+            } else {
+                low = mid + 1;
+            }
+        }
+
+        while (low < high) {
+            uint256 mid = Math.average(low, high);
+            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
+                high = mid;
+            } else {
+                low = mid + 1;
+            }
+        }
+
+        return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
+    }
+
+    /**
+     * @dev Delegate votes from the sender to `delegatee`.
+     */
+    function delegate(address delegatee) public virtual override {
+        _delegate(_msgSender(), delegatee);
+    }
+
+    /**
+     * @dev Delegates votes from signer to `delegatee`
+     */
+    function delegateBySig(
+        address delegatee,
+        uint256 nonce,
+        uint256 expiry,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) public virtual override {
+        require(block.timestamp <= expiry, "ERC20Votes: signature expired");
+        address signer = ECDSA.recover(
+            _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
+            v,
+            r,
+            s
+        );
+        require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
+        _delegate(signer, delegatee);
+    }
+
+    /**
+     * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
+     */
+    function _maxSupply() internal view virtual returns (uint224) {
+        return type(uint224).max;
+    }
+
+    /**
+     * @dev Snapshots the totalSupply after it has been increased.
+     */
+    function _mint(address account, uint256 amount) internal virtual override {
+        super._mint(account, amount);
+        require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
+
+        _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
+    }
+
+    /**
+     * @dev Snapshots the totalSupply after it has been decreased.
+     */
+    function _burn(address account, uint256 amount) internal virtual override {
+        super._burn(account, amount);
+
+        _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
+    }
+
+    /**
+     * @dev Move voting power when tokens are transferred.
+     *
+     * Emits a {IVotes-DelegateVotesChanged} event.
+     */
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 amount
+    ) internal virtual override {
+        super._afterTokenTransfer(from, to, amount);
+
+        _moveVotingPower(delegates(from), delegates(to), amount);
+    }
+
+    /**
+     * @dev Change delegation for `delegator` to `delegatee`.
+     *
+     * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
+     */
+    function _delegate(address delegator, address delegatee) internal virtual {
+        address currentDelegate = delegates(delegator);
+        uint256 delegatorBalance = balanceOf(delegator);
+        _delegates[delegator] = delegatee;
+
+        emit DelegateChanged(delegator, currentDelegate, delegatee);
+
+        _moveVotingPower(currentDelegate, delegatee, delegatorBalance);
+    }
+
+    function _moveVotingPower(
+        address src,
+        address dst,
+        uint256 amount
+    ) private {
+        if (src != dst && amount > 0) {
+            if (src != address(0)) {
+                (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
+                emit DelegateVotesChanged(src, oldWeight, newWeight);
+            }
+
+            if (dst != address(0)) {
+                (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
+                emit DelegateVotesChanged(dst, oldWeight, newWeight);
+            }
+        }
+    }
+
+    function _writeCheckpoint(
+        Checkpoint[] storage ckpts,
+        function(uint256, uint256) view returns (uint256) op,
+        uint256 delta
+    ) private returns (uint256 oldWeight, uint256 newWeight) {
+        uint256 pos = ckpts.length;
+
+        Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
+
+        oldWeight = oldCkpt.votes;
+        newWeight = op(oldWeight, delta);
+
+        if (pos > 0 && oldCkpt.fromBlock == block.number) {
+            _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
+        } else {
+            ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));
+        }
+    }
+
+    function _add(uint256 a, uint256 b) private pure returns (uint256) {
+        return a + b;
+    }
+
+    function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
+        return a - b;
+    }
+
+    /**
+     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
+     */
+    function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
+        assembly {
+            mstore(0, ckpts.slot)
+            result.slot := add(keccak256(0, 0x20), pos)
+        }
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
+
+pragma solidity ^0.8.0;
+
+import "../IERC20.sol";
+
+/**
+ * @dev Interface for the optional metadata functions from the ERC20 standard.
+ *
+ * _Available since v4.1._
+ */
+interface IERC20Metadata is IERC20 {
+    /**
+     * @dev Returns the name of the token.
+     */
+    function name() external view returns (string memory);
+
+    /**
+     * @dev Returns the symbol of the token.
+     */
+    function symbol() external view returns (string memory);
+
+    /**
+     * @dev Returns the decimals places of the token.
+     */
+    function decimals() external view returns (uint8);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)
+
+pragma solidity ^0.8.0;
+
+import "./draft-IERC20Permit.sol";
+import "../ERC20.sol";
+import "../../../utils/cryptography/ECDSA.sol";
+import "../../../utils/cryptography/EIP712.sol";
+import "../../../utils/Counters.sol";
+
+/**
+ * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ *
+ * _Available since v3.4._
+ */
+abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
+    using Counters for Counters.Counter;
+
+    mapping(address => Counters.Counter) private _nonces;
+
+    // solhint-disable-next-line var-name-mixedcase
+    bytes32 private constant _PERMIT_TYPEHASH =
+        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
+    /**
+     * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.
+     * However, to ensure consistency with the upgradeable transpiler, we will continue
+     * to reserve a slot.
+     * @custom:oz-renamed-from _PERMIT_TYPEHASH
+     */
+    // solhint-disable-next-line var-name-mixedcase
+    bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
+
+    /**
+     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
+     *
+     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
+     */
+    constructor(string memory name) EIP712(name, "1") {}
+
+    /**
+     * @dev See {IERC20Permit-permit}.
+     */
+    function permit(
+        address owner,
+        address spender,
+        uint256 value,
+        uint256 deadline,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) public virtual override {
+        require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
+
+        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
+
+        bytes32 hash = _hashTypedDataV4(structHash);
+
+        address signer = ECDSA.recover(hash, v, r, s);
+        require(signer == owner, "ERC20Permit: invalid signature");
+
+        _approve(owner, spender, value);
+    }
+
+    /**
+     * @dev See {IERC20Permit-nonces}.
+     */
+    function nonces(address owner) public view virtual override returns (uint256) {
+        return _nonces[owner].current();
+    }
+
+    /**
+     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
+     */
+    // solhint-disable-next-line func-name-mixedcase
+    function DOMAIN_SEPARATOR() external view override returns (bytes32) {
+        return _domainSeparatorV4();
+    }
+
+    /**
+     * @dev "Consume a nonce": return the current value and increment.
+     *
+     * _Available since v4.1._
+     */
+    function _useNonce(address owner) internal virtual returns (uint256 current) {
+        Counters.Counter storage nonce = _nonces[owner];
+        current = nonce.current();
+        nonce.increment();
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ */
+interface IERC20Permit {
+    /**
+     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+     * given ``owner``'s signed approval.
+     *
+     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
+     * ordering also apply here.
+     *
+     * Emits an {Approval} event.
+     *
+     * Requirements:
+     *
+     * - `spender` cannot be the zero address.
+     * - `deadline` must be a timestamp in the future.
+     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+     * over the EIP712-formatted function arguments.
+     * - the signature must use ``owner``'s current nonce (see {nonces}).
+     *
+     * For more information on the signature format, see the
+     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+     * section].
+     */
+    function permit(
+        address owner,
+        address spender,
+        uint256 value,
+        uint256 deadline,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) external;
+
+    /**
+     * @dev Returns the current nonce for `owner`. This value must be
+     * included whenever a signature is generated for {permit}.
+     *
+     * Every successful call to {permit} increases ``owner``'s nonce by one. This
+     * prevents a signature from being used multiple times.
+     */
+    function nonces(address owner) external view returns (uint256);
+
+    /**
+     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+     */
+    // solhint-disable-next-line func-name-mixedcase
+    function DOMAIN_SEPARATOR() external view returns (bytes32);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Context.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+    function _msgSender() internal view virtual returns (address) {
+        return msg.sender;
+    }
+
+    function _msgData() internal view virtual returns (bytes calldata) {
+        return msg.data;
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Counters.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @title Counters
+ * @author Matt Condon (@shrugs)
+ * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
+ * of elements in a mapping, issuing ERC721 ids, or counting request ids.
+ *
+ * Include with `using Counters for Counters.Counter;`
+ */
+library Counters {
+    struct Counter {
+        // This variable should never be directly accessed by users of the library: interactions must be restricted to
+        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
+        // this feature: see https://github.com/ethereum/solidity/issues/4637
+        uint256 _value; // default: 0
+    }
+
+    function current(Counter storage counter) internal view returns (uint256) {
+        return counter._value;
+    }
+
+    function increment(Counter storage counter) internal {
+        unchecked {
+            counter._value += 1;
+        }
+    }
+
+    function decrement(Counter storage counter) internal {
+        uint256 value = counter._value;
+        require(value > 0, "Counter: decrement overflow");
+        unchecked {
+            counter._value = value - 1;
+        }
+    }
+
+    function reset(Counter storage counter) internal {
+        counter._value = 0;
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/Strings.sol
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
+
+pragma solidity ^0.8.0;
+
+import "./math/Math.sol";
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+    bytes16 private constant _SYMBOLS = "0123456789abcdef";
+    uint8 private constant _ADDRESS_LENGTH = 20;
+
+    /**
+     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+     */
+    function toString(uint256 value) internal pure returns (string memory) {
+        unchecked {
+            uint256 length = Math.log10(value) + 1;
+            string memory buffer = new string(length);
+            uint256 ptr;
+            /// @solidity memory-safe-assembly
+            assembly {
+                ptr := add(buffer, add(32, length))
+            }
+            while (true) {
+                ptr--;
+                /// @solidity memory-safe-assembly
+                assembly {
+                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+                }
+                value /= 10;
+                if (value == 0) break;
+            }
+            return buffer;
+        }
+    }
+
+    /**
+     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+     */
+    function toHexString(uint256 value) internal pure returns (string memory) {
+        unchecked {
+            return toHexString(value, Math.log256(value) + 1);
+        }
+    }
+
+    /**
+     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+     */
+    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+        bytes memory buffer = new bytes(2 * length + 2);
+        buffer[0] = "0";
+        buffer[1] = "x";
+        for (uint256 i = 2 * length + 1; i > 1; --i) {
+            buffer[i] = _SYMBOLS[value & 0xf];
+            value >>= 4;
+        }
+        require(value == 0, "Strings: hex length insufficient");
+        return string(buffer);
+    }
+
+    /**
+     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
+     */
+    function toHexString(address addr) internal pure returns (string memory) {
+        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/ECDSA.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/ECDSA.sol
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
+
+pragma solidity ^0.8.0;
+
+import "../Strings.sol";
+
+/**
+ * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
+ *
+ * These functions can be used to verify that a message was signed by the holder
+ * of the private keys of a given address.
+ */
+library ECDSA {
+    enum RecoverError {
+        NoError,
+        InvalidSignature,
+        InvalidSignatureLength,
+        InvalidSignatureS,
+        InvalidSignatureV // Deprecated in v4.8
+    }
+
+    function _throwError(RecoverError error) private pure {
+        if (error == RecoverError.NoError) {
+            return; // no error: do nothing
+        } else if (error == RecoverError.InvalidSignature) {
+            revert("ECDSA: invalid signature");
+        } else if (error == RecoverError.InvalidSignatureLength) {
+            revert("ECDSA: invalid signature length");
+        } else if (error == RecoverError.InvalidSignatureS) {
+            revert("ECDSA: invalid signature 's' value");
+        }
+    }
+
+    /**
+     * @dev Returns the address that signed a hashed message (`hash`) with
+     * `signature` or error string. This address can then be used for verification purposes.
+     *
+     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+     * this function rejects them by requiring the `s` value to be in the lower
+     * half order, and the `v` value to be either 27 or 28.
+     *
+     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+     * verification to be secure: it is possible to craft signatures that
+     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+     * this is by receiving a hash of the original message (which may otherwise
+     * be too long), and then calling {toEthSignedMessageHash} on it.
+     *
+     * Documentation for signature generation:
+     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
+     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
+     *
+     * _Available since v4.3._
+     */
+    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
+        if (signature.length == 65) {
+            bytes32 r;
+            bytes32 s;
+            uint8 v;
+            // ecrecover takes the signature parameters, and the only way to get them
+            // currently is to use assembly.
+            /// @solidity memory-safe-assembly
+            assembly {
+                r := mload(add(signature, 0x20))
+                s := mload(add(signature, 0x40))
+                v := byte(0, mload(add(signature, 0x60)))
+            }
+            return tryRecover(hash, v, r, s);
+        } else {
+            return (address(0), RecoverError.InvalidSignatureLength);
+        }
+    }
+
+    /**
+     * @dev Returns the address that signed a hashed message (`hash`) with
+     * `signature`. This address can then be used for verification purposes.
+     *
+     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
+     * this function rejects them by requiring the `s` value to be in the lower
+     * half order, and the `v` value to be either 27 or 28.
+     *
+     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+     * verification to be secure: it is possible to craft signatures that
+     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+     * this is by receiving a hash of the original message (which may otherwise
+     * be too long), and then calling {toEthSignedMessageHash} on it.
+     */
+    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
+        (address recovered, RecoverError error) = tryRecover(hash, signature);
+        _throwError(error);
+        return recovered;
+    }
+
+    /**
+     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
+     *
+     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
+     *
+     * _Available since v4.3._
+     */
+    function tryRecover(
+        bytes32 hash,
+        bytes32 r,
+        bytes32 vs
+    ) internal pure returns (address, RecoverError) {
+        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
+        uint8 v = uint8((uint256(vs) >> 255) + 27);
+        return tryRecover(hash, v, r, s);
+    }
+
+    /**
+     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
+     *
+     * _Available since v4.2._
+     */
+    function recover(
+        bytes32 hash,
+        bytes32 r,
+        bytes32 vs
+    ) internal pure returns (address) {
+        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
+        _throwError(error);
+        return recovered;
+    }
+
+    /**
+     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
+     * `r` and `s` signature fields separately.
+     *
+     * _Available since v4.3._
+     */
+    function tryRecover(
+        bytes32 hash,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) internal pure returns (address, RecoverError) {
+        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
+        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
+        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
+        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
+        //
+        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
+        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
+        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
+        // these malleable signatures as well.
+        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
+            return (address(0), RecoverError.InvalidSignatureS);
+        }
+
+        // If the signature is valid (and not malleable), return the signer address
+        address signer = ecrecover(hash, v, r, s);
+        if (signer == address(0)) {
+            return (address(0), RecoverError.InvalidSignature);
+        }
+
+        return (signer, RecoverError.NoError);
+    }
+
+    /**
+     * @dev Overload of {ECDSA-recover} that receives the `v`,
+     * `r` and `s` signature fields separately.
+     */
+    function recover(
+        bytes32 hash,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) internal pure returns (address) {
+        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
+        _throwError(error);
+        return recovered;
+    }
+
+    /**
+     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
+     * produces hash corresponding to the one signed with the
+     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+     * JSON-RPC method as part of EIP-191.
+     *
+     * See {recover}.
+     */
+    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
+        // 32 is the length in bytes of hash,
+        // enforced by the type signature above
+        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
+    }
+
+    /**
+     * @dev Returns an Ethereum Signed Message, created from `s`. This
+     * produces hash corresponding to the one signed with the
+     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
+     * JSON-RPC method as part of EIP-191.
+     *
+     * See {recover}.
+     */
+    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
+        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
+    }
+
+    /**
+     * @dev Returns an Ethereum Signed Typed Data, created from a
+     * `domainSeparator` and a `structHash`. This produces hash corresponding
+     * to the one signed with the
+     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
+     * JSON-RPC method as part of EIP-712.
+     *
+     * See {recover}.
+     */
+    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
+        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/EIP712.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/cryptography/EIP712.sol
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
+
+pragma solidity ^0.8.0;
+
+import "./ECDSA.sol";
+
+/**
+ * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
+ *
+ * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
+ * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
+ * they need in their contracts using a combination of `abi.encode` and `keccak256`.
+ *
+ * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
+ * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
+ * ({_hashTypedDataV4}).
+ *
+ * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
+ * the chain id to protect against replay attacks on an eventual fork of the chain.
+ *
+ * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
+ * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
+ *
+ * _Available since v3.4._
+ */
+abstract contract EIP712 {
+    /* solhint-disable var-name-mixedcase */
+    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
+    // invalidate the cached domain separator if the chain id changes.
+    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
+    uint256 private immutable _CACHED_CHAIN_ID;
+    address private immutable _CACHED_THIS;
+
+    bytes32 private immutable _HASHED_NAME;
+    bytes32 private immutable _HASHED_VERSION;
+    bytes32 private immutable _TYPE_HASH;
+
+    /* solhint-enable var-name-mixedcase */
+
+    /**
+     * @dev Initializes the domain separator and parameter caches.
+     *
+     * The meaning of `name` and `version` is specified in
+     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
+     *
+     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
+     * - `version`: the current major version of the signing domain.
+     *
+     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
+     * contract upgrade].
+     */
+    constructor(string memory name, string memory version) {
+        bytes32 hashedName = keccak256(bytes(name));
+        bytes32 hashedVersion = keccak256(bytes(version));
+        bytes32 typeHash = keccak256(
+            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
+        );
+        _HASHED_NAME = hashedName;
+        _HASHED_VERSION = hashedVersion;
+        _CACHED_CHAIN_ID = block.chainid;
+        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
+        _CACHED_THIS = address(this);
+        _TYPE_HASH = typeHash;
+    }
+
+    /**
+     * @dev Returns the domain separator for the current chain.
+     */
+    function _domainSeparatorV4() internal view returns (bytes32) {
+        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
+            return _CACHED_DOMAIN_SEPARATOR;
+        } else {
+            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
+        }
+    }
+
+    function _buildDomainSeparator(
+        bytes32 typeHash,
+        bytes32 nameHash,
+        bytes32 versionHash
+    ) private view returns (bytes32) {
+        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
+    }
+
+    /**
+     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
+     * function returns the hash of the fully encoded EIP712 message for this domain.
+     *
+     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
+     *
+     * ```solidity
+     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
+     *     keccak256("Mail(address to,string contents)"),
+     *     mailTo,
+     *     keccak256(bytes(mailContents))
+     * )));
+     * address signer = ECDSA.recover(digest, signature);
+     * ```
+     */
+    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
+        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/Math.sol
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+    enum Rounding {
+        Down, // Toward negative infinity
+        Up, // Toward infinity
+        Zero // Toward zero
+    }
+
+    /**
+     * @dev Returns the largest of two numbers.
+     */
+    function max(uint256 a, uint256 b) internal pure returns (uint256) {
+        return a > b ? a : b;
+    }
+
+    /**
+     * @dev Returns the smallest of two numbers.
+     */
+    function min(uint256 a, uint256 b) internal pure returns (uint256) {
+        return a < b ? a : b;
+    }
+
+    /**
+     * @dev Returns the average of two numbers. The result is rounded towards
+     * zero.
+     */
+    function average(uint256 a, uint256 b) internal pure returns (uint256) {
+        // (a + b) / 2 can overflow.
+        return (a & b) + (a ^ b) / 2;
+    }
+
+    /**
+     * @dev Returns the ceiling of the division of two numbers.
+     *
+     * This differs from standard division with `/` in that it rounds up instead
+     * of rounding down.
+     */
+    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+        // (a + b - 1) / b can overflow on addition, so we distribute.
+        return a == 0 ? 0 : (a - 1) / b + 1;
+    }
+
+    /**
+     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
+     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
+     * with further edits by Uniswap Labs also under MIT license.
+     */
+    function mulDiv(
+        uint256 x,
+        uint256 y,
+        uint256 denominator
+    ) internal pure returns (uint256 result) {
+        unchecked {
+            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+            // variables such that product = prod1 * 2^256 + prod0.
+            uint256 prod0; // Least significant 256 bits of the product
+            uint256 prod1; // Most significant 256 bits of the product
+            assembly {
+                let mm := mulmod(x, y, not(0))
+                prod0 := mul(x, y)
+                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+            }
+
+            // Handle non-overflow cases, 256 by 256 division.
+            if (prod1 == 0) {
+                return prod0 / denominator;
+            }
+
+            // Make sure the result is less than 2^256. Also prevents denominator == 0.
+            require(denominator > prod1);
+
+            ///////////////////////////////////////////////
+            // 512 by 256 division.
+            ///////////////////////////////////////////////
+
+            // Make division exact by subtracting the remainder from [prod1 prod0].
+            uint256 remainder;
+            assembly {
+                // Compute remainder using mulmod.
+                remainder := mulmod(x, y, denominator)
+
+                // Subtract 256 bit number from 512 bit number.
+                prod1 := sub(prod1, gt(remainder, prod0))
+                prod0 := sub(prod0, remainder)
+            }
+
+            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
+            // See https://cs.stackexchange.com/q/138556/92363.
+
+            // Does not overflow because the denominator cannot be zero at this stage in the function.
+            uint256 twos = denominator & (~denominator + 1);
+            assembly {
+                // Divide denominator by twos.
+                denominator := div(denominator, twos)
+
+                // Divide [prod1 prod0] by twos.
+                prod0 := div(prod0, twos)
+
+                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+                twos := add(div(sub(0, twos), twos), 1)
+            }
+
+            // Shift in bits from prod1 into prod0.
+            prod0 |= prod1 * twos;
+
+            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+            // four bits. That is, denominator * inv = 1 mod 2^4.
+            uint256 inverse = (3 * denominator) ^ 2;
+
+            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
+            // in modular arithmetic, doubling the correct bits in each step.
+            inverse *= 2 - denominator * inverse; // inverse mod 2^8
+            inverse *= 2 - denominator * inverse; // inverse mod 2^16
+            inverse *= 2 - denominator * inverse; // inverse mod 2^32
+            inverse *= 2 - denominator * inverse; // inverse mod 2^64
+            inverse *= 2 - denominator * inverse; // inverse mod 2^128
+            inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+            // is no longer required.
+            result = prod0 * inverse;
+            return result;
+        }
+    }
+
+    /**
+     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+     */
+    function mulDiv(
+        uint256 x,
+        uint256 y,
+        uint256 denominator,
+        Rounding rounding
+    ) internal pure returns (uint256) {
+        uint256 result = mulDiv(x, y, denominator);
+        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
+            result += 1;
+        }
+        return result;
+    }
+
+    /**
+     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
+     *
+     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+     */
+    function sqrt(uint256 a) internal pure returns (uint256) {
+        if (a == 0) {
+            return 0;
+        }
+
+        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+        //
+        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+        //
+        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+        //
+        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+        uint256 result = 1 << (log2(a) >> 1);
+
+        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+        // into the expected uint128 result.
+        unchecked {
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            return min(result, a / result);
+        }
+    }
+
+    /**
+     * @notice Calculates sqrt(a), following the selected rounding direction.
+     */
+    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = sqrt(a);
+            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 2, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log2(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >> 128 > 0) {
+                value >>= 128;
+                result += 128;
+            }
+            if (value >> 64 > 0) {
+                value >>= 64;
+                result += 64;
+            }
+            if (value >> 32 > 0) {
+                value >>= 32;
+                result += 32;
+            }
+            if (value >> 16 > 0) {
+                value >>= 16;
+                result += 16;
+            }
+            if (value >> 8 > 0) {
+                value >>= 8;
+                result += 8;
+            }
+            if (value >> 4 > 0) {
+                value >>= 4;
+                result += 4;
+            }
+            if (value >> 2 > 0) {
+                value >>= 2;
+                result += 2;
+            }
+            if (value >> 1 > 0) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log2(value);
+            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 10, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log10(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >= 10**64) {
+                value /= 10**64;
+                result += 64;
+            }
+            if (value >= 10**32) {
+                value /= 10**32;
+                result += 32;
+            }
+            if (value >= 10**16) {
+                value /= 10**16;
+                result += 16;
+            }
+            if (value >= 10**8) {
+                value /= 10**8;
+                result += 8;
+            }
+            if (value >= 10**4) {
+                value /= 10**4;
+                result += 4;
+            }
+            if (value >= 10**2) {
+                value /= 10**2;
+                result += 2;
+            }
+            if (value >= 10**1) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log10(value);
+            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 256, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     *
+     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+     */
+    function log256(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >> 128 > 0) {
+                value >>= 128;
+                result += 16;
+            }
+            if (value >> 64 > 0) {
+                value >>= 64;
+                result += 8;
+            }
+            if (value >> 32 > 0) {
+                value >>= 32;
+                result += 4;
+            }
+            if (value >> 16 > 0) {
+                value >>= 16;
+                result += 2;
+            }
+            if (value >> 8 > 0) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log256(value);
+            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
+        }
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/SafeCast.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/@openzeppelin/contracts/utils/math/SafeCast.sol
@@ -0,0 +1,1136 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
+// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
+ * checks.
+ *
+ * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
+ * easily result in undesired exploitation or bugs, since developers usually
+ * assume that overflows raise errors. `SafeCast` restores this intuition by
+ * reverting the transaction when such an operation overflows.
+ *
+ * Using this library instead of the unchecked operations eliminates an entire
+ * class of bugs, so it's recommended to use it always.
+ *
+ * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
+ * all math on `uint256` and `int256` and then downcasting.
+ */
+library SafeCast {
+    /**
+     * @dev Returns the downcasted uint248 from uint256, reverting on
+     * overflow (when the input is greater than largest uint248).
+     *
+     * Counterpart to Solidity's `uint248` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 248 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint248(uint256 value) internal pure returns (uint248) {
+        require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
+        return uint248(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint240 from uint256, reverting on
+     * overflow (when the input is greater than largest uint240).
+     *
+     * Counterpart to Solidity's `uint240` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 240 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint240(uint256 value) internal pure returns (uint240) {
+        require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
+        return uint240(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint232 from uint256, reverting on
+     * overflow (when the input is greater than largest uint232).
+     *
+     * Counterpart to Solidity's `uint232` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 232 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint232(uint256 value) internal pure returns (uint232) {
+        require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
+        return uint232(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint224 from uint256, reverting on
+     * overflow (when the input is greater than largest uint224).
+     *
+     * Counterpart to Solidity's `uint224` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 224 bits
+     *
+     * _Available since v4.2._
+     */
+    function toUint224(uint256 value) internal pure returns (uint224) {
+        require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
+        return uint224(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint216 from uint256, reverting on
+     * overflow (when the input is greater than largest uint216).
+     *
+     * Counterpart to Solidity's `uint216` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 216 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint216(uint256 value) internal pure returns (uint216) {
+        require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
+        return uint216(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint208 from uint256, reverting on
+     * overflow (when the input is greater than largest uint208).
+     *
+     * Counterpart to Solidity's `uint208` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 208 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint208(uint256 value) internal pure returns (uint208) {
+        require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
+        return uint208(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint200 from uint256, reverting on
+     * overflow (when the input is greater than largest uint200).
+     *
+     * Counterpart to Solidity's `uint200` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 200 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint200(uint256 value) internal pure returns (uint200) {
+        require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
+        return uint200(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint192 from uint256, reverting on
+     * overflow (when the input is greater than largest uint192).
+     *
+     * Counterpart to Solidity's `uint192` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 192 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint192(uint256 value) internal pure returns (uint192) {
+        require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
+        return uint192(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint184 from uint256, reverting on
+     * overflow (when the input is greater than largest uint184).
+     *
+     * Counterpart to Solidity's `uint184` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 184 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint184(uint256 value) internal pure returns (uint184) {
+        require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
+        return uint184(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint176 from uint256, reverting on
+     * overflow (when the input is greater than largest uint176).
+     *
+     * Counterpart to Solidity's `uint176` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 176 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint176(uint256 value) internal pure returns (uint176) {
+        require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
+        return uint176(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint168 from uint256, reverting on
+     * overflow (when the input is greater than largest uint168).
+     *
+     * Counterpart to Solidity's `uint168` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 168 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint168(uint256 value) internal pure returns (uint168) {
+        require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
+        return uint168(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint160 from uint256, reverting on
+     * overflow (when the input is greater than largest uint160).
+     *
+     * Counterpart to Solidity's `uint160` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 160 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint160(uint256 value) internal pure returns (uint160) {
+        require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
+        return uint160(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint152 from uint256, reverting on
+     * overflow (when the input is greater than largest uint152).
+     *
+     * Counterpart to Solidity's `uint152` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 152 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint152(uint256 value) internal pure returns (uint152) {
+        require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
+        return uint152(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint144 from uint256, reverting on
+     * overflow (when the input is greater than largest uint144).
+     *
+     * Counterpart to Solidity's `uint144` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 144 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint144(uint256 value) internal pure returns (uint144) {
+        require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
+        return uint144(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint136 from uint256, reverting on
+     * overflow (when the input is greater than largest uint136).
+     *
+     * Counterpart to Solidity's `uint136` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 136 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint136(uint256 value) internal pure returns (uint136) {
+        require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
+        return uint136(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint128 from uint256, reverting on
+     * overflow (when the input is greater than largest uint128).
+     *
+     * Counterpart to Solidity's `uint128` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 128 bits
+     *
+     * _Available since v2.5._
+     */
+    function toUint128(uint256 value) internal pure returns (uint128) {
+        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
+        return uint128(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint120 from uint256, reverting on
+     * overflow (when the input is greater than largest uint120).
+     *
+     * Counterpart to Solidity's `uint120` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 120 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint120(uint256 value) internal pure returns (uint120) {
+        require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
+        return uint120(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint112 from uint256, reverting on
+     * overflow (when the input is greater than largest uint112).
+     *
+     * Counterpart to Solidity's `uint112` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 112 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint112(uint256 value) internal pure returns (uint112) {
+        require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
+        return uint112(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint104 from uint256, reverting on
+     * overflow (when the input is greater than largest uint104).
+     *
+     * Counterpart to Solidity's `uint104` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 104 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint104(uint256 value) internal pure returns (uint104) {
+        require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
+        return uint104(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint96 from uint256, reverting on
+     * overflow (when the input is greater than largest uint96).
+     *
+     * Counterpart to Solidity's `uint96` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 96 bits
+     *
+     * _Available since v4.2._
+     */
+    function toUint96(uint256 value) internal pure returns (uint96) {
+        require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
+        return uint96(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint88 from uint256, reverting on
+     * overflow (when the input is greater than largest uint88).
+     *
+     * Counterpart to Solidity's `uint88` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 88 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint88(uint256 value) internal pure returns (uint88) {
+        require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
+        return uint88(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint80 from uint256, reverting on
+     * overflow (when the input is greater than largest uint80).
+     *
+     * Counterpart to Solidity's `uint80` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 80 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint80(uint256 value) internal pure returns (uint80) {
+        require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
+        return uint80(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint72 from uint256, reverting on
+     * overflow (when the input is greater than largest uint72).
+     *
+     * Counterpart to Solidity's `uint72` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 72 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint72(uint256 value) internal pure returns (uint72) {
+        require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
+        return uint72(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint64 from uint256, reverting on
+     * overflow (when the input is greater than largest uint64).
+     *
+     * Counterpart to Solidity's `uint64` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 64 bits
+     *
+     * _Available since v2.5._
+     */
+    function toUint64(uint256 value) internal pure returns (uint64) {
+        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
+        return uint64(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint56 from uint256, reverting on
+     * overflow (when the input is greater than largest uint56).
+     *
+     * Counterpart to Solidity's `uint56` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 56 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint56(uint256 value) internal pure returns (uint56) {
+        require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
+        return uint56(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint48 from uint256, reverting on
+     * overflow (when the input is greater than largest uint48).
+     *
+     * Counterpart to Solidity's `uint48` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 48 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint48(uint256 value) internal pure returns (uint48) {
+        require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
+        return uint48(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint40 from uint256, reverting on
+     * overflow (when the input is greater than largest uint40).
+     *
+     * Counterpart to Solidity's `uint40` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 40 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint40(uint256 value) internal pure returns (uint40) {
+        require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
+        return uint40(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint32 from uint256, reverting on
+     * overflow (when the input is greater than largest uint32).
+     *
+     * Counterpart to Solidity's `uint32` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 32 bits
+     *
+     * _Available since v2.5._
+     */
+    function toUint32(uint256 value) internal pure returns (uint32) {
+        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
+        return uint32(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint24 from uint256, reverting on
+     * overflow (when the input is greater than largest uint24).
+     *
+     * Counterpart to Solidity's `uint24` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 24 bits
+     *
+     * _Available since v4.7._
+     */
+    function toUint24(uint256 value) internal pure returns (uint24) {
+        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
+        return uint24(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint16 from uint256, reverting on
+     * overflow (when the input is greater than largest uint16).
+     *
+     * Counterpart to Solidity's `uint16` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 16 bits
+     *
+     * _Available since v2.5._
+     */
+    function toUint16(uint256 value) internal pure returns (uint16) {
+        require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
+        return uint16(value);
+    }
+
+    /**
+     * @dev Returns the downcasted uint8 from uint256, reverting on
+     * overflow (when the input is greater than largest uint8).
+     *
+     * Counterpart to Solidity's `uint8` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 8 bits
+     *
+     * _Available since v2.5._
+     */
+    function toUint8(uint256 value) internal pure returns (uint8) {
+        require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
+        return uint8(value);
+    }
+
+    /**
+     * @dev Converts a signed int256 into an unsigned uint256.
+     *
+     * Requirements:
+     *
+     * - input must be greater than or equal to 0.
+     *
+     * _Available since v3.0._
+     */
+    function toUint256(int256 value) internal pure returns (uint256) {
+        require(value >= 0, "SafeCast: value must be positive");
+        return uint256(value);
+    }
+
+    /**
+     * @dev Returns the downcasted int248 from int256, reverting on
+     * overflow (when the input is less than smallest int248 or
+     * greater than largest int248).
+     *
+     * Counterpart to Solidity's `int248` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 248 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt248(int256 value) internal pure returns (int248 downcasted) {
+        downcasted = int248(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int240 from int256, reverting on
+     * overflow (when the input is less than smallest int240 or
+     * greater than largest int240).
+     *
+     * Counterpart to Solidity's `int240` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 240 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt240(int256 value) internal pure returns (int240 downcasted) {
+        downcasted = int240(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int232 from int256, reverting on
+     * overflow (when the input is less than smallest int232 or
+     * greater than largest int232).
+     *
+     * Counterpart to Solidity's `int232` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 232 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt232(int256 value) internal pure returns (int232 downcasted) {
+        downcasted = int232(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int224 from int256, reverting on
+     * overflow (when the input is less than smallest int224 or
+     * greater than largest int224).
+     *
+     * Counterpart to Solidity's `int224` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 224 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt224(int256 value) internal pure returns (int224 downcasted) {
+        downcasted = int224(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int216 from int256, reverting on
+     * overflow (when the input is less than smallest int216 or
+     * greater than largest int216).
+     *
+     * Counterpart to Solidity's `int216` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 216 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt216(int256 value) internal pure returns (int216 downcasted) {
+        downcasted = int216(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int208 from int256, reverting on
+     * overflow (when the input is less than smallest int208 or
+     * greater than largest int208).
+     *
+     * Counterpart to Solidity's `int208` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 208 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt208(int256 value) internal pure returns (int208 downcasted) {
+        downcasted = int208(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int200 from int256, reverting on
+     * overflow (when the input is less than smallest int200 or
+     * greater than largest int200).
+     *
+     * Counterpart to Solidity's `int200` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 200 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt200(int256 value) internal pure returns (int200 downcasted) {
+        downcasted = int200(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int192 from int256, reverting on
+     * overflow (when the input is less than smallest int192 or
+     * greater than largest int192).
+     *
+     * Counterpart to Solidity's `int192` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 192 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt192(int256 value) internal pure returns (int192 downcasted) {
+        downcasted = int192(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int184 from int256, reverting on
+     * overflow (when the input is less than smallest int184 or
+     * greater than largest int184).
+     *
+     * Counterpart to Solidity's `int184` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 184 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt184(int256 value) internal pure returns (int184 downcasted) {
+        downcasted = int184(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int176 from int256, reverting on
+     * overflow (when the input is less than smallest int176 or
+     * greater than largest int176).
+     *
+     * Counterpart to Solidity's `int176` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 176 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt176(int256 value) internal pure returns (int176 downcasted) {
+        downcasted = int176(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int168 from int256, reverting on
+     * overflow (when the input is less than smallest int168 or
+     * greater than largest int168).
+     *
+     * Counterpart to Solidity's `int168` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 168 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt168(int256 value) internal pure returns (int168 downcasted) {
+        downcasted = int168(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int160 from int256, reverting on
+     * overflow (when the input is less than smallest int160 or
+     * greater than largest int160).
+     *
+     * Counterpart to Solidity's `int160` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 160 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt160(int256 value) internal pure returns (int160 downcasted) {
+        downcasted = int160(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int152 from int256, reverting on
+     * overflow (when the input is less than smallest int152 or
+     * greater than largest int152).
+     *
+     * Counterpart to Solidity's `int152` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 152 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt152(int256 value) internal pure returns (int152 downcasted) {
+        downcasted = int152(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int144 from int256, reverting on
+     * overflow (when the input is less than smallest int144 or
+     * greater than largest int144).
+     *
+     * Counterpart to Solidity's `int144` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 144 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt144(int256 value) internal pure returns (int144 downcasted) {
+        downcasted = int144(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int136 from int256, reverting on
+     * overflow (when the input is less than smallest int136 or
+     * greater than largest int136).
+     *
+     * Counterpart to Solidity's `int136` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 136 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt136(int256 value) internal pure returns (int136 downcasted) {
+        downcasted = int136(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int128 from int256, reverting on
+     * overflow (when the input is less than smallest int128 or
+     * greater than largest int128).
+     *
+     * Counterpart to Solidity's `int128` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 128 bits
+     *
+     * _Available since v3.1._
+     */
+    function toInt128(int256 value) internal pure returns (int128 downcasted) {
+        downcasted = int128(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int120 from int256, reverting on
+     * overflow (when the input is less than smallest int120 or
+     * greater than largest int120).
+     *
+     * Counterpart to Solidity's `int120` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 120 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt120(int256 value) internal pure returns (int120 downcasted) {
+        downcasted = int120(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int112 from int256, reverting on
+     * overflow (when the input is less than smallest int112 or
+     * greater than largest int112).
+     *
+     * Counterpart to Solidity's `int112` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 112 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt112(int256 value) internal pure returns (int112 downcasted) {
+        downcasted = int112(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int104 from int256, reverting on
+     * overflow (when the input is less than smallest int104 or
+     * greater than largest int104).
+     *
+     * Counterpart to Solidity's `int104` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 104 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt104(int256 value) internal pure returns (int104 downcasted) {
+        downcasted = int104(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int96 from int256, reverting on
+     * overflow (when the input is less than smallest int96 or
+     * greater than largest int96).
+     *
+     * Counterpart to Solidity's `int96` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 96 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt96(int256 value) internal pure returns (int96 downcasted) {
+        downcasted = int96(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int88 from int256, reverting on
+     * overflow (when the input is less than smallest int88 or
+     * greater than largest int88).
+     *
+     * Counterpart to Solidity's `int88` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 88 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt88(int256 value) internal pure returns (int88 downcasted) {
+        downcasted = int88(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int80 from int256, reverting on
+     * overflow (when the input is less than smallest int80 or
+     * greater than largest int80).
+     *
+     * Counterpart to Solidity's `int80` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 80 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt80(int256 value) internal pure returns (int80 downcasted) {
+        downcasted = int80(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int72 from int256, reverting on
+     * overflow (when the input is less than smallest int72 or
+     * greater than largest int72).
+     *
+     * Counterpart to Solidity's `int72` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 72 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt72(int256 value) internal pure returns (int72 downcasted) {
+        downcasted = int72(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int64 from int256, reverting on
+     * overflow (when the input is less than smallest int64 or
+     * greater than largest int64).
+     *
+     * Counterpart to Solidity's `int64` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 64 bits
+     *
+     * _Available since v3.1._
+     */
+    function toInt64(int256 value) internal pure returns (int64 downcasted) {
+        downcasted = int64(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int56 from int256, reverting on
+     * overflow (when the input is less than smallest int56 or
+     * greater than largest int56).
+     *
+     * Counterpart to Solidity's `int56` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 56 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt56(int256 value) internal pure returns (int56 downcasted) {
+        downcasted = int56(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int48 from int256, reverting on
+     * overflow (when the input is less than smallest int48 or
+     * greater than largest int48).
+     *
+     * Counterpart to Solidity's `int48` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 48 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt48(int256 value) internal pure returns (int48 downcasted) {
+        downcasted = int48(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int40 from int256, reverting on
+     * overflow (when the input is less than smallest int40 or
+     * greater than largest int40).
+     *
+     * Counterpart to Solidity's `int40` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 40 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt40(int256 value) internal pure returns (int40 downcasted) {
+        downcasted = int40(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int32 from int256, reverting on
+     * overflow (when the input is less than smallest int32 or
+     * greater than largest int32).
+     *
+     * Counterpart to Solidity's `int32` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 32 bits
+     *
+     * _Available since v3.1._
+     */
+    function toInt32(int256 value) internal pure returns (int32 downcasted) {
+        downcasted = int32(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int24 from int256, reverting on
+     * overflow (when the input is less than smallest int24 or
+     * greater than largest int24).
+     *
+     * Counterpart to Solidity's `int24` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 24 bits
+     *
+     * _Available since v4.7._
+     */
+    function toInt24(int256 value) internal pure returns (int24 downcasted) {
+        downcasted = int24(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int16 from int256, reverting on
+     * overflow (when the input is less than smallest int16 or
+     * greater than largest int16).
+     *
+     * Counterpart to Solidity's `int16` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 16 bits
+     *
+     * _Available since v3.1._
+     */
+    function toInt16(int256 value) internal pure returns (int16 downcasted) {
+        downcasted = int16(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
+    }
+
+    /**
+     * @dev Returns the downcasted int8 from int256, reverting on
+     * overflow (when the input is less than smallest int8 or
+     * greater than largest int8).
+     *
+     * Counterpart to Solidity's `int8` operator.
+     *
+     * Requirements:
+     *
+     * - input must fit into 8 bits
+     *
+     * _Available since v3.1._
+     */
+    function toInt8(int256 value) internal pure returns (int8 downcasted) {
+        downcasted = int8(value);
+        require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
+    }
+
+    /**
+     * @dev Converts an unsigned uint256 into a signed int256.
+     *
+     * Requirements:
+     *
+     * - input must be less than or equal to maxInt256.
+     *
+     * _Available since v3.0._
+     */
+    function toInt256(uint256 value) internal pure returns (int256) {
+        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
+        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
+        return int256(value);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/ZeppelinContract.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/ZeppelinContract.sol
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.9;
+
+import "./@openzeppelin/contracts/token/ERC20/ERC20.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
+import "./@openzeppelin/contracts/security/Pausable.sol";
+import "./@openzeppelin/contracts/access/Ownable.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
+import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";
+
+contract ZeppelinContract is ERC20, ERC20Burnable, Pausable, Ownable, ERC20Permit, ERC20Votes, ERC20FlashMint {
+    constructor()
+        ERC20("ZeppelinContract", "UNQ")
+        ERC20Permit("ZeppelinContract")
+    {}
+
+    function pause() public onlyOwner {
+        _pause();
+    }
+
+    function unpause() public onlyOwner {
+        _unpause();
+    }
+
+    function mint(address to, uint256 amount) public onlyOwner {
+        _mint(to, amount);
+    }
+
+    function _beforeTokenTransfer(address from, address to, uint256 amount)
+        internal
+        whenNotPaused
+        override
+    {
+        super._beforeTokenTransfer(from, to, amount);
+    }
+
+    // The following functions are overrides required by Solidity.
+
+    function _afterTokenTransfer(address from, address to, uint256 amount)
+        internal
+        override(ERC20, ERC20Votes)
+    {
+        super._afterTokenTransfer(from, to, amount);
+    }
+
+    function _mint(address to, uint256 amount)
+        internal
+        override(ERC20, ERC20Votes)
+    {
+        super._mint(to, amount);
+    }
+
+    function _burn(address account, uint256 amount)
+        internal
+        override(ERC20, ERC20Votes)
+    {
+        super._burn(account, amount);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.abidiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.abi
@@ -0,0 +1 @@
+[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint32","name":"pos","type":"uint32"}],"name":"checkpoints","outputs":[{"components":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint224","name":"votes","type":"uint224"}],"internalType":"struct ERC20Votes.Checkpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPastVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
addedtests/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.bindiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC20/bin/ZeppelinContract.bin
@@ -0,0 +1 @@
+6101406040523480156200001257600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525080604051806040016040528060018152602001603160f81b8152506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b8152508160039081620000ad919062000269565b506004620000bc828262000269565b50506005805460ff1916905550620000d4336200016a565b815160209283012081519183019190912060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818801819052818301969096526060810194909452608080850193909352308483018190528151808603909301835260c094850190915281519190950120905291909152610120525062000335565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001ef57607f821691505b6020821081036200021057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200026457600081815260208120601f850160051c810160208610156200023f5750805b601f850160051c820191505b8181101562000260578281556001016200024b565b5050505b505050565b81516001600160401b03811115620002855762000285620001c4565b6200029d81620002968454620001da565b8462000216565b602080601f831160018114620002d55760008415620002bc5750858301515b600019600386901b1c1916600185901b17855562000260565b600085815260208120601f198616915b828110156200030657888601518255948401946001909101908401620002e5565b5085821015620003255787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e05161010051610120516125f06200038560003960006112ad015260006112fc015260006112d7015260006112300152600061125a0152600061128401526125f06000f3fe608060405234801561001057600080fd5b50600436106102065760003560e01c806370a082311161011a5780639ab24eb0116100ad578063d505accf1161007c578063d505accf1461046a578063d9d98ce41461047d578063dd62ed3e14610490578063f1127ed8146104a3578063f2fde38b146104e057600080fd5b80639ab24eb01461041e578063a457c2d714610431578063a9059cbb14610444578063c3cda5201461045757600080fd5b80638456cb59116100e95780638456cb59146103e55780638da5cb5b146103ed5780638e539e8c1461040357806395d89b411461041657600080fd5b806370a082311461038e578063715018a6146103b757806379cc6790146103bf5780637ecebe00146103d257600080fd5b80633f4ba83a1161019d5780635c19a95c1161016c5780635c19a95c146103225780635c975abb146103355780635cffe9de14610340578063613255ab146103535780636fcfff451461036657600080fd5b80633f4ba83a146102ae57806340c10f19146102b857806342966c68146102cb578063587cde1e146102de57600080fd5b8063313ce567116101d9578063313ce567146102715780633644e5151461028057806339509351146102885780633a46b1a81461029b57600080fd5b806306fdde031461020b578063095ea7b31461022957806318160ddd1461024c57806323b872dd1461025e575b600080fd5b6102136104f3565b604051610220919061217e565b60405180910390f35b61023c6102373660046121e1565b610585565b6040519015158152602001610220565b6002545b604051908152602001610220565b61023c61026c36600461220d565b61059f565b60405160128152602001610220565b6102506105c3565b61023c6102963660046121e1565b6105d2565b6102506102a93660046121e1565b6105f4565b6102b6610673565b005b6102b66102c63660046121e1565b610685565b6102b66102d936600461224e565b61069b565b61030a6102ec366004612267565b6001600160a01b039081166000908152600860205260409020541690565b6040516001600160a01b039091168152602001610220565b6102b6610330366004612267565b6106a8565b60055460ff1661023c565b61023c61034e366004612284565b6106b2565b610250610361366004612267565b610896565b610379610374366004612267565b6108be565b60405163ffffffff9091168152602001610220565b61025061039c366004612267565b6001600160a01b031660009081526020819052604090205490565b6102b66108e0565b6102b66103cd3660046121e1565b6108f2565b6102506103e0366004612267565b610907565b6102b6610925565b60055461010090046001600160a01b031661030a565b61025061041136600461224e565b610935565b610213610991565b61025061042c366004612267565b6109a0565b61023c61043f3660046121e1565b610a27565b61023c6104523660046121e1565b610aa2565b6102b6610465366004612339565b610ab0565b6102b6610478366004612393565b610be6565b61025061048b3660046121e1565b610d4a565b61025061049e366004612401565b610dab565b6104b66104b136600461243a565b610dd6565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610220565b6102b66104ee366004612267565b610e5a565b60606003805461050290612471565b80601f016020809104026020016040519081016040528092919081815260200182805461052e90612471565b801561057b5780601f106105505761010080835404028352916020019161057b565b820191906000526020600020905b81548152906001019060200180831161055e57829003601f168201915b5050505050905090565b600033610593818585610ed0565b60019150505b92915050565b6000336105ad858285610ff4565b6105b885858561106e565b506001949350505050565b60006105cd611223565b905090565b6000336105938185856105e58383610dab565b6105ef91906124bb565b610ed0565b600043821061064a5760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064015b60405180910390fd5b6001600160a01b038316600090815260096020526040902061066c908361134a565b9392505050565b61067b611441565b6106836114a1565b565b61068d611441565b61069782826114f3565b5050565b6106a533826114fd565b50565b6106a53382611507565b60006106bd85610896565b8411156107205760405162461bcd60e51b815260206004820152602b60248201527f4552433230466c6173684d696e743a20616d6f756e742065786365656473206d60448201526a30bc233630b9b42637b0b760a91b6064820152608401610641565b600061072c8686610d4a565b905061073887866114f3565b6040516323e30c8b60e01b81527f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9906001600160a01b038916906323e30c8b906107909033908b908b9088908c908c906004016124ce565b6020604051808303816000875af11580156107af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d3919061252a565b1461082c5760405162461bcd60e51b8152602060048201526024808201527f4552433230466c6173684d696e743a20696e76616c69642072657475726e2076604482015263616c756560e01b6064820152608401610641565b6000610842883061083d858a6124bb565b610ff4565b81158061085657506001600160a01b038116155b156108735761086e8861086984896124bb565b6114fd565b610888565b61087d88876114fd565b61088888828461106e565b506001979650505050505050565b60006001600160a01b03821630146108af576000610599565b60025461059990600019612543565b6001600160a01b03811660009081526009602052604081205461059990611580565b6108e8611441565b61068360006115e9565b6108fd823383610ff4565b61069782826114fd565b6001600160a01b038116600090815260066020526040812054610599565b61092d611441565b610683611643565b60004382106109865760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610641565b610599600a8361134a565b60606004805461050290612471565b6001600160a01b0381166000908152600960205260408120548015610a14576001600160a01b03831660009081526009602052604090206109e2600183612543565b815481106109f2576109f2612556565b60009182526020909120015464010000000090046001600160e01b0316610a17565b60005b6001600160e01b03169392505050565b60003381610a358286610dab565b905083811015610a955760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610641565b6105b88286868403610ed0565b60003361059381858561106e565b83421115610b005760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610641565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b038816918101919091526060810186905260808101859052600090610b7a90610b729060a00160405160208183030381529060405280519060200120611680565b8585856116ce565b9050610b85816116f6565b8614610bd35760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610641565b610bdd8188611507565b50505050505050565b83421115610c365760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610641565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610c658c6116f6565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610cc082611680565b90506000610cd0828787876116ce565b9050896001600160a01b0316816001600160a01b031614610d335760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610641565b610d3e8a8a8a610ed0565b50505050505050505050565b60006001600160a01b0383163014610da45760405162461bcd60e51b815260206004820152601b60248201527f4552433230466c6173684d696e743a2077726f6e6720746f6b656e00000000006044820152606401610641565b600061066c565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60408051808201909152600080825260208201526001600160a01b0383166000908152600960205260409020805463ffffffff8416908110610e1a57610e1a612556565b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b610e62611441565b6001600160a01b038116610ec75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610641565b6106a5816115e9565b6001600160a01b038316610f325760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610641565b6001600160a01b038216610f935760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610641565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006110008484610dab565b90506000198114611068578181101561105b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610641565b6110688484848403610ed0565b50505050565b6001600160a01b0383166110d25760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610641565b6001600160a01b0382166111345760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610641565b61113f83838361171e565b6001600160a01b038316600090815260208190526040902054818110156111b75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610641565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361106884848461172b565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561127c57507f000000000000000000000000000000000000000000000000000000000000000046145b156112a657507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b8154600090818160058111156113a457600061136584611736565b61136f9085612543565b600088815260209020909150869082015463ffffffff161115611394578091506113a2565b61139f8160016124bb565b92505b505b808210156113f15760006113b8838361181e565b600088815260209020909150869082015463ffffffff1611156113dd578091506113eb565b6113e88160016124bb565b92505b506113a4565b801561142b5761141486611406600184612543565b600091825260209091200190565b5464010000000090046001600160e01b031661142e565b60005b6001600160e01b03169695505050505050565b6005546001600160a01b036101009091041633146106835760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610641565b6114a9611839565b6005805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6106978282611882565b610697828261190c565b6001600160a01b038281166000818152600860208181526040808420805485845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611068828483611924565b600063ffffffff8211156115e55760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610641565b5090565b600580546001600160a01b03838116610100818102610100600160a81b031985161790945560405193909204169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b61164b611a61565b6005805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114d63390565b600061059961168d611223565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006116df87878787611aa7565b915091506116ec81611b6b565b5095945050505050565b6001600160a01b03811660009081526006602052604090208054600181018255905b50919050565b611726611a61565b505050565b611726838383611cb5565b60008160000361174857506000919050565b6000600161175584611ce7565b901c6001901b9050600181848161176e5761176e61256c565b048201901c905060018184816117865761178661256c565b048201901c9050600181848161179e5761179e61256c565b048201901c905060018184816117b6576117b661256c565b048201901c905060018184816117ce576117ce61256c565b048201901c905060018184816117e6576117e661256c565b048201901c905060018184816117fe576117fe61256c565b048201901c905061066c818285816118185761181861256c565b04611d7b565b600061182d6002848418612582565b61066c908484166124bb565b60055460ff166106835760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610641565b61188c8282611d91565b6002546001600160e01b0310156118fe5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610641565b611068600a611e6483611e70565b6119168282611fc4565b611068600a61210983611e70565b816001600160a01b0316836001600160a01b0316141580156119465750600081115b15611726576001600160a01b038316156119d4576001600160a01b038316600090815260096020526040812081906119819061210985611e70565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516119c9929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611726576001600160a01b03821660009081526009602052604081208190611a0a90611e6485611e70565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051611a52929190918252602082015260400190565b60405180910390a25050505050565b60055460ff16156106835760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610641565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611ade5750600090506003611b62565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611b32573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611b5b57600060019250925050611b62565b9150600090505b94509492505050565b6000816004811115611b7f57611b7f6125a4565b03611b875750565b6001816004811115611b9b57611b9b6125a4565b03611be85760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610641565b6002816004811115611bfc57611bfc6125a4565b03611c495760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610641565b6003816004811115611c5d57611c5d6125a4565b036106a55760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610641565b6001600160a01b0383811660009081526008602052604080822054858416835291205461172692918216911683611924565b600080608083901c15611cfc57608092831c92015b604083901c15611d0e57604092831c92015b602083901c15611d2057602092831c92015b601083901c15611d3257601092831c92015b600883901c15611d4457600892831c92015b600483901c15611d5657600492831c92015b600283901c15611d6857600292831c92015b600183901c156105995760010192915050565b6000818310611d8a578161066c565b5090919050565b6001600160a01b038216611de75760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610641565b611df36000838361171e565b8060026000828254611e0591906124bb565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36106976000838361172b565b600061066c82846124bb565b82546000908190818115611ebd57611e8d87611406600185612543565b60408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152611ed2565b60408051808201909152600080825260208201525b905080602001516001600160e01b03169350611ef284868863ffffffff16565b9250600082118015611f0a5750805163ffffffff1643145b15611f4f57611f1883612115565b611f2788611406600186612543565b80546001600160e01b03929092166401000000000263ffffffff909216919091179055611fba565b866040518060400160405280611f6443611580565b63ffffffff168152602001611f7886612115565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b6001600160a01b0382166120245760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610641565b6120308260008361171e565b6001600160a01b038216600090815260208190526040902054818110156120a45760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610641565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36117268360008461172b565b600061066c8284612543565b60006001600160e01b038211156115e55760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610641565b600060208083528351808285015260005b818110156121ab5785810183015185820160400152820161218f565b506000604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b03811681146106a557600080fd5b600080604083850312156121f457600080fd5b82356121ff816121cc565b946020939093013593505050565b60008060006060848603121561222257600080fd5b833561222d816121cc565b9250602084013561223d816121cc565b929592945050506040919091013590565b60006020828403121561226057600080fd5b5035919050565b60006020828403121561227957600080fd5b813561066c816121cc565b60008060008060006080868803121561229c57600080fd5b85356122a7816121cc565b945060208601356122b7816121cc565b935060408601359250606086013567ffffffffffffffff808211156122db57600080fd5b818801915088601f8301126122ef57600080fd5b8135818111156122fe57600080fd5b89602082850101111561231057600080fd5b9699959850939650602001949392505050565b803560ff8116811461233457600080fd5b919050565b60008060008060008060c0878903121561235257600080fd5b863561235d816121cc565b9550602087013594506040870135935061237960608801612323565b92506080870135915060a087013590509295509295509295565b600080600080600080600060e0888a0312156123ae57600080fd5b87356123b9816121cc565b965060208801356123c9816121cc565b955060408801359450606088013593506123e560808901612323565b925060a0880135915060c0880135905092959891949750929550565b6000806040838503121561241457600080fd5b823561241f816121cc565b9150602083013561242f816121cc565b809150509250929050565b6000806040838503121561244d57600080fd5b8235612458816121cc565b9150602083013563ffffffff8116811461242f57600080fd5b600181811c9082168061248557607f821691505b60208210810361171857634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610599576105996124a5565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f8501168301019050979650505050505050565b60006020828403121561253c57600080fd5b5051919050565b81810381811115610599576105996124a5565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60008261259f57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052602160045260246000fdfea264697066735822122057e08ed799a9773c2de4d8c40122801fc9994042a2e3e3ac01e5aa1c384b1c4b64736f6c63430008110033
\ No newline at end of file
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/README.mddiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/README.md
@@ -0,0 +1,12 @@
+# OpenZeppelin Contracts
+
+The files in this directory were sourced unmodified from OpenZeppelin Contracts v4.8.1.
+
+They are not meant to be edited.
+
+The originals can be found on [GitHub] and [npm].
+
+[GitHub]: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v4.8.1
+[npm]: https://www.npmjs.com/package/@openzeppelin/contracts/v/4.8.1
+
+Generated with OpenZeppelin Contracts Wizard (https://zpl.in/wizard).
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/access/Ownable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/access/Ownable.sol
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../utils/Context.sol";
+
+/**
+ * @dev Contract module which provides a basic access control mechanism, where
+ * there is an account (an owner) that can be granted exclusive access to
+ * specific functions.
+ *
+ * By default, the owner account will be the one that deploys the contract. This
+ * can later be changed with {transferOwnership}.
+ *
+ * This module is used through inheritance. It will make available the modifier
+ * `onlyOwner`, which can be applied to your functions to restrict their use to
+ * the owner.
+ */
+abstract contract Ownable is Context {
+    address private _owner;
+
+    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
+
+    /**
+     * @dev Initializes the contract setting the deployer as the initial owner.
+     */
+    constructor() {
+        _transferOwnership(_msgSender());
+    }
+
+    /**
+     * @dev Throws if called by any account other than the owner.
+     */
+    modifier onlyOwner() {
+        _checkOwner();
+        _;
+    }
+
+    /**
+     * @dev Returns the address of the current owner.
+     */
+    function owner() public view virtual returns (address) {
+        return _owner;
+    }
+
+    /**
+     * @dev Throws if the sender is not the owner.
+     */
+    function _checkOwner() internal view virtual {
+        require(owner() == _msgSender(), "Ownable: caller is not the owner");
+    }
+
+    /**
+     * @dev Leaves the contract without owner. It will not be possible to call
+     * `onlyOwner` functions anymore. Can only be called by the current owner.
+     *
+     * NOTE: Renouncing ownership will leave the contract without an owner,
+     * thereby removing any functionality that is only available to the owner.
+     */
+    function renounceOwnership() public virtual onlyOwner {
+        _transferOwnership(address(0));
+    }
+
+    /**
+     * @dev Transfers ownership of the contract to a new account (`newOwner`).
+     * Can only be called by the current owner.
+     */
+    function transferOwnership(address newOwner) public virtual onlyOwner {
+        require(newOwner != address(0), "Ownable: new owner is the zero address");
+        _transferOwnership(newOwner);
+    }
+
+    /**
+     * @dev Transfers ownership of the contract to a new account (`newOwner`).
+     * Internal function without access restriction.
+     */
+    function _transferOwnership(address newOwner) internal virtual {
+        address oldOwner = _owner;
+        _owner = newOwner;
+        emit OwnershipTransferred(oldOwner, newOwner);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/ERC721.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/ERC721.sol
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC721.sol";
+import "./IERC721Receiver.sol";
+import "./extensions/IERC721Metadata.sol";
+import "../../utils/Address.sol";
+import "../../utils/Context.sol";
+import "../../utils/Strings.sol";
+import "../../utils/introspection/ERC165.sol";
+
+/**
+ * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
+ * the Metadata extension, but not including the Enumerable extension, which is available separately as
+ * {ERC721Enumerable}.
+ */
+contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
+    using Address for address;
+    using Strings for uint256;
+
+    // Token name
+    string private _name;
+
+    // Token symbol
+    string private _symbol;
+
+    // Mapping from token ID to owner address
+    mapping(uint256 => address) private _owners;
+
+    // Mapping owner address to token count
+    mapping(address => uint256) private _balances;
+
+    // Mapping from token ID to approved address
+    mapping(uint256 => address) private _tokenApprovals;
+
+    // Mapping from owner to operator approvals
+    mapping(address => mapping(address => bool)) private _operatorApprovals;
+
+    /**
+     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
+     */
+    constructor(string memory name_, string memory symbol_) {
+        _name = name_;
+        _symbol = symbol_;
+    }
+
+    /**
+     * @dev See {IERC165-supportsInterface}.
+     */
+    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
+        return
+            interfaceId == type(IERC721).interfaceId ||
+            interfaceId == type(IERC721Metadata).interfaceId ||
+            super.supportsInterface(interfaceId);
+    }
+
+    /**
+     * @dev See {IERC721-balanceOf}.
+     */
+    function balanceOf(address owner) public view virtual override returns (uint256) {
+        require(owner != address(0), "ERC721: address zero is not a valid owner");
+        return _balances[owner];
+    }
+
+    /**
+     * @dev See {IERC721-ownerOf}.
+     */
+    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
+        address owner = _ownerOf(tokenId);
+        require(owner != address(0), "ERC721: invalid token ID");
+        return owner;
+    }
+
+    /**
+     * @dev See {IERC721Metadata-name}.
+     */
+    function name() public view virtual override returns (string memory) {
+        return _name;
+    }
+
+    /**
+     * @dev See {IERC721Metadata-symbol}.
+     */
+    function symbol() public view virtual override returns (string memory) {
+        return _symbol;
+    }
+
+    /**
+     * @dev See {IERC721Metadata-tokenURI}.
+     */
+    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
+        _requireMinted(tokenId);
+
+        string memory baseURI = _baseURI();
+        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
+    }
+
+    /**
+     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
+     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
+     * by default, can be overridden in child contracts.
+     */
+    function _baseURI() internal view virtual returns (string memory) {
+        return "";
+    }
+
+    /**
+     * @dev See {IERC721-approve}.
+     */
+    function approve(address to, uint256 tokenId) public virtual override {
+        address owner = ERC721.ownerOf(tokenId);
+        require(to != owner, "ERC721: approval to current owner");
+
+        require(
+            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
+            "ERC721: approve caller is not token owner or approved for all"
+        );
+
+        _approve(to, tokenId);
+    }
+
+    /**
+     * @dev See {IERC721-getApproved}.
+     */
+    function getApproved(uint256 tokenId) public view virtual override returns (address) {
+        _requireMinted(tokenId);
+
+        return _tokenApprovals[tokenId];
+    }
+
+    /**
+     * @dev See {IERC721-setApprovalForAll}.
+     */
+    function setApprovalForAll(address operator, bool approved) public virtual override {
+        _setApprovalForAll(_msgSender(), operator, approved);
+    }
+
+    /**
+     * @dev See {IERC721-isApprovedForAll}.
+     */
+    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
+        return _operatorApprovals[owner][operator];
+    }
+
+    /**
+     * @dev See {IERC721-transferFrom}.
+     */
+    function transferFrom(
+        address from,
+        address to,
+        uint256 tokenId
+    ) public virtual override {
+        //solhint-disable-next-line max-line-length
+        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
+
+        _transfer(from, to, tokenId);
+    }
+
+    /**
+     * @dev See {IERC721-safeTransferFrom}.
+     */
+    function safeTransferFrom(
+        address from,
+        address to,
+        uint256 tokenId
+    ) public virtual override {
+        safeTransferFrom(from, to, tokenId, "");
+    }
+
+    /**
+     * @dev See {IERC721-safeTransferFrom}.
+     */
+    function safeTransferFrom(
+        address from,
+        address to,
+        uint256 tokenId,
+        bytes memory data
+    ) public virtual override {
+        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
+        _safeTransfer(from, to, tokenId, data);
+    }
+
+    /**
+     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
+     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
+     *
+     * `data` is additional data, it has no specified format and it is sent in call to `to`.
+     *
+     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
+     * implement alternative mechanisms to perform token transfer, such as signature-based.
+     *
+     * Requirements:
+     *
+     * - `from` cannot be the zero address.
+     * - `to` cannot be the zero address.
+     * - `tokenId` token must exist and be owned by `from`.
+     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+     *
+     * Emits a {Transfer} event.
+     */
+    function _safeTransfer(
+        address from,
+        address to,
+        uint256 tokenId,
+        bytes memory data
+    ) internal virtual {
+        _transfer(from, to, tokenId);
+        require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
+    }
+
+    /**
+     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
+     */
+    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
+        return _owners[tokenId];
+    }
+
+    /**
+     * @dev Returns whether `tokenId` exists.
+     *
+     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
+     *
+     * Tokens start existing when they are minted (`_mint`),
+     * and stop existing when they are burned (`_burn`).
+     */
+    function _exists(uint256 tokenId) internal view virtual returns (bool) {
+        return _ownerOf(tokenId) != address(0);
+    }
+
+    /**
+     * @dev Returns whether `spender` is allowed to manage `tokenId`.
+     *
+     * Requirements:
+     *
+     * - `tokenId` must exist.
+     */
+    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
+        address owner = ERC721.ownerOf(tokenId);
+        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
+    }
+
+    /**
+     * @dev Safely mints `tokenId` and transfers it to `to`.
+     *
+     * Requirements:
+     *
+     * - `tokenId` must not exist.
+     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+     *
+     * Emits a {Transfer} event.
+     */
+    function _safeMint(address to, uint256 tokenId) internal virtual {
+        _safeMint(to, tokenId, "");
+    }
+
+    /**
+     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
+     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
+     */
+    function _safeMint(
+        address to,
+        uint256 tokenId,
+        bytes memory data
+    ) internal virtual {
+        _mint(to, tokenId);
+        require(
+            _checkOnERC721Received(address(0), to, tokenId, data),
+            "ERC721: transfer to non ERC721Receiver implementer"
+        );
+    }
+
+    /**
+     * @dev Mints `tokenId` and transfers it to `to`.
+     *
+     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
+     *
+     * Requirements:
+     *
+     * - `tokenId` must not exist.
+     * - `to` cannot be the zero address.
+     *
+     * Emits a {Transfer} event.
+     */
+    function _mint(address to, uint256 tokenId) internal virtual {
+        require(to != address(0), "ERC721: mint to the zero address");
+        require(!_exists(tokenId), "ERC721: token already minted");
+
+        _beforeTokenTransfer(address(0), to, tokenId, 1);
+
+        // Check that tokenId was not minted by `_beforeTokenTransfer` hook
+        require(!_exists(tokenId), "ERC721: token already minted");
+
+        unchecked {
+            // Will not overflow unless all 2**256 token ids are minted to the same owner.
+            // Given that tokens are minted one by one, it is impossible in practice that
+            // this ever happens. Might change if we allow batch minting.
+            // The ERC fails to describe this case.
+            _balances[to] += 1;
+        }
+
+        _owners[tokenId] = to;
+
+        emit Transfer(address(0), to, tokenId);
+
+        _afterTokenTransfer(address(0), to, tokenId, 1);
+    }
+
+    /**
+     * @dev Destroys `tokenId`.
+     * The approval is cleared when the token is burned.
+     * This is an internal function that does not check if the sender is authorized to operate on the token.
+     *
+     * Requirements:
+     *
+     * - `tokenId` must exist.
+     *
+     * Emits a {Transfer} event.
+     */
+    function _burn(uint256 tokenId) internal virtual {
+        address owner = ERC721.ownerOf(tokenId);
+
+        _beforeTokenTransfer(owner, address(0), tokenId, 1);
+
+        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
+        owner = ERC721.ownerOf(tokenId);
+
+        // Clear approvals
+        delete _tokenApprovals[tokenId];
+
+        unchecked {
+            // Cannot overflow, as that would require more tokens to be burned/transferred
+            // out than the owner initially received through minting and transferring in.
+            _balances[owner] -= 1;
+        }
+        delete _owners[tokenId];
+
+        emit Transfer(owner, address(0), tokenId);
+
+        _afterTokenTransfer(owner, address(0), tokenId, 1);
+    }
+
+    /**
+     * @dev Transfers `tokenId` from `from` to `to`.
+     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
+     *
+     * Requirements:
+     *
+     * - `to` cannot be the zero address.
+     * - `tokenId` token must be owned by `from`.
+     *
+     * Emits a {Transfer} event.
+     */
+    function _transfer(
+        address from,
+        address to,
+        uint256 tokenId
+    ) internal virtual {
+        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
+        require(to != address(0), "ERC721: transfer to the zero address");
+
+        _beforeTokenTransfer(from, to, tokenId, 1);
+
+        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
+        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
+
+        // Clear approvals from the previous owner
+        delete _tokenApprovals[tokenId];
+
+        unchecked {
+            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
+            // `from`'s balance is the number of token held, which is at least one before the current
+            // transfer.
+            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
+            // all 2**256 token ids to be minted, which in practice is impossible.
+            _balances[from] -= 1;
+            _balances[to] += 1;
+        }
+        _owners[tokenId] = to;
+
+        emit Transfer(from, to, tokenId);
+
+        _afterTokenTransfer(from, to, tokenId, 1);
+    }
+
+    /**
+     * @dev Approve `to` to operate on `tokenId`
+     *
+     * Emits an {Approval} event.
+     */
+    function _approve(address to, uint256 tokenId) internal virtual {
+        _tokenApprovals[tokenId] = to;
+        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
+    }
+
+    /**
+     * @dev Approve `operator` to operate on all of `owner` tokens
+     *
+     * Emits an {ApprovalForAll} event.
+     */
+    function _setApprovalForAll(
+        address owner,
+        address operator,
+        bool approved
+    ) internal virtual {
+        require(owner != operator, "ERC721: approve to caller");
+        _operatorApprovals[owner][operator] = approved;
+        emit ApprovalForAll(owner, operator, approved);
+    }
+
+    /**
+     * @dev Reverts if the `tokenId` has not been minted yet.
+     */
+    function _requireMinted(uint256 tokenId) internal view virtual {
+        require(_exists(tokenId), "ERC721: invalid token ID");
+    }
+
+    /**
+     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
+     * The call is not executed if the target address is not a contract.
+     *
+     * @param from address representing the previous owner of the given token ID
+     * @param to target address that will receive the tokens
+     * @param tokenId uint256 ID of the token to be transferred
+     * @param data bytes optional data to send along with the call
+     * @return bool whether the call correctly returned the expected magic value
+     */
+    function _checkOnERC721Received(
+        address from,
+        address to,
+        uint256 tokenId,
+        bytes memory data
+    ) private returns (bool) {
+        if (to.isContract()) {
+            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
+                return retval == IERC721Receiver.onERC721Received.selector;
+            } catch (bytes memory reason) {
+                if (reason.length == 0) {
+                    revert("ERC721: transfer to non ERC721Receiver implementer");
+                } else {
+                    /// @solidity memory-safe-assembly
+                    assembly {
+                        revert(add(32, reason), mload(reason))
+                    }
+                }
+            }
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
+     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
+     *
+     * Calling conditions:
+     *
+     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
+     * - When `from` is zero, the tokens will be minted for `to`.
+     * - When `to` is zero, ``from``'s tokens will be burned.
+     * - `from` and `to` are never both zero.
+     * - `batchSize` is non-zero.
+     *
+     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     */
+    function _beforeTokenTransfer(
+        address from,
+        address to,
+        uint256, /* firstTokenId */
+        uint256 batchSize
+    ) internal virtual {
+        if (batchSize > 1) {
+            if (from != address(0)) {
+                _balances[from] -= batchSize;
+            }
+            if (to != address(0)) {
+                _balances[to] += batchSize;
+            }
+        }
+    }
+
+    /**
+     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
+     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
+     *
+     * Calling conditions:
+     *
+     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
+     * - When `from` is zero, the tokens were minted for `to`.
+     * - When `to` is zero, ``from``'s tokens were burned.
+     * - `from` and `to` are never both zero.
+     * - `batchSize` is non-zero.
+     *
+     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+     */
+    function _afterTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual {}
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721.sol
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)
+
+pragma solidity ^0.8.0;
+
+import "../../utils/introspection/IERC165.sol";
+
+/**
+ * @dev Required interface of an ERC721 compliant contract.
+ */
+interface IERC721 is IERC165 {
+    /**
+     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
+     */
+    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+
+    /**
+     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
+     */
+    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+
+    /**
+     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
+     */
+    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+
+    /**
+     * @dev Returns the number of tokens in ``owner``'s account.
+     */
+    function balanceOf(address owner) external view returns (uint256 balance);
+
+    /**
+     * @dev Returns the owner of the `tokenId` token.
+     *
+     * Requirements:
+     *
+     * - `tokenId` must exist.
+     */
+    function ownerOf(uint256 tokenId) external view returns (address owner);
+
+    /**
+     * @dev Safely transfers `tokenId` token from `from` to `to`.
+     *
+     * Requirements:
+     *
+     * - `from` cannot be the zero address.
+     * - `to` cannot be the zero address.
+     * - `tokenId` token must exist and be owned by `from`.
+     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
+     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+     *
+     * Emits a {Transfer} event.
+     */
+    function safeTransferFrom(
+        address from,
+        address to,
+        uint256 tokenId,
+        bytes calldata data
+    ) external;
+
+    /**
+     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
+     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
+     *
+     * Requirements:
+     *
+     * - `from` cannot be the zero address.
+     * - `to` cannot be the zero address.
+     * - `tokenId` token must exist and be owned by `from`.
+     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
+     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
+     *
+     * Emits a {Transfer} event.
+     */
+    function safeTransferFrom(
+        address from,
+        address to,
+        uint256 tokenId
+    ) external;
+
+    /**
+     * @dev Transfers `tokenId` token from `from` to `to`.
+     *
+     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
+     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
+     * understand this adds an external call which potentially creates a reentrancy vulnerability.
+     *
+     * Requirements:
+     *
+     * - `from` cannot be the zero address.
+     * - `to` cannot be the zero address.
+     * - `tokenId` token must be owned by `from`.
+     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
+     *
+     * Emits a {Transfer} event.
+     */
+    function transferFrom(
+        address from,
+        address to,
+        uint256 tokenId
+    ) external;
+
+    /**
+     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
+     * The approval is cleared when the token is transferred.
+     *
+     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
+     *
+     * Requirements:
+     *
+     * - The caller must own the token or be an approved operator.
+     * - `tokenId` must exist.
+     *
+     * Emits an {Approval} event.
+     */
+    function approve(address to, uint256 tokenId) external;
+
+    /**
+     * @dev Approve or remove `operator` as an operator for the caller.
+     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
+     *
+     * Requirements:
+     *
+     * - The `operator` cannot be the caller.
+     *
+     * Emits an {ApprovalForAll} event.
+     */
+    function setApprovalForAll(address operator, bool _approved) external;
+
+    /**
+     * @dev Returns the account approved for `tokenId` token.
+     *
+     * Requirements:
+     *
+     * - `tokenId` must exist.
+     */
+    function getApproved(uint256 tokenId) external view returns (address operator);
+
+    /**
+     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
+     *
+     * See {setApprovalForAll}
+     */
+    function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721Receiver.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @title ERC721 token receiver interface
+ * @dev Interface for any contract that wants to support safeTransfers
+ * from ERC721 asset contracts.
+ */
+interface IERC721Receiver {
+    /**
+     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
+     * by `operator` from `from`, this function is called.
+     *
+     * It must return its Solidity selector to confirm the token transfer.
+     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
+     *
+     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
+     */
+    function onERC721Received(
+        address operator,
+        address from,
+        uint256 tokenId,
+        bytes calldata data
+    ) external returns (bytes4);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+import "../../../utils/Context.sol";
+
+/**
+ * @title ERC721 Burnable Token
+ * @dev ERC721 Token that can be burned (destroyed).
+ */
+abstract contract ERC721Burnable is Context, ERC721 {
+    /**
+     * @dev Burns `tokenId`. See {ERC721-_burn}.
+     *
+     * Requirements:
+     *
+     * - The caller must own `tokenId` or be an approved operator.
+     */
+    function burn(uint256 tokenId) public virtual {
+        //solhint-disable-next-line max-line-length
+        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
+        _burn(tokenId);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+import "./IERC721Enumerable.sol";
+
+/**
+ * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
+ * enumerability of all the token ids in the contract as well as all token ids owned by each
+ * account.
+ */
+abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
+    // Mapping from owner to list of owned token IDs
+    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
+
+    // Mapping from token ID to index of the owner tokens list
+    mapping(uint256 => uint256) private _ownedTokensIndex;
+
+    // Array with all token ids, used for enumeration
+    uint256[] private _allTokens;
+
+    // Mapping from token id to position in the allTokens array
+    mapping(uint256 => uint256) private _allTokensIndex;
+
+    /**
+     * @dev See {IERC165-supportsInterface}.
+     */
+    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
+        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
+    }
+
+    /**
+     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
+     */
+    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
+        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
+        return _ownedTokens[owner][index];
+    }
+
+    /**
+     * @dev See {IERC721Enumerable-totalSupply}.
+     */
+    function totalSupply() public view virtual override returns (uint256) {
+        return _allTokens.length;
+    }
+
+    /**
+     * @dev See {IERC721Enumerable-tokenByIndex}.
+     */
+    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
+        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
+        return _allTokens[index];
+    }
+
+    /**
+     * @dev See {ERC721-_beforeTokenTransfer}.
+     */
+    function _beforeTokenTransfer(
+        address from,
+        address to,
+        uint256 firstTokenId,
+        uint256 batchSize
+    ) internal virtual override {
+        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
+
+        if (batchSize > 1) {
+            // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
+            revert("ERC721Enumerable: consecutive transfers not supported");
+        }
+
+        uint256 tokenId = firstTokenId;
+
+        if (from == address(0)) {
+            _addTokenToAllTokensEnumeration(tokenId);
+        } else if (from != to) {
+            _removeTokenFromOwnerEnumeration(from, tokenId);
+        }
+        if (to == address(0)) {
+            _removeTokenFromAllTokensEnumeration(tokenId);
+        } else if (to != from) {
+            _addTokenToOwnerEnumeration(to, tokenId);
+        }
+    }
+
+    /**
+     * @dev Private function to add a token to this extension's ownership-tracking data structures.
+     * @param to address representing the new owner of the given token ID
+     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
+     */
+    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
+        uint256 length = ERC721.balanceOf(to);
+        _ownedTokens[to][length] = tokenId;
+        _ownedTokensIndex[tokenId] = length;
+    }
+
+    /**
+     * @dev Private function to add a token to this extension's token tracking data structures.
+     * @param tokenId uint256 ID of the token to be added to the tokens list
+     */
+    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
+        _allTokensIndex[tokenId] = _allTokens.length;
+        _allTokens.push(tokenId);
+    }
+
+    /**
+     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
+     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
+     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
+     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
+     * @param from address representing the previous owner of the given token ID
+     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
+     */
+    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
+        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
+        // then delete the last slot (swap and pop).
+
+        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
+        uint256 tokenIndex = _ownedTokensIndex[tokenId];
+
+        // When the token to delete is the last token, the swap operation is unnecessary
+        if (tokenIndex != lastTokenIndex) {
+            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
+
+            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
+            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
+        }
+
+        // This also deletes the contents at the last position of the array
+        delete _ownedTokensIndex[tokenId];
+        delete _ownedTokens[from][lastTokenIndex];
+    }
+
+    /**
+     * @dev Private function to remove a token from this extension's token tracking data structures.
+     * This has O(1) time complexity, but alters the order of the _allTokens array.
+     * @param tokenId uint256 ID of the token to be removed from the tokens list
+     */
+    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
+        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
+        // then delete the last slot (swap and pop).
+
+        uint256 lastTokenIndex = _allTokens.length - 1;
+        uint256 tokenIndex = _allTokensIndex[tokenId];
+
+        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
+        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
+        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
+        uint256 lastTokenId = _allTokens[lastTokenIndex];
+
+        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
+        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
+
+        // This also deletes the contents at the last position of the array
+        delete _allTokensIndex[tokenId];
+        _allTokens.pop();
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol)
+
+pragma solidity ^0.8.0;
+
+import "../ERC721.sol";
+
+/**
+ * @dev ERC721 token with storage based token URI management.
+ */
+abstract contract ERC721URIStorage is ERC721 {
+    using Strings for uint256;
+
+    // Optional mapping for token URIs
+    mapping(uint256 => string) private _tokenURIs;
+
+    /**
+     * @dev See {IERC721Metadata-tokenURI}.
+     */
+    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
+        _requireMinted(tokenId);
+
+        string memory _tokenURI = _tokenURIs[tokenId];
+        string memory base = _baseURI();
+
+        // If there is no base URI, return the token URI.
+        if (bytes(base).length == 0) {
+            return _tokenURI;
+        }
+        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
+        if (bytes(_tokenURI).length > 0) {
+            return string(abi.encodePacked(base, _tokenURI));
+        }
+
+        return super.tokenURI(tokenId);
+    }
+
+    /**
+     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
+     *
+     * Requirements:
+     *
+     * - `tokenId` must exist.
+     */
+    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
+        require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
+        _tokenURIs[tokenId] = _tokenURI;
+    }
+
+    /**
+     * @dev See {ERC721-_burn}. This override additionally checks to see if a
+     * token-specific URI was set for the token, and if so, it deletes the token URI from
+     * the storage mapping.
+     */
+    function _burn(uint256 tokenId) internal virtual override {
+        super._burn(tokenId);
+
+        if (bytes(_tokenURIs[tokenId]).length != 0) {
+            delete _tokenURIs[tokenId];
+        }
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
+
+pragma solidity ^0.8.0;
+
+import "../IERC721.sol";
+
+/**
+ * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
+ * @dev See https://eips.ethereum.org/EIPS/eip-721
+ */
+interface IERC721Enumerable is IERC721 {
+    /**
+     * @dev Returns the total amount of tokens stored by the contract.
+     */
+    function totalSupply() external view returns (uint256);
+
+    /**
+     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
+     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
+     */
+    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
+
+    /**
+     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
+     * Use along with {totalSupply} to enumerate all tokens.
+     */
+    function tokenByIndex(uint256 index) external view returns (uint256);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
+
+pragma solidity ^0.8.0;
+
+import "../IERC721.sol";
+
+/**
+ * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+ * @dev See https://eips.ethereum.org/EIPS/eip-721
+ */
+interface IERC721Metadata is IERC721 {
+    /**
+     * @dev Returns the token collection name.
+     */
+    function name() external view returns (string memory);
+
+    /**
+     * @dev Returns the token collection symbol.
+     */
+    function symbol() external view returns (string memory);
+
+    /**
+     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
+     */
+    function tokenURI(uint256 tokenId) external view returns (string memory);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Address.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Address.sol
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
+
+pragma solidity ^0.8.1;
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+    /**
+     * @dev Returns true if `account` is a contract.
+     *
+     * [IMPORTANT]
+     * ====
+     * It is unsafe to assume that an address for which this function returns
+     * false is an externally-owned account (EOA) and not a contract.
+     *
+     * Among others, `isContract` will return false for the following
+     * types of addresses:
+     *
+     *  - an externally-owned account
+     *  - a contract in construction
+     *  - an address where a contract will be created
+     *  - an address where a contract lived, but was destroyed
+     * ====
+     *
+     * [IMPORTANT]
+     * ====
+     * You shouldn't rely on `isContract` to protect against flash loan attacks!
+     *
+     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
+     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
+     * constructor.
+     * ====
+     */
+    function isContract(address account) internal view returns (bool) {
+        // This method relies on extcodesize/address.code.length, which returns 0
+        // for contracts in construction, since the code is only stored at the end
+        // of the constructor execution.
+
+        return account.code.length > 0;
+    }
+
+    /**
+     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
+     * `recipient`, forwarding all available gas and reverting on errors.
+     *
+     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
+     * of certain opcodes, possibly making contracts go over the 2300 gas limit
+     * imposed by `transfer`, making them unable to receive funds via
+     * `transfer`. {sendValue} removes this limitation.
+     *
+     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
+     *
+     * IMPORTANT: because control is transferred to `recipient`, care must be
+     * taken to not create reentrancy vulnerabilities. Consider using
+     * {ReentrancyGuard} or the
+     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+     */
+    function sendValue(address payable recipient, uint256 amount) internal {
+        require(address(this).balance >= amount, "Address: insufficient balance");
+
+        (bool success, ) = recipient.call{value: amount}("");
+        require(success, "Address: unable to send value, recipient may have reverted");
+    }
+
+    /**
+     * @dev Performs a Solidity function call using a low level `call`. A
+     * plain `call` is an unsafe replacement for a function call: use this
+     * function instead.
+     *
+     * If `target` reverts with a revert reason, it is bubbled up by this
+     * function (like regular Solidity function calls).
+     *
+     * Returns the raw returned data. To convert to the expected return value,
+     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
+     *
+     * Requirements:
+     *
+     * - `target` must be a contract.
+     * - calling `target` with `data` must not revert.
+     *
+     * _Available since v3.1._
+     */
+    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
+     * `errorMessage` as a fallback revert reason when `target` reverts.
+     *
+     * _Available since v3.1._
+     */
+    function functionCall(
+        address target,
+        bytes memory data,
+        string memory errorMessage
+    ) internal returns (bytes memory) {
+        return functionCallWithValue(target, data, 0, errorMessage);
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+     * but also transferring `value` wei to `target`.
+     *
+     * Requirements:
+     *
+     * - the calling contract must have an ETH balance of at least `value`.
+     * - the called Solidity function must be `payable`.
+     *
+     * _Available since v3.1._
+     */
+    function functionCallWithValue(
+        address target,
+        bytes memory data,
+        uint256 value
+    ) internal returns (bytes memory) {
+        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
+     * with `errorMessage` as a fallback revert reason when `target` reverts.
+     *
+     * _Available since v3.1._
+     */
+    function functionCallWithValue(
+        address target,
+        bytes memory data,
+        uint256 value,
+        string memory errorMessage
+    ) internal returns (bytes memory) {
+        require(address(this).balance >= value, "Address: insufficient balance for call");
+        (bool success, bytes memory returndata) = target.call{value: value}(data);
+        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+     * but performing a static call.
+     *
+     * _Available since v3.3._
+     */
+    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+        return functionStaticCall(target, data, "Address: low-level static call failed");
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+     * but performing a static call.
+     *
+     * _Available since v3.3._
+     */
+    function functionStaticCall(
+        address target,
+        bytes memory data,
+        string memory errorMessage
+    ) internal view returns (bytes memory) {
+        (bool success, bytes memory returndata) = target.staticcall(data);
+        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+     * but performing a delegate call.
+     *
+     * _Available since v3.4._
+     */
+    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+    }
+
+    /**
+     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
+     * but performing a delegate call.
+     *
+     * _Available since v3.4._
+     */
+    function functionDelegateCall(
+        address target,
+        bytes memory data,
+        string memory errorMessage
+    ) internal returns (bytes memory) {
+        (bool success, bytes memory returndata) = target.delegatecall(data);
+        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
+    }
+
+    /**
+     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
+     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
+     *
+     * _Available since v4.8._
+     */
+    function verifyCallResultFromTarget(
+        address target,
+        bool success,
+        bytes memory returndata,
+        string memory errorMessage
+    ) internal view returns (bytes memory) {
+        if (success) {
+            if (returndata.length == 0) {
+                // only check isContract if the call was successful and the return data is empty
+                // otherwise we already know that it was a contract
+                require(isContract(target), "Address: call to non-contract");
+            }
+            return returndata;
+        } else {
+            _revert(returndata, errorMessage);
+        }
+    }
+
+    /**
+     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
+     * revert reason or using the provided one.
+     *
+     * _Available since v4.3._
+     */
+    function verifyCallResult(
+        bool success,
+        bytes memory returndata,
+        string memory errorMessage
+    ) internal pure returns (bytes memory) {
+        if (success) {
+            return returndata;
+        } else {
+            _revert(returndata, errorMessage);
+        }
+    }
+
+    function _revert(bytes memory returndata, string memory errorMessage) private pure {
+        // Look for revert reason and bubble it up if present
+        if (returndata.length > 0) {
+            // The easiest way to bubble the revert reason is using memory via assembly
+            /// @solidity memory-safe-assembly
+            assembly {
+                let returndata_size := mload(returndata)
+                revert(add(32, returndata), returndata_size)
+            }
+        } else {
+            revert(errorMessage);
+        }
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Context.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Context.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+    function _msgSender() internal view virtual returns (address) {
+        return msg.sender;
+    }
+
+    function _msgData() internal view virtual returns (bytes calldata) {
+        return msg.data;
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Counters.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Counters.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @title Counters
+ * @author Matt Condon (@shrugs)
+ * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
+ * of elements in a mapping, issuing ERC721 ids, or counting request ids.
+ *
+ * Include with `using Counters for Counters.Counter;`
+ */
+library Counters {
+    struct Counter {
+        // This variable should never be directly accessed by users of the library: interactions must be restricted to
+        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
+        // this feature: see https://github.com/ethereum/solidity/issues/4637
+        uint256 _value; // default: 0
+    }
+
+    function current(Counter storage counter) internal view returns (uint256) {
+        return counter._value;
+    }
+
+    function increment(Counter storage counter) internal {
+        unchecked {
+            counter._value += 1;
+        }
+    }
+
+    function decrement(Counter storage counter) internal {
+        uint256 value = counter._value;
+        require(value > 0, "Counter: decrement overflow");
+        unchecked {
+            counter._value = value - 1;
+        }
+    }
+
+    function reset(Counter storage counter) internal {
+        counter._value = 0;
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Strings.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/Strings.sol
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
+
+pragma solidity ^0.8.0;
+
+import "./math/Math.sol";
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+    bytes16 private constant _SYMBOLS = "0123456789abcdef";
+    uint8 private constant _ADDRESS_LENGTH = 20;
+
+    /**
+     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+     */
+    function toString(uint256 value) internal pure returns (string memory) {
+        unchecked {
+            uint256 length = Math.log10(value) + 1;
+            string memory buffer = new string(length);
+            uint256 ptr;
+            /// @solidity memory-safe-assembly
+            assembly {
+                ptr := add(buffer, add(32, length))
+            }
+            while (true) {
+                ptr--;
+                /// @solidity memory-safe-assembly
+                assembly {
+                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
+                }
+                value /= 10;
+                if (value == 0) break;
+            }
+            return buffer;
+        }
+    }
+
+    /**
+     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+     */
+    function toHexString(uint256 value) internal pure returns (string memory) {
+        unchecked {
+            return toHexString(value, Math.log256(value) + 1);
+        }
+    }
+
+    /**
+     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+     */
+    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+        bytes memory buffer = new bytes(2 * length + 2);
+        buffer[0] = "0";
+        buffer[1] = "x";
+        for (uint256 i = 2 * length + 1; i > 1; --i) {
+            buffer[i] = _SYMBOLS[value & 0xf];
+            value >>= 4;
+        }
+        require(value == 0, "Strings: hex length insufficient");
+        return string(buffer);
+    }
+
+    /**
+     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
+     */
+    function toHexString(address addr) internal pure returns (string memory) {
+        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/ERC165.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/ERC165.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC165.sol";
+
+/**
+ * @dev Implementation of the {IERC165} interface.
+ *
+ * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
+ * for the additional interface id that will be supported. For example:
+ *
+ * ```solidity
+ * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
+ * }
+ * ```
+ *
+ * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
+ */
+abstract contract ERC165 is IERC165 {
+    /**
+     * @dev See {IERC165-supportsInterface}.
+     */
+    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+        return interfaceId == type(IERC165).interfaceId;
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/IERC165.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/introspection/IERC165.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Interface of the ERC165 standard, as defined in the
+ * https://eips.ethereum.org/EIPS/eip-165[EIP].
+ *
+ * Implementers can declare support of contract interfaces, which can then be
+ * queried by others ({ERC165Checker}).
+ *
+ * For an implementation, see {ERC165}.
+ */
+interface IERC165 {
+    /**
+     * @dev Returns true if this contract implements the interface defined by
+     * `interfaceId`. See the corresponding
+     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
+     * to learn more about how these ids are created.
+     *
+     * This function call must use less than 30 000 gas.
+     */
+    function supportsInterface(bytes4 interfaceId) external view returns (bool);
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/math/Math.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/@openzeppelin/contracts/utils/math/Math.sol
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
+
+pragma solidity ^0.8.0;
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+    enum Rounding {
+        Down, // Toward negative infinity
+        Up, // Toward infinity
+        Zero // Toward zero
+    }
+
+    /**
+     * @dev Returns the largest of two numbers.
+     */
+    function max(uint256 a, uint256 b) internal pure returns (uint256) {
+        return a > b ? a : b;
+    }
+
+    /**
+     * @dev Returns the smallest of two numbers.
+     */
+    function min(uint256 a, uint256 b) internal pure returns (uint256) {
+        return a < b ? a : b;
+    }
+
+    /**
+     * @dev Returns the average of two numbers. The result is rounded towards
+     * zero.
+     */
+    function average(uint256 a, uint256 b) internal pure returns (uint256) {
+        // (a + b) / 2 can overflow.
+        return (a & b) + (a ^ b) / 2;
+    }
+
+    /**
+     * @dev Returns the ceiling of the division of two numbers.
+     *
+     * This differs from standard division with `/` in that it rounds up instead
+     * of rounding down.
+     */
+    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+        // (a + b - 1) / b can overflow on addition, so we distribute.
+        return a == 0 ? 0 : (a - 1) / b + 1;
+    }
+
+    /**
+     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
+     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
+     * with further edits by Uniswap Labs also under MIT license.
+     */
+    function mulDiv(
+        uint256 x,
+        uint256 y,
+        uint256 denominator
+    ) internal pure returns (uint256 result) {
+        unchecked {
+            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+            // variables such that product = prod1 * 2^256 + prod0.
+            uint256 prod0; // Least significant 256 bits of the product
+            uint256 prod1; // Most significant 256 bits of the product
+            assembly {
+                let mm := mulmod(x, y, not(0))
+                prod0 := mul(x, y)
+                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+            }
+
+            // Handle non-overflow cases, 256 by 256 division.
+            if (prod1 == 0) {
+                return prod0 / denominator;
+            }
+
+            // Make sure the result is less than 2^256. Also prevents denominator == 0.
+            require(denominator > prod1);
+
+            ///////////////////////////////////////////////
+            // 512 by 256 division.
+            ///////////////////////////////////////////////
+
+            // Make division exact by subtracting the remainder from [prod1 prod0].
+            uint256 remainder;
+            assembly {
+                // Compute remainder using mulmod.
+                remainder := mulmod(x, y, denominator)
+
+                // Subtract 256 bit number from 512 bit number.
+                prod1 := sub(prod1, gt(remainder, prod0))
+                prod0 := sub(prod0, remainder)
+            }
+
+            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
+            // See https://cs.stackexchange.com/q/138556/92363.
+
+            // Does not overflow because the denominator cannot be zero at this stage in the function.
+            uint256 twos = denominator & (~denominator + 1);
+            assembly {
+                // Divide denominator by twos.
+                denominator := div(denominator, twos)
+
+                // Divide [prod1 prod0] by twos.
+                prod0 := div(prod0, twos)
+
+                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+                twos := add(div(sub(0, twos), twos), 1)
+            }
+
+            // Shift in bits from prod1 into prod0.
+            prod0 |= prod1 * twos;
+
+            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+            // four bits. That is, denominator * inv = 1 mod 2^4.
+            uint256 inverse = (3 * denominator) ^ 2;
+
+            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
+            // in modular arithmetic, doubling the correct bits in each step.
+            inverse *= 2 - denominator * inverse; // inverse mod 2^8
+            inverse *= 2 - denominator * inverse; // inverse mod 2^16
+            inverse *= 2 - denominator * inverse; // inverse mod 2^32
+            inverse *= 2 - denominator * inverse; // inverse mod 2^64
+            inverse *= 2 - denominator * inverse; // inverse mod 2^128
+            inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+            // is no longer required.
+            result = prod0 * inverse;
+            return result;
+        }
+    }
+
+    /**
+     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+     */
+    function mulDiv(
+        uint256 x,
+        uint256 y,
+        uint256 denominator,
+        Rounding rounding
+    ) internal pure returns (uint256) {
+        uint256 result = mulDiv(x, y, denominator);
+        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
+            result += 1;
+        }
+        return result;
+    }
+
+    /**
+     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
+     *
+     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+     */
+    function sqrt(uint256 a) internal pure returns (uint256) {
+        if (a == 0) {
+            return 0;
+        }
+
+        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+        //
+        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+        //
+        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+        //
+        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+        uint256 result = 1 << (log2(a) >> 1);
+
+        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+        // into the expected uint128 result.
+        unchecked {
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            result = (result + a / result) >> 1;
+            return min(result, a / result);
+        }
+    }
+
+    /**
+     * @notice Calculates sqrt(a), following the selected rounding direction.
+     */
+    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = sqrt(a);
+            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 2, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log2(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >> 128 > 0) {
+                value >>= 128;
+                result += 128;
+            }
+            if (value >> 64 > 0) {
+                value >>= 64;
+                result += 64;
+            }
+            if (value >> 32 > 0) {
+                value >>= 32;
+                result += 32;
+            }
+            if (value >> 16 > 0) {
+                value >>= 16;
+                result += 16;
+            }
+            if (value >> 8 > 0) {
+                value >>= 8;
+                result += 8;
+            }
+            if (value >> 4 > 0) {
+                value >>= 4;
+                result += 4;
+            }
+            if (value >> 2 > 0) {
+                value >>= 2;
+                result += 2;
+            }
+            if (value >> 1 > 0) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log2(value);
+            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 10, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log10(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >= 10**64) {
+                value /= 10**64;
+                result += 64;
+            }
+            if (value >= 10**32) {
+                value /= 10**32;
+                result += 32;
+            }
+            if (value >= 10**16) {
+                value /= 10**16;
+                result += 16;
+            }
+            if (value >= 10**8) {
+                value /= 10**8;
+                result += 8;
+            }
+            if (value >= 10**4) {
+                value /= 10**4;
+                result += 4;
+            }
+            if (value >= 10**2) {
+                value /= 10**2;
+                result += 2;
+            }
+            if (value >= 10**1) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log10(value);
+            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
+        }
+    }
+
+    /**
+     * @dev Return the log in base 256, rounded down, of a positive value.
+     * Returns 0 if given 0.
+     *
+     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+     */
+    function log256(uint256 value) internal pure returns (uint256) {
+        uint256 result = 0;
+        unchecked {
+            if (value >> 128 > 0) {
+                value >>= 128;
+                result += 16;
+            }
+            if (value >> 64 > 0) {
+                value >>= 64;
+                result += 8;
+            }
+            if (value >> 32 > 0) {
+                value >>= 32;
+                result += 4;
+            }
+            if (value >> 16 > 0) {
+                value >>= 16;
+                result += 2;
+            }
+            if (value >> 8 > 0) {
+                result += 1;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+     * Returns 0 if given 0.
+     */
+    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+        unchecked {
+            uint256 result = log256(value);
+            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
+        }
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/ZeppelinContract.soldiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/ZeppelinContract.sol
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.9;
+
+import "./@openzeppelin/contracts/token/ERC721/ERC721.sol";
+import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
+import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
+import "./@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
+import "./@openzeppelin/contracts/access/Ownable.sol";
+import "./@openzeppelin/contracts/utils/Counters.sol";
+
+contract ZeppelinContract is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Burnable, Ownable {
+    using Counters for Counters.Counter;
+
+    Counters.Counter private _tokenIdCounter;
+
+    constructor() ERC721("ZeppelinContract", "UNQ") {}
+
+    function _baseURI() internal pure override returns (string memory) {
+        return "test";
+    }
+
+    function safeMint(address to, string memory uri) public onlyOwner {
+        uint256 tokenId = _tokenIdCounter.current();
+        _tokenIdCounter.increment();
+        _safeMint(to, tokenId);
+        _setTokenURI(tokenId, uri);
+    }
+
+    // The following functions are overrides required by Solidity.
+
+    function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
+        internal
+        override(ERC721, ERC721Enumerable)
+    {
+        super._beforeTokenTransfer(from, to, tokenId, batchSize);
+    }
+
+    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
+        super._burn(tokenId);
+    }
+
+    function tokenURI(uint256 tokenId)
+        public
+        view
+        override(ERC721, ERC721URIStorage)
+        returns (string memory)
+    {
+        return super.tokenURI(tokenId);
+    }
+
+    function supportsInterface(bytes4 interfaceId)
+        public
+        view
+        override(ERC721, ERC721Enumerable)
+        returns (bool)
+    {
+        return super.supportsInterface(interfaceId);
+    }
+}
addedtests/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.abidiffbeforeafterboth
after · tests/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.abi
1[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"string","name":"uri","type":"string"}],"name":"safeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
addedtests/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.bindiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/openZeppelin/ERC721/bin/ZeppelinContract.bin
@@ -0,0 +1 @@
+60806040523480156200001157600080fd5b506040518060400160405280601081526020016f16995c1c195b1a5b90dbdb9d1c9858dd60821b81525060405180604001604052806003815260200162554e5160e81b815250816000908162000068919062000195565b50600162000077828262000195565b505050620000946200008e6200009a60201b60201c565b6200009e565b62000261565b3390565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200011b57607f821691505b6020821081036200013c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019057600081815260208120601f850160051c810160208610156200016b5750805b601f850160051c820191505b818110156200018c5782815560010162000177565b5050505b505050565b81516001600160401b03811115620001b157620001b1620000f0565b620001c981620001c2845462000106565b8462000142565b602080601f831160018114620002015760008415620001e85750858301515b600019600386901b1c1916600185901b1785556200018c565b600085815260208120601f198616915b82811015620002325788860151825594840194600190910190840162000211565b5085821015620002515787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b611f0d80620002716000396000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c80636352211e116100b8578063a22cb4651161007c578063a22cb46514610271578063b88d4fde14610284578063c87b56dd14610297578063d204c45e146102aa578063e985e9c5146102bd578063f2fde38b146102f957600080fd5b80636352211e1461022a57806370a082311461023d578063715018a6146102505780638da5cb5b1461025857806395d89b411461026957600080fd5b806323b872dd116100ff57806323b872dd146101cb5780632f745c59146101de57806342842e0e146101f157806342966c68146102045780634f6ccce71461021757600080fd5b806301ffc9a71461013c57806306fdde0314610164578063081812fc14610179578063095ea7b3146101a457806318160ddd146101b9575b600080fd5b61014f61014a3660046118ab565b61030c565b60405190151581526020015b60405180910390f35b61016c61031d565b60405161015b9190611918565b61018c61018736600461192b565b6103af565b6040516001600160a01b03909116815260200161015b565b6101b76101b2366004611960565b6103d6565b005b6008545b60405190815260200161015b565b6101b76101d936600461198a565b6104f0565b6101bd6101ec366004611960565b610522565b6101b76101ff36600461198a565b6105b8565b6101b761021236600461192b565b6105d3565b6101bd61022536600461192b565b610604565b61018c61023836600461192b565b610697565b6101bd61024b3660046119c6565b6106f7565b6101b761077d565b600b546001600160a01b031661018c565b61016c610791565b6101b761027f3660046119e1565b6107a0565b6101b7610292366004611aa9565b6107af565b61016c6102a536600461192b565b6107e7565b6101b76102b8366004611b25565b6107f2565b61014f6102cb366004611b87565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6101b76103073660046119c6565b610829565b60006103178261089f565b92915050565b60606000805461032c90611bba565b80601f016020809104026020016040519081016040528092919081815260200182805461035890611bba565b80156103a55780601f1061037a576101008083540402835291602001916103a5565b820191906000526020600020905b81548152906001019060200180831161038857829003601f168201915b5050505050905090565b60006103ba826108c4565b506000908152600460205260409020546001600160a01b031690565b60006103e182610697565b9050806001600160a01b0316836001600160a01b0316036104535760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061046f575061046f81336102cb565b6104e15760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161044a565b6104eb8383610923565b505050565b6104fb335b82610991565b6105175760405162461bcd60e51b815260040161044a90611bf4565b6104eb838383610a10565b600061052d836106f7565b821061058f5760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b606482015260840161044a565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6104eb838383604051806020016040528060008152506107af565b6105dc336104f5565b6105f85760405162461bcd60e51b815260040161044a90611bf4565b61060181610b81565b50565b600061060f60085490565b82106106725760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b606482015260840161044a565b6008828154811061068557610685611c41565b90600052602060002001549050919050565b6000818152600260205260408120546001600160a01b0316806103175760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b60006001600160a01b0382166107615760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161044a565b506001600160a01b031660009081526003602052604090205490565b610785610b8a565b61078f6000610be4565b565b60606001805461032c90611bba565b6107ab338383610c36565b5050565b6107b93383610991565b6107d55760405162461bcd60e51b815260040161044a90611bf4565b6107e184848484610d04565b50505050565b606061031782610d37565b6107fa610b8a565b6000610805600c5490565b9050610815600c80546001019055565b61081f8382610e4b565b6104eb8183610e65565b610831610b8a565b6001600160a01b0381166108965760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161044a565b61060181610be4565b60006001600160e01b0319821663780e9d6360e01b1480610317575061031782610ef8565b6000818152600260205260409020546001600160a01b03166106015760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161044a565b600081815260046020526040902080546001600160a01b0319166001600160a01b038416908117909155819061095882610697565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061099d83610697565b9050806001600160a01b0316846001600160a01b031614806109e457506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80610a085750836001600160a01b03166109fd846103af565b6001600160a01b0316145b949350505050565b826001600160a01b0316610a2382610697565b6001600160a01b031614610a495760405162461bcd60e51b815260040161044a90611c57565b6001600160a01b038216610aab5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161044a565b610ab88383836001610f48565b826001600160a01b0316610acb82610697565b6001600160a01b031614610af15760405162461bcd60e51b815260040161044a90611c57565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61060181610f54565b600b546001600160a01b0316331461078f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161044a565b600b80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b031603610c975760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161044a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b610d0f848484610a10565b610d1b84848484610f94565b6107e15760405162461bcd60e51b815260040161044a90611c9c565b6060610d42826108c4565b6000828152600a602052604081208054610d5b90611bba565b80601f0160208091040260200160405190810160405280929190818152602001828054610d8790611bba565b8015610dd45780601f10610da957610100808354040283529160200191610dd4565b820191906000526020600020905b815481529060010190602001808311610db757829003601f168201915b505050505090506000610dfe6040805180820190915260048152631d195cdd60e21b602082015290565b90508051600003610e10575092915050565b815115610e42578082604051602001610e2a929190611cee565b60405160208183030381529060405292505050919050565b610a0884611095565b6107ab828260405180602001604052806000815250611115565b6000828152600260205260409020546001600160a01b0316610ee05760405162461bcd60e51b815260206004820152602e60248201527f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b606482015260840161044a565b6000828152600a602052604090206104eb8282611d6b565b60006001600160e01b031982166380ac58cd60e01b1480610f2957506001600160e01b03198216635b5e139f60e01b145b8061031757506301ffc9a760e01b6001600160e01b0319831614610317565b6107e184848484611148565b610f5d81611288565b6000818152600a602052604090208054610f7690611bba565b159050610601576000818152600a6020526040812061060191611847565b60006001600160a01b0384163b1561108a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610fd8903390899088908890600401611e2b565b6020604051808303816000875af1925050508015611013575060408051601f3d908101601f1916820190925261101091810190611e68565b60015b611070573d808015611041576040519150601f19603f3d011682016040523d82523d6000602084013e611046565b606091505b5080516000036110685760405162461bcd60e51b815260040161044a90611c9c565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610a08565b506001949350505050565b60606110a0826108c4565b60006110c36040805180820190915260048152631d195cdd60e21b602082015290565b905060008151116110e3576040518060200160405280600081525061110e565b806110ed8461132b565b6040516020016110fe929190611cee565b6040516020818303038152906040525b9392505050565b61111f83836113be565b61112c6000848484610f94565b6104eb5760405162461bcd60e51b815260040161044a90611c9c565b61115484848484611557565b60018111156111c35760405162461bcd60e51b815260206004820152603560248201527f455243373231456e756d657261626c653a20636f6e7365637574697665207472604482015274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b606482015260840161044a565b816001600160a01b03851661121f5761121a81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611242565b836001600160a01b0316856001600160a01b0316146112425761124285826115df565b6001600160a01b03841661125e576112598161167c565b611281565b846001600160a01b0316846001600160a01b03161461128157611281848261172b565b5050505050565b600061129382610697565b90506112a3816000846001610f48565b6112ac82610697565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b606060006113388361176f565b600101905060008167ffffffffffffffff81111561135857611358611a1d565b6040519080825280601f01601f191660200182016040528015611382576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461138c57509392505050565b6001600160a01b0382166114145760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161044a565b6000818152600260205260409020546001600160a01b0316156114795760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b611487600083836001610f48565b6000818152600260205260409020546001600160a01b0316156114ec5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161044a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60018111156107e1576001600160a01b0384161561159d576001600160a01b03841660009081526003602052604081208054839290611597908490611e9b565b90915550505b6001600160a01b038316156107e1576001600160a01b038316600090815260036020526040812080548392906115d4908490611eae565b909155505050505050565b600060016115ec846106f7565b6115f69190611e9b565b600083815260076020526040902054909150808214611649576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b60085460009061168e90600190611e9b565b600083815260096020526040812054600880549394509092849081106116b6576116b6611c41565b9060005260206000200154905080600883815481106116d7576116d7611c41565b600091825260208083209091019290925582815260099091526040808220849055858252812055600880548061170f5761170f611ec1565b6001900381819060005260206000200160009055905550505050565b6000611736836106f7565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106117ae5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106117da576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106117f857662386f26fc10000830492506010015b6305f5e1008310611810576305f5e100830492506008015b612710831061182457612710830492506004015b60648310611836576064830492506002015b600a83106103175760010192915050565b50805461185390611bba565b6000825580601f10611863575050565b601f01602090049060005260206000209081019061060191905b80821115611891576000815560010161187d565b5090565b6001600160e01b03198116811461060157600080fd5b6000602082840312156118bd57600080fd5b813561110e81611895565b60005b838110156118e35781810151838201526020016118cb565b50506000910152565b600081518084526119048160208601602086016118c8565b601f01601f19169290920160200192915050565b60208152600061110e60208301846118ec565b60006020828403121561193d57600080fd5b5035919050565b80356001600160a01b038116811461195b57600080fd5b919050565b6000806040838503121561197357600080fd5b61197c83611944565b946020939093013593505050565b60008060006060848603121561199f57600080fd5b6119a884611944565b92506119b660208501611944565b9150604084013590509250925092565b6000602082840312156119d857600080fd5b61110e82611944565b600080604083850312156119f457600080fd5b6119fd83611944565b915060208301358015158114611a1257600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611a4e57611a4e611a1d565b604051601f8501601f19908116603f01168101908282118183101715611a7657611a76611a1d565b81604052809350858152868686011115611a8f57600080fd5b858560208301376000602087830101525050509392505050565b60008060008060808587031215611abf57600080fd5b611ac885611944565b9350611ad660208601611944565b925060408501359150606085013567ffffffffffffffff811115611af957600080fd5b8501601f81018713611b0a57600080fd5b611b1987823560208401611a33565b91505092959194509250565b60008060408385031215611b3857600080fd5b611b4183611944565b9150602083013567ffffffffffffffff811115611b5d57600080fd5b8301601f81018513611b6e57600080fd5b611b7d85823560208401611a33565b9150509250929050565b60008060408385031215611b9a57600080fd5b611ba383611944565b9150611bb160208401611944565b90509250929050565b600181811c90821680611bce57607f821691505b602082108103611bee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60008351611d008184602088016118c8565b835190830190611d148183602088016118c8565b01949350505050565b601f8211156104eb57600081815260208120601f850160051c81016020861015611d445750805b601f850160051c820191505b81811015611d6357828155600101611d50565b505050505050565b815167ffffffffffffffff811115611d8557611d85611a1d565b611d9981611d938454611bba565b84611d1d565b602080601f831160018114611dce5760008415611db65750858301515b600019600386901b1c1916600185901b178555611d63565b600085815260208120601f198616915b82811015611dfd57888601518255948401946001909101908401611dde565b5085821015611e1b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611e5e908301846118ec565b9695505050505050565b600060208284031215611e7a57600080fd5b815161110e81611895565b634e487b7160e01b600052601160045260246000fd5b8181038181111561031757610317611e85565b8082018082111561031757610317611e85565b634e487b7160e01b600052603160045260246000fdfea26469706673582212207960bc65d7484ab1502ccdc352c91f0fb91535a525cf99e1b6392e242548279a64736f6c63430008110033
\ No newline at end of file
addedtests/src/benchmarks/utils/types.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/benchmarks/utils/types.ts
@@ -0,0 +1,62 @@
+export interface IFeeGas {
+  fee?: number | bigint,
+  gas?: number | bigint,
+  substrate?: number,
+  zeppelin?: {
+    fee: number | bigint,
+    gas: number | bigint,
+  }
+
+}
+export interface IFeeGasCsv extends IFeeGasVm {
+  function: 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 = {};
+
+    Object.keys(model).forEach(key => {
+      res[key] = {};
+      if (model[key].fee && model[key].gas) {
+        res[key].ethFee = model[key].fee;
+        res[key].ethGas = model[key].gas;
+      }
+      if (model[key].substrate)
+        res[key].substrate = model[key].substrate;
+      if (model[key].zeppelin) {
+        res[key].zeppelinFee = model[key].zeppelin?.fee;
+        res[key].zeppelinGas = model[key].zeppelin?.gas;
+      }
+    });
+
+    return res;
+  }
+}
\ No newline at end of file
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/eth/util/playgrounds/unique.dev.ts
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -16,7 +16,7 @@
 import {evmToAddress} from '@polkadot/util-crypto';
 import {IKeyringPair} from '@polkadot/types/types';
 
-import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
+import {ArrangeGroup, DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
 
 import {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types';
 
@@ -461,6 +461,41 @@
   }
 }
 
+export class FeeGas {
+  fee: number | bigint = 0n;
+
+  gas: number | bigint = 0n;
+
+  public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
+    const instance = new FeeGas();
+    instance.fee = instance.convertToTokens(fee);
+    instance.gas = await instance.convertToGas(fee, helper);
+    return instance;
+  }
+
+  private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
+    const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
+    return fee / gasPrice;
+  }
+
+  private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
+    return Number((value * 1000n) / nominal) / 1000;
+  }
+}
+
+class EthArrangeGroup extends ArrangeGroup {
+  helper: EthUniqueHelper;
+
+  constructor(helper: EthUniqueHelper) {
+    super(helper);
+    this.helper = helper;
+  }
+
+  async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
+    const fee = await this.calculcateFee(payer, promise);
+    return await FeeGas.build(this.helper, fee);
+  }
+}
 export class EthUniqueHelper extends DevUniqueHelper {
   web3: Web3 | null = null;
   web3Provider: WebsocketProvider | null = null;
@@ -471,7 +506,7 @@
   ethNativeContract: NativeContractGroup;
   ethContract: ContractGroup;
   ethProperty: EthPropertyGroup;
-
+  arrange: EthArrangeGroup;
   constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
     options.helperBase = options.helperBase ?? EthUniqueHelper;
 
@@ -482,6 +517,8 @@
     this.ethNativeContract = new NativeContractGroup(this);
     this.ethContract = new ContractGroup(this);
     this.ethProperty = new EthPropertyGroup(this);
+    this.arrange = new EthArrangeGroup(this);
+    super.arrange = this.arrange;
   }
 
   getWeb3(): Web3 {
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -186,7 +186,7 @@
 
 export class DevKaruraHelper extends DevAcalaHelper {}
 
-class ArrangeGroup {
+export class ArrangeGroup {
   helper: DevUniqueHelper;
 
   scheduledIdSlider = 0;
@@ -321,7 +321,7 @@
   };
 
   async calculcateFee(payer: ICrossAccountId, promise: () => Promise<any>): Promise<bigint> {
-    const address = payer.Substrate ? payer.Substrate : await this.helper.address.ethToSubstrate(payer.Ethereum!);
+    const address = payer.Substrate ? payer.Substrate : this.helper.address.ethToSubstrate(payer.Ethereum!);
     let balance = await this.helper.balance.getSubstrate(address);
 
     await promise();