From b89a3c86d3bf0888a636bc7da1949affa12d867d Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Mon, 24 Jun 2024 11:05:56 +0200 Subject: [PATCH 1/8] fix: account token ownership limit when mint --- pallets/nonfungible/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nonfungible/src/lib.rs b/pallets/nonfungible/src/lib.rs index 0ea6459446..613ec5436b 100644 --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -853,7 +853,7 @@ impl Pallet { *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?; ensure!( - *balance <= collection.limits.account_token_ownership_limit(), + *balance < collection.limits.account_token_ownership_limit(), >::AccountTokenLimitExceeded, ); } From 75699574656bb0a34caddf3c9abdbffef79ba85d Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Mon, 24 Jun 2024 13:44:34 +0200 Subject: [PATCH 2/8] fix: limit tests --- js-packages/tests/limits.test.ts | 4 ++-- runtime/tests/src/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js-packages/tests/limits.test.ts b/js-packages/tests/limits.test.ts index f0dcb3553e..b6502185bc 100644 --- a/js-packages/tests/limits.test.ts +++ b/js-packages/tests/limits.test.ts @@ -43,7 +43,7 @@ describe('Number of tokens per address (NFT)', () => { itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); - await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 2}); await collection.mintToken(alice); await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); @@ -81,7 +81,7 @@ describe('Number of tokens per address (ReFungible)', () => { itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {}); - await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 2}); await collection.mintToken(alice); await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); diff --git a/runtime/tests/src/tests.rs b/runtime/tests/src/tests.rs index 9a58acca11..3ee65cb1ab 100644 --- a/runtime/tests/src/tests.rs +++ b/runtime/tests/src/tests.rs @@ -2405,7 +2405,7 @@ fn owned_tokens_bound_neg() { let origin1 = RuntimeOrigin::signed(1); - for _ in 1..=MAX_TOKEN_OWNERSHIP { + for _ in 1..MAX_TOKEN_OWNERSHIP { let data = default_nft_data(); create_test_item(collection_id, &data.clone().into()); } From 054110e015fd237fed77be1ef21bba6cea13fbea Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Mon, 24 Jun 2024 13:45:22 +0200 Subject: [PATCH 3/8] fix: account token ownership limit rft mint --- pallets/refungible/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/refungible/src/lib.rs b/pallets/refungible/src/lib.rs index 47966766a6..f1ae19689d 100644 --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -848,7 +848,7 @@ impl Pallet { *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?; ensure!( - *balance <= collection.limits.account_token_ownership_limit(), + *balance < collection.limits.account_token_ownership_limit(), >::AccountTokenLimitExceeded, ); } From de9f4cae90f0e53b6591b93aeacf0d747e621b91 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Tue, 25 Jun 2024 10:03:16 +0200 Subject: [PATCH 4/8] Revert "fix: account token ownership limit rft mint" This reverts commit 054110e015fd237fed77be1ef21bba6cea13fbea. --- pallets/refungible/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/refungible/src/lib.rs b/pallets/refungible/src/lib.rs index f1ae19689d..47966766a6 100644 --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -848,7 +848,7 @@ impl Pallet { *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?; ensure!( - *balance < collection.limits.account_token_ownership_limit(), + *balance <= collection.limits.account_token_ownership_limit(), >::AccountTokenLimitExceeded, ); } From d9598519dda018384a13237ec5af4e6bb5c32eb2 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Tue, 25 Jun 2024 10:05:17 +0200 Subject: [PATCH 5/8] Revert "fix: limit tests" This reverts commit 75699574656bb0a34caddf3c9abdbffef79ba85d. --- js-packages/tests/limits.test.ts | 4 ++-- runtime/tests/src/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js-packages/tests/limits.test.ts b/js-packages/tests/limits.test.ts index b6502185bc..f0dcb3553e 100644 --- a/js-packages/tests/limits.test.ts +++ b/js-packages/tests/limits.test.ts @@ -43,7 +43,7 @@ describe('Number of tokens per address (NFT)', () => { itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); - await collection.setLimits(alice, {accountTokenOwnershipLimit: 2}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); await collection.mintToken(alice); await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); @@ -81,7 +81,7 @@ describe('Number of tokens per address (ReFungible)', () => { itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {}); - await collection.setLimits(alice, {accountTokenOwnershipLimit: 2}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); await collection.mintToken(alice); await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); diff --git a/runtime/tests/src/tests.rs b/runtime/tests/src/tests.rs index 3ee65cb1ab..9a58acca11 100644 --- a/runtime/tests/src/tests.rs +++ b/runtime/tests/src/tests.rs @@ -2405,7 +2405,7 @@ fn owned_tokens_bound_neg() { let origin1 = RuntimeOrigin::signed(1); - for _ in 1..MAX_TOKEN_OWNERSHIP { + for _ in 1..=MAX_TOKEN_OWNERSHIP { let data = default_nft_data(); create_test_item(collection_id, &data.clone().into()); } From 8ba1f548cb0ed63903fe149d799e8c0395a31ede Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Tue, 25 Jun 2024 10:06:07 +0200 Subject: [PATCH 6/8] Revert "fix: account token ownership limit when mint" This reverts commit b89a3c86d3bf0888a636bc7da1949affa12d867d. --- pallets/nonfungible/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/nonfungible/src/lib.rs b/pallets/nonfungible/src/lib.rs index 613ec5436b..0ea6459446 100644 --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -853,7 +853,7 @@ impl Pallet { *balance = balance.checked_add(1).ok_or(ArithmeticError::Overflow)?; ensure!( - *balance < collection.limits.account_token_ownership_limit(), + *balance <= collection.limits.account_token_ownership_limit(), >::AccountTokenLimitExceeded, ); } From 79f3d062f414762b8e4493ce22b7050437f92a1f Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Tue, 25 Jun 2024 10:07:56 +0200 Subject: [PATCH 7/8] fix: account token ownership limit when transfer --- pallets/nonfungible/src/lib.rs | 2 +- pallets/refungible/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/nonfungible/src/lib.rs b/pallets/nonfungible/src/lib.rs index 0ea6459446..8db862a582 100644 --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -746,7 +746,7 @@ impl Pallet { .ok_or(ArithmeticError::Overflow)?; ensure!( - balance_to < collection.limits.account_token_ownership_limit(), + balance_to <= collection.limits.account_token_ownership_limit(), >::AccountTokenLimitExceeded, ); diff --git a/pallets/refungible/src/lib.rs b/pallets/refungible/src/lib.rs index 47966766a6..bb89ba0d2d 100644 --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -679,7 +679,7 @@ impl Pallet { .checked_add(1) .ok_or(ArithmeticError::Overflow)?; ensure!( - account_balance_to < collection.limits.account_token_ownership_limit(), + account_balance_to <= collection.limits.account_token_ownership_limit(), >::AccountTokenLimitExceeded, ); From 16b3e6230f37e4277d47063bdbc0415479f55d6f Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Tue, 25 Jun 2024 18:03:12 +0000 Subject: [PATCH 8/8] test: account token ownership transfer tests --- js-packages/tests/limits.test.ts | 50 ++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/js-packages/tests/limits.test.ts b/js-packages/tests/limits.test.ts index f0dcb3553e..7d6126f271 100644 --- a/js-packages/tests/limits.test.ts +++ b/js-packages/tests/limits.test.ts @@ -19,11 +19,12 @@ import {expect, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from '@u describe('Number of tokens per address (NFT)', () => { let alice: IKeyringPair; + let bob: IKeyringPair; before(async () => { await usingPlaygrounds(async (helper, privateKey) => { const donor = await privateKey({url: import.meta.url}); - [alice] = await helper.arrange.createAccounts([10n], donor); + [alice, bob] = await helper.arrange.createAccounts([10n, 0n], donor); }); }); @@ -51,17 +52,40 @@ describe('Number of tokens per address (NFT)', () => { await collection.burnToken(alice, 1); await expect(collection.burn(alice)).to.be.not.rejected; }); + + itSub('Can transfer tokens to address equal to accountTokenOwnershipLimit', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); + + // Limit 1 - can transfer #1 token + const tkn1 = await collection.mintToken(alice); + await collection.transferToken(alice, tkn1.tokenId, {Substrate: bob.address}); + + // Limit 1 - cannot transfer #2 token + const tkn2 = await collection.mintToken(alice); + await expect(collection.transferToken(alice, tkn2.tokenId, {Substrate: bob.address})).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); + + // Increase limit to 2 + // Now can transfer token #2 + await collection.setLimits(alice, {accountTokenOwnershipLimit: 2}); + await collection.transferToken(alice, tkn2.tokenId, {Substrate: bob.address}); + + // But cannot transfer token #3 + const tkn3 = await collection.mintToken(alice); + await expect(collection.transferToken(alice, tkn3.tokenId, {Substrate: bob.address})).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); + }); }); describe('Number of tokens per address (ReFungible)', () => { let alice: IKeyringPair; + let bob: IKeyringPair; before(async function() { await usingPlaygrounds(async (helper, privateKey) => { requirePalletsOrSkip(this, helper, [Pallets.ReFungible]); const donor = await privateKey({url: import.meta.url}); - [alice] = await helper.arrange.createAccounts([10n], donor); + [alice, bob] = await helper.arrange.createAccounts([10n, 0n], donor); }); }); @@ -89,6 +113,28 @@ describe('Number of tokens per address (ReFungible)', () => { await collection.burnToken(alice, 1); await expect(collection.burn(alice)).to.be.not.rejected; }); + + itSub('Can transfer tokens to address equal to accountTokenOwnershipLimit', async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); + + // Limit 1 - can transfer #1 token + const tkn1 = await collection.mintToken(alice); + await collection.transferToken(alice, tkn1.tokenId, {Substrate: bob.address}); + + // Limit 1 - cannot transfer #2 token + const tkn2 = await collection.mintToken(alice); + await expect(collection.transferToken(alice, tkn2.tokenId, {Substrate: bob.address})).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); + + // Increase limit to 2 + // Now can transfer token #2 + await collection.setLimits(alice, {accountTokenOwnershipLimit: 2}); + await collection.transferToken(alice, tkn2.tokenId, {Substrate: bob.address}); + + // But cannot transfer token #3 + const tkn3 = await collection.mintToken(alice); + await expect(collection.transferToken(alice, tkn3.tokenId, {Substrate: bob.address})).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); + }); }); // todo:playgrounds skipped ~ postponed