git.delta.rocks / unique-network / refs/commits / 6b48a5a77b12

difftreelog

OwnerCanTransfer flag

Dev2022-06-14parent: #681a5b7.patch.diff
in: master

10 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
1164 old_limit: &CollectionLimits,1164 old_limit: &CollectionLimits,
1165 mut new_limit: CollectionLimits,1165 mut new_limit: CollectionLimits,
1166 ) -> Result<CollectionLimits, DispatchError> {1166 ) -> Result<CollectionLimits, DispatchError> {
1167 let limits = old_limit;
1167 limit_default!(old_limit, new_limit,1168 limit_default!(old_limit, new_limit,
1168 account_token_ownership_limit => ensure!(1169 account_token_ownership_limit => ensure!(
1169 new_limit <= MAX_TOKEN_OWNERSHIP,1170 new_limit <= MAX_TOKEN_OWNERSHIP,
1190 ),1191 ),
1191 sponsor_approve_timeout => {},1192 sponsor_approve_timeout => {},
1192 owner_can_transfer => ensure!(1193 owner_can_transfer => ensure!(
1194 !limits.owner_can_transfer_instaled() ||
1193 old_limit || !new_limit,1195 old_limit || !new_limit,
1194 <Error<T>>::OwnerPermissionsCantBeReverted,1196 <Error<T>>::OwnerPermissionsCantBeReverted,
1195 ),1197 ),
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
409 .min(MAX_SPONSOR_TIMEOUT)409 .min(MAX_SPONSOR_TIMEOUT)
410 }410 }
411 pub fn owner_can_transfer(&self) -> bool {411 pub fn owner_can_transfer(&self) -> bool {
412 self.owner_can_transfer.unwrap_or(true)412 self.owner_can_transfer.unwrap_or(false)
413 }413 }
414 pub fn owner_can_transfer_instaled(&self) -> bool {
415 self.owner_can_transfer.is_some()
416 }
414 pub fn owner_can_destroy(&self) -> bool {417 pub fn owner_can_destroy(&self) -> bool {
415 self.owner_can_destroy.unwrap_or(true)418 self.owner_can_destroy.unwrap_or(true)
416 }419 }
modifiedtests/src/approve.test.tsdiffbeforeafterboth
28 setCollectionLimitsExpectSuccess,28 setCollectionLimitsExpectSuccess,
29 transferExpectSuccess,29 transferExpectSuccess,
30 addCollectionAdminExpectSuccess,30 addCollectionAdminExpectSuccess,
31 adminApproveFromExpectSuccess,31 adminApproveFromExpectFail,
32 getCreatedCollectionCount,32 getCreatedCollectionCount,
33 transferFromExpectSuccess,33 transferFromExpectSuccess,
34 transferFromExpectFail,34 transferFromExpectFail,
84 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 0);84 await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 0);
85 });85 });
8686
87 it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => {87 it('can`t be called by collection owner on non-owned item when OwnerCanTransfer == false', async () => {
88 const collectionId = await createCollectionExpectSuccess();88 const collectionId = await createCollectionExpectSuccess();
89 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);89 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
9090
91 await adminApproveFromExpectSuccess(collectionId, itemId, alice, bob.address, charlie.address);91 await adminApproveFromExpectFail(collectionId, itemId, alice, bob.address, charlie.address);
92 });92 });
93});93});
9494
292 });292 });
293});293});
294294
295describe('Administrator and collection owner do not need approval in order to execute TransferFrom:', () => {295describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {
296 let alice: IKeyringPair;296 let alice: IKeyringPair;
297 let bob: IKeyringPair;297 let bob: IKeyringPair;
298 let charlie: IKeyringPair;298 let charlie: IKeyringPair;
309309
310 it('NFT', async () => {310 it('NFT', async () => {
311 const collectionId = await createCollectionExpectSuccess();311 const collectionId = await createCollectionExpectSuccess();
312 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
312 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', charlie.address);313 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', charlie.address);
313 await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'NFT');314 await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'NFT');
314 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);315 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
317318
318 it('Fungible up to an approved amount', async () => {319 it('Fungible up to an approved amount', async () => {
319 const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});320 const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}});
321 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
320 const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', charlie.address); 322 const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', charlie.address);
321 await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'Fungible');323 await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'Fungible');
322 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);324 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
325327
326 it('ReFungible up to an approved amount', async () => {328 it('ReFungible up to an approved amount', async () => {
327 const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});329 const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}});
330 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
328 const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address);331 const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address);
329 await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'ReFungible');332 await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'ReFungible');
330 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);333 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
402 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);405 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);
403406
404 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);407 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
405 await adminApproveFromExpectSuccess(collectionId, itemId, bob, alice.address, charlie.address);408 await adminApproveFromExpectFail(collectionId, itemId, bob, alice.address, charlie.address);
406 });409 });
407});410});
408411
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
23 normalizeAccountId,23 normalizeAccountId,
24 addCollectionAdminExpectSuccess,24 addCollectionAdminExpectSuccess,
25 getBalance,25 getBalance,
26 setCollectionLimitsExpectSuccess,
26 isTokenExists,27 isTokenExists,
27} from './util/helpers';28} from './util/helpers';
2829
149 it('Burn item in NFT collection', async () => {150 it('Burn item in NFT collection', async () => {
150 const createMode = 'NFT';151 const createMode = 'NFT';
151 const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});152 const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
153 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
152 const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);154 const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
153 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);155 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
154156
167 it('Burn item in Fungible collection', async () => {169 it('Burn item in Fungible collection', async () => {
168 const createMode = 'Fungible';170 const createMode = 'Fungible';
169 const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});171 const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
172 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
170 const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); // Helper creates 10 fungible tokens173 const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); // Helper creates 10 fungible tokens
171 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);174 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
172175
189 it('Burn item in ReFungible collection', async () => {192 it('Burn item in ReFungible collection', async () => {
190 const createMode = 'ReFungible';193 const createMode = 'ReFungible';
191 const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});194 const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
195 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
192 const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);196 const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
193 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);197 await addCollectionAdminExpectSuccess(alice, collectionId, bob.address);
194198
modifiedtests/src/eth/crossTransfer.test.tsdiffbeforeafterboth
18 createFungibleItemExpectSuccess,18 createFungibleItemExpectSuccess,
19 transferExpectSuccess,19 transferExpectSuccess,
20 transferFromExpectSuccess,20 transferFromExpectSuccess,
21 setCollectionLimitsExpectSuccess,
21 createItemExpectSuccess} from '../util/helpers';22 createItemExpectSuccess} from '../util/helpers';
22import {collectionIdToAddress,23import {collectionIdToAddress,
23 createEthAccountWithBalance,24 createEthAccountWithBalance,
35 const alice = privateKeyWrapper('//Alice');36 const alice = privateKeyWrapper('//Alice');
36 const bob = privateKeyWrapper('//Bob');37 const bob = privateKeyWrapper('//Bob');
37 const charlie = privateKeyWrapper('//Charlie');38 const charlie = privateKeyWrapper('//Charlie');
39 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});
38 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});40 await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Substrate: alice.address});
39 await transferExpectSuccess(collection, 0, alice, {Ethereum: subToEth(charlie.address)} , 200, 'Fungible');41 await transferExpectSuccess(collection, 0, alice, {Ethereum: subToEth(charlie.address)} , 200, 'Fungible');
40 await transferFromExpectSuccess(collection, 0, alice, {Ethereum: subToEth(charlie.address)}, charlie, 50, 'Fungible');42 await transferFromExpectSuccess(collection, 0, alice, {Ethereum: subToEth(charlie.address)}, charlie, 50, 'Fungible');
48 });50 });
49 const alice = privateKeyWrapper('//Alice');51 const alice = privateKeyWrapper('//Alice');
50 const bob = privateKeyWrapper('//Bob');52 const bob = privateKeyWrapper('//Bob');
53 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});
51 const bobProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);54 const bobProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
52 const aliceProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);55 const aliceProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
5356
71 const alice = privateKeyWrapper('//Alice');74 const alice = privateKeyWrapper('//Alice');
72 const bob = privateKeyWrapper('//Bob');75 const bob = privateKeyWrapper('//Bob');
73 const charlie = privateKeyWrapper('//Charlie');76 const charlie = privateKeyWrapper('//Charlie');
77 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});
74 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});78 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});
75 await transferExpectSuccess(collection, tokenId, alice, {Ethereum: subToEth(charlie.address)}, 1, 'NFT');79 await transferExpectSuccess(collection, tokenId, alice, {Ethereum: subToEth(charlie.address)}, 1, 'NFT');
76 await transferFromExpectSuccess(collection, tokenId, alice, {Ethereum: subToEth(charlie.address)}, charlie, 1, 'NFT');80 await transferFromExpectSuccess(collection, tokenId, alice, {Ethereum: subToEth(charlie.address)}, charlie, 1, 'NFT');
85 const alice = privateKeyWrapper('//Alice');89 const alice = privateKeyWrapper('//Alice');
86 const bob = privateKeyWrapper('//Bob');90 const bob = privateKeyWrapper('//Bob');
87 const charlie = privateKeyWrapper('//Charlie');91 const charlie = privateKeyWrapper('//Charlie');
92 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});
88 const bobProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);93 const bobProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
89 const aliceProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);94 const aliceProxy = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
90 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});95 const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Substrate: alice.address});
modifiedtests/src/limits.test.tsdiffbeforeafterboth
406 it('Effective collection limits', async () => {406 it('Effective collection limits', async () => {
407 await usingApi(async (api) => {407 await usingApi(async (api) => {
408 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});408 const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
409 409 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
410
410 { // Check that limits is undefined411 { // Check that limits is undefined
411 const collection = await api.rpc.unique.collectionById(collectionId);412 const collection = await api.rpc.unique.collectionById(collectionId);
419 expect(limits.tokenLimit.toHuman()).to.be.null;420 expect(limits.tokenLimit.toHuman()).to.be.null;
420 expect(limits.sponsorTransferTimeout.toHuman()).to.be.null;421 expect(limits.sponsorTransferTimeout.toHuman()).to.be.null;
421 expect(limits.sponsorApproveTimeout.toHuman()).to.be.null;422 expect(limits.sponsorApproveTimeout.toHuman()).to.be.null;
422 expect(limits.ownerCanTransfer.toHuman()).to.be.null;423 expect(limits.ownerCanTransfer.toHuman()).to.be.true;
423 expect(limits.ownerCanDestroy.toHuman()).to.be.null;424 expect(limits.ownerCanDestroy.toHuman()).to.be.null;
424 expect(limits.transfersEnabled.toHuman()).to.be.null;425 expect(limits.transfersEnabled.toHuman()).to.be.null;
425 }426 }
modifiedtests/src/nesting/graphs.test.tsdiffbeforeafterboth
3import {expect} from 'chai';3import {expect} from 'chai';
4import {tokenIdToCross} from '../eth/util/helpers';4import {tokenIdToCross} from '../eth/util/helpers';
5import usingApi, {executeTransaction} from '../substrate/substrate-api';5import usingApi, {executeTransaction} from '../substrate/substrate-api';
6import {getCreateCollectionResult, transferExpectSuccess} from '../util/helpers';6import {getCreateCollectionResult, transferExpectSuccess, setCollectionLimitsExpectSuccess} from '../util/helpers';
77
8/**8/**
9 * ```dot9 * ```dot
36 await usingApi(async (api, privateKeyWrapper) => {36 await usingApi(async (api, privateKeyWrapper) => {
37 const alice = privateKeyWrapper('//Alice');37 const alice = privateKeyWrapper('//Alice');
38 const collection = await buildComplexObjectGraph(api, alice);38 const collection = await buildComplexObjectGraph(api, alice);
39 await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true});
3940
40 // to self41 // to self
41 await expect(42 await expect(
modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth
15 transferExpectFailure,15 transferExpectFailure,
16 transferExpectSuccess,16 transferExpectSuccess,
17 transferFromExpectSuccess,17 transferFromExpectSuccess,
18 setCollectionLimitsExpectSuccess,
18} from '../util/helpers';19} from '../util/helpers';
19import {IKeyringPair} from '@polkadot/types/types';20import {IKeyringPair} from '@polkadot/types/types';
2021
92 it('Checks token children', async () => {93 it('Checks token children', async () => {
93 await usingApi(async api => {94 await usingApi(async api => {
94 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});95 const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
96 await setCollectionLimitsExpectSuccess(alice, collectionA, {ownerCanTransfer: true});
95 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {tokenOwner: true}});97 await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: {tokenOwner: true}});
96 const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});98 const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
9799
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
9999
100 it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => {100 it('can be called by collection owner on non-owned item when OwnerCanTransfer == true', async () => {
101 const collectionId = await createCollectionExpectSuccess();101 const collectionId = await createCollectionExpectSuccess();
102 await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true});
102 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);103 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address);
103104
104 await transferFromExpectSuccess(collectionId, itemId, alice, bob, charlie);105 await transferFromExpectSuccess(collectionId, itemId, alice, bob, charlie);
257 await usingApi(async () => {258 await usingApi(async () => {
258 // nft259 // nft
259 const nftCollectionId = await createCollectionExpectSuccess();260 const nftCollectionId = await createCollectionExpectSuccess();
261 await setCollectionLimitsExpectSuccess(alice, nftCollectionId, {ownerCanTransfer: true});
260 const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');262 const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT');
261 await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId, 1);263 await burnItemExpectSuccess(alice, nftCollectionId, newNftTokenId, 1);
262 await approveExpectFail(nftCollectionId, newNftTokenId, alice, bob);264 await approveExpectFail(nftCollectionId, newNftTokenId, alice, bob);
266 it('transferFrom burnt token before approve Fungible', async () => {268 it('transferFrom burnt token before approve Fungible', async () => {
267 await usingApi(async () => {269 await usingApi(async () => {
268 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});270 const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
271 await setCollectionLimitsExpectSuccess(alice, fungibleCollectionId, {ownerCanTransfer: true});
269 const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');272 const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible');
270 await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);273 await burnItemExpectSuccess(alice, fungibleCollectionId, newFungibleTokenId, 10);
271 await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);274 await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address);
276 it('transferFrom burnt token before approve ReFungible', async () => {279 it('transferFrom burnt token before approve ReFungible', async () => {
277 await usingApi(async () => {280 await usingApi(async () => {
278 const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});281 const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
282 await setCollectionLimitsExpectSuccess(alice, reFungibleCollectionId, {ownerCanTransfer: true});
279 const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');283 const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible');
280 await burnItemExpectSuccess(alice, reFungibleCollectionId, newReFungibleTokenId, 100);284 await burnItemExpectSuccess(alice, reFungibleCollectionId, newReFungibleTokenId, 100);
281 await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, alice, bob);285 await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, alice, bob);
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
921 });921 });
922}922}
923
924export async function adminApproveFromExpectFail(
925 collectionId: number,
926 tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,
927) {
928 await usingApi(async (api: ApiPromise) => {
929 const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);
930 const events = await expect(submitTransactionAsync(admin, approveUniqueTx)).to.be.rejected;
931 const result = getGenericResult(events);
932 expect(result.success).to.be.false;
933 });
934}
923935
924export async function936export async function
925getFreeBalance(account: IKeyringPair): Promise<bigint> {937getFreeBalance(account: IKeyringPair): Promise<bigint> {