1234567891011121314151617import {readFile} from 'fs/promises';18import {getBalanceSingle, transferBalanceExpectSuccess} from '../../substrate/get-balance';19import privateKey from '../../substrate/privateKey';20import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionLimitsExpectSuccess, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers';21import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, SponsoringMode, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';22import {evmToAddress} from '@polkadot/util-crypto';23import nonFungibleAbi from '../nonFungibleAbi.json';24import fungibleAbi from '../fungibleAbi.json';25import {expect} from 'chai';2627const PRICE = 2000n;2829describe('Matcher contract usage', () => {30 itWeb3('With UNQ', async ({api, web3}) => {31 const alice = privateKey('//Alice');32 const matcherOwner = await createEthAccountWithBalance(api, web3);33 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {34 from: matcherOwner,35 ...GAS_ARGS,36 });37 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});38 const helpers = contractHelpers(web3, matcherOwner);39 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});40 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});41 await transferBalanceToEth(api, alice, matcher.options.address);4243 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});44 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});45 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});46 await setCollectionSponsorExpectSuccess(collectionId, alice.address);47 await transferBalanceToEth(api, alice, subToEth(alice.address));48 await confirmSponsorshipExpectSuccess(collectionId);4950 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});51 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));5253 const seller = privateKey(`//Seller/${Date.now()}`);54 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});5556 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);5758 59 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});6061 62 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});6364 65 {66 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));67 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));68 }6970 71 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});7273 74 {75 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);76 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});77 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);78 }7980 81 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});8283 84 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});8586 87 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});88 });8990 91 itWeb3.skip('With custom ERC20', async ({api, web3}) => {92 const alice = privateKey('//Alice');93 const matcherOwner = await createEthAccountWithBalance(api, web3);94 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {95 from: matcherOwner,96 ...GAS_ARGS,97 });98 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});99100 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});101 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});102103 const fungibleId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});104 const evmFungible = new web3.eth.Contract(fungibleAbi as any, collectionIdToAddress(fungibleId), {from: matcherOwner, ...GAS_ARGS});105 await createFungibleItemExpectSuccess(alice, fungibleId, {Value: PRICE}, {Ethereum: subToEth(alice.address)});106107 const seller = privateKey('//Bob');108109 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);110111 112 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});113 114 await transferBalanceExpectSuccess(api, seller, evmToAddress(subToEth(seller.address)), 10n ** 18n);115 await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), 10n ** 18n);116117 118 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});119120 121 {122 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));123 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));124 }125126 127 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});128129 130 {131 const sellerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call());132 const buyerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call());133134 await executeEthTxOnSub(web3, api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));135 136 await executeEthTxOnSub(web3, api, alice, matcher, m =>137 m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));138139 140 expect(BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call()) - sellerBalanceBeforePurchase === PRICE);141 expect(buyerBalanceBeforePurchase - BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call()) === PRICE);142 }143144 145 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});146147148 149 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});150151 152 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});153 });154155 itWeb3('With escrow', async ({api, web3}) => {156 const alice = privateKey('//Alice');157 const matcherOwner = await createEthAccountWithBalance(api, web3);158 const escrow = await createEthAccountWithBalance(api, web3);159 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {160 from: matcherOwner,161 ...GAS_ARGS,162 });163 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});164 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});165 const helpers = contractHelpers(web3, matcherOwner);166 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});167 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});168 await transferBalanceToEth(api, alice, matcher.options.address);169170 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});171 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});172 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});173 await setCollectionSponsorExpectSuccess(collectionId, alice.address);174 await transferBalanceToEth(api, alice, subToEth(alice.address));175 await confirmSponsorshipExpectSuccess(collectionId);176177 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});178 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));179180 const seller = privateKey(`//Seller/${Date.now()}`);181 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});182183 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);184185 186 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});187188 189 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});190191 192 {193 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));194 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));195 }196197 198 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});199200 201 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});202203 204 {205 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');206 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());207208 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));209210 211 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');212 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());213 }214215 216 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});217218 219 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});220221 222 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});223 });224});