git.delta.rocks / unique-network / refs/commits / d4b692346f53

difftreelog

source

tests/src/confirmSponsorship.test.ts18.4 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import chai from 'chai';18import chaiAsPromised from 'chai-as-promised';19import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';20import {21  createCollectionExpectSuccess,22  setCollectionSponsorExpectSuccess,23  destroyCollectionExpectSuccess,24  confirmSponsorshipExpectSuccess,25  confirmSponsorshipExpectFailure,26  createItemExpectSuccess,27  findUnusedAddress,28  getGenericResult,29  enableAllowListExpectSuccess,30  enablePublicMintingExpectSuccess,31  addToAllowListExpectSuccess,32  normalizeAccountId,33  addCollectionAdminExpectSuccess,34  getCreatedCollectionCount,35  UNIQUE,36} from './util/helpers';37import {IKeyringPair} from '@polkadot/types/types';3839chai.use(chaiAsPromised);40const expect = chai.expect;4142let alice: IKeyringPair;43let bob: IKeyringPair;44let charlie: IKeyringPair;4546describe('integration test: ext. confirmSponsorship():', () => {4748  before(async () => {49    await usingApi(async (api, privateKeyWrapper) => {50      alice = privateKeyWrapper('//Alice');51      bob = privateKeyWrapper('//Bob');52      charlie = privateKeyWrapper('//Charlie');53    });54  });5556  it('Confirm collection sponsorship', async () => {57    const collectionId = await createCollectionExpectSuccess();58    await setCollectionSponsorExpectSuccess(collectionId, bob.address);59    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');60  });61  it('Add sponsor to a collection after the same sponsor was already added and confirmed', async () => {62    const collectionId = await createCollectionExpectSuccess();63    await setCollectionSponsorExpectSuccess(collectionId, bob.address);64    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');65    await setCollectionSponsorExpectSuccess(collectionId, bob.address);66  });67  it('Add new sponsor to a collection after another sponsor was already added and confirmed', async () => {68    const collectionId = await createCollectionExpectSuccess();69    await setCollectionSponsorExpectSuccess(collectionId, bob.address);70    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');71    await setCollectionSponsorExpectSuccess(collectionId, charlie.address);72  });7374  it('NFT: Transfer fees are paid by the sponsor after confirmation', async () => {75    const collectionId = await createCollectionExpectSuccess();76    await setCollectionSponsorExpectSuccess(collectionId, bob.address);77    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');7879    await usingApi(async (api, privateKeyWrapper) => {80      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();8182      // Find unused address83      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);8485      // Mint token for unused address86      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', zeroBalance.address);8788      // Transfer this tokens from unused address to Alice89      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);90      const events = await submitTransactionAsync(zeroBalance, zeroToAlice);91      const result = getGenericResult(events);92      expect(result.success).to.be.true;9394      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();9596      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;97    });9899  });100101  it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => {102    const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});103    await setCollectionSponsorExpectSuccess(collectionId, bob.address);104    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');105106    await usingApi(async (api, privateKeyWrapper) => {107      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();108109      // Find unused address110      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);111112      // Mint token for unused address113      const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);114115      // Transfer this tokens from unused address to Alice116      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);117      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);118      const result1 = getGenericResult(events1);119      expect(result1.success).to.be.true;120121      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();122123      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;124    });125  });126127  it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {128    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});129    await setCollectionSponsorExpectSuccess(collectionId, bob.address);130    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');131132    await usingApi(async (api, privateKeyWrapper) => {133      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();134135      // Find unused address136      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);137138      // Mint token for unused address139      const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);140141      // Transfer this tokens from unused address to Alice142      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);143      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);144      const result1 = getGenericResult(events1);145146      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();147148      expect(result1.success).to.be.true;149      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;150    });151  });152153  it('CreateItem fees are paid by the sponsor after confirmation', async () => {154    const collectionId = await createCollectionExpectSuccess();155    await setCollectionSponsorExpectSuccess(collectionId, bob.address);156    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');157158    // Enable collection allow list159    await enableAllowListExpectSuccess(alice, collectionId);160161    // Enable public minting162    await enablePublicMintingExpectSuccess(alice, collectionId);163164    // Create Item165    await usingApi(async (api, privateKeyWrapper) => {166      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();167168      // Find unused address169      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);170171      // Add zeroBalance address to allow list172      await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);173174      // Mint token using unused address as signer175      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);176177      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();178179      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;180    });181  });182183  it('NFT: Sponsoring of transfers is rate limited', async () => {184    const collectionId = await createCollectionExpectSuccess();185    await setCollectionSponsorExpectSuccess(collectionId, bob.address);186    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');187188    await usingApi(async (api, privateKeyWrapper) => {189      // Find unused address190      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);191192      // Mint token for alice193      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);194195      // Transfer this token from Alice to unused address and back196      // Alice to Zero gets sponsored197      const aliceToZero = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);198      const events1 = await submitTransactionAsync(alice, aliceToZero);199      const result1 = getGenericResult(events1);200201      // Second transfer should fail202      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();203      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);204      const badTransaction = async function () {205        await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);206      };207      await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');208      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();209210      // Try again after Zero gets some balance - now it should succeed211      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);212      await submitTransactionAsync(alice, balancetx);213      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);214      const result2 = getGenericResult(events2);215216      expect(result1.success).to.be.true;217      expect(result2.success).to.be.true;218      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);219    });220  });221222  it('Fungible: Sponsoring is rate limited', async () => {223    const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});224    await setCollectionSponsorExpectSuccess(collectionId, bob.address);225    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');226227    await usingApi(async (api, privateKeyWrapper) => {228      // Find unused address229      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);230231      // Mint token for unused address232      const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);233234      // Transfer this tokens in parts from unused address to Alice235      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);236      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);237      const result1 = getGenericResult(events1);238      expect(result1.success).to.be.true;239240      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();241      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected;242      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();243244      // Try again after Zero gets some balance - now it should succeed245      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);246      await submitTransactionAsync(alice, balancetx);247      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);248      const result2 = getGenericResult(events2);249      expect(result2.success).to.be.true;250251      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);252    });253  });254255  it('ReFungible: Sponsoring is rate limited', async () => {256    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});257    await setCollectionSponsorExpectSuccess(collectionId, bob.address);258    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');259260    await usingApi(async (api, privateKeyWrapper) => {261      // Find unused address262      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);263264      // Mint token for alice265      const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);266267      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1);268269      // Zero to alice gets sponsored270      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);271      const result1 = getGenericResult(events1);272      expect(result1.success).to.be.true;273274      // Second transfer should fail275      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();276      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejectedWith('Inability to pay some fees');277      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();278      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);279280      // Try again after Zero gets some balance - now it should succeed281      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);282      await submitTransactionAsync(alice, balancetx);283      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);284      const result2 = getGenericResult(events2);285      expect(result2.success).to.be.true;286    });287  });288289  it('NFT: Sponsoring of createItem is rate limited', async () => {290    const collectionId = await createCollectionExpectSuccess();291    await setCollectionSponsorExpectSuccess(collectionId, bob.address);292    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');293294    // Enable collection allow list295    await enableAllowListExpectSuccess(alice, collectionId);296297    // Enable public minting298    await enablePublicMintingExpectSuccess(alice, collectionId);299300    await usingApi(async (api, privateKeyWrapper) => {301      // Find unused address302      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);303304      // Add zeroBalance address to allow list305      await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);306307      // Mint token using unused address as signer - gets sponsored308      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);309310      // Second mint should fail311      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();312313      const badTransaction = async function () {314        await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);315      };316      await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');317      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();318319      // Try again after Zero gets some balance - now it should succeed320      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);321      await submitTransactionAsync(alice, balancetx);322      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);323324      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);325    });326  });327328});329330describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {331  before(async () => {332    await usingApi(async (api, privateKeyWrapper) => {333      alice = privateKeyWrapper('//Alice');334      bob = privateKeyWrapper('//Bob');335      charlie = privateKeyWrapper('//Charlie');336    });337  });338339  it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => {340    // Find the collection that never existed341    let collectionId = 0;342    await usingApi(async (api) => {343      collectionId = await getCreatedCollectionCount(api) + 1;344    });345346    await confirmSponsorshipExpectFailure(collectionId, '//Bob');347  });348349  it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => {350    const collectionId = await createCollectionExpectSuccess();351    await setCollectionSponsorExpectSuccess(collectionId, bob.address);352353    await usingApi(async (api) => {354      const transfer = api.tx.balances.transfer(charlie.address, 1e15);355      await submitTransactionAsync(alice, transfer);356    });357358    await confirmSponsorshipExpectFailure(collectionId, '//Charlie');359  });360361  it('(!negative test!) Confirm sponsorship using owner address', async () => {362    const collectionId = await createCollectionExpectSuccess();363    await setCollectionSponsorExpectSuccess(collectionId, bob.address);364    await confirmSponsorshipExpectFailure(collectionId, '//Alice');365  });366367  it('(!negative test!) Confirm sponsorship by collection admin', async () => {368    const collectionId = await createCollectionExpectSuccess();369    await setCollectionSponsorExpectSuccess(collectionId, bob.address);370    await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address);371    await confirmSponsorshipExpectFailure(collectionId, '//Charlie');372  });373374  it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => {375    const collectionId = await createCollectionExpectSuccess();376    await confirmSponsorshipExpectFailure(collectionId, '//Bob');377  });378379  it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => {380    const collectionId = await createCollectionExpectSuccess();381    await destroyCollectionExpectSuccess(collectionId);382    await confirmSponsorshipExpectFailure(collectionId, '//Bob');383  });384385  it('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async () => {386    const collectionId = await createCollectionExpectSuccess();387    await setCollectionSponsorExpectSuccess(collectionId, bob.address);388    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');389390    await usingApi(async (api, privateKeyWrapper) => {391      // Find unused address392      const ownerZeroBalance = await findUnusedAddress(api, privateKeyWrapper);393394      // Find another unused address395      const senderZeroBalance = await findUnusedAddress(api, privateKeyWrapper);396397      // Mint token for an unused address398      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', ownerZeroBalance.address);399400      const sponsorBalanceBeforeTx = (await api.query.system.account(bob.address)).data.free.toBigInt();401402      // Try to transfer this token from an unsponsored unused adress to Alice403      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);404      await expect(submitTransactionExpectFailAsync(senderZeroBalance, zeroToAlice)).to.be.rejected;405406      const sponsorBalanceAfterTx = (await api.query.system.account(bob.address)).data.free.toBigInt();407408      expect(sponsorBalanceAfterTx).to.equal(sponsorBalanceBeforeTx);409    });410  });411});