difftreelog
Limits logic fixed. Tests added
in: master
4 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -302,9 +302,6 @@
/// Amount of collections destroyed, used for total amount tracking with
/// CreatedCollectionCount
DestroyedCollectionCount: u32;
- /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles)
- /// Account id (real)
- pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;
//#endregion
//#region Basic collections
@@ -1595,11 +1592,19 @@
collection.consume_sload()?;
let account_items: u32 =
<AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;
- ensure!(
- collection.limits.account_token_ownership_limit > account_items,
- Error::<T>::AccountTokenLimitExceeded
- );
+ // zero limit means collection limit is disabled
+ // otherwise get lower value
+ let limit = if collection.limits.account_token_ownership_limit == 0
+ || collection.limits.account_token_ownership_limit > ACCOUNT_TOKEN_OWNERSHIP_LIMIT
+ {
+ ACCOUNT_TOKEN_OWNERSHIP_LIMIT
+ } else {
+ collection.limits.account_token_ownership_limit
+ };
+
+ ensure!(limit > account_items, Error::<T>::AccountTokenLimitExceeded);
+
// preliminary transfer check
ensure!(collection.transfers_enabled, Error::<T>::TransferNotAllowed);
@@ -1622,12 +1627,23 @@
as u32)
.checked_add(amount)
.ok_or(Error::<T>::AccountTokenLimitExceeded)?;
+
+ // zero limit means collection limit is disabled
+ // otherwise get lower value
+ let account_token_limit = if collection.limits.account_token_ownership_limit == 0
+ || collection.limits.account_token_ownership_limit > ACCOUNT_TOKEN_OWNERSHIP_LIMIT
+ {
+ ACCOUNT_TOKEN_OWNERSHIP_LIMIT
+ } else {
+ collection.limits.account_token_ownership_limit
+ };
+
ensure!(
collection.limits.token_limit >= total_items,
Error::<T>::CollectionTokenLimitExceeded
);
ensure!(
- collection.limits.account_token_ownership_limit >= account_items,
+ account_token_limit >= account_items,
Error::<T>::AccountTokenLimitExceeded
);
@@ -2362,32 +2378,19 @@
item_index: TokenId,
owner: &T::CrossAccountId,
) -> DispatchResult {
- // add to account limit
collection.consume_sload()?;
- if <AccountItemCount<T>>::contains_key(owner.as_sub()) {
- // bound Owned tokens by a single address
+ let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());
+ if list_exists {
collection.consume_sload()?;
- let count = <AccountItemCount<T>>::get(owner.as_sub());
+ let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());
+
+ // bound Owned tokens by a single address in collection
+ let account_items: u32 = list.len() as u32;
ensure!(
- count < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,
+ account_items < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,
Error::<T>::AddressOwnershipLimitExceeded
);
-
- collection.consume_sstore()?;
- <AccountItemCount<T>>::insert(
- owner.as_sub(),
- count.checked_add(1).ok_or(Error::<T>::NumOverflow)?,
- );
- } else {
- collection.consume_sstore()?;
- <AccountItemCount<T>>::insert(owner.as_sub(), 1);
- }
- collection.consume_sload()?;
- let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());
- if list_exists {
- collection.consume_sload()?;
- let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());
let item_contains = list.contains(&item_index.clone());
if !item_contains {
@@ -2410,16 +2413,6 @@
item_index: TokenId,
owner: &T::CrossAccountId,
) -> DispatchResult {
- // update counter
- collection.consume_sload()?;
- collection.consume_sstore()?;
- <AccountItemCount<T>>::insert(
- owner.as_sub(),
- <AccountItemCount<T>>::get(owner.as_sub())
- .checked_sub(1)
- .ok_or(Error::<T>::NumOverflow)?,
- );
-
collection.consume_sload()?;
let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());
if list_exists {
pallets/nft/src/sponsorship.rsdiffbeforeafterboth--- a/pallets/nft/src/sponsorship.rs
+++ b/pallets/nft/src/sponsorship.rs
@@ -61,10 +61,15 @@
sponsor_transfer = match collection_mode {
CollectionMode::NFT => {
// get correct limit
- let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
- collection_limits.sponsor_transfer_timeout
+ let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {
+ if collection_limits.sponsor_transfer_timeout > NFT_SPONSOR_TRANSFER_TIMEOUT
+ {
+ collection_limits.sponsor_transfer_timeout
+ } else {
+ NFT_SPONSOR_TRANSFER_TIMEOUT
+ }
} else {
- NFT_SPONSOR_TRANSFER_TIMEOUT
+ 0
};
let mut sponsored = true;
@@ -83,13 +88,18 @@
}
CollectionMode::Fungible(_) => {
// get correct limit
- let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
- collection_limits.sponsor_transfer_timeout
+ let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {
+ if collection_limits.sponsor_transfer_timeout
+ > FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT
+ {
+ collection_limits.sponsor_transfer_timeout
+ } else {
+ FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT
+ }
} else {
- FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT
+ 0
};
- let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
let mut sponsored = true;
if FungibleTransferBasket::<T>::contains_key(collection_id, who) {
let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);
@@ -106,10 +116,16 @@
}
CollectionMode::ReFungible => {
// get correct limit
- let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
- collection_limits.sponsor_transfer_timeout
+ let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {
+ if collection_limits.sponsor_transfer_timeout
+ > REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT
+ {
+ collection_limits.sponsor_transfer_timeout
+ } else {
+ REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT
+ }
} else {
- REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT
+ 0
};
let mut sponsored = true;
tests/src/limits.test.tsdiffbeforeafterboth1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { IKeyringPair } from '@polkadot/types/types';7import privateKey from './substrate/privateKey';8import usingApi from './substrate/substrate-api';9import {10 createCollectionExpectSuccess,11 destroyCollectionExpectSuccess,12 setCollectionLimitsExpectSuccess,13 setCollectionSponsorExpectSuccess,14 confirmSponsorshipExpectSuccess,15 createItemExpectSuccess,16 createItemExpectFailure,17 transferExpectSuccess,18 getFreeBalance,19 waitNewBlocks,20} from './util/helpers'; 21import { expect } from 'chai';2223describe('Number of tokens per address (NFT)', () => {24 let Alice: IKeyringPair;2526 before(async () => {27 await usingApi(async () => {28 Alice = privateKey('//Alice');29 });30 });3132 it('Collection limits allow greater number than chain limits, chain limits are enforced', async () => {33 34 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });35 await setCollectionLimitsExpectSuccess(Alice, collectionId, { AccountTokenOwnershipLimit: 20 });36 for(let i = 0; i < 10; i++){37 await createItemExpectSuccess(Alice, collectionId, 'NFT');38 }39 await createItemExpectFailure(Alice, collectionId, 'NFT');40 await destroyCollectionExpectSuccess(collectionId);41 });4243 it('Collection limits allow lower number than chain limits, collection limits are enforced', async () => {4445 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });46 await setCollectionLimitsExpectSuccess(Alice, collectionId, { AccountTokenOwnershipLimit: 1 });47 await createItemExpectSuccess(Alice, collectionId, 'NFT');48 await createItemExpectFailure(Alice, collectionId, 'NFT');49 await destroyCollectionExpectSuccess(collectionId);50 });51});5253describe('Number of tokens per address (ReFungible)', () => {54 let Alice: IKeyringPair;5556 before(async () => {57 await usingApi(async () => {58 Alice = privateKey('//Alice');59 });60 });6162 it('Collection limits allow greater number than chain limits, chain limits are enforced', async () => { 63 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible' }});64 await setCollectionLimitsExpectSuccess(Alice, collectionId, { AccountTokenOwnershipLimit: 20 });65 for(let i = 0; i < 10; i++){66 await createItemExpectSuccess(Alice, collectionId, 'ReFungible');67 }68 await createItemExpectFailure(Alice, collectionId, 'ReFungible');69 await destroyCollectionExpectSuccess(collectionId);70 });7172 it('Collection limits allow lower number than chain limits, collection limits are enforced', async () => {73 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible' }});74 await setCollectionLimitsExpectSuccess(Alice, collectionId, { AccountTokenOwnershipLimit: 1 });75 await createItemExpectSuccess(Alice, collectionId, 'ReFungible');76 await createItemExpectFailure(Alice, collectionId, 'ReFungible');77 await destroyCollectionExpectSuccess(collectionId);78 });79});8081describe('Sponsor timeout (NFT)', () => {82 let Alice: IKeyringPair;83 let Bob: IKeyringPair;84 let Charlie: IKeyringPair;8586 before(async () => {87 await usingApi(async () => {88 Alice = privateKey('//Alice');89 Bob = privateKey('//Bob');90 Charlie = privateKey('//Charlie');91 });92 });9394 it('Collection limits have greater timeout value than chain limits, collection limits are enforced', async () => { 95 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });96 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 7 });97 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'NFT');98 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);99 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');100 await transferExpectSuccess(collectionId, tokenId, Alice, Bob);101 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();102103 // check setting SponsorTimeout = 5, fail104 await waitNewBlocks(5);105 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie);106 const aliceBalanceAfterUnsponsoredTransaction = (await getFreeBalance(Alice)).toNumber();107 expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);108109 // check setting SponsorTimeout = 7, success110 await waitNewBlocks(2); // 5 + 2111 await transferExpectSuccess(collectionId, tokenId, Charlie, Bob);112 const aliceBalanceAfterSponsoredTransaction = (await getFreeBalance(Alice)).toNumber();113 expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);114 await destroyCollectionExpectSuccess(collectionId);115 });116117 it('Collection limits have lower timeout value than chain limits, chain limits are enforced', async () => {118119 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });120 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 1 });121 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'NFT');122 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);123 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');124 await transferExpectSuccess(collectionId, tokenId, Alice, Bob);125 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();126127 // check setting SponsorTimeout = 1, fail128 await waitNewBlocks(1);129 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie);130 const aliceBalanceAfterUnsponsoredTransaction = (await getFreeBalance(Alice)).toNumber();131 expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);132133 // check setting SponsorTimeout = 5, success134 await waitNewBlocks(4);135 await transferExpectSuccess(collectionId, tokenId, Charlie, Bob);136 const aliceBalanceAfterSponsoredTransaction = (await getFreeBalance(Alice)).toNumber();137 expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);138 await destroyCollectionExpectSuccess(collectionId);139 });140});141142describe('Sponsor timeout (Fungible)', () => {143 let Alice: IKeyringPair;144 let Bob: IKeyringPair;145 let Charlie: IKeyringPair;146147 before(async () => {148 await usingApi(async () => {149 Alice = privateKey('//Alice');150 Bob = privateKey('//Bob');151 Charlie = privateKey('//Charlie');152 });153 });154155 it('Collection limits have greater timeout value than chain limits, collection limits are enforced', async () => { 156 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});157 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 7 });158 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'Fungible');159 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);160 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');161 await transferExpectSuccess(collectionId, tokenId, Alice, Bob, 10, 'Fungible');162 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');163 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();164165 // check setting SponsorTimeout = 5, fail166 await waitNewBlocks(5);167 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');168 const aliceBalanceAfterUnsponsoredTransaction = (await getFreeBalance(Alice)).toNumber();169 expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);170171 // check setting SponsorTimeout = 7, success172 await waitNewBlocks(2); // 5 + 2173 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');174 const aliceBalanceAfterSponsoredTransaction = (await getFreeBalance(Alice)).toNumber();175 expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);176177 await destroyCollectionExpectSuccess(collectionId);178 });179180 it('Collection limits have lower timeout value than chain limits, chain limits are enforced', async () => {181182 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});183 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 1 });184 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'Fungible');185 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);186 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');187 await transferExpectSuccess(collectionId, tokenId, Alice, Bob, 10, 'Fungible');188 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');189 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();190191 // check setting SponsorTimeout = 1, fail192 await waitNewBlocks(1);193 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');194 const aliceBalanceAfterUnsponsoredTransaction = (await getFreeBalance(Alice)).toNumber();195 expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);196197 // check setting SponsorTimeout = 5, success198 await waitNewBlocks(4);199 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');200 const aliceBalanceAfterSponsoredTransaction = (await getFreeBalance(Alice)).toNumber();201 expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);202203 await destroyCollectionExpectSuccess(collectionId);204 });205});206207describe('Sponsor timeout (ReFungible)', () => {208 let Alice: IKeyringPair;209 let Bob: IKeyringPair;210 let Charlie: IKeyringPair;211212 before(async () => {213 await usingApi(async () => {214 Alice = privateKey('//Alice');215 Bob = privateKey('//Bob');216 Charlie = privateKey('//Charlie');217 });218 });219220 it('Collection limits have greater timeout value than chain limits, collection limits are enforced', async () => { 221 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible' }});222 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 7 });223 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'ReFungible');224 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);225 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');226 await transferExpectSuccess(collectionId, tokenId, Alice, Bob, 100, 'ReFungible');227 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();228229 // check setting SponsorTimeout = 5, fail230 await waitNewBlocks(5);231 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 20, 'ReFungible');232 const aliceBalanceAfterUnsponsoredTransaction = (await getFreeBalance(Alice)).toNumber();233 expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);234235 // check setting SponsorTimeout = 7, success236 await waitNewBlocks(2); // 5 + 2237 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 20, 'ReFungible');238 const aliceBalanceAfterSponsoredTransaction = (await getFreeBalance(Alice)).toNumber();239 expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);240 await destroyCollectionExpectSuccess(collectionId);241 });242243 it('Collection limits have lower timeout value than chain limits, chain limits are enforced', async () => {244245 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });246 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 1 });247 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'NFT');248 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);249 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');250 await transferExpectSuccess(collectionId, tokenId, Alice, Bob);251 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();252253 // check setting SponsorTimeout = 1, fail254 await waitNewBlocks(1);255 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie);256 const aliceBalanceAfterUnsponsoredTransaction = (await getFreeBalance(Alice)).toNumber();257 expect(aliceBalanceAfterUnsponsoredTransaction).to.be.equals(aliceBalanceBefore);258259 // check setting SponsorTimeout = 5, success260 await waitNewBlocks(4);261 await transferExpectSuccess(collectionId, tokenId, Charlie, Bob);262 const aliceBalanceAfterSponsoredTransaction = (await getFreeBalance(Alice)).toNumber();263 expect(aliceBalanceAfterSponsoredTransaction).to.be.lessThan(aliceBalanceBefore);264 await destroyCollectionExpectSuccess(collectionId);265 });266});267268describe('Collection zero limits (NFT)', () => {269 let Alice: IKeyringPair;270 let Bob: IKeyringPair;271 let Charlie: IKeyringPair;272273 before(async () => {274 await usingApi(async () => {275 Alice = privateKey('//Alice');276 Bob = privateKey('//Bob');277 Charlie = privateKey('//Charlie');278 });279 });280281 it('Limits have 0 in tokens per address field, the chain limits are applied', async () => { 282 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });283 await setCollectionLimitsExpectSuccess(Alice, collectionId, { AccountTokenOwnershipLimit: 0 });284 for(let i = 0; i < 10; i++){285 await createItemExpectSuccess(Alice, collectionId, 'NFT');286 }287 await createItemExpectFailure(Alice, collectionId, 'NFT');288 });289290 it('Limits have 0 in sponsor timeout, no limits are applied', async () => {291292 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });293 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 0 });294 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'NFT');295 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);296 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');297 await transferExpectSuccess(collectionId, tokenId, Alice, Bob);298 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();299300 // check setting SponsorTimeout = 0, success with next block301 await waitNewBlocks(1);302 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie);303 const aliceBalanceAfterSponsoredTransaction1 = (await getFreeBalance(Alice)).toNumber();304 expect(aliceBalanceAfterSponsoredTransaction1).to.be.lessThan(aliceBalanceBefore);305 });306});307308describe.only('Collection zero limits (Fungible)', () => {309 let Alice: IKeyringPair;310 let Bob: IKeyringPair;311 let Charlie: IKeyringPair;312313 before(async () => {314 await usingApi(async () => {315 Alice = privateKey('//Alice');316 Bob = privateKey('//Bob');317 Charlie = privateKey('//Charlie');318 });319 });320321 it('Limits have 0 in sponsor timeout, no limits are applied', async () => {322 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});323 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 0 });324 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'Fungible');325 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);326 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');327 await transferExpectSuccess(collectionId, tokenId, Alice, Bob, 10, 'Fungible');328 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();329 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');330331 // check setting SponsorTimeout = 0, success with next block332 await waitNewBlocks(1);333 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 2, 'Fungible');334 const aliceBalanceAfterSponsoredTransaction1 = (await getFreeBalance(Alice)).toNumber();335 expect(aliceBalanceAfterSponsoredTransaction1).to.be.lessThan(aliceBalanceBefore);336 });337});338339describe.only('Collection zero limits (ReFungible)', () => {340 let Alice: IKeyringPair;341 let Bob: IKeyringPair;342 let Charlie: IKeyringPair;343344 before(async () => {345 await usingApi(async () => {346 Alice = privateKey('//Alice');347 Bob = privateKey('//Bob');348 Charlie = privateKey('//Charlie');349 });350 });351352 it('Limits have 0 in tokens per address field, the chain limits are applied', async () => { 353 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible' }});354 await setCollectionLimitsExpectSuccess(Alice, collectionId, { AccountTokenOwnershipLimit: 0 });355 for(let i = 0; i < 10; i++){356 await createItemExpectSuccess(Alice, collectionId, 'ReFungible');357 }358 await createItemExpectFailure(Alice, collectionId, 'ReFungible');359 });360361 it('Limits have 0 in sponsor timeout, no limits are applied', async () => {362363 const collectionId = await createCollectionExpectSuccess({ mode: { type: 'ReFungible' } });364 await setCollectionLimitsExpectSuccess(Alice, collectionId, { SponsorTimeout: 0 });365 const tokenId = await createItemExpectSuccess(Alice, collectionId, 'ReFungible');366 await setCollectionSponsorExpectSuccess(collectionId, Alice.address);367 await confirmSponsorshipExpectSuccess(collectionId, '//Alice');368 await transferExpectSuccess(collectionId, tokenId, Alice, Bob, 100, 'ReFungible');369 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 20, 'ReFungible');370 const aliceBalanceBefore = (await getFreeBalance(Alice)).toNumber();371372 // check setting SponsorTimeout = 0, success with next block373 await waitNewBlocks(1);374 await transferExpectSuccess(collectionId, tokenId, Bob, Charlie, 20, 'ReFungible');375 const aliceBalanceAfterSponsoredTransaction1 = (await getFreeBalance(Alice)).toNumber();376 expect(aliceBalanceAfterSponsoredTransaction1).to.be.lessThan(aliceBalanceBefore);377 });378});tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -797,6 +797,17 @@
}
export async function
+getFreeBalance(account: IKeyringPair) : Promise<BigNumber>
+{
+ let balance = new BigNumber(0) ;
+ await usingApi(async (api) => {
+ balance = new BigNumber((await api.query.system.account(account.address)).data.free.toString());
+ });
+
+ return balance;
+}
+
+export async function
scheduleTransferExpectSuccess(
collectionId: number,
tokenId: number,
@@ -870,8 +881,11 @@
if (type === 'ReFungible') {
const nftItemData =
(await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;
- expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);
- expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());
+ const expectedOwner = toSubstrateAddress(to);
+ const ownerIndex = nftItemData.Owner.findIndex(v => toSubstrateAddress(v.Owner as any as string) == expectedOwner);
+ expect(ownerIndex).to.not.equal(-1);
+ expect(nftItemData.Owner[ownerIndex].Owner).to.be.deep.equal(normalizeAccountId(to));
+ expect(nftItemData.Owner[ownerIndex].Fraction).to.be.greaterThanOrEqual(value as number);
}
});
}
@@ -1171,4 +1185,21 @@
export async function queryNftOwner(api: ApiPromise, collectionId: number, tokenId: number): Promise<CrossAccountId> {
return normalizeAccountId((await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON().Owner);
-}
\ No newline at end of file
+}
+
+export async function waitNewBlocks(blocksCount = 1): Promise<void> {
+ await usingApi(async (api) => {
+ const promise = new Promise<void>(async (resolve) => {
+
+ const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {
+ if (blocksCount > 0) {
+ blocksCount--;
+ } else {
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+ return promise;
+ });
+}