git.delta.rocks / unique-network / refs/commits / 2dfd73643010

difftreelog

source

tests/src/eth/marketplace/marketplace.test.ts13.1 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {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    // To transfer item to matcher it first needs to be transfered to EVM account of bob59    await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});6061    // Token is owned by seller initially62    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});6364    // Ask65    {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    // Token is transferred to matcher71    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});7273    // Buy74    {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    // Token is transferred to evm account of alice81    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});8283    // Transfer token to substrate side of alice84    await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});8586    // Token is transferred to substrate account of alice, seller received funds87    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});88  });8990  // selling for custom tokens excluded from release91  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    // To transfer item to matcher it first needs to be transfered to EVM account of bob112    await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});113    // Fees will be paid from EVM account, so we should have some balance here114    await transferBalanceExpectSuccess(api, seller, evmToAddress(subToEth(seller.address)), 10n ** 18n);115    await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), 10n ** 18n);116117    // Token is owned by seller initially118    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});119120    // Ask121    {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    // Token is transferred to matcher127    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});128129    // Buy130    {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      // There is two functions named 'buy', so we should provide full signature136      await executeEthTxOnSub(web3, api, alice, matcher, m =>137        m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));138139      // Approved price is removed from buyer balance, and added to seller140      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    // Token is transferred to evm account of alice145    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});146147148    // Transfer token to substrate side of alice149    await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});150151    // Token is transferred to substrate account of alice152    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    // To transfer item to matcher it first needs to be transfered to EVM account of bob186    await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});187188    // Token is owned by seller initially189    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});190191    // Ask192    {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    // Token is transferred to matcher198    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});199200    // Give buyer KSM201    await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});202203    // Buy204    {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      // Price is removed from buyer balance, and added to seller211      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    // Token is transferred to evm account of alice216    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});217218    // Transfer token to substrate side of alice219    await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});220221    // Token is transferred to substrate account of alice, seller received funds222    expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});223  });224});