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

difftreelog

source

tests/src/confirmSponsorship.test.ts18.5 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  requirePallets,37  Pallets,38} from './util/helpers';39import {IKeyringPair} from '@polkadot/types/types';4041chai.use(chaiAsPromised);42const expect = chai.expect;4344let alice: IKeyringPair;45let bob: IKeyringPair;46let charlie: IKeyringPair;4748describe('integration test: ext. confirmSponsorship():', () => {4950  before(async () => {51    await usingApi(async (api, privateKeyWrapper) => {52      alice = privateKeyWrapper('//Alice');53      bob = privateKeyWrapper('//Bob');54      charlie = privateKeyWrapper('//Charlie');55    });56  });5758  it('Confirm collection sponsorship', async () => {59    const collectionId = await createCollectionExpectSuccess();60    await setCollectionSponsorExpectSuccess(collectionId, bob.address);61    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');62  });63  it('Add sponsor to a collection after the same sponsor was already added and confirmed', async () => {64    const collectionId = await createCollectionExpectSuccess();65    await setCollectionSponsorExpectSuccess(collectionId, bob.address);66    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');67    await setCollectionSponsorExpectSuccess(collectionId, bob.address);68  });69  it('Add new sponsor to a collection after another sponsor was already added and confirmed', async () => {70    const collectionId = await createCollectionExpectSuccess();71    await setCollectionSponsorExpectSuccess(collectionId, bob.address);72    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');73    await setCollectionSponsorExpectSuccess(collectionId, charlie.address);74  });7576  it('NFT: Transfer fees are paid by the sponsor after confirmation', async () => {77    const collectionId = await createCollectionExpectSuccess();78    await setCollectionSponsorExpectSuccess(collectionId, bob.address);79    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');8081    await usingApi(async (api, privateKeyWrapper) => {82      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();8384      // Find unused address85      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);8687      // Mint token for unused address88      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', zeroBalance.address);8990      // Transfer this tokens from unused address to Alice91      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);92      const events = await submitTransactionAsync(zeroBalance, zeroToAlice);93      const result = getGenericResult(events);94      expect(result.success).to.be.true;9596      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();9798      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;99    });100101  });102103  it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => {104    const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});105    await setCollectionSponsorExpectSuccess(collectionId, bob.address);106    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');107108    await usingApi(async (api, privateKeyWrapper) => {109      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();110111      // Find unused address112      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);113114      // Mint token for unused address115      const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);116117      // Transfer this tokens from unused address to Alice118      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);119      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);120      const result1 = getGenericResult(events1);121      expect(result1.success).to.be.true;122123      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();124125      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;126    });127  });128129  it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async function() {130    await requirePallets(this, [Pallets.ReFungible]);131132    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});133    await setCollectionSponsorExpectSuccess(collectionId, bob.address);134    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');135136    await usingApi(async (api, privateKeyWrapper) => {137      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();138139      // Find unused address140      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);141142      // Mint token for unused address143      const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);144145      // Transfer this tokens from unused address to Alice146      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);147      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);148      const result1 = getGenericResult(events1);149150      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();151152      expect(result1.success).to.be.true;153      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;154    });155  });156157  it('CreateItem fees are paid by the sponsor after confirmation', async () => {158    const collectionId = await createCollectionExpectSuccess();159    await setCollectionSponsorExpectSuccess(collectionId, bob.address);160    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');161162    // Enable collection allow list163    await enableAllowListExpectSuccess(alice, collectionId);164165    // Enable public minting166    await enablePublicMintingExpectSuccess(alice, collectionId);167168    // Create Item169    await usingApi(async (api, privateKeyWrapper) => {170      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();171172      // Find unused address173      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);174175      // Add zeroBalance address to allow list176      await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);177178      // Mint token using unused address as signer179      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);180181      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();182183      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;184    });185  });186187  it('NFT: Sponsoring of transfers is rate limited', async () => {188    const collectionId = await createCollectionExpectSuccess();189    await setCollectionSponsorExpectSuccess(collectionId, bob.address);190    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');191192    await usingApi(async (api, privateKeyWrapper) => {193      // Find unused address194      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);195196      // Mint token for alice197      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);198199      // Transfer this token from Alice to unused address and back200      // Alice to Zero gets sponsored201      const aliceToZero = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);202      const events1 = await submitTransactionAsync(alice, aliceToZero);203      const result1 = getGenericResult(events1);204205      // Second transfer should fail206      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();207      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);208      const badTransaction = async function () {209        await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);210      };211      await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');212      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();213214      // Try again after Zero gets some balance - now it should succeed215      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);216      await submitTransactionAsync(alice, balancetx);217      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);218      const result2 = getGenericResult(events2);219220      expect(result1.success).to.be.true;221      expect(result2.success).to.be.true;222      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);223    });224  });225226  it('Fungible: Sponsoring is rate limited', async () => {227    const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});228    await setCollectionSponsorExpectSuccess(collectionId, bob.address);229    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');230231    await usingApi(async (api, privateKeyWrapper) => {232      // Find unused address233      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);234235      // Mint token for unused address236      const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);237238      // Transfer this tokens in parts from unused address to Alice239      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);240      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);241      const result1 = getGenericResult(events1);242      expect(result1.success).to.be.true;243244      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();245      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected;246      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();247248      // Try again after Zero gets some balance - now it should succeed249      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);250      await submitTransactionAsync(alice, balancetx);251      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);252      const result2 = getGenericResult(events2);253      expect(result2.success).to.be.true;254255      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);256    });257  });258259  it('ReFungible: Sponsoring is rate limited', async function() {260    await requirePallets(this, [Pallets.ReFungible]);261262    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});263    await setCollectionSponsorExpectSuccess(collectionId, bob.address);264    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');265266    await usingApi(async (api, privateKeyWrapper) => {267      // Find unused address268      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);269270      // Mint token for alice271      const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);272273      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1);274275      // Zero to alice gets sponsored276      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);277      const result1 = getGenericResult(events1);278      expect(result1.success).to.be.true;279280      // Second transfer should fail281      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();282      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejectedWith('Inability to pay some fees');283      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();284      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);285286      // Try again after Zero gets some balance - now it should succeed287      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);288      await submitTransactionAsync(alice, balancetx);289      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);290      const result2 = getGenericResult(events2);291      expect(result2.success).to.be.true;292    });293  });294295  it('NFT: Sponsoring of createItem is rate limited', async () => {296    const collectionId = await createCollectionExpectSuccess();297    await setCollectionSponsorExpectSuccess(collectionId, bob.address);298    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');299300    // Enable collection allow list301    await enableAllowListExpectSuccess(alice, collectionId);302303    // Enable public minting304    await enablePublicMintingExpectSuccess(alice, collectionId);305306    await usingApi(async (api, privateKeyWrapper) => {307      // Find unused address308      const zeroBalance = await findUnusedAddress(api, privateKeyWrapper);309310      // Add zeroBalance address to allow list311      await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);312313      // Mint token using unused address as signer - gets sponsored314      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);315316      // Second mint should fail317      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();318319      const badTransaction = async function () {320        await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);321      };322      await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');323      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();324325      // Try again after Zero gets some balance - now it should succeed326      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);327      await submitTransactionAsync(alice, balancetx);328      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);329330      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);331    });332  });333334});335336describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {337  before(async () => {338    await usingApi(async (api, privateKeyWrapper) => {339      alice = privateKeyWrapper('//Alice');340      bob = privateKeyWrapper('//Bob');341      charlie = privateKeyWrapper('//Charlie');342    });343  });344345  it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => {346    // Find the collection that never existed347    let collectionId = 0;348    await usingApi(async (api) => {349      collectionId = await getCreatedCollectionCount(api) + 1;350    });351352    await confirmSponsorshipExpectFailure(collectionId, '//Bob');353  });354355  it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => {356    const collectionId = await createCollectionExpectSuccess();357    await setCollectionSponsorExpectSuccess(collectionId, bob.address);358359    await usingApi(async (api) => {360      const transfer = api.tx.balances.transfer(charlie.address, 1e15);361      await submitTransactionAsync(alice, transfer);362    });363364    await confirmSponsorshipExpectFailure(collectionId, '//Charlie');365  });366367  it('(!negative test!) Confirm sponsorship using owner address', async () => {368    const collectionId = await createCollectionExpectSuccess();369    await setCollectionSponsorExpectSuccess(collectionId, bob.address);370    await confirmSponsorshipExpectFailure(collectionId, '//Alice');371  });372373  it('(!negative test!) Confirm sponsorship by collection admin', async () => {374    const collectionId = await createCollectionExpectSuccess();375    await setCollectionSponsorExpectSuccess(collectionId, bob.address);376    await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address);377    await confirmSponsorshipExpectFailure(collectionId, '//Charlie');378  });379380  it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => {381    const collectionId = await createCollectionExpectSuccess();382    await confirmSponsorshipExpectFailure(collectionId, '//Bob');383  });384385  it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => {386    const collectionId = await createCollectionExpectSuccess();387    await destroyCollectionExpectSuccess(collectionId);388    await confirmSponsorshipExpectFailure(collectionId, '//Bob');389  });390391  it('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async () => {392    const collectionId = await createCollectionExpectSuccess();393    await setCollectionSponsorExpectSuccess(collectionId, bob.address);394    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');395396    await usingApi(async (api, privateKeyWrapper) => {397      // Find unused address398      const ownerZeroBalance = await findUnusedAddress(api, privateKeyWrapper);399400      // Find another unused address401      const senderZeroBalance = await findUnusedAddress(api, privateKeyWrapper);402403      // Mint token for an unused address404      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', ownerZeroBalance.address);405406      const sponsorBalanceBeforeTx = (await api.query.system.account(bob.address)).data.free.toBigInt();407408      // Try to transfer this token from an unsponsored unused adress to Alice409      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);410      await expect(submitTransactionExpectFailAsync(senderZeroBalance, zeroToAlice)).to.be.rejected;411412      const sponsorBalanceAfterTx = (await api.query.system.account(bob.address)).data.free.toBigInt();413414      expect(sponsorBalanceAfterTx).to.equal(sponsorBalanceBeforeTx);415    });416  });417});