1import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';2import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.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/tests/eth/util/playgrounds/types.js';9import type {RMRKNestableMintable} from './ABIGEN/index.js';1011const {dirname} = makeNames(import.meta.url);1213export const CONTRACT_IMPORT: ContractImports[] = [14 {15 fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,16 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol',17 },18 {19 fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,20 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol',21 },22 {23 fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,24 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol',25 },26 {27 fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,28 solPath: '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol',29 },30 {31 fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,32 solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',33 },34 {35 fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,36 solPath: '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol',37 },38 {39 fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Address.sol`,40 solPath: '@openzeppelin/contracts/utils/Address.sol',41 },42 {43 fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,44 solPath: '@openzeppelin/contracts/utils/Context.sol',45 },46 {47 fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,48 solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',49 },50 {51 fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,52 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol',53 },54 {55 fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,56 solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol',57 },58 {59 fsPath: `${dirname}/RMRKNestableMintable.sol`,60 solPath: 'RMRKNestableMintable.sol',61 },62];636465const main = async () => {6667 await usingEthPlaygrounds(async (helper, privateKey) => {6869 const donor = await privateKey('//Alice'); 7071 const eth = await measureEth(helper, donor);72 const sub = await measureSub(helper, donor);73 const rmrk = await measureRMRK(helper, donor);74 console.table({susbtrate: sub, eth: eth, rmrk: rmrk});75 });76};7778async function measureRMRK(helper: EthUniqueHelper, donor: IKeyringPair) {79 const CONTRACT_SOURCE = (80 await readFile(`${dirname}/RMRKNestableMintable.sol`)81 ).toString();82 const RELAYER_SOURCE = (await readFile(`${dirname}/relayer.sol`)).toString();8384 const ethSigner = await helper.eth.createAccountWithBalance(donor);8586 const contract = await helper.ethContract.deployByCode(87 ethSigner,88 'RMRKNestableMintable',89 CONTRACT_SOURCE,90 CONTRACT_IMPORT,91 5000000,92 );9394 const relayer = await helper.ethContract.deployByCode(95 ethSigner,96 'Relayer',97 RELAYER_SOURCE,98 CONTRACT_IMPORT,99 5000000,100 [contract.options.address],101 );102103 const relayerAddress = relayer.options.address;104105 const rmrk = contract as any as RMRKNestableMintable;106 const createTokenFor = async (receiver: string) => {107 const tokenReceipt = await rmrk.methods.safeMint(receiver).send({from: ethSigner});108 return tokenReceipt.events!['Transfer'].returnValues.tokenId as number;109 };110111112 const nestId = await createTokenFor(ethSigner);113 const outerCollectionNestedId = 10;114 const contractOwnedNestId = await createTokenFor(relayerAddress);115 const nextTokenId = contractOwnedNestId + 1;116117 const nestTransfer = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {118 const addChildData = rmrk.methods.addChild(nestId, outerCollectionNestedId, []).encodeABI();119 await relayer.methods.relay(addChildData).send({from: ethSigner});120 await rmrk.methods.acceptChild(nestId, 0, relayerAddress, outerCollectionNestedId).send({from: ethSigner});121 });122123124 const nestMint = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {125 const nestMintData = rmrk.methods.nestMint(rmrk.options.address, nextTokenId, contractOwnedNestId).encodeABI();126 await relayer.methods.relay(nestMintData).send({from: ethSigner});127 const acceptNestedToken = rmrk.methods.acceptChild(contractOwnedNestId, 0, rmrk.options.address, nextTokenId).encodeABI();128 await relayer.methods.relay(acceptNestedToken).send({from: ethSigner});129 });130131132 const unnestToken = await helper.arrange.calculcateFee({Ethereum: ethSigner}, async () => {133 const unnestData = rmrk.methods.transferChild(contractOwnedNestId, ethSigner, 0, 0, rmrk.options.address, nextTokenId, false, []).encodeABI();134 await relayer.methods.relay(unnestData).send({from: ethSigner});135 });136137 return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};138}139140async function measureEth(helper: EthUniqueHelper, donor: IKeyringPair) {141 const owner = await helper.eth.createAccountWithBalance(donor);142 const {collectionId, contract} = await createNestingCollection(helper, owner);143144 145 const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner});146 const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId;147 const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);148149 150 const nestMint = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {151 await contract.methods.mint(targetNftTokenAddress).send({from: owner});152 });153154 155 const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner});156 const nestedTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId;157158 const nestTransfer = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {159 await contract.methods.transfer(targetNftTokenAddress, nestedTokenId).send({from: owner});160 });161162 const unnestToken = await helper.arrange.calculcateFee({Ethereum: owner}, async () => {163 await contract.methods.transferFrom(targetNftTokenAddress, owner, nestedTokenId).send({from: owner});164 });165 return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};166}167168async function measureSub(helper: EthUniqueHelper, donor: IKeyringPair) {169170 const [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);171172 const targetNFTCollection = await helper.nft.mintCollection(alice);173 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});174175176 const collectionForNesting = await helper.nft.mintCollection(bob);177 178 await targetNFTCollection.setPermissions(alice, {179 nesting: {tokenOwner: true},180 });181182 const nestMint = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {183 await (collectionForNesting.mintToken(bob, targetTokenBob.nestingAccount()));184 });185186 const nestedToken2 = await collectionForNesting.mintToken(bob);187 const nestTransfer = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {188 await nestedToken2.nest(bob, targetTokenBob);189 });190191 const unnestToken = await helper.arrange.calculcateFee({Substrate: bob.address}, async () => {192 await nestedToken2.transferFrom(bob, targetTokenBob.nestingAccount(), {Substrate: bob.address});193 });194195 return {mint: convertToTokens(nestMint), transfer: convertToTokens(nestTransfer), unnest: convertToTokens(unnestToken)};196}197198199const createNestingCollection = async (200 helper: EthUniqueHelper,201 owner: string,202): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {203 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');204205 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);206 await contract.methods.setCollectionNesting(true).send({from: owner});207208 return {collectionId, collectionAddress, contract};209};210211main()212 .then(() => process.exit(0))213 .catch((e) => {214 console.log(e);215 process.exit(1);216 });217218219220221222