From 1ac708f72a4bde90695331956e2ba721e06c80f4 Mon Sep 17 00:00:00 2001 From: bugrazoid Date: Wed, 06 Jul 2022 06:41:58 +0000 Subject: [PATCH] Merge pull request #411 from UniqueNetwork/feature/total_pieces Add rpc method for total_pieces --- --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -184,12 +184,21 @@ token: TokenId, at: Option, ) -> Result>; + #[method(name = "unique_effectiveCollectionLimits")] fn effective_collection_limits( &self, collection_id: CollectionId, at: Option, ) -> Result>; + + #[method(name = "unique_totalPieces")] + fn total_pieces( + &self, + collection_id: CollectionId, + token_id: TokenId, + at: Option, + ) -> Result>; } mod rmrk_unique_rpc { @@ -463,6 +472,7 @@ pass_method!(collection_stats() -> CollectionStats, unique_api); pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option, unique_api); pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option, unique_api); + pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option, unique_api); } #[allow(deprecated)] --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -1384,6 +1384,8 @@ fn account_balance(&self, account: T::CrossAccountId) -> u32; /// Amount of specific token account have (Applicable to fungible/refungible) fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128; + /// Amount of token pieces + fn total_pieces(&self, token: TokenId) -> Option; fn allowance( &self, sender: T::CrossAccountId, --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -25,7 +25,8 @@ use up_data_structs::{Property, PropertyKey, PropertyValue, PropertyKeyPermission}; use crate::{ - Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo, + Allowance, TotalSupply, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, + weights::WeightInfo, }; pub struct CommonWeights(PhantomData); @@ -405,4 +406,11 @@ fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions> { None } + + fn total_pieces(&self, token: TokenId) -> Option { + if token != TokenId::default() { + return None; + } + >::try_get(self.id).ok() + } } --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -487,4 +487,12 @@ fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions> { None } + + fn total_pieces(&self, token: TokenId) -> Option { + if >::contains_key((self.id, token)) { + Some(1) + } else { + None + } + } } --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -411,6 +411,10 @@ fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions> { Some(self) } + + fn total_pieces(&self, token: TokenId) -> Option { + >::total_pieces(self.id, token) + } } impl RefungibleExtensions for RefungibleHandle { --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -710,4 +710,8 @@ >::insert((collection.id, token), amount); Ok(()) } + + fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option { + >::try_get((collection_id, token_id)).ok() + } } --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -181,6 +181,7 @@ pub struct TokenData { pub properties: Vec, pub owner: Option, + pub pieces: u128, } pub struct OverflowError; --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -80,5 +80,6 @@ fn collection_stats() -> Result; fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result>; fn effective_collection_limits(collection_id: CollectionId) -> Result>; + fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result>; } } --- a/runtime/common/src/runtime_apis.rs +++ b/runtime/common/src/runtime_apis.rs @@ -89,7 +89,8 @@ ) -> Result, DispatchError> { let token_data = TokenData { properties: Self::token_properties(collection, token_id, keys)?, - owner: Self::token_owner(collection, token_id)? + owner: Self::token_owner(collection, token_id)?, + pieces: Self::total_pieces(collection, token_id)?.unwrap_or(0), }; Ok(token_data) @@ -142,6 +143,10 @@ fn effective_collection_limits(collection: CollectionId) -> Result, DispatchError> { Ok(>::effective_collection_limits(collection)) } + + fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result, DispatchError> { + dispatch_unique_runtime!(collection.total_pieces(token_id)) + } } impl sp_api::Core for Runtime { --- a/tests/src/createItem.test.ts +++ b/tests/src/createItem.test.ts @@ -24,6 +24,8 @@ createCollectionWithPropsExpectSuccess, createItemWithPropsExpectSuccess, createItemWithPropsExpectFailure, + createCollection, + transferExpectSuccess, } from './util/helpers'; const expect = chai.expect; @@ -95,6 +97,82 @@ await createItemWithPropsExpectSuccess(alice, newCollectionID, createMode, [{key: 'key1', value: 'val1'}]); }); + + it('Check total pieces of Fungible token', async () => { + await usingApi(async api => { + const createMode = 'Fungible'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); + const amountPieces = 10n; + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode, bob.address); + { + const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + } + + await transferExpectSuccess(collectionId, tokenId, bob, alice, 1, createMode); + { + const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + } + + const totalPieces = (await api.rpc.unique.tokenData(collectionId, tokenId, [])).pieces; + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + }); + }); + + it('Check total pieces of NFT token', async () => { + await usingApi(async api => { + const createMode = 'NFT'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}}); + const amountPieces = 1n; + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode, bob.address); + { + const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + } + + await transferExpectSuccess(collectionId, tokenId, bob, alice, 1, createMode); + { + const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + } + + const totalPieces = (await api.rpc.unique.tokenData(collectionId, tokenId, [])).pieces; + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + }); + }); + + it('Check total pieces of ReFungible token', async () => { + await usingApi(async api => { + const createMode = 'ReFungible'; + const createCollectionResult = await createCollection(api, alice, {mode: {type: createMode}}); + const collectionId = createCollectionResult.collectionId; + const amountPieces = 100n; + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode, bob.address); + { + const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + } + + await transferExpectSuccess(collectionId, tokenId, bob, alice, 60n, createMode); + { + const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + } + + const totalPieces = (await api.rpc.unique.tokenData(collectionId, tokenId, [])).pieces; + expect(totalPieces.isSome).to.be.true; + expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); + }); + }); }); describe('Negative integration test: ext. createItem():', () => { @@ -169,4 +247,37 @@ await createItemWithPropsExpectFailure(alice, newCollectionID, 'NFT', [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]); }); }); + + it('Check total pieces for invalid Fungible token', async () => { + await usingApi(async api => { + const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}}); + const collectionId = createCollectionResult.collectionId; + const invalidTokenId = 1000_000; + + expect((await api.rpc.unique.totalPieces(collectionId, invalidTokenId)).isNone).to.be.true; + expect((await api.rpc.unique.tokenData(collectionId, invalidTokenId, [])).pieces.isNone).to.be.true; + }); + }); + + it('Check total pieces for invalid NFT token', async () => { + await usingApi(async api => { + const createCollectionResult = await createCollection(api, alice, {mode: {type: 'NFT'}}); + const collectionId = createCollectionResult.collectionId; + const invalidTokenId = 1000_000; + + expect((await api.rpc.unique.totalPieces(collectionId, invalidTokenId)).isNone).to.be.true; + expect((await api.rpc.unique.tokenData(collectionId, invalidTokenId, [])).pieces.isNone).to.be.true; + }); + }); + + it('Check total pieces for invalid Refungible token', async () => { + await usingApi(async api => { + const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}}); + const collectionId = createCollectionResult.collectionId; + const invalidTokenId = 1000_000; + + expect((await api.rpc.unique.totalPieces(collectionId, invalidTokenId)).isNone).to.be.true; + expect((await api.rpc.unique.tokenData(collectionId, invalidTokenId, [])).pieces.isNone).to.be.true; + }); + }); }); --- a/tests/src/interfaces/unique/definitions.ts +++ b/tests/src/interfaces/unique/definitions.ts @@ -79,5 +79,6 @@ allowed: fun('Check if user is allowed to use collection', [collectionParam, crossAccountParam()], 'bool'), nextSponsored: fun('Get number of blocks when sponsored transaction is available', [collectionParam, crossAccountParam(), tokenParam], 'Option'), effectiveCollectionLimits: fun('Get effective collection limits', [collectionParam], 'Option'), + totalPieces: fun('Get total pieces of token', [collectionParam, tokenParam], 'Option'), }, }; -- gitstuff