difftreelog
test marketplace sponsorship config
in: master
2 files changed
tests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth1import {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, transferBalanceToEth} 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 alice = privateKey('//Alice');16 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});17 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId));18 const matcherOwner = await createEthAccountWithBalance(api, web3);19 const helpers = contractHelpers(web3, matcherOwner);2021 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {22 from: matcherOwner,23 ...GAS_ARGS,24 });25 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});2627 await transferBalanceToEth(api, alice, matcher.options.address);28 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});2930 await transferBalanceToEth(api, alice, subToEth(alice.address));31 await setCollectionSponsorExpectSuccess(collectionId, alice.address);32 await confirmSponsorshipExpectSuccess(collectionId);3334 const seller = privateKey('//Seller/' + Date.now());35 await addToAllowListExpectSuccess(alice, collectionId, {Ethereum:subToEth(seller.address)});36 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});3738 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);3940 // To transfer item to matcher it first needs to be transfered to EVM account of seller41 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});42 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});4344 // Ask45 {46 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));47 await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));48 }4950 // Token is transferred to matcher51 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});5253 // Buy54 {55 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);56 await executeEthTxOnSub(api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});57 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);58 }5960 // Token is transferred to evm account of alice61 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});6263 // Transfer token to substrate side of alice64 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});6566 // Token is transferred to substrate account of alice, seller received funds67 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});68 });6970 // selling for custom tokens excluded from release71 itWeb3.skip('With custom ERC20', async ({api, web3}) => {72 const matcherOwner = await createEthAccountWithBalance(api, web3);73 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {74 from: matcherOwner,75 ...GAS_ARGS,76 });77 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});7879 const alice = privateKey('//Alice');80 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});81 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});8283 const fungibleId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});84 const evmFungible = new web3.eth.Contract(fungibleAbi as any, collectionIdToAddress(fungibleId), {from: matcherOwner, ...GAS_ARGS});85 await createFungibleItemExpectSuccess(alice, fungibleId, {Value: PRICE}, {Ethereum: subToEth(alice.address)});8687 const seller = privateKey('//Bob');8889 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);9091 // To transfer item to matcher it first needs to be transfered to EVM account of bob92 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});93 // Fees will be paid from EVM account, so we should have some balance here94 await transferBalanceExpectSuccess(api, seller, evmToAddress(subToEth(seller.address)), 10n ** 18n);95 await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), 10n ** 18n);9697 // Token is owned by seller initially98 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});99100 // Ask101 {102 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));103 await executeEthTxOnSub(api, seller, matcher, m => m.setAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));104 }105106 // Token is transferred to matcher107 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});108109 // Buy110 {111 const sellerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call());112 const buyerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call());113114 await executeEthTxOnSub(api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));115 // There is two functions named 'buy', so we should provide full signature116 await executeEthTxOnSub(api, alice, matcher, m =>117 m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));118119 // Approved price is removed from buyer balance, and added to seller120 expect(BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call()) - sellerBalanceBeforePurchase === PRICE);121 expect(buyerBalanceBeforePurchase - BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call()) === PRICE);122 }123124 // Token is transferred to evm account of alice125 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});126127128 // Transfer token to substrate side of alice129 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});130131 // Token is transferred to substrate account of alice132 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});133 });134135 itWeb3('With escrow', async ({api, web3}) => {136 const alice = privateKey('//Alice');137 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});138 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId));139 const matcherOwner = await createEthAccountWithBalance(api, web3);140 const helpers = contractHelpers(web3, matcherOwner);141 const escrow = await createEthAccountWithBalance(api, web3);142143 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {144 from: matcherOwner,145 ...GAS_ARGS,146 });147 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});148 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});149150 await transferBalanceToEth(api, alice, matcher.options.address);151 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});152153 await transferBalanceToEth(api, alice, subToEth(alice.address));154 await setCollectionSponsorExpectSuccess(collectionId, alice.address);155 await confirmSponsorshipExpectSuccess(collectionId);156157 const seller = privateKey('//Seller/' + Date.now());158 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});159 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));160161 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);162163 // To transfer item to matcher it first needs to be transfered to EVM account of seller164 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});165 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});166167 // Ask168 {169 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));170 await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));171 }172173 // Token is transferred to matcher174 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});175176 // Give buyer KSM177 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});178179 // Buy180 {181 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');182 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());183184 await executeEthTxOnSub(api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));185186 // Price is removed from buyer balance, and added to seller187 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');188 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());189 }190191 // Token is transferred to evm account of alice192 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});193194 // Transfer token to substrate side of alice195 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});196197 // Token is transferred to substrate account of alice, seller received funds198 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});199 });200});tests/src/eth/util/helpers.tsdiffbeforeafterboth--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -228,6 +228,18 @@
return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS});
}
+/**
+ * Execute ethereum method call using substrate account
+ * @param to target contract
+ * @param mkTx - closure, receiving `contract.methods`, and returning method call,
+ * to be used as following (assuming `to` = erc20 contract):
+ * `m => m.transfer(to, amount)`
+ *
+ * # Example
+ * ```ts
+ * executeEthTxOnSub(api, alice, erc20Contract, m => m.transfer(target, amount));
+ * ```
+ */
export async function executeEthTxOnSub(api: ApiPromise, from: IKeyringPair, to: any, mkTx: (methods: any) => any, {value = 0}: {value?: bigint | number} = { }) {
const tx = api.tx.evm.call(
subToEth(from.address),
@@ -246,6 +258,11 @@
return (await getBalance(api, [evmToAddress(address)]))[0];
}
+/**
+ * Measure how much gas given closure consumes
+ *
+ * @param user which user balance will be checked
+ */
export async function recordEthFee(api: ApiPromise, user: string, call: () => Promise<any>): Promise<bigint> {
const before = await ethBalanceViaSub(api, user);