difftreelog
fix remove native ft from childrens
in: master
4 files changed
pallets/balances-adapter/src/common.rsdiffbeforeafterboth--- a/pallets/balances-adapter/src/common.rs
+++ b/pallets/balances-adapter/src/common.rs
@@ -85,7 +85,7 @@
}
}
-/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallete
+/// Implementation of `CommonCollectionOperations` for `FungibleHandle`. It wraps FungibleHandle Pallet
/// methods and adds weight info.
impl<T: Config> CommonCollectionOperations<T> for NativeFungibleHandle<T> {
fn create_item(
pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -1347,37 +1347,18 @@
}
fn token_has_children(collection_id: CollectionId, token_id: TokenId) -> bool {
- let address = T::CrossTokenAddressMapping::token_to_address(collection_id, token_id);
- let balance = <pallet_balances::Pallet<T>>::free_balance(address.as_sub());
-
- balance > T::Balance::default()
- || <TokenChildren<T>>::iter_prefix((collection_id, token_id))
- .next()
- .is_some()
+ <TokenChildren<T>>::iter_prefix((collection_id, token_id))
+ .next()
+ .is_some()
}
pub fn token_children_ids(collection_id: CollectionId, token_id: TokenId) -> Vec<TokenChild> {
- let mut tokens: Vec<_> = vec![];
-
- let address = T::CrossTokenAddressMapping::token_to_address(collection_id, token_id);
- let balance = <pallet_balances::Pallet<T>>::free_balance(address.as_sub());
- if balance > T::Balance::default() {
- tokens.push(TokenChild {
- token: TokenId(0),
- collection: pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID,
+ <TokenChildren<T>>::iter_prefix((collection_id, token_id))
+ .map(|((child_collection_id, child_id), _)| TokenChild {
+ collection: child_collection_id,
+ token: child_id,
})
- }
-
- tokens.extend(
- <TokenChildren<T>>::iter_prefix((collection_id, token_id)).map(
- |((child_collection_id, child_id), _)| TokenChild {
- collection: child_collection_id,
- token: child_id,
- },
- ),
- );
-
- tokens
+ .collect()
}
/// Mint single NFT token.
tests/src/sub/nesting/common.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 {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';2021let alice: IKeyringPair;22let bob: IKeyringPair;2324describe('Common nesting tests', () => {25 before(async () => {26 await usingPlaygrounds(async (helper, privateKey) => {27 const donor = await privateKey({url: import.meta.url});28 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);29 });30 });3132 [33 {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},34 {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},35 {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},36 {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},37 ].map(testCase => {38 itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode'in restricted mode'''}`, testCase.requiredPallets, async ({helper}) => {39 // Only NFT can be target for nesting in40 const targetNFTCollection = await helper.nft.mintCollection(alice);41 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});4243 const collectionForNesting = await helper[testCase.mode].mintCollection(bob);44 // permissions should be set:45 await targetNFTCollection.setPermissions(alice, {46 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},47 });4849 // 1. Bob can immediately create nested token:50 const nestedToken1 = testCase.mode === 'nft'51 ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())52 : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());53 expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});54 expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());5556 // 2. Bob can mint and nest token:57 const nestedToken2 = await collectionForNesting.mintToken(bob);58 await nestedToken2.nest(bob, targetTokenBob);59 expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});60 expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());61 });62 });636465 [66 {restrictedMode: true},67 {restrictedMode: false},68 ].map(testCase => {69 itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode'in restricted mode'''}`, async ({helper}) => {70 // Only NFT allows nesting, permissions should be set:71 const targetNFTCollection = await helper.nft.mintCollection(alice);72 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});7374 const collectionForNesting = await helper.ft.mintCollection(bob);75 // permissions should be set:76 await targetNFTCollection.setPermissions(alice, {77 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},78 });7980 // 1. Alice can immediately create nested tokens:81 await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());82 expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);83 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);8485 // 2. Alice can mint and nest token:86 await collectionForNesting.mint(bob, 100n);87 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);88 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);89 expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);90 });91 });9293 [94 {restrictedMode: true},95 {restrictedMode: false},96 ].map(testCase => {97 itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode'in restricted mode'''}`, async ({helper}) => {98 // Only NFT allows nesting, permissions should be set:99 const targetNFTCollection = await helper.nft.mintCollection(alice);100 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});101 expect(await targetTokenBob.getChildren()).to.be.empty;102103 const collectionForNesting = helper.ft.getCollectionObject(0);104 // permissions should be set:105 await targetNFTCollection.setPermissions(alice, {106 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},107 });108109 // Bob can nest Native FT into their NFT:110 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);111 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);112 expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: 0, tokenId: 0}]);113 });114 });115116117 itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {118 const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});119 const tokenA = await collectionToNest.mintToken(alice);120 const tokenB = await collectionToNest.mintToken(alice);121122 // Create a nested token123 const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});124 const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});125 const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});126 const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);127128 const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());129 const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());130 const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());131 await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);132 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());133 expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());134 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);135 expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);136137 expect(await tokenA.getChildren()).to.be.length(4);138 expect(await tokenB.getChildren()).to.be.length(0);139140 // Transfer the nested token to another token141 await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());142 await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);143 await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);144 await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);145146 expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});147 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());148149 expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);150 expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);151152 expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);153 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);154155 expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);156 expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);157158 // RFT, FT, and native FT159 expect(await tokenA.getChildren()).to.be.length(3);160 // NFT, RFT, FT, and native FT161 expect(await tokenB.getChildren()).to.be.length(4);162 });163});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 {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueNFTCollection, UniqueRFTCollection} from '../../util/playgrounds/unique';2021let alice: IKeyringPair;22let bob: IKeyringPair;2324describe('Common nesting tests', () => {25 before(async () => {26 await usingPlaygrounds(async (helper, privateKey) => {27 const donor = await privateKey({url: import.meta.url});28 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);29 });30 });3132 [33 {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},34 {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},35 {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},36 {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},37 ].map(testCase => {38 itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode'in restricted mode'''}`, testCase.requiredPallets, async ({helper}) => {39 // Only NFT can be target for nesting in40 const targetNFTCollection = await helper.nft.mintCollection(alice);41 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});4243 const collectionForNesting = await helper[testCase.mode].mintCollection(bob);44 // permissions should be set:45 await targetNFTCollection.setPermissions(alice, {46 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},47 });4849 // 1. Bob can immediately create nested token:50 const nestedToken1 = testCase.mode === 'nft'51 ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())52 : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());53 expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});54 expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());5556 // 2. Bob can mint and nest token:57 const nestedToken2 = await collectionForNesting.mintToken(bob);58 await nestedToken2.nest(bob, targetTokenBob);59 expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});60 expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());61 });62 });636465 [66 {restrictedMode: true},67 {restrictedMode: false},68 ].map(testCase => {69 itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode'in restricted mode'''}`, async ({helper}) => {70 // Only NFT allows nesting, permissions should be set:71 const targetNFTCollection = await helper.nft.mintCollection(alice);72 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});7374 const collectionForNesting = await helper.ft.mintCollection(bob);75 // permissions should be set:76 await targetNFTCollection.setPermissions(alice, {77 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},78 });7980 // 1. Alice can immediately create nested tokens:81 await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());82 expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);83 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);8485 // 2. Alice can mint and nest token:86 await collectionForNesting.mint(bob, 100n);87 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);88 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);89 expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);90 });91 });9293 [94 {restrictedMode: true},95 {restrictedMode: false},96 ].map(testCase => {97 itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode'in restricted mode'''}`, async ({helper}) => {98 // Only NFT allows nesting, permissions should be set:99 const targetNFTCollection = await helper.nft.mintCollection(alice);100 const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});101 expect(await targetTokenBob.getChildren()).to.be.empty;102103 const collectionForNesting = helper.ft.getCollectionObject(0);104 // permissions should be set:105 await targetNFTCollection.setPermissions(alice, {106 nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},107 });108109 // Bob can nest Native FT into their NFT:110 await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);111 expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);112 // Native FT should't be visible in NFT children:113 expect(await targetTokenBob.getChildren()).to.be.deep.equal([]);114 });115 });116117118 itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {119 const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});120 const tokenA = await collectionToNest.mintToken(alice);121 const tokenB = await collectionToNest.mintToken(alice);122123 // Create a nested token124 const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});125 const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});126 const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});127 const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);128129 const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());130 const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());131 const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());132 await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);133 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());134 expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());135 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);136 expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);137138 expect(await tokenA.getChildren()).to.be.length(3);139 expect(await tokenB.getChildren()).to.be.length(0);140141 // Transfer the nested token to another token142 await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());143 await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);144 await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);145 await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);146147 expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});148 expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());149150 expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);151 expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);152153 expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);154 expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);155156 expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);157 expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);158159 // RFT, FT, and without native FT160 expect(await tokenA.getChildren()).to.be.length(2);161 // NFT, RFT, FT, and without native FT162 expect(await tokenB.getChildren()).to.be.length(3);163 });164});tests/src/sub/nesting/e2e.test.tsdiffbeforeafterboth--- a/tests/src/sub/nesting/e2e.test.ts
+++ b/tests/src/sub/nesting/e2e.test.ts
@@ -80,25 +80,22 @@
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
{tokenId: 0, collectionId: collectionB.collectionId},
{tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
- {tokenId: 0, collectionId: collectionNative.collectionId},
- ]).and.has.length(4);
+ ]).and.has.length(3);
// Burn all nested pieces
await tokenC.burnFrom(alice, targetToken.nestingAccount(), 2n);
expect(await targetToken.getChildren()).to.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
{tokenId: 0, collectionId: collectionB.collectionId},
- {tokenId: 0, collectionId: collectionNative.collectionId},
])
- .and.has.length(3);
+ .and.has.length(2);
// Move part of the fungible token inside token A deeper in the nesting tree
await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
expect(await targetToken.getChildren()).to.be.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
{tokenId: 0, collectionId: collectionB.collectionId},
- {tokenId: 0, collectionId: collectionNative.collectionId},
- ]).and.has.length(3);
+ ]).and.has.length(2);
// Nested token also has children now:
expect(await tokenA.getChildren()).to.have.deep.members([
{tokenId: 0, collectionId: collectionB.collectionId},
@@ -108,8 +105,7 @@
await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
expect(await targetToken.getChildren()).to.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionNative.collectionId},
- ]).and.has.length(2);
+ ]).and.has.length(1);
expect(await tokenA.getChildren()).to.have.deep.members([
{tokenId: 0, collectionId: collectionB.collectionId},
]).and.has.length(1);