difftreelog
Merge remote-tracking branch 'origin/master' into develop
in: master
2 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth111011101111 // Transfer permissions check1111 // Transfer permissions check1112 let target_collection = <Collection<T>>::get(collection_id);1112 let target_collection = <Collection<T>>::get(collection_id);1113 ensure!(1114 Self::is_item_owner(sender.clone(), collection_id, item_id) ||1115 (1113 let allowance_limit = if (1116 target_collection.limits.owner_can_transfer &&1114 target_collection.limits.owner_can_transfer &&1117 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1115 Self::is_owner_or_admin_permissions(1116 collection_id,1117 sender.clone(),1118 )1118 ),1119 ) {1120 None1121 } else if let Some(amount) = Self::owned_amount(1122 sender.clone(),1123 collection_id,1124 item_id,1125 ) {1126 Some(amount)1127 } else {1119 Error::<T>::NoPermission1128 fail!(Error::<T>::NoPermission);1120 );1129 };112111301122 if target_collection.access == AccessMode::WhiteList {1131 if target_collection.access == AccessMode::WhiteList {1123 Self::check_white_list(collection_id, &sender)?;1132 Self::check_white_list(collection_id, &sender)?;1129 if allowance_exists {1138 if allowance_exists {1130 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1139 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1131 }1140 }1141 if let Some(limit) = allowance_limit {1142 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1143 }1132 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);1144 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);113311451134 Ok(())1146 Ok(())1912 Ok(())1924 Ok(())1913 }1925 }19261927 fn owned_amount(1928 subject: T::AccountId,1929 collection_id: CollectionId,1930 item_id: TokenId,1931 ) -> Option<u128> {1932 let target_collection = <Collection<T>>::get(collection_id);19331934 match target_collection.mode {1935 CollectionMode::NFT => {1936 if <NftItemList<T>>::get(collection_id, item_id).owner == subject {1937 return Some(1)1938 }1939 None1940 },1941 CollectionMode::Fungible(_) => {1942 if <FungibleItemList<T>>::contains_key(collection_id, &subject) {1943 return Some(<FungibleItemList<T>>::get(collection_id, &subject)1944 .value);1945 }1946 None1947 },1948 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)1949 .owner1950 .iter()1951 .find(|i| i.owner == subject)1952 .map(|i| i.fraction),1953 CollectionMode::Invalid => None,1954 }1955 }191419561915 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1957 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1916 let target_collection = <Collection<T>>::get(collection_id);1958 let target_collection = <Collection<T>>::get(collection_id);tests/src/approve.test.tsdiffbeforeafterboth2// This file is subject to the terms and conditions defined in2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.3// file 'LICENSE', which is part of this source code package.4//4//5import { ApiPromise } from '@polkadot/api';6import { IKeyringPair } from '@polkadot/types/types';5import { IKeyringPair } from '@polkadot/types/types';7import BN from 'bn.js';6import { ApiPromise } from '@polkadot/api';8import chai from 'chai';7import chai from 'chai';9import chaiAsPromised from 'chai-as-promised';8import chaiAsPromised from 'chai-as-promised';10import privateKey from './substrate/privateKey';9import privateKey from './substrate/privateKey';13 approveExpectFail,12 approveExpectFail,14 approveExpectSuccess,13 approveExpectSuccess,15 createCollectionExpectSuccess,14 createCollectionExpectSuccess,16 createFungibleItemExpectSuccess,17 createItemExpectSuccess,15 createItemExpectSuccess,18 destroyCollectionExpectSuccess,16 destroyCollectionExpectSuccess,19 setCollectionLimitsExpectSuccess,17 setCollectionLimitsExpectSuccess,20 transferFromExpectSuccess,18 transferExpectSuccess,21 U128_MAX,22} from './util/helpers';19} from './util/helpers';232024chai.use(chaiAsPromised);21chai.use(chaiAsPromised);25const expect = chai.expect;262227describe('Integration Test approve(spender, collection_id, item_id, amount):', () => {23describe('Integration Test approve(spender, collection_id, item_id, amount):', () => {28 let Alice: IKeyringPair;24 let Alice: IKeyringPair;29 let Bob: IKeyringPair;25 let Bob: IKeyringPair;30 let Charlie: IKeyringPair;26 let Charlie: IKeyringPair;312732 before(async () => {28 before(async () => {33 await usingApi(async (api) => {29 await usingApi(async () => {34 Alice = privateKey('//Alice');30 Alice = privateKey('//Alice');35 Bob = privateKey('//Bob');31 Bob = privateKey('//Bob');36 Charlie = privateKey('//Charlie');32 Charlie = privateKey('//Charlie');37 });33 });38 });34 });393540 it('Execute the extrinsic and check approvedList', async () => {36 it('Execute the extrinsic and check approvedList', async () => {41 await usingApi(async (api: ApiPromise) => {42 const nftCollectionId = await createCollectionExpectSuccess();37 const nftCollectionId = await createCollectionExpectSuccess();43 // nft38 // nft44 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');39 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');52 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});47 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});53 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');48 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');54 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);49 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);55 });56 });50 });575158 it('Remove approval by using 0 amount', async () => {52 it('Remove approval by using 0 amount', async () => {59 await usingApi(async (api: ApiPromise) => {60 const nftCollectionId = await createCollectionExpectSuccess();53 const nftCollectionId = await createCollectionExpectSuccess();61 // nft54 // nft62 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');55 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');73 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');66 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');74 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 1);67 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 1);75 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 0);68 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 0);76 });77 });69 });787079 it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => {71 it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => {112 });104 });113105114 it('Approve for a collection that was destroyed', async () => {106 it('Approve for a collection that was destroyed', async () => {115 await usingApi(async (api: ApiPromise) => {116 // nft107 // nft117 const nftCollectionId = await createCollectionExpectSuccess();108 const nftCollectionId = await createCollectionExpectSuccess();118 await destroyCollectionExpectSuccess(nftCollectionId);109 await destroyCollectionExpectSuccess(nftCollectionId);126 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});117 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});127 await destroyCollectionExpectSuccess(reFungibleCollectionId);118 await destroyCollectionExpectSuccess(reFungibleCollectionId);128 await approveExpectFail(reFungibleCollectionId, 1, Alice, Bob);119 await approveExpectFail(reFungibleCollectionId, 1, Alice, Bob);129 });130 });120 });131121132 it('Approve transfer of a token that does not exist', async () => {122 it('Approve transfer of a token that does not exist', async () => {133 await usingApi(async (api: ApiPromise) => {134 // nft123 // nft135 const nftCollectionId = await createCollectionExpectSuccess();124 const nftCollectionId = await createCollectionExpectSuccess();136 await approveExpectFail(nftCollectionId, 2, Alice, Bob);125 await approveExpectFail(nftCollectionId, 2, Alice, Bob);141 const reFungibleCollectionId =130 const reFungibleCollectionId =142 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});131 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});143 await approveExpectFail(reFungibleCollectionId, 2, Alice, Bob);132 await approveExpectFail(reFungibleCollectionId, 2, Alice, Bob);144 });145 });133 });146134147 it('Approve using the address that does not own the approved token', async () => {135 it('Approve using the address that does not own the approved token', async () => {148 await usingApi(async (api: ApiPromise) => {149 const nftCollectionId = await createCollectionExpectSuccess();136 const nftCollectionId = await createCollectionExpectSuccess();150 // nft137 // nft151 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');138 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');159 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});146 await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});160 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');147 const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');161 await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice);148 await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice);162 });163 });149 });150151 it('should fail if approved more NFTs than owned', async () => {152 const nftCollectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });153 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');154 await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');155 await approveExpectSuccess(nftCollectionId, newNftTokenId, Bob, Alice);156 await approveExpectFail(nftCollectionId, newNftTokenId, Bob, Alice);157 });158159 it('should fail if approved more ReFungibles than owned', async () => {160 const nftCollectionId = await createCollectionExpectSuccess({ mode: { type: 'ReFungible' } });161 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'ReFungible');162 await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 100, 'ReFungible');163 await approveExpectSuccess(nftCollectionId, newNftTokenId, Bob, Alice, 100);164 await approveExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, 1);165 });166167 it('should fail if approved more Fungibles than owned', async () => {168 const nftCollectionId = await createCollectionExpectSuccess({ mode: { type: 'Fungible', decimalPoints: 0 } });169 const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'Fungible');170 await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 10, 'Fungible');171 await approveExpectSuccess(nftCollectionId, newNftTokenId, Bob, Alice, 10);172 await approveExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, 1);173 });164174165 it('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async () => {175 it('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async () => {166 const collectionId = await createCollectionExpectSuccess();176 const collectionId = await createCollectionExpectSuccess();