1234567891011121314151617import {readFile} from 'fs/promises';18import {getBalanceSingle} from '../../substrate/get-balance';19import {20 addToAllowListExpectSuccess, 21 confirmSponsorshipExpectSuccess, 22 createCollectionExpectSuccess, 23 createItemExpectSuccess, 24 getTokenOwner,25 setCollectionLimitsExpectSuccess, 26 setCollectionSponsorExpectSuccess, 27 transferExpectSuccess, 28 transferFromExpectSuccess,29 transferBalanceTo,30} from '../../util/helpers';31import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, SponsoringMode, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';32import {evmToAddress} from '@polkadot/util-crypto';33import nonFungibleAbi from '../nonFungibleAbi.json';3435import {expect} from 'chai';3637const PRICE = 2000n;3839describe('Matcher contract usage', () => {40 itWeb3('With UNQ', async ({api, web3, privateKeyWrapper}) => {41 const alice = privateKeyWrapper('//Alice');42 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);43 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {44 from: matcherOwner,45 ...GAS_ARGS,46 });47 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});48 const helpers = contractHelpers(web3, matcherOwner);49 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});50 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});51 await transferBalanceToEth(api, alice, matcher.options.address);5253 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});54 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});55 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});56 await setCollectionSponsorExpectSuccess(collectionId, alice.address);57 await transferBalanceToEth(api, alice, subToEth(alice.address));58 await confirmSponsorshipExpectSuccess(collectionId);5960 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});61 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));6263 const seller = privateKeyWrapper(`//Seller/${Date.now()}`);64 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});6566 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);6768 69 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});7071 72 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});7374 75 {76 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));77 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));78 }7980 81 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});8283 84 {85 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);86 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});87 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);88 }8990 91 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});9293 94 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});9596 97 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});98 });99100101 itWeb3('With escrow', async ({api, web3, privateKeyWrapper}) => {102 const alice = privateKeyWrapper('//Alice');103 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);104 const escrow = await createEthAccountWithBalance(api, web3, privateKeyWrapper);105 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {106 from: matcherOwner,107 ...GAS_ARGS,108 });109 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});110 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});111 const helpers = contractHelpers(web3, 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});114 await transferBalanceToEth(api, alice, matcher.options.address);115116 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});117 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});118 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});119 await setCollectionSponsorExpectSuccess(collectionId, alice.address);120 await transferBalanceToEth(api, alice, subToEth(alice.address));121 await confirmSponsorshipExpectSuccess(collectionId);122123 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});124 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));125126 const seller = privateKeyWrapper(`//Seller/${Date.now()}`);127 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});128129 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);130131 132 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});133134 135 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});136137 138 {139 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));140 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));141 }142143 144 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});145146 147 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});148149 150 {151 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');152 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());153154 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));155156 157 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');158 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());159 }160161 162 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});163164 165 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});166167 168 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});169 });170171172 itWeb3('Sell tokens from substrate user via EVM contract', async ({api, web3, privateKeyWrapper}) => {173 const alice = privateKeyWrapper('//Alice');174 const matcherOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);175 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {176 from: matcherOwner,177 ...GAS_ARGS,178 });179 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});180 await transferBalanceToEth(api, alice, matcher.options.address);181182 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});183 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});184 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});185186 const seller = privateKeyWrapper(`//Seller/${Date.now()}`);187 await transferBalanceTo(api, alice, seller.address);188 189 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);190191 192 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});193194 195 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});196197 198 {199 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));200 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));201 }202203 204 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});205206 207 {208 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);209 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});210 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);211 }212213 214 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});215216 217 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});218219 220 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});221 });222});