difftreelog
fix rft admin can unnest
in: master
2 files changed
pallets/refungible/src/lib.rsdiffbeforeafterboth1178 collection.check_allowlist(spender)?;1178 collection.check_allowlist(spender)?;1179 }1179 }11801181 if collection.limits.owner_can_transfer() && collection.is_owner_or_admin(spender) {1182 return Ok(None);1183 }11841180 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1185 if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {1181 // TODO: should collection owner be allowed to perform this transfer?1186 // TODO: should collection owner be allowed to perform this transfer?tests/src/nesting/nest.test.tsdiffbeforeafterboth--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -16,6 +16,7 @@
import {IKeyringPair} from '@polkadot/types/types';
import {expect, itSub, Pallets, usingPlaygrounds} from '../util';
+import {UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';
describe('Integration Test: Composite nesting tests', () => {
let alice: IKeyringPair;
@@ -138,7 +139,7 @@
before(async () => {
await usingPlaygrounds(async (helper, privateKey) => {
const donor = await privateKey({filename: __filename});
- [alice, bob, charlie] = await helper.arrange.createAccounts([50n, 10n, 10n], donor);
+ [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 20n, 20n], donor);
});
});
@@ -335,6 +336,205 @@
await newToken.transfer(charlie, targetToken.nestingAccount(), 2n);
expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);
});
+
+ async function checkNestedRft({
+ expectedBalance,
+ childrenShouldPresent,
+ nestedRft,
+ targetNft,
+ }: {
+ expectedBalance: bigint,
+ childrenShouldPresent: boolean,
+ nestedRft: UniqueRFToken,
+ targetNft: UniqueNFToken,
+ }) {
+ const balance = await nestedRft.getBalance(targetNft.nestingAccount());
+ expect(balance).to.be.equal(expectedBalance);
+
+ const children = await targetNft.getChildren();
+
+ if (childrenShouldPresent) {
+ expect(children[0]).to.be.deep.equal({
+ collectionId: nestedRft.collectionId,
+ tokenId: nestedRft.tokenId,
+ });
+ } else {
+ expect(children.length).to.be.equal(0);
+ }
+ }
+
+ itSub.ifWithPallets('ReFungible: allows a collection owner to transfer nested token', [Pallets.ReFungible], async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice);
+ const collectionRFT = await helper.rft.mintCollection(alice, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+
+ await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
+
+ const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
+ const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
+
+ await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
+ await checkNestedRft({
+ expectedBalance: 5n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+
+ await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);
+ await checkNestedRft({
+ expectedBalance: 3n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+ expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);
+
+ await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);
+ await checkNestedRft({
+ expectedBalance: 0n,
+ childrenShouldPresent: false,
+ nestedRft,
+ targetNft,
+ });
+ expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);
+ });
+
+ itSub.ifWithPallets('ReFungible: allows a collection admin to transfer nested token', [Pallets.ReFungible], async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice);
+ const collectionRFT = await helper.rft.mintCollection(alice, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ await collectionRFT.addAdmin(alice, {Substrate: bob.address});
+
+ await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
+
+ const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
+ const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
+
+ await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
+ await checkNestedRft({
+ expectedBalance: 5n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+
+ await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);
+ await checkNestedRft({
+ expectedBalance: 3n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+ expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);
+
+ await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);
+ await checkNestedRft({
+ expectedBalance: 0n,
+ childrenShouldPresent: false,
+ nestedRft,
+ targetNft,
+ });
+ expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);
+ });
+
+ itSub.ifWithPallets('ReFungible: allows a collection owner to burn nested token', [Pallets.ReFungible], async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ const collectionRFT = await helper.rft.mintCollection(alice, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+
+ await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
+
+ const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
+ const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
+
+ await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
+ await checkNestedRft({
+ expectedBalance: 5n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+
+ await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 2n);
+ await checkNestedRft({
+ expectedBalance: 3n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+
+ await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 3n);
+ await checkNestedRft({
+ expectedBalance: 0n,
+ childrenShouldPresent: false,
+ nestedRft,
+ targetNft,
+ });
+
+ // Check if we can burn target NFT when all nested RFTs are gone
+ await targetNft.burnFrom(alice, {Substrate: charlie.address});
+ });
+
+ itSub.ifWithPallets('ReFungible: allows a collection admin to burn nested token', [Pallets.ReFungible], async ({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ const collectionRFT = await helper.rft.mintCollection(alice, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ await collectionNFT.addAdmin(alice, {Substrate: bob.address});
+ await collectionRFT.addAdmin(alice, {Substrate: bob.address});
+
+ await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
+
+ const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
+ const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
+
+ await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
+ await checkNestedRft({
+ expectedBalance: 5n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+
+ await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 2n);
+ await checkNestedRft({
+ expectedBalance: 3n,
+ childrenShouldPresent: true,
+ nestedRft,
+ targetNft,
+ });
+
+ await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 3n);
+ await checkNestedRft({
+ expectedBalance: 0n,
+ childrenShouldPresent: false,
+ nestedRft,
+ targetNft,
+ });
+
+ // Check if we can burn target NFT when all nested RFTs are gone
+ await targetNft.burnFrom(bob, {Substrate: charlie.address});
+ });
});
describe('Negative Test: Nesting', () => {