1import {readFile} from 'fs/promises';2import {getBalanceSingle, transferBalanceExpectSuccess} from '../../substrate/get-balance';3import privateKey from '../../substrate/privateKey';4import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers';5import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, subToEth, subToEthLowercase} from '../util/helpers';6import {evmToAddress} from '@polkadot/util-crypto';7import nonFungibleAbi from '../nonFungibleAbi.json';8import fungibleAbi from '../fungibleAbi.json';9import {expect} from 'chai';1011const PRICE = 2000n;1213describe('Matcher contract usage', () => {14 itWeb3('With UNQ', async ({api, web3}) => {15 const matcherOwner = await createEthAccountWithBalance(api, web3);16 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {17 from: matcherOwner,18 ...GAS_ARGS,19 });20 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});21 const helpers = contractHelpers(web3, matcherOwner);22 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});23 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});2425 const alice = privateKey('//Alice');26 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});27 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});28 await setCollectionSponsorExpectSuccess(collectionId, alice.address);29 await confirmSponsorshipExpectSuccess(collectionId);3031 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});32 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));3334 const seller = privateKey('//Bob');35 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});36 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));3738 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);3940 41 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});4243 44 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});4546 47 {48 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));49 await executeEthTxOnSub(web3, api, seller, matcher, m => m.setAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));50 }5152 53 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});5455 56 {57 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);58 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});59 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);60 }6162 63 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});646566 67 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});6869 70 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});71 });7273 74 itWeb3.skip('With custom ERC20', async ({api, web3}) => {75 const matcherOwner = await createEthAccountWithBalance(api, web3);76 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {77 from: matcherOwner,78 ...GAS_ARGS,79 });80 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});8182 const alice = privateKey('//Alice');83 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});84 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});8586 const fungibleId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});87 const evmFungible = new web3.eth.Contract(fungibleAbi as any, collectionIdToAddress(fungibleId), {from: matcherOwner, ...GAS_ARGS});88 await createFungibleItemExpectSuccess(alice, fungibleId, {Value: PRICE}, {Ethereum: subToEth(alice.address)});8990 const seller = privateKey('//Bob');9192 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);9394 95 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});96 97 await transferBalanceExpectSuccess(api, seller, evmToAddress(subToEth(seller.address)), 10n ** 18n);98 await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), 10n ** 18n);99100 101 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});102103 104 {105 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));106 await executeEthTxOnSub(web3, api, seller, matcher, m => m.setAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));107 }108109 110 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});111112 113 {114 const sellerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call());115 const buyerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call());116117 await executeEthTxOnSub(web3, api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));118 119 await executeEthTxOnSub(web3, api, alice, matcher, m =>120 m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));121122 123 expect(BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call()) - sellerBalanceBeforePurchase === PRICE);124 expect(buyerBalanceBeforePurchase - BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call()) === PRICE);125 }126127 128 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});129130131 132 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});133134 135 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});136 });137138 itWeb3('With escrow', async ({api, web3}) => {139 const matcherOwner = await createEthAccountWithBalance(api, web3);140 const escrow = await createEthAccountWithBalance(api, web3);141 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {142 from: matcherOwner,143 ...GAS_ARGS,144 });145 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});146 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});147 const helpers = contractHelpers(web3, matcherOwner);148 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});149 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});150151 const alice = privateKey('//Alice');152 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});153 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});154 await setCollectionSponsorExpectSuccess(collectionId, alice.address);155 await confirmSponsorshipExpectSuccess(collectionId);156157 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});158 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));159160 const seller = privateKey('//Bob');161 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});162 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));163164 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);165166 167 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});168169 170 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});171172 173 {174 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));175 await executeEthTxOnSub(web3, api, seller, matcher, m => m.setAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));176 }177178 179 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});180181 182 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});183184 185 {186 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');187 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());188189 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));190191 192 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');193 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());194 }195196 197 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});198199 200 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});201202 203 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});204 });205});