1import {usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';2import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';3import {readFile} from 'fs/promises';4import type {IKeyringPair} from '@polkadot/types/types';5import {Contract} from 'web3-eth-contract';6import {convertToTokens} from '../utils/common.js';7import {makeNames} from '@unique/test-utils/util.js';8import type {ContractImports} from '@unique/test-utils/eth/types.js';9import type {RMRKNestableMintable} from './ABIGEN/index.js';1011const {dirname} = makeNames(import.meta.url);1213const NODE_MODULES = `${dirname}/../../../../node_modules`;1415export const CONTRACT_IMPORT: ContractImports[] = [16 {17 fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,18 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol',19 },20 {21 fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,22 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol',23 },24 {25 fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,26 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol',27 },28 {29 fsPath: `${NODE_MODULES}/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,30 solPath: '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol',31 },32 {33 fsPath: `${NODE_MODULES}/@openzeppelin/contracts/token/ERC721/IERC721.sol`,34 solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',35 },36 {37 fsPath: `${NODE_MODULES}/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,38 solPath: '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol',39 },40 {41 fsPath: `${NODE_MODULES}/@openzeppelin/contracts/utils/Address.sol`,42 solPath: '@openzeppelin/contracts/utils/Address.sol',43 },44 {45 fsPath: `${NODE_MODULES}/@openzeppelin/contracts/utils/Context.sol`,46 solPath: '@openzeppelin/contracts/utils/Context.sol',47 },48 {49 fsPath: `${NODE_MODULES}/@openzeppelin/contracts/utils/introspection/IERC165.sol`,50 solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',51 },52 {53 fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,54 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol',55 },56 {57 fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,58 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol',59 },60 {61 fsPath: `${dirname}/RMRKNestableMintable.sol`,62 solPath: 'RMRKNestableMintable.sol',63 },64];656667const main = async () => {6869 await usingEthPlaygrounds(async (helper, privateKey) => {7071 const donor = await privateKey('//Alice'); 7273 const eth = await measureEth(helper, donor);74 const sub = await measureSub(helper, donor);75 const rmrk = await measureRMRK(helper, donor);76 console.table({susbtrate: sub, eth: eth, rmrk: rmrk});77 });78};7980async function measureRMRK(helper: EthUniqueHelper, donor: IKeyringPair) {81 const CONTRACT_SOURCE = (82 await readFile(`${dirname}/RMRKNestableMintable.sol`)83 ).toString();84 const RELAYER_SOURCE = (await readFile(`${dirname}/relayer.sol`)).toString();8586 const ethSigner = await helper.eth.createAccountWithBalance(donor);8788 const contract = await helper.ethContract.deployByCode(89 ethSigner,90 'RMRKNestableMintable',91 CONTRACT_SOURCE,92 CONTRACT_IMPORT,93 5000000,94 );9596 const relayer = await helper.ethContract.deployByCode(97 ethSigner,98 'Relayer',99 RELAYER_SOURCE,100 CONTRACT_IMPORT,101 5000000,102 [contract.options.address],103 );104105 const relayerAddress = relayer.options.address;106107 const rmrk = contract as any as RMRKNestableMintable;108 const createTokenFor = async (receiver: string) => {109 const tokenReceipt = await rmrk.methods.safeMint(receiver).send({from: ethSigner});110 return tokenReceipt.events!['Transfer'].returnValues.tokenId as number;111 };112113114 const nestId = await createTokenFor(ethSigner);115 const outerCollectionNestedId = 10;116 const contractOwnedNestId = await createTokenFor(relayerAddress);117 const nextTokenId = contractOwnedNestId + 1;118119 const nestTransfer = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {120 const addChildData = rmrk.methods.addChild(nestId, outerCollectionNestedId, []).encodeABI();121 await relayer.methods.relay(addChildData).send({from: ethSigner});122 await rmrk.methods.acceptChild(nestId, 0, relayerAddress, outerCollectionNestedId).send({from: ethSigner});123 });124125126 const nestMint = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {127 const nestMintData = rmrk.methods.nestMint(rmrk.options.address, nextTokenId, contractOwnedNestId).encodeABI();128 await relayer.methods.relay(nestMintData).send({from: ethSigner});129 const acceptNestedToken = rmrk.methods.acceptChild(contractOwnedNestId, 0, rmrk.options.address, nextTokenId).encodeABI();130 await relayer.methods.relay(acceptNestedToken).send({from: ethSigner});131 });132133134 const unnestToken = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {135 const unnestData = rmrk.methods.transferChild(contractOwnedNestId, ethSigner, 0, 0, rmrk.options.address, nextTokenId, false, []).encodeABI();136 await relayer.methods.relay(unnestData).send({from: ethSigner});137 });138139 return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};140}141142async function measureEth(helper: EthUniqueHelper, donor: IKeyringPair) {143 const owner = await helper.eth.createAccountWithBalance(donor);144 const {collectionId, contract} = await createNestingCollection(helper, owner);145146 147 const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});148 const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;149 const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);150151 152 const nestMint = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {153 await contract.methods.mint(targetNftTokenAddress).send({from: owner});154 });155156 157 const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});158 const nestedTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;159160 const nestTransfer = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {161 await contract.methods.transfer(targetNftTokenAddress, nestedTokenId).send({from: owner});162 });163164 const unnestToken = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {165 await contract.methods.transferFrom(targetNftTokenAddress, owner, nestedTokenId).send({from: owner});166 });167 return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};168}169170async function measureSub(helper: EthUniqueHelper, donor: IKeyringPair) {171172 const [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);173174 const targetNFTCollection = await helper.nft.mintCollection(alice);175 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});176177178 const collectionForNesting = await helper.nft.mintCollection(bob);179 180 await targetNFTCollection.setPermissions(alice, {181 nesting: {tokenOwner: true},182 });183184 const nestMint = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {185 await (collectionForNesting.mintToken(bob, targetTokenBob.nestingAccount()));186 });187188 const nestedToken2 = await collectionForNesting.mintToken(bob);189 const nestTransfer = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {190 await nestedToken2.nest(bob, targetTokenBob);191 });192193 const unnestToken = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {194 await nestedToken2.transferFrom(bob, targetTokenBob.nestingAccount(), {Substrate: bob.address});195 });196197 return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};198}199200201const createNestingCollection = async (202 helper: EthUniqueHelper,203 owner: string,204): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {205 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');206207 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);208 await contract.methods.setCollectionNesting(true).send({from: owner});209210 return {collectionId, collectionAddress, contract};211};212213main()214 .then(() => process.exit(0))215 .catch((e) => {216 console.log(e);217 process.exit(1);218 });219220221222223224