difftreelog
refac: incapsulate CollectionHandler into CollectionDispatch
in: master
13 files changed
pallets/balances-adapter/src/lib.rsdiffbeforeafterboth--- a/pallets/balances-adapter/src/lib.rs
+++ b/pallets/balances-adapter/src/lib.rs
@@ -3,6 +3,7 @@
#![warn(missing_docs)]
extern crate alloc;
+use frame_support::sp_runtime::DispatchResult;
pub use pallet::*;
use pallet_common::CollectionHandle;
use pallet_evm_coder_substrate::{WithRecorder, SubstrateRecorder};
@@ -10,24 +11,23 @@
pub mod common;
pub mod erc;
-pub struct NativeFungibleHandle<T: Config>(CollectionHandle<T>);
+pub struct NativeFungibleHandle<T: Config>(SubstrateRecorder<T>);
impl<T: Config> NativeFungibleHandle<T> {
- pub fn cast(inner: CollectionHandle<T>) -> Self {
- Self(inner)
+ pub fn new() -> NativeFungibleHandle<T> {
+ Self(SubstrateRecorder::new(u64::MAX))
}
- /// Casts [`NativeFungibleHandle`] into [`CollectionHandle`][`pallet_common::CollectionHandle`].
- pub fn into_inner(self) -> pallet_common::CollectionHandle<T> {
- self.0
+ pub fn check_is_internal(&self) -> DispatchResult {
+ Ok(())
}
}
impl<T: Config> WithRecorder<T> for NativeFungibleHandle<T> {
fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
- &self.0.recorder
+ &self.0
}
fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
- self.0.recorder
+ self.0
}
}
#[frame_support::pallet]
pallets/common/src/dispatch.rsdiffbeforeafterboth--- a/pallets/common/src/dispatch.rs
+++ b/pallets/common/src/dispatch.rs
@@ -34,16 +34,11 @@
collection: CollectionId,
call: C,
) -> DispatchResultWithPostInfo {
- let handle =
- CollectionHandle::try_get(collection).map_err(|error| DispatchErrorWithPostInfo {
- post_info: PostDispatchInfo {
- actual_weight: Some(dispatch_weight::<T>()),
- pays_fee: Pays::Yes,
- },
- error,
- })?;
- handle
- .check_is_internal()
+ let dispatched = T::CollectionDispatch::dispatch(collection)
+ .and_then(|dispatched| {
+ dispatched.check_is_internal()?;
+ Ok(dispatched)
+ })
.map_err(|error| DispatchErrorWithPostInfo {
post_info: PostDispatchInfo {
actual_weight: Some(dispatch_weight::<T>()),
@@ -51,7 +46,6 @@
},
error,
})?;
- let dispatched = T::CollectionDispatch::dispatch(handle);
let mut result = call(dispatched.as_dyn());
match &mut result {
Ok(PostDispatchInfo {
@@ -72,6 +66,8 @@
/// Interface for working with different collections through the dispatcher.
pub trait CollectionDispatch<T: Config> {
+ fn check_is_internal(&self) -> DispatchResult;
+
/// Create a collection. The collection will be created according to the value of [`data.mode`](CreateCollectionData::mode).
///
/// * `sender` - The user who will become the owner of the collection.
@@ -92,7 +88,9 @@
/// Get a specialized collection from the handle.
///
/// * `handle` - Collection handle.
- fn dispatch(handle: CollectionHandle<T>) -> Self;
+ fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError>
+ where
+ Self: Sized;
/// Get the implementation of [`CommonCollectionOperations`].
fn as_dyn(&self) -> &dyn CommonCollectionOperations<T>;
pallets/common/src/erc.rsdiffbeforeafterboth--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -77,6 +77,14 @@
fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;
}
+impl CommonEvmHandler for () {
+ const CODE: &'static [u8] = &[];
+
+ fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
+ None
+ }
+}
+
/// @title A contract that allows you to work with collections.
#[solidity_interface(name = Collection, enum(derive(PreDispatch)), enum_attr(weight))]
impl<T: Config> CollectionHandle<T>
pallets/structure/src/benchmarking.rsdiffbeforeafterboth--- a/pallets/structure/src/benchmarking.rs
+++ b/pallets/structure/src/benchmarking.rs
@@ -42,7 +42,7 @@
},
CollectionFlags::default(),
)?;
- let dispatch = T::CollectionDispatch::dispatch(CollectionHandle::try_get(CollectionId(1))?);
+ let dispatch = T::CollectionDispatch::dispatch(CollectionId(1))?;
let dispatch = dispatch.as_dyn();
dispatch.create_item(caller_cross.clone(), caller_cross.clone(), CreateItemData::NFT(CreateNftData::default()), &Unlimited)?;
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -155,11 +155,10 @@
token: TokenId,
) -> Result<Parent<T::CrossAccountId>, DispatchError> {
// TODO: Reduce cost by not reading collection config
- let handle = match CollectionHandle::try_get(collection) {
+ let handle = match T::CollectionDispatch::dispatch(collection) {
Ok(v) => v,
Err(_) => return Ok(Parent::TokenNotFound),
};
- let handle = T::CollectionDispatch::dispatch(handle);
let handle = handle.as_dyn();
Ok(match handle.token_owner(token) {
@@ -279,8 +278,7 @@
self_budget: &dyn Budget,
breadth_budget: &dyn Budget,
) -> DispatchResultWithPostInfo {
- let handle = <CollectionHandle<T>>::try_get(collection)?;
- let dispatch = T::CollectionDispatch::dispatch(handle);
+ let dispatch = T::CollectionDispatch::dispatch(collection)?;
let dispatch = dispatch.as_dyn();
dispatch.burn_item_recursively(from.clone(), token, self_budget, breadth_budget)
}
@@ -404,10 +402,8 @@
let Some((collection, token)) = T::CrossTokenAddressMapping::address_to_token(account) else {
return Ok(())
};
-
- let handle = <CollectionHandle<T>>::try_get(collection)?;
- let dispatch = T::CollectionDispatch::dispatch(handle);
+ let dispatch = T::CollectionDispatch::dispatch(collection)?;
let dispatch = dispatch.as_dyn();
action(dispatch, token)
runtime/common/dispatch.rsdiffbeforeafterboth--- a/runtime/common/dispatch.rs
+++ b/runtime/common/dispatch.rs
@@ -50,6 +50,7 @@
Refungible(RefungibleHandle<T>),
NativeFungible(NativeFungibleHandle<T>),
}
+
impl<T> CollectionDispatch<T> for CollectionDispatchT<T>
where
T: pallet_common::Config
@@ -59,6 +60,15 @@
+ pallet_refungible::Config
+ pallet_balances_adapter::Config,
{
+ fn check_is_internal(&self) -> DispatchResult {
+ match self {
+ Self::Fungible(h) => h.check_is_internal(),
+ Self::Nonfungible(h) => h.check_is_internal(),
+ Self::Refungible(h) => h.check_is_internal(),
+ Self::NativeFungible(h) => h.check_is_internal(),
+ }
+ }
+
fn create(
sender: T::CrossAccountId,
payer: T::CrossAccountId,
@@ -104,18 +114,17 @@
Ok(())
}
- fn dispatch(handle: CollectionHandle<T>) -> Self {
- match handle.mode {
- CollectionMode::Fungible(_) => {
- if handle.id != up_data_structs::CollectionId(0) {
- Self::Fungible(FungibleHandle::cast(handle))
- } else {
- Self::NativeFungible(NativeFungibleHandle::cast(handle))
- }
- }
+ fn dispatch(collection_id: CollectionId) -> Result<Self, DispatchError> {
+ if collection_id == CollectionId(0) {
+ return Ok(Self::NativeFungible(NativeFungibleHandle::new()));
+ }
+
+ let handle = <CollectionHandle<T>>::try_get(collection_id)?;
+ Ok(match handle.mode {
+ CollectionMode::Fungible(_) => Self::Fungible(FungibleHandle::cast(handle)),
CollectionMode::NFT => Self::Nonfungible(NonfungibleHandle::cast(handle)),
CollectionMode::ReFungible => Self::Refungible(RefungibleHandle::cast(handle)),
- }
+ })
}
fn as_dyn(&self) -> &dyn CommonCollectionOperations<T> {
@@ -172,15 +181,19 @@
}
fn call(handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
if let Some(collection_id) = map_eth_to_id(&handle.code_address()) {
- let collection =
- <CollectionHandle<T>>::new_with_gas_limit(collection_id, handle.remaining_gas())?;
- let dispatched = Self::dispatch(collection);
+ if collection_id == CollectionId(0) {
+ <NativeFungibleHandle<T>>::new().call(handle)
+ } else {
+ let collection = <CollectionHandle<T>>::new_with_gas_limit(
+ collection_id,
+ handle.remaining_gas(),
+ )?;
- match dispatched {
- Self::Fungible(h) => h.call(handle),
- Self::Nonfungible(h) => h.call(handle),
- Self::Refungible(h) => h.call(handle),
- Self::NativeFungible(h) => h.call(handle),
+ match collection.mode {
+ CollectionMode::Fungible(_) => FungibleHandle::cast(collection).call(handle),
+ CollectionMode::NFT => NonfungibleHandle::cast(collection).call(handle),
+ CollectionMode::ReFungible => RefungibleHandle::cast(collection).call(handle),
+ }
}
} else if let Some((collection_id, token_id)) =
<T as pallet_common::Config>::EvmTokenAddressMapping::address_to_token(
runtime/common/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -17,7 +17,7 @@
#[macro_export]
macro_rules! dispatch_unique_runtime {
($collection:ident.$method:ident($($name:ident),*) $($rest:tt)*) => {{
- let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch(<pallet_common::CollectionHandle<Runtime>>::try_get($collection)?);
+ let collection = <Runtime as pallet_common::Config>::CollectionDispatch::dispatch($collection)?;
let dispatch = collection.as_dyn();
Ok::<_, DispatchError>(dispatch.$method($($name),*) $($rest)*)
tests/src/eth/fungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/fungible.test.ts
+++ b/tests/src/eth/fungible.test.ts
@@ -33,7 +33,7 @@
'substrate' as const,
'ethereum' as const,
].map(testCase => {
- itEth.only(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
+ itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {
// 1. Create receiver depending on the test case:
const receiverEth = helper.eth.createAccount();
const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
tests/src/eth/nativeFungible.test.tsdiffbeforeafterboth--- a/tests/src/eth/nativeFungible.test.ts
+++ b/tests/src/eth/nativeFungible.test.ts
@@ -29,7 +29,7 @@
});
});
- itEth.only('Can perform approve()', async ({helper}) => {
+ itEth.skip('Can perform approve()', async ({helper}) => {
const owner = await helper.eth.createAccountWithBalance(donor);
const spender = helper.eth.createAccount();
const collection = await helper.ft.mintCollection(alice);
tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth--- a/tests/src/eth/util/playgrounds/types.ts
+++ b/tests/src/eth/util/playgrounds/types.ts
@@ -48,3 +48,5 @@
field: CollectionLimitField,
value: OptionUint,
}
+
+export const NON_EXISTENT_COLLECTION_ID = 4_294_967_295;
\ No newline at end of file
tests/src/pallet-presence.test.tsdiffbeforeafterboth--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -19,6 +19,7 @@
// Pallets that must always be present
const requiredPallets = [
'balances',
+ 'balancesadapter',
'common',
'timestamp',
'transactionpayment',
tests/src/transfer.test.tsdiffbeforeafterboth1// 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 {IKeyringPair} from '@polkadot/types/types';18import {itEth, usingEthPlaygrounds} from './eth/util';19import {itSub, Pallets, usingPlaygrounds, expect} from './util';2021describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {22 let donor: IKeyringPair;23 let alice: IKeyringPair;24 let bob: IKeyringPair;2526 before(async () => {27 await usingPlaygrounds(async (helper, privateKey) => {28 donor = await privateKey({url: import.meta.url});29 [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);30 });31 });3233 itSub('Balance transfers and check balance', async ({helper}) => {34 const alicesBalanceBefore = await helper.balance.getSubstrate(alice.address);35 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);3637 expect(await helper.balance.transferToSubstrate(alice, bob.address, 1n)).to.be.true;3839 const alicesBalanceAfter = await helper.balance.getSubstrate(alice.address);40 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);4142 expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;43 expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;44 });4546 itSub('Inability to pay fees error message is correct', async ({helper}) => {47 const [zero] = await helper.arrange.createAccounts([0n], donor);4849 // console.error = () => {};50 // The following operation throws an error into the console and the logs. Pay it no heed as long as the test succeeds.51 await expect(helper.balance.transferToSubstrate(zero, donor.address, 1n))52 .to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');53 });5455 itSub('[nft] User can transfer owned token', async ({helper}) => {56 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-1-NFT', description: '', tokenPrefix: 'T'});57 const nft = await collection.mintToken(alice);5859 await nft.transfer(alice, {Substrate: bob.address});60 expect(await nft.getOwner()).to.be.deep.equal({Substrate: bob.address});61 });6263 itSub('[fungible] User can transfer owned token', async ({helper}) => {64 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-1-FT', description: '', tokenPrefix: 'T'});65 await collection.mint(alice, 10n);6667 await collection.transfer(alice, {Substrate: bob.address}, 9n);68 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);69 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);70 });7172 itSub.ifWithPallets('[refungible] User can transfer owned token', [Pallets.ReFungible], async ({helper}) => {73 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});74 const rft = await collection.mintToken(alice, 10n);7576 await rft.transfer(alice, {Substrate: bob.address}, 9n);77 expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);78 expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);79 });8081 itSub('[nft] Collection admin can transfer owned token', async ({helper}) => {82 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-2-NFT', description: '', tokenPrefix: 'T'});83 await collection.addAdmin(alice, {Substrate: bob.address});8485 const nft = await collection.mintToken(bob, {Substrate: bob.address});86 await nft.transfer(bob, {Substrate: alice.address});8788 expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});89 });9091 itSub('[fungible] Collection admin can transfer owned token', async ({helper}) => {92 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-2-FT', description: '', tokenPrefix: 'T'});93 await collection.addAdmin(alice, {Substrate: bob.address});9495 await collection.mint(bob, 10n, {Substrate: bob.address});96 await collection.transfer(bob, {Substrate: alice.address}, 1n);9798 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);99 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);100 });101102 itSub.ifWithPallets('[refungible] Collection admin can transfer owned token', [Pallets.ReFungible], async ({helper}) => {103 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-2-RFT', description: '', tokenPrefix: 'T'});104 await collection.addAdmin(alice, {Substrate: bob.address});105106 const rft = await collection.mintToken(bob, 10n, {Substrate: bob.address});107 await rft.transfer(bob, {Substrate: alice.address}, 1n);108109 expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);110 expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);111 });112});113114describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {115 let alice: IKeyringPair;116 let bob: IKeyringPair;117118 before(async () => {119 await usingPlaygrounds(async (helper, privateKey) => {120 const donor = await privateKey({url: import.meta.url});121 [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);122 });123 });124125126 itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {127 const collectionId = (1 << 32) - 1;128 await expect(helper.nft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))129 .to.be.rejectedWith(/common\.CollectionNotFound/);130 });131132 itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {133 const collectionId = (1 << 32) - 1;134 await expect(helper.ft.transfer(alice, collectionId, {Substrate: bob.address}))135 .to.be.rejectedWith(/common\.CollectionNotFound/);136 });137138 itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {139 const collectionId = (1 << 32) - 1;140 await expect(helper.rft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))141 .to.be.rejectedWith(/common\.CollectionNotFound/);142 });143144 itSub('[nft] Transfer with deleted collection_id', async ({helper}) => {145 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-1-NFT', description: '', tokenPrefix: 'T'});146 const nft = await collection.mintToken(alice);147148 await nft.burn(alice);149 await collection.burn(alice);150151 await expect(nft.transfer(alice, {Substrate: bob.address}))152 .to.be.rejectedWith(/common\.CollectionNotFound/);153 });154155 itSub('[fungible] Transfer with deleted collection_id', async ({helper}) => {156 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-1-FT', description: '', tokenPrefix: 'T'});157 await collection.mint(alice, 10n);158159 await collection.burnTokens(alice, 10n);160 await collection.burn(alice);161162 await expect(collection.transfer(alice, {Substrate: bob.address}))163 .to.be.rejectedWith(/common\.CollectionNotFound/);164 });165166 itSub.ifWithPallets('[refungible] Transfer with deleted collection_id', [Pallets.ReFungible], async ({helper}) => {167 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-1-RFT', description: '', tokenPrefix: 'T'});168 const rft = await collection.mintToken(alice, 10n);169170 await rft.burn(alice, 10n);171 await collection.burn(alice);172173 await expect(rft.transfer(alice, {Substrate: bob.address}))174 .to.be.rejectedWith(/common\.CollectionNotFound/);175 });176177 itSub('[nft] Transfer with not existed item_id', async ({helper}) => {178 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-2-NFT', description: '', tokenPrefix: 'T'});179 await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))180 .to.be.rejectedWith(/common\.TokenNotFound/);181 });182183 itSub('[fungible] Transfer with not existed item_id', async ({helper}) => {184 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-2-FT', description: '', tokenPrefix: 'T'});185 await expect(collection.transfer(alice, {Substrate: bob.address}))186 .to.be.rejectedWith(/common\.TokenValueTooLow/);187 });188189 itSub.ifWithPallets('[refungible] Transfer with not existed item_id', [Pallets.ReFungible], async ({helper}) => {190 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-2-RFT', description: '', tokenPrefix: 'T'});191 await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))192 .to.be.rejectedWith(/common\.TokenValueTooLow/);193 });194195 itSub('Zero transfer NFT', async ({helper}) => {196 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});197 const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});198 const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});199 // 1. Zero transfer of own tokens allowed:200 await helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: bob.address}, collection.collectionId, tokenAlice.tokenId, 0]);201 // 2. Zero transfer of non-owned tokens not allowed:202 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');203 // 3. Zero transfer of non-existing tokens not allowed:204 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, 10, 0])).to.be.rejectedWith('common.TokenNotFound');205 expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});206 expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});207 // 4. Storage is not corrupted:208 await tokenAlice.transfer(alice, {Substrate: bob.address});209 await tokenBob.transfer(bob, {Substrate: alice.address});210 expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});211 expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});212 });213214 itSub('[nft] Transfer with deleted item_id', async ({helper}) => {215 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});216 const nft = await collection.mintToken(alice);217218 await nft.burn(alice);219220 await expect(nft.transfer(alice, {Substrate: bob.address}))221 .to.be.rejectedWith(/common\.TokenNotFound/);222 });223224 itSub('[fungible] Transfer with deleted item_id', async ({helper}) => {225 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-3-FT', description: '', tokenPrefix: 'T'});226 await collection.mint(alice, 10n);227228 await collection.burnTokens(alice, 10n);229230 await expect(collection.transfer(alice, {Substrate: bob.address}))231 .to.be.rejectedWith(/common\.TokenValueTooLow/);232 });233234 itSub.ifWithPallets('[refungible] Transfer with deleted item_id', [Pallets.ReFungible], async ({helper}) => {235 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-3-RFT', description: '', tokenPrefix: 'T'});236 const rft = await collection.mintToken(alice, 10n);237238 await rft.burn(alice, 10n);239240 await expect(rft.transfer(alice, {Substrate: bob.address}))241 .to.be.rejectedWith(/common\.TokenValueTooLow/);242 });243244 itSub('[nft] Transfer with recipient that is not owner', async ({helper}) => {245 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-4-NFT', description: '', tokenPrefix: 'T'});246 const nft = await collection.mintToken(alice);247248 await expect(nft.transfer(bob, {Substrate: bob.address}))249 .to.be.rejectedWith(/common\.NoPermission/);250 expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});251 });252253 itSub('[fungible] Transfer with recipient that is not owner', async ({helper}) => {254 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-4-FT', description: '', tokenPrefix: 'T'});255 await collection.mint(alice, 10n);256257 await expect(collection.transfer(bob, {Substrate: bob.address}, 9n))258 .to.be.rejectedWith(/common\.TokenValueTooLow/);259 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);260 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(10n);261 });262263 itSub.ifWithPallets('[refungible] Transfer with recipient that is not owner', [Pallets.ReFungible], async ({helper}) => {264 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});265 const rft = await collection.mintToken(alice, 10n);266267 await expect(rft.transfer(bob, {Substrate: bob.address}, 9n))268 .to.be.rejectedWith(/common\.TokenValueTooLow/);269 expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(0n);270 expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(10n);271 });272});273274describe('Transfers to self (potentially over substrate-evm boundary)', () => {275 let donor: IKeyringPair;276277 before(async function() {278 await usingEthPlaygrounds(async (_, privateKey) => {279 donor = await privateKey({url: import.meta.url});280 });281 });282283 itEth('Transfers to self. In case of same frontend', async ({helper}) => {284 const [owner] = await helper.arrange.createAccounts([10n], donor);285 const collection = await helper.ft.mintCollection(owner, {});286 await collection.mint(owner, 100n);287288 const ownerProxy = helper.address.substrateToEth(owner.address);289290 // transfer to own proxy291 await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);292 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);293 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);294295 // transfer-from own proxy to own proxy again296 await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Ethereum: ownerProxy}, 5n);297 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);298 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);299 });300301 itEth('Transfers to self. In case of substrate-evm boundary', async ({helper}) => {302 const [owner] = await helper.arrange.createAccounts([10n], donor);303 const collection = await helper.ft.mintCollection(owner, {});304 await collection.mint(owner, 100n);305306 const ownerProxy = helper.address.substrateToEth(owner.address);307308 // transfer to own proxy309 await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);310 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);311 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);312313 // transfer-from own proxy to self314 await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Substrate: owner.address}, 5n);315 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(95n);316 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(5n);317 });318319 itEth('Transfers to self. In case of inside substrate-evm', async ({helper}) => {320 const [owner] = await helper.arrange.createAccounts([10n], donor);321 const collection = await helper.ft.mintCollection(owner, {});322 await collection.mint(owner, 100n);323324 // transfer to self again325 await collection.transfer(owner, {Substrate: owner.address}, 10n);326 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);327328 // transfer-from self to self again329 await collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 5n);330 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);331 });332333 itEth('Transfers to self. In case of inside substrate-evm when not enought "Fungibles"', async ({helper}) => {334 const [owner] = await helper.arrange.createAccounts([10n], donor);335 const collection = await helper.ft.mintCollection(owner, {});336 await collection.mint(owner, 10n);337338 // transfer to self again339 await expect(collection.transfer(owner, {Substrate: owner.address}, 11n))340 .to.be.rejectedWith(/common\.TokenValueTooLow/);341342 // transfer-from self to self again343 await expect(collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 12n))344 .to.be.rejectedWith(/common\.TokenValueTooLow/);345 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(10n);346 });347});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 {IKeyringPair} from '@polkadot/types/types';18import {itEth, usingEthPlaygrounds} from './eth/util';19import {itSub, Pallets, usingPlaygrounds, expect} from './util';20import {NON_EXISTENT_COLLECTION_ID} from './eth/util/playgrounds/types';2122describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {23 let donor: IKeyringPair;24 let alice: IKeyringPair;25 let bob: IKeyringPair;2627 before(async () => {28 await usingPlaygrounds(async (helper, privateKey) => {29 donor = await privateKey({url: import.meta.url});30 [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);31 });32 });3334 itSub('Balance transfers and check balance', async ({helper}) => {35 const alicesBalanceBefore = await helper.balance.getSubstrate(alice.address);36 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);3738 expect(await helper.balance.transferToSubstrate(alice, bob.address, 1n)).to.be.true;3940 const alicesBalanceAfter = await helper.balance.getSubstrate(alice.address);41 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);4243 expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;44 expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;45 });4647 itSub('Inability to pay fees error message is correct', async ({helper}) => {48 const [zero] = await helper.arrange.createAccounts([0n], donor);4950 // console.error = () => {};51 // The following operation throws an error into the console and the logs. Pay it no heed as long as the test succeeds.52 await expect(helper.balance.transferToSubstrate(zero, donor.address, 1n))53 .to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');54 });5556 itSub('[nft] User can transfer owned token', async ({helper}) => {57 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-1-NFT', description: '', tokenPrefix: 'T'});58 const nft = await collection.mintToken(alice);5960 await nft.transfer(alice, {Substrate: bob.address});61 expect(await nft.getOwner()).to.be.deep.equal({Substrate: bob.address});62 });6364 itSub('[fungible] User can transfer owned token', async ({helper}) => {65 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-1-FT', description: '', tokenPrefix: 'T'});66 await collection.mint(alice, 10n);6768 await collection.transfer(alice, {Substrate: bob.address}, 9n);69 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);70 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);71 });7273 itSub.ifWithPallets('[refungible] User can transfer owned token', [Pallets.ReFungible], async ({helper}) => {74 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});75 const rft = await collection.mintToken(alice, 10n);7677 await rft.transfer(alice, {Substrate: bob.address}, 9n);78 expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);79 expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);80 });8182 itSub('[nft] Collection admin can transfer owned token', async ({helper}) => {83 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-2-NFT', description: '', tokenPrefix: 'T'});84 await collection.addAdmin(alice, {Substrate: bob.address});8586 const nft = await collection.mintToken(bob, {Substrate: bob.address});87 await nft.transfer(bob, {Substrate: alice.address});8889 expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});90 });9192 itSub('[fungible] Collection admin can transfer owned token', async ({helper}) => {93 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-2-FT', description: '', tokenPrefix: 'T'});94 await collection.addAdmin(alice, {Substrate: bob.address});9596 await collection.mint(bob, 10n, {Substrate: bob.address});97 await collection.transfer(bob, {Substrate: alice.address}, 1n);9899 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);100 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);101 });102103 itSub.ifWithPallets('[refungible] Collection admin can transfer owned token', [Pallets.ReFungible], async ({helper}) => {104 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-2-RFT', description: '', tokenPrefix: 'T'});105 await collection.addAdmin(alice, {Substrate: bob.address});106107 const rft = await collection.mintToken(bob, 10n, {Substrate: bob.address});108 await rft.transfer(bob, {Substrate: alice.address}, 1n);109110 expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);111 expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);112 });113});114115describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {116 let alice: IKeyringPair;117 let bob: IKeyringPair;118119 before(async () => {120 await usingPlaygrounds(async (helper, privateKey) => {121 const donor = await privateKey({url: import.meta.url});122 [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);123 });124 });125126127 itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {128 await expect(helper.nft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))129 .to.be.rejectedWith(/common\.CollectionNotFound/);130 });131132 itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {133 await expect(helper.ft.transfer(alice, NON_EXISTENT_COLLECTION_ID, {Substrate: bob.address}))134 .to.be.rejectedWith(/common\.CollectionNotFound/);135 });136137 itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {138 await expect(helper.rft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))139 .to.be.rejectedWith(/common\.CollectionNotFound/);140 });141142 itSub('[nft] Transfer with deleted collection_id', async ({helper}) => {143 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-1-NFT', description: '', tokenPrefix: 'T'});144 const nft = await collection.mintToken(alice);145146 await nft.burn(alice);147 await collection.burn(alice);148149 await expect(nft.transfer(alice, {Substrate: bob.address}))150 .to.be.rejectedWith(/common\.CollectionNotFound/);151 });152153 itSub('[fungible] Transfer with deleted collection_id', async ({helper}) => {154 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-1-FT', description: '', tokenPrefix: 'T'});155 await collection.mint(alice, 10n);156157 await collection.burnTokens(alice, 10n);158 await collection.burn(alice);159160 await expect(collection.transfer(alice, {Substrate: bob.address}))161 .to.be.rejectedWith(/common\.CollectionNotFound/);162 });163164 itSub.ifWithPallets('[refungible] Transfer with deleted collection_id', [Pallets.ReFungible], async ({helper}) => {165 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-1-RFT', description: '', tokenPrefix: 'T'});166 const rft = await collection.mintToken(alice, 10n);167168 await rft.burn(alice, 10n);169 await collection.burn(alice);170171 await expect(rft.transfer(alice, {Substrate: bob.address}))172 .to.be.rejectedWith(/common\.CollectionNotFound/);173 });174175 itSub('[nft] Transfer with not existed item_id', async ({helper}) => {176 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-2-NFT', description: '', tokenPrefix: 'T'});177 await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))178 .to.be.rejectedWith(/common\.TokenNotFound/);179 });180181 itSub('[fungible] Transfer with not existed item_id', async ({helper}) => {182 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-2-FT', description: '', tokenPrefix: 'T'});183 await expect(collection.transfer(alice, {Substrate: bob.address}))184 .to.be.rejectedWith(/common\.TokenValueTooLow/);185 });186187 itSub.ifWithPallets('[refungible] Transfer with not existed item_id', [Pallets.ReFungible], async ({helper}) => {188 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-2-RFT', description: '', tokenPrefix: 'T'});189 await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))190 .to.be.rejectedWith(/common\.TokenValueTooLow/);191 });192193 itSub('Zero transfer NFT', async ({helper}) => {194 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});195 const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});196 const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});197 // 1. Zero transfer of own tokens allowed:198 await helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: bob.address}, collection.collectionId, tokenAlice.tokenId, 0]);199 // 2. Zero transfer of non-owned tokens not allowed:200 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');201 // 3. Zero transfer of non-existing tokens not allowed:202 await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, 10, 0])).to.be.rejectedWith('common.TokenNotFound');203 expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});204 expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});205 // 4. Storage is not corrupted:206 await tokenAlice.transfer(alice, {Substrate: bob.address});207 await tokenBob.transfer(bob, {Substrate: alice.address});208 expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});209 expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});210 });211212 itSub('[nft] Transfer with deleted item_id', async ({helper}) => {213 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});214 const nft = await collection.mintToken(alice);215216 await nft.burn(alice);217218 await expect(nft.transfer(alice, {Substrate: bob.address}))219 .to.be.rejectedWith(/common\.TokenNotFound/);220 });221222 itSub('[fungible] Transfer with deleted item_id', async ({helper}) => {223 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-3-FT', description: '', tokenPrefix: 'T'});224 await collection.mint(alice, 10n);225226 await collection.burnTokens(alice, 10n);227228 await expect(collection.transfer(alice, {Substrate: bob.address}))229 .to.be.rejectedWith(/common\.TokenValueTooLow/);230 });231232 itSub.ifWithPallets('[refungible] Transfer with deleted item_id', [Pallets.ReFungible], async ({helper}) => {233 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-3-RFT', description: '', tokenPrefix: 'T'});234 const rft = await collection.mintToken(alice, 10n);235236 await rft.burn(alice, 10n);237238 await expect(rft.transfer(alice, {Substrate: bob.address}))239 .to.be.rejectedWith(/common\.TokenValueTooLow/);240 });241242 itSub('[nft] Transfer with recipient that is not owner', async ({helper}) => {243 const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-4-NFT', description: '', tokenPrefix: 'T'});244 const nft = await collection.mintToken(alice);245246 await expect(nft.transfer(bob, {Substrate: bob.address}))247 .to.be.rejectedWith(/common\.NoPermission/);248 expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});249 });250251 itSub('[fungible] Transfer with recipient that is not owner', async ({helper}) => {252 const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-4-FT', description: '', tokenPrefix: 'T'});253 await collection.mint(alice, 10n);254255 await expect(collection.transfer(bob, {Substrate: bob.address}, 9n))256 .to.be.rejectedWith(/common\.TokenValueTooLow/);257 expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);258 expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(10n);259 });260261 itSub.ifWithPallets('[refungible] Transfer with recipient that is not owner', [Pallets.ReFungible], async ({helper}) => {262 const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});263 const rft = await collection.mintToken(alice, 10n);264265 await expect(rft.transfer(bob, {Substrate: bob.address}, 9n))266 .to.be.rejectedWith(/common\.TokenValueTooLow/);267 expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(0n);268 expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(10n);269 });270});271272describe('Transfers to self (potentially over substrate-evm boundary)', () => {273 let donor: IKeyringPair;274275 before(async function() {276 await usingEthPlaygrounds(async (_, privateKey) => {277 donor = await privateKey({url: import.meta.url});278 });279 });280281 itEth('Transfers to self. In case of same frontend', async ({helper}) => {282 const [owner] = await helper.arrange.createAccounts([10n], donor);283 const collection = await helper.ft.mintCollection(owner, {});284 await collection.mint(owner, 100n);285286 const ownerProxy = helper.address.substrateToEth(owner.address);287288 // transfer to own proxy289 await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);290 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);291 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);292293 // transfer-from own proxy to own proxy again294 await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Ethereum: ownerProxy}, 5n);295 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);296 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);297 });298299 itEth('Transfers to self. In case of substrate-evm boundary', async ({helper}) => {300 const [owner] = await helper.arrange.createAccounts([10n], donor);301 const collection = await helper.ft.mintCollection(owner, {});302 await collection.mint(owner, 100n);303304 const ownerProxy = helper.address.substrateToEth(owner.address);305306 // transfer to own proxy307 await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);308 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);309 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);310311 // transfer-from own proxy to self312 await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Substrate: owner.address}, 5n);313 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(95n);314 expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(5n);315 });316317 itEth('Transfers to self. In case of inside substrate-evm', async ({helper}) => {318 const [owner] = await helper.arrange.createAccounts([10n], donor);319 const collection = await helper.ft.mintCollection(owner, {});320 await collection.mint(owner, 100n);321322 // transfer to self again323 await collection.transfer(owner, {Substrate: owner.address}, 10n);324 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);325326 // transfer-from self to self again327 await collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 5n);328 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);329 });330331 itEth('Transfers to self. In case of inside substrate-evm when not enought "Fungibles"', async ({helper}) => {332 const [owner] = await helper.arrange.createAccounts([10n], donor);333 const collection = await helper.ft.mintCollection(owner, {});334 await collection.mint(owner, 10n);335336 // transfer to self again337 await expect(collection.transfer(owner, {Substrate: owner.address}, 11n))338 .to.be.rejectedWith(/common\.TokenValueTooLow/);339340 // transfer-from self to self again341 await expect(collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 12n))342 .to.be.rejectedWith(/common\.TokenValueTooLow/);343 expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(10n);344 });345});tests/src/transferFrom.test.tsdiffbeforeafterboth--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -16,6 +16,7 @@
import {IKeyringPair} from '@polkadot/types/types';
import {itSub, Pallets, usingPlaygrounds, expect} from './util';
+import {NON_EXISTENT_COLLECTION_ID} from './eth/util/playgrounds/types';
describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => {
let alice: IKeyringPair;
@@ -97,10 +98,9 @@
});
itSub('transferFrom for a collection that does not exist', async ({helper}) => {
- const collectionId = (1 << 32) - 1;
- await expect(helper.collection.approveToken(alice, collectionId, 0, {Substrate: bob.address}, 1n))
+ await expect(helper.collection.approveToken(alice, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: bob.address}, 1n))
.to.be.rejectedWith(/common\.CollectionNotFound/);
- await expect(helper.collection.transferTokenFrom(bob, collectionId, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))
+ await expect(helper.collection.transferTokenFrom(bob, NON_EXISTENT_COLLECTION_ID, 0, {Substrate: alice.address}, {Substrate: bob.address}, 1n))
.to.be.rejectedWith(/common\.CollectionNotFound/);
});