--- a/tests/src/eth/marketplace/marketplace.test.ts +++ b/tests/src/eth/marketplace/marketplace.test.ts @@ -2,7 +2,7 @@ import {getBalanceSingle, transferBalanceExpectSuccess} from '../../substrate/get-balance'; import privateKey from '../../substrate/privateKey'; import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers'; -import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, subToEth, subToEthLowercase} from '../util/helpers'; +import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers'; import {evmToAddress} from '@polkadot/util-crypto'; import nonFungibleAbi from '../nonFungibleAbi.json'; import fungibleAbi from '../fungibleAbi.json'; @@ -12,35 +12,33 @@ describe('Matcher contract usage', () => { itWeb3('With UNQ', async ({api, web3}) => { + const alice = privateKey('//Alice'); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); + const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId)); const matcherOwner = await createEthAccountWithBalance(api, web3); + const helpers = contractHelpers(web3, matcherOwner); + const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, { from: matcherOwner, ...GAS_ARGS, }); const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner}); - const helpers = contractHelpers(web3, matcherOwner); + + await transferBalanceToEth(api, alice, matcher.options.address); await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner}); - await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner}); - const alice = privateKey('//Alice'); - const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner}); + await transferBalanceToEth(api, alice, subToEth(alice.address)); await setCollectionSponsorExpectSuccess(collectionId, alice.address); await confirmSponsorshipExpectSuccess(collectionId); - await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner}); - await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address))); - - const seller = privateKey('//Bob'); + const seller = privateKey('//Seller/' + Date.now()); + await addToAllowListExpectSuccess(alice, collectionId, {Ethereum:subToEth(seller.address)}); await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner}); - await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address))); const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address); - // To transfer item to matcher it first needs to be transfered to EVM account of bob + // To transfer item to matcher it first needs to be transfered to EVM account of seller await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)}); - - // Token is owned by seller initially expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)}); // Ask @@ -55,14 +53,12 @@ // Buy { const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address); - // There is two functions named 'buy', so we should provide full signature - await executeEthTxOnSub(api, alice, matcher, m => m['buy(address,uint256)'](evmCollection.options.address, tokenId), {value: PRICE}); + await executeEthTxOnSub(api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE}); expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE); } // Token is transferred to evm account of alice expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)}); - // Transfer token to substrate side of alice await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address}); @@ -137,37 +133,35 @@ }); itWeb3('With escrow', async ({api, web3}) => { + const alice = privateKey('//Alice'); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); + const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId)); const matcherOwner = await createEthAccountWithBalance(api, web3); + const helpers = contractHelpers(web3, matcherOwner); const escrow = await createEthAccountWithBalance(api, web3); + const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, { from: matcherOwner, ...GAS_ARGS, }); const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner}); await matcher.methods.setEscrow(escrow).send({from: matcherOwner}); - const helpers = contractHelpers(web3, matcherOwner); + + await transferBalanceToEth(api, alice, matcher.options.address); await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner}); - await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner}); - const alice = privateKey('//Alice'); - const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner}); + await transferBalanceToEth(api, alice, subToEth(alice.address)); await setCollectionSponsorExpectSuccess(collectionId, alice.address); await confirmSponsorshipExpectSuccess(collectionId); - - await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner}); - await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address))); - const seller = privateKey('//Bob'); + const seller = privateKey('//Seller/' + Date.now()); await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner}); await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address))); const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address); - // To transfer item to matcher it first needs to be transfered to EVM account of bob + // To transfer item to matcher it first needs to be transfered to EVM account of seller await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)}); - - // Token is owned by seller initially expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)}); // Ask --- 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): Promise { const before = await ethBalanceViaSub(api, user);