git.delta.rocks / unique-network / refs/commits / 47cbedfeaa3a

difftreelog

Merge pull request #382 from UniqueNetwork/feature/eth-nesting-tests

ut-akuznetsov2022-06-14parents: #681a5b7 #bcb4810.patch.diff
in: master
Feature/eth nesting tests

2 files changed

modifiedtests/package.jsondiffbeforeafterboth
before · tests/package.json
1{2  "name": "unique-tests",3  "version": "1.0.0",4  "description": "Unique Chain Tests",5  "main": "",6  "devDependencies": {7    "@polkadot/ts": "0.4.22",8    "@polkadot/typegen": "8.7.2-15",9    "@types/chai": "^4.3.1",10    "@types/chai-as-promised": "^7.1.5",11    "@types/mocha": "^9.1.1",12    "@types/node": "^17.0.35",13    "@typescript-eslint/eslint-plugin": "^5.26.0",14    "@typescript-eslint/parser": "^5.26.0",15    "chai": "^4.3.6",16    "eslint": "^8.16.0",17    "mocha": "^10.0.0",18    "ts-node": "^10.8.0",19    "typescript": "^4.7.2"20  },21  "mocha": {22    "timeout": 9999999,23    "require": "ts-node/register"24  },25  "scripts": {26    "lint": "eslint --ext .ts,.js src/",27    "fix": "eslint --ext .ts,.js src/ --fix",28    "test": "mocha --timeout 9999999 -r ts-node/register './src/**/*.test.ts'",29    "testEth": "mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.test.ts'",30    "testEthMarketplace": "mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.test.ts'",31    "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",32    "loadTransfer": "ts-node src/transfer.nload.ts",33    "testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts",34    "testEvent": "mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.test.ts",35    "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts",36    "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts",37    "testStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/**.test.ts",38    "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/properties.test.ts",39    "testMigrationStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",40    "testRmrk": "mocha --timeout 9999999 -r ts-node/register ./**/rmrk/**.test.ts",41    "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",42    "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",43    "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts",44    "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts",45    "testConfirmSponsorship": "mocha --timeout 9999999 -r ts-node/register ./**/confirmSponsorship.test.ts",46    "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",47    "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts",48    "testRemoveFromAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromAllowList.test.ts",49    "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",50    "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts",51    "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts",52    "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts",53    "testCreateMultipleItemsEx": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItemsEx.test.ts",54    "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",55    "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",56    "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",57    "testDestroyCollection": "mocha --timeout 9999999 -r ts-node/register ./**/destroyCollection.test.ts",58    "testToggleContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractAllowList.test.ts",59    "testAddToContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractAllowList.test.ts",60    "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts",61    "testBurnItem": "mocha --timeout 9999999 -r ts-node/register ./**/burnItem.test.ts",62    "testSetMintPermission": "mocha --timeout 9999999 -r ts-node/register ./**/setMintPermission.test.ts",63    "testCreditFeesToTreasury": "mocha --timeout 9999999 -r ts-node/register ./**/creditFeesToTreasury.test.ts",64    "testContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/contractSponsoring.test.ts",65    "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",66    "testRemoveFromContractAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromContractAllowList.test.ts",67    "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",68    "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",69    "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",70    "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts",71    "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",72    "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",73    "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",74    "testXcmTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/xcmTransfer.test.ts",75    "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",76    "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",77    "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",78    "testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",79    "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",80    "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",81    "polkadot-types-from-defs": "ts-node ./node_modules/.bin/polkadot-types-from-defs --endpoint src/interfaces/metadata.json --input src/interfaces/ --package .",82    "polkadot-types-from-chain": "ts-node ./node_modules/.bin/polkadot-types-from-chain --endpoint src/interfaces/metadata.json --output src/interfaces/ --package .",83    "polkadot-types": "echo \"export default {}\" > src/interfaces/lookup.ts && yarn polkadot-types-fetch-metadata && yarn polkadot-types-from-defs && yarn polkadot-types-from-defs && yarn polkadot-types-from-chain"84  },85  "author": "",86  "license": "SEE LICENSE IN ../LICENSE",87  "homepage": "",88  "dependencies": {89    "@polkadot/api": "8.7.2-15",90    "@polkadot/api-contract": "8.7.2-15",91    "@polkadot/util-crypto": "9.4.1",92    "bignumber.js": "^9.0.2",93    "chai-as-promised": "^7.1.1",94    "find-process": "^1.4.7",95    "solc": "0.8.14-fixed",96    "web3": "^1.7.3"97  },98  "standard": {99    "globals": [100      "it",101      "assert",102      "beforeEach",103      "afterEach",104      "describe",105      "contract",106      "artifacts"107    ]108  },109  "resolutions": {110    "simple-get": "^4.0.1"111  }112}
addedtests/src/eth/nesting/nest.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/nesting/nest.test.ts
@@ -0,0 +1,214 @@
+import {ApiPromise} from '@polkadot/api';
+import {Contract} from 'web3-eth-contract';
+import {expect} from 'chai';
+import Web3 from 'web3';
+import {createEthAccountWithBalance, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, tokenIdToAddress} from '../../eth/util/helpers';
+import nonFungibleAbi from '../nonFungibleAbi.json';
+
+const createNestingCollection = async (
+  api: ApiPromise,
+  web3: Web3,
+  owner: string,
+): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
+  const collectionHelper = evmCollectionHelpers(web3, owner);
+        
+  const result = await collectionHelper.methods
+    .createNonfungibleCollection('A', 'B', 'C')
+    .send();
+  const {collectionIdAddress: collectionAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+
+  const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionAddress, {from: owner, ...GAS_ARGS});
+  await contract.methods.setCollectionNesting(true).send({from: owner});
+
+  return {collectionId, collectionAddress, contract};
+};
+
+describe('Integration Test: EVM Nesting', () => {
+  itWeb3('NFT: allows an Owner to nest/unnest their token', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const {collectionId, contract} = await createNestingCollection(api, web3, owner);
+
+    // Create a token to be nested
+    const nftTokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      owner,
+      nftTokenId,
+    ).send({from: owner});
+
+    // Nest into a token
+    const firstTargetNftTokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      owner,
+      firstTargetNftTokenId,
+    ).send({from: owner});
+
+    const targetNftTokenAddress = tokenIdToAddress(collectionId, firstTargetNftTokenId);
+
+    await contract.methods.transfer(targetNftTokenAddress, nftTokenId).send({from: owner});
+    expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+    // Re-nest into another
+    const secondTargetNftTokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      owner,
+      secondTargetNftTokenId,
+    ).send({from: owner});
+    const nextNftTokenAddress = tokenIdToAddress(collectionId, secondTargetNftTokenId);
+
+    await contract.methods.transfer(nextNftTokenAddress, nftTokenId).send({from: owner});
+    expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(nextNftTokenAddress);
+  });
+
+  itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
+    const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);
+    await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
+
+    // Create a token to nest into
+    const targetNftTokenId = await contractA.methods.nextTokenId().call();
+    await contractA.methods.mint(
+      owner,
+      targetNftTokenId,
+    ).send({from: owner});
+    const nftTokenAddressA1 = tokenIdToAddress(collectionIdA, targetNftTokenId);
+
+    // Create a token for nesting in the same collection as the target
+    const nftTokenIdA = await contractA.methods.nextTokenId().call();
+    await contractA.methods.mint(
+      owner,
+      nftTokenIdA,
+    ).send({from: owner});
+
+    // Create a token for nesting in a different collection
+    const nftTokenIdB = await contractB.methods.nextTokenId().call();
+    await contractB.methods.mint(
+      owner,
+      nftTokenIdB,
+    ).send({from: owner});
+
+    // Nest
+    await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
+    expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
+
+    await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
+    expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
+  });
+});
+
+describe('Negative Test: EVM Nesting', async() => {
+  itWeb3('NFT: disallows to nest token if nesting is disabled', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const {collectionId, contract} = await createNestingCollection(api, web3, owner);
+    await contract.methods.setCollectionNesting(false).send({from: owner});
+
+    // Create a token to nest into
+    const targetNftTokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      owner,
+      targetNftTokenId,
+    ).send({from: owner});
+
+    const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNftTokenId);
+
+    // Create a token to nest
+    const nftTokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      owner,
+      nftTokenId,
+    ).send({from: owner});
+
+    // Try to nest
+    await expect(contract.methods
+      .transfer(targetNftTokenAddress, nftTokenId)
+      .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
+  });
+  
+  itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const {collectionId, contract} = await createNestingCollection(api, web3, owner);
+
+    // Mint a token
+    const targetTokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      owner,
+      targetTokenId,
+    ).send({from: owner});
+    const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId);
+    
+    // Mint a token belonging to a different account
+    const tokenId = await contract.methods.nextTokenId().call();
+    await contract.methods.mint(
+      malignant,
+      tokenId,
+    ).send({from: owner});
+      
+    // Try to nest one token in another as a non-owner account
+    await expect(contract.methods
+      .transfer(targetTokenAddress, tokenId)
+      .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+  });
+  
+  itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+    const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
+    const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);
+
+    await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
+
+    // Create a token in one collection
+    const nftTokenIdA = await contractA.methods.nextTokenId().call();
+    await contractA.methods.mint(
+      owner,
+      nftTokenIdA,
+    ).send({from: owner});
+    const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);
+
+    // Create a token in another collection belonging to someone else
+    const nftTokenIdB = await contractB.methods.nextTokenId().call();
+    await contractB.methods.mint(
+      malignant,
+      nftTokenIdB,
+    ).send({from: owner});
+
+    // Try to drag someone else's token into the other collection and nest
+    await expect(contractB.methods
+      .transfer(nftTokenAddressA, nftTokenIdB)
+      .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+  });
+  
+  itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
+
+    const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
+    const {contract: contractB} = await createNestingCollection(api, web3, owner);
+
+    await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});
+
+    // Create a token in one collection
+    const nftTokenIdA = await contractA.methods.nextTokenId().call();
+    await contractA.methods.mint(
+      owner,
+      nftTokenIdA,
+    ).send({from: owner});
+    const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);
+
+    // Create a token in another collection
+    const nftTokenIdB = await contractB.methods.nextTokenId().call();
+    await contractB.methods.mint(
+      owner,
+      nftTokenIdB,
+    ).send({from: owner});
+
+    // Try to nest into a token in the other collection, disallowed in the first
+    await expect(contractB.methods
+      .transfer(nftTokenAddressA, nftTokenIdB)
+      .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
+  });
+});