difftreelog
Merge pull request #230 from UniqueNetwork/feature/core-202
in: master
orml-vesting pallet
3 files changed
runtime/Cargo.tomldiffbeforeafterboth--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -60,7 +60,7 @@
'pallet-transaction-payment/std',
'pallet-transaction-payment-rpc-runtime-api/std',
'pallet-treasury/std',
- 'pallet-vesting/std',
+ # 'pallet-vesting/std',
'pallet-evm/std',
'pallet-evm-migration/std',
'pallet-evm-contract-helpers/std',
@@ -97,6 +97,8 @@
'xcm/std',
'xcm-builder/std',
'xcm-executor/std',
+
+ "orml-vesting/std",
]
limit-testing = ['pallet-nft/limit-testing', 'nft-data-structs/limit-testing']
@@ -210,10 +212,10 @@
git = 'https://github.com/paritytech/substrate.git'
branch = 'polkadot-v0.9.12'
-[dependencies.pallet-vesting]
-default-features = false
-git = 'https://github.com/paritytech/substrate.git'
-branch = 'polkadot-v0.9.12'
+# [dependencies.pallet-vesting]
+# default-features = false
+# git = 'https://github.com/paritytech/substrate.git'
+# branch = 'polkadot-v0.9.12'
[dependencies.sp-arithmetic]
default-features = false
@@ -359,6 +361,10 @@
branch = 'release-v0.9.12'
default-features = false
+[dependencies.orml-vesting]
+git = "https://github.com/open-web3-stack/open-runtime-module-library"
+version = "0.4.1-dev"
+default-features = false
################################################################################
# local dependencies
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -22,8 +22,7 @@
use sp_runtime::{
Permill, Perbill, Percent, create_runtime_str, generic, impl_opaque_keys,
traits::{
- AccountIdLookup, ConvertInto, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify,
- AccountIdConversion,
+ AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, Verify, AccountIdConversion,
},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature,
@@ -70,7 +69,7 @@
use fp_rpc::TransactionStatus;
use sp_core::crypto::Public;
use sp_runtime::{
- traits::{Dispatchable, PostDispatchInfoOf},
+ traits::{BlockNumberProvider, Dispatchable, PostDispatchInfoOf},
transaction_validity::TransactionValidityError,
};
@@ -515,17 +514,33 @@
type Call = Call;
}
+pub struct RelayChainBlockNumberProvider<T>(sp_std::marker::PhantomData<T>);
+
+impl<T: cumulus_pallet_parachain_system::Config> BlockNumberProvider
+ for RelayChainBlockNumberProvider<T>
+{
+ type BlockNumber = BlockNumber;
+
+ fn current_block_number() -> Self::BlockNumber {
+ cumulus_pallet_parachain_system::Pallet::<T>::validation_data()
+ .map(|d| d.relay_parent_number)
+ .unwrap_or_default()
+ }
+}
+
parameter_types! {
pub const MinVestedTransfer: Balance = 10 * UNIQUE;
+ pub const MaxVestingSchedules: u32 = 28;
}
-impl pallet_vesting::Config for Runtime {
+impl orml_vesting::Config for Runtime {
type Event = Event;
- type Currency = Balances;
- type BlockNumberToBalance = ConvertInto;
+ type Currency = pallet_balances::Pallet<Runtime>;
type MinVestedTransfer = MinVestedTransfer;
+ type VestedTransferOrigin = EnsureSigned<AccountId>;
type WeightInfo = ();
- const MAX_VESTING_SCHEDULES: u32 = 28;
+ type MaxVestingSchedules = MaxVestingSchedules;
+ type BlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
}
parameter_types! {
@@ -841,7 +856,8 @@
Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
System: system::{Pallet, Call, Storage, Config, Event<T>} = 36,
- Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
+ Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
+ // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
// Contracts: pallet_contracts::{Pallet, Call, Storage, Event<T>} = 38,
// XCM helpers.
tests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth1import {readFile} from 'fs/promises';2import {getBalanceSingle, transferBalanceExpectSuccess} from '../../substrate/get-balance';3import privateKey from '../../substrate/privateKey';4import {addToWhiteListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers';5import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, subToEth, subToEthLowercase} 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.only('Matcher contract usage', () => {14 itWeb3('With UNQ', async ({api, web3}) => {15 const matcherOwner = await createEthAccountWithBalance(api, web3);16 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {17 from: matcherOwner,18 ...GAS_ARGS,19 });20 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});21 const helpers = contractHelpers(web3, matcherOwner);22 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});23 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});2425 const alice = privateKey('//Alice');26 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});27 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});28 await setCollectionSponsorExpectSuccess(collectionId, alice.address);29 await confirmSponsorshipExpectSuccess(collectionId);3031 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});32 await addToWhiteListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));3334 const seller = privateKey('//Bob');35 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});36 await addToWhiteListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));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 bob41 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});4243 // Token is owned by seller initially44 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});4546 // Ask47 {48 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));49 await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));50 }5152 // Token is transferred to matcher53 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});5455 // Buy56 {57 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);58 // There is two functions named 'buy', so we should provide full signature59 await executeEthTxOnSub(api, alice, matcher, m => m['buy(address,uint256)'](evmCollection.options.address, tokenId), {value: PRICE});60 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);61 }6263 // Token is transferred to evm account of alice64 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});656667 // Transfer token to substrate side of alice68 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});6970 // Token is transferred to substrate account of alice, seller received funds71 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});72 });7374 // selling for custom tokens excluded from release75 itWeb3.skip('With custom ERC20', async ({api, web3}) => {76 const matcherOwner = await createEthAccountWithBalance(api, web3);77 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {78 from: matcherOwner,79 ...GAS_ARGS,80 });81 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});8283 const alice = privateKey('//Alice');84 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});85 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});8687 const fungibleId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});88 const evmFungible = new web3.eth.Contract(fungibleAbi as any, collectionIdToAddress(fungibleId), {from: matcherOwner, ...GAS_ARGS});89 await createFungibleItemExpectSuccess(alice, fungibleId, {Value: PRICE}, {Ethereum: subToEth(alice.address)});9091 const seller = privateKey('//Bob');9293 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);9495 // To transfer item to matcher it first needs to be transfered to EVM account of bob96 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});97 // Fees will be paid from EVM account, so we should have some balance here98 await transferBalanceExpectSuccess(api, seller, evmToAddress(subToEth(seller.address)), 10n ** 18n);99 await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), 10n ** 18n);100101 // Token is owned by seller initially102 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});103104 // Ask105 {106 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));107 await executeEthTxOnSub(api, seller, matcher, m => m.setAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));108 }109110 // Token is transferred to matcher111 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});112113 // Buy114 {115 const sellerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call());116 const buyerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call());117118 await executeEthTxOnSub(api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));119 // There is two functions named 'buy', so we should provide full signature120 await executeEthTxOnSub(api, alice, matcher, m =>121 m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));122123 // Approved price is removed from buyer balance, and added to seller124 expect(BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call()) - sellerBalanceBeforePurchase === PRICE);125 expect(buyerBalanceBeforePurchase - BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call()) === PRICE);126 }127128 // Token is transferred to evm account of alice129 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});130131132 // Transfer token to substrate side of alice133 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});134135 // Token is transferred to substrate account of alice136 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});137 });138139 itWeb3('With escrow', async ({api, web3}) => {140 const matcherOwner = await createEthAccountWithBalance(api, web3);141 const escrow = await createEthAccountWithBalance(api, web3);142 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {143 from: matcherOwner,144 ...GAS_ARGS,145 });146 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});147 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});148 const helpers = contractHelpers(web3, matcherOwner);149 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});150 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});151152 const alice = privateKey('//Alice');153 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});154 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});155 await setCollectionSponsorExpectSuccess(collectionId, alice.address);156 await confirmSponsorshipExpectSuccess(collectionId);157158 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});159 await addToWhiteListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));160161 const seller = privateKey('//Bob');162 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});163 await addToWhiteListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));164165 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);166167 // To transfer item to matcher it first needs to be transfered to EVM account of bob168 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});169170 // Token is owned by seller initially171 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});172173 // Ask174 {175 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));176 await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));177 }178179 // Token is transferred to matcher180 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});181182 // Give buyer KSM183 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});184185 // Buy186 {187 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');188 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());189190 await executeEthTxOnSub(api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));191192 // Price is removed from buyer balance, and added to seller193 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');194 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());195 }196197 // Token is transferred to evm account of alice198 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});199200 // Transfer token to substrate side of alice201 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});202203 // Token is transferred to substrate account of alice, seller received funds204 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});205 });206});1import {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} 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 matcherOwner = await createEthAccountWithBalance(api, web3);16 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {17 from: matcherOwner,18 ...GAS_ARGS,19 });20 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});21 const helpers = contractHelpers(web3, matcherOwner);22 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});23 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});2425 const alice = privateKey('//Alice');26 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});27 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});28 await setCollectionSponsorExpectSuccess(collectionId, alice.address);29 await confirmSponsorshipExpectSuccess(collectionId);3031 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});32 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));3334 const seller = privateKey('//Bob');35 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});36 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));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 bob41 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});4243 // Token is owned by seller initially44 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});4546 // Ask47 {48 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));49 await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));50 }5152 // Token is transferred to matcher53 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});5455 // Buy56 {57 const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);58 // There is two functions named 'buy', so we should provide full signature59 await executeEthTxOnSub(api, alice, matcher, m => m['buy(address,uint256)'](evmCollection.options.address, tokenId), {value: PRICE});60 expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);61 }6263 // Token is transferred to evm account of alice64 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});656667 // Transfer token to substrate side of alice68 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});6970 // Token is transferred to substrate account of alice, seller received funds71 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});72 });7374 // selling for custom tokens excluded from release75 itWeb3.skip('With custom ERC20', async ({api, web3}) => {76 const matcherOwner = await createEthAccountWithBalance(api, web3);77 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {78 from: matcherOwner,79 ...GAS_ARGS,80 });81 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});8283 const alice = privateKey('//Alice');84 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});85 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});8687 const fungibleId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});88 const evmFungible = new web3.eth.Contract(fungibleAbi as any, collectionIdToAddress(fungibleId), {from: matcherOwner, ...GAS_ARGS});89 await createFungibleItemExpectSuccess(alice, fungibleId, {Value: PRICE}, {Ethereum: subToEth(alice.address)});9091 const seller = privateKey('//Bob');9293 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);9495 // To transfer item to matcher it first needs to be transfered to EVM account of bob96 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});97 // Fees will be paid from EVM account, so we should have some balance here98 await transferBalanceExpectSuccess(api, seller, evmToAddress(subToEth(seller.address)), 10n ** 18n);99 await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), 10n ** 18n);100101 // Token is owned by seller initially102 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});103104 // Ask105 {106 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));107 await executeEthTxOnSub(api, seller, matcher, m => m.setAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));108 }109110 // Token is transferred to matcher111 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});112113 // Buy114 {115 const sellerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call());116 const buyerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call());117118 await executeEthTxOnSub(api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));119 // There is two functions named 'buy', so we should provide full signature120 await executeEthTxOnSub(api, alice, matcher, m =>121 m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));122123 // Approved price is removed from buyer balance, and added to seller124 expect(BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call()) - sellerBalanceBeforePurchase === PRICE);125 expect(buyerBalanceBeforePurchase - BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call()) === PRICE);126 }127128 // Token is transferred to evm account of alice129 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});130131132 // Transfer token to substrate side of alice133 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});134135 // Token is transferred to substrate account of alice136 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});137 });138139 itWeb3('With escrow', async ({api, web3}) => {140 const matcherOwner = await createEthAccountWithBalance(api, web3);141 const escrow = await createEthAccountWithBalance(api, web3);142 const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {143 from: matcherOwner,144 ...GAS_ARGS,145 });146 const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});147 await matcher.methods.setEscrow(escrow).send({from: matcherOwner});148 const helpers = contractHelpers(web3, matcherOwner);149 await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});150 await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});151152 const alice = privateKey('//Alice');153 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});154 const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});155 await setCollectionSponsorExpectSuccess(collectionId, alice.address);156 await confirmSponsorshipExpectSuccess(collectionId);157158 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});159 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));160161 const seller = privateKey('//Bob');162 await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});163 await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));164165 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);166167 // To transfer item to matcher it first needs to be transfered to EVM account of bob168 await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});169170 // Token is owned by seller initially171 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});172173 // Ask174 {175 await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));176 await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));177 }178179 // Token is transferred to matcher180 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: matcher.options.address.toLowerCase()});181182 // Give buyer KSM183 await matcher.methods.depositKSM(PRICE, subToEth(alice.address)).send({from: escrow});184185 // Buy186 {187 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');188 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());189190 await executeEthTxOnSub(api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));191192 // Price is removed from buyer balance, and added to seller193 expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');194 expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal(PRICE.toString());195 }196197 // Token is transferred to evm account of alice198 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(alice.address)});199200 // Transfer token to substrate side of alice201 await transferFromExpectSuccess(collectionId, tokenId, alice, {Ethereum: subToEth(alice.address)}, {Substrate: alice.address});202203 // Token is transferred to substrate account of alice, seller received funds204 expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Substrate: alice.address});205 });206});