1234567891011121314151617import {readFile} from 'fs/promises';18import {getBalanceSingle} from '../../substrate/get-balance';19import privateKey from '../../substrate/privateKey';20import {21 addToAllowListExpectSuccess, 22 confirmSponsorshipExpectSuccess, 23 createCollectionExpectSuccess, 24 createItemExpectSuccess, 25 getTokenOwner,26 setCollectionLimitsExpectSuccess, 27 setCollectionSponsorExpectSuccess, 28 transferExpectSuccess, 29 transferFromExpectSuccess,30 transferBalanceTo,31} from '../../util/helpers';32import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, SponsoringMode, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';33import {evmToAddress} from '@polkadot/util-crypto';34import nonFungibleAbi from '../nonFungibleAbi.json';3536import {expect} from 'chai';3738const PRICE = 2000n;3940describe('Matcher contract usage', () => {41 itWeb3('With UNQ', async ({api, web3}) => {42 const alice = privateKey('//Alice');43 const matcherOwner = await createEthAccountWithBalance(api, web3);44 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {45 from: matcherOwner,46 ...GAS_ARGS,47 });48 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});49 const helpers = contractHelpers(web3, matcherOwner);50 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});51 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});52 await transferBalanceToEth(api, alice, matcher.options.address);5354 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});55 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});56 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});57 await setCollectionSponsorExpectSuccess(collectionId, alice.address);58 await transferBalanceToEth(api, alice, subToEth(alice.address));59 await confirmSponsorshipExpectSuccess(collectionId);6061 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});62 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));6364 const seller = privateKey(`//Seller/${Date.now()}`);65 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});6667 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);6869 70 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});7172 73 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});7475 76 {77 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));78 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));79 }8081 82 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});8384 85 {86 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);87 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});88 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);89 }9091 92 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});9394 95 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});9697 98 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});99 });100101102 itWeb3('With escrow', async ({api, web3}) => {103 const alice = privateKey('//Alice');104 const matcherOwner = await createEthAccountWithBalance(api, web3);105 const escrow = await createEthAccountWithBalance(api, web3);106 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {107 from: matcherOwner,108 ...GAS_ARGS,109 });110 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});111 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});112 const helpers = contractHelpers(web3, matcherOwner);113 await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner});114 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});115 await transferBalanceToEth(api, alice, matcher.options.address);116117 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});118 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});119 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});120 await setCollectionSponsorExpectSuccess(collectionId, alice.address);121 await transferBalanceToEth(api, alice, subToEth(alice.address));122 await confirmSponsorshipExpectSuccess(collectionId);123124 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});125 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));126127 const seller = privateKey(`//Seller/${Date.now()}`);128 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});129130 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);131132 133 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});134135 136 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});137138 139 {140 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));141 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));142 }143144 145 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});146147 148 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});149150 151 {152 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');153 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());154155 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));156157 158 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');159 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());160 }161162 163 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});164165 166 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});167168 169 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});170 });171172173 itWeb3('Sell tokens from substrate user via EVM contract', async ({api, web3}) => {174 const alice = privateKey('//Alice');175 const matcherOwner = await createEthAccountWithBalance(api, web3);176 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {177 from: matcherOwner,178 ...GAS_ARGS,179 });180 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});181 await transferBalanceToEth(api, alice, matcher.options.address);182183 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});184 await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});185 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});186187 const seller = privateKey(`//Seller/${Date.now()}`);188 await transferBalanceTo(api, alice, seller.address);189 190 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);191192 193 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});194195 196 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});197198 199 {200 await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));201 await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));202 }203204 205 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});206207 208 {209 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);210 await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});211 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);212 }213214 215 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});216217 218 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});219220 221 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});222 });223});