1234567891011121314151617import type {IKeyringPair} from '@polkadot/types/types';18import {readFile} from 'fs/promises';19import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from '@unique/test-utils/eth/util.js';20import {makeNames} from '@unique/test-utils/util.js';2122const {dirname} = makeNames(import.meta.url);23const EVM_ABI_DIR = `${dirname}/../../../evm-abi`;2425describe('Matcher contract usage', () => {26 const PRICE = 2000n;27 let donor: IKeyringPair;28 let alice: IKeyringPair;29 let aliceMirror: string;30 let aliceDoubleMirror: string;31 let seller: IKeyringPair;32 let sellerMirror: string;3334 before(async () => {35 await usingEthPlaygrounds(async (_helper, privateKey) => {36 donor = await privateKey({url: import.meta.url});37 });38 });3940 beforeEach(async () => {41 await usingEthPlaygrounds(async (helper, privateKey) => {42 [alice] = await helper.arrange.createAccounts([1000n], donor);43 aliceMirror = helper.address.substrateToEth(alice.address).toLowerCase();44 aliceDoubleMirror = helper.address.ethToSubstrate(aliceMirror);45 seller = await privateKey(`//Seller/${Date.now()}`);46 sellerMirror = helper.address.substrateToEth(seller.address).toLowerCase();4748 await helper.balance.transferToSubstrate(donor, aliceDoubleMirror, 10_000_000_000_000_000_000n);49 });50 });5152 itEth('With UNQ', async ({helper}) => {53 const matcherOwner = await helper.eth.createAccountWithBalance(donor);54 const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);5556 const sponsor = await helper.eth.createAccountWithBalance(donor);57 const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);58 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});59 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});6061 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});62 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});6364 const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: {Substrate: alice.address}});65 await collection.confirmSponsorship(alice);66 await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});67 const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');68 await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);6970 await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});71 await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});7273 const token = await collection.mintToken(alice, {Ethereum: sellerMirror});7475 76 expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});7778 79 {80 await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');81 await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');82 }8384 85 expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});8687 88 {89 const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);90 await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());91 expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);92 }9394 95 expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});9697 98 await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});99100 101 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});102 });103104 itEth('With escrow', async ({helper}) => {105 const matcherOwner = await helper.eth.createAccountWithBalance(donor);106 const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);107108 const sponsor = await helper.eth.createAccountWithBalance(donor);109 const escrow = await helper.eth.createAccountWithBalance(donor);110 await matcher.methods.setEscrow(escrow, true).send({from: matcherOwner});111 const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);112 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});113 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});114115 await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner});116 await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor});117118 const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: {Substrate: alice.address}});119 await collection.confirmSponsorship(alice);120 await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror});121 const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');122 await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror);123124125 await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner});126127 await helpers.methods.toggleAllowed(matcher.options.address, sellerMirror, true).send({from: matcherOwner});128129 const token = await collection.mintToken(alice, {Ethereum: sellerMirror});130131 132 expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});133134 135 {136 await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');137 await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');138 }139140 141 expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});142143 144 await matcher.methods.depositKSM(PRICE, aliceMirror).send({from: escrow});145146 147 {148 expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal('0');149 expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal(PRICE.toString());150151 await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buyKSM(evmCollection.options.address, token.tokenId, aliceMirror, aliceMirror).encodeABI(), '0');152153 154 expect(await matcher.methods.balanceKSM(aliceMirror).call()).to.be.equal('0');155 expect(await matcher.methods.balanceKSM(sellerMirror).call()).to.be.equal(PRICE.toString());156 }157158 159 expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});160161 162 await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});163164 165 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});166 });167168 itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {169 const matcherOwner = await helper.eth.createAccountWithBalance(donor);170 const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);171172 await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);173174 const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}});175 const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');176177 await helper.balance.transferToSubstrate(donor, seller.address, 100_000_000_000_000_000_000n);178179 const token = await collection.mintToken(alice, {Ethereum: sellerMirror});180181 182 expect(await token.getOwner()).to.be.deep.equal({Ethereum: sellerMirror});183184 185 {186 await helper.eth.sendEVM(seller, evmCollection.options.address, evmCollection.methods.approve(matcher.options.address, token.tokenId).encodeABI(), '0');187 await helper.eth.sendEVM(seller, matcher.options.address, matcher.methods.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, token.tokenId).encodeABI(), '0');188 }189190 191 expect(await token.getOwner()).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});192193 194 {195 const sellerBalanceBeforePurchase = await helper.balance.getSubstrate(seller.address);196 await helper.eth.sendEVM(alice, matcher.options.address, matcher.methods.buy(evmCollection.options.address, token.tokenId).encodeABI(), PRICE.toString());197 expect(await helper.balance.getSubstrate(seller.address) - sellerBalanceBeforePurchase === PRICE);198 }199200 201 expect(await token.getOwner()).to.be.deep.equal({Ethereum: aliceMirror});202203 204 await token.transferFrom(alice, {Ethereum: aliceMirror}, {Substrate: alice.address});205206 207 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});208 });209});