git.delta.rocks / unique-network / refs/commits / 2976d69d82a2

difftreelog

source

tests/src/confirmSponsorship.test.ts18.1 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 {Keyring} from '@polkadot/api';38import {IKeyringPair} from '@polkadot/types/types';3940chai.use(chaiAsPromised);41const expect = chai.expect;4243let alice: IKeyringPair;44let bob: IKeyringPair;45let charlie: IKeyringPair;4647describe('integration test: ext. confirmSponsorship():', () => {4849  before(async () => {50    await usingApi(async () => {51      const keyring = new Keyring({type: 'sr25519'});52      alice = keyring.addFromUri('//Alice');53      bob = keyring.addFromUri('//Bob');54      charlie = keyring.addFromUri('//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) => {82      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();8384      // Find unused address85      const zeroBalance = await findUnusedAddress(api);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) => {109      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();110111      // Find unused address112      const zeroBalance = await findUnusedAddress(api);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 () => {130    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});131    await setCollectionSponsorExpectSuccess(collectionId, bob.address);132    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');133134    await usingApi(async (api) => {135      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();136137      // Find unused address138      const zeroBalance = await findUnusedAddress(api);139140      // Mint token for unused address141      const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);142143      // Transfer this tokens from unused address to Alice144      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);145      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);146      const result1 = getGenericResult(events1);147148      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();149150      expect(result1.success).to.be.true;151      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;152    });153  });154155  it('CreateItem fees are paid by the sponsor after confirmation', async () => {156    const collectionId = await createCollectionExpectSuccess();157    await setCollectionSponsorExpectSuccess(collectionId, bob.address);158    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');159160    // Enable collection allow list161    await enableAllowListExpectSuccess(alice, collectionId);162163    // Enable public minting164    await enablePublicMintingExpectSuccess(alice, collectionId);165166    // Create Item167    await usingApi(async (api) => {168      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();169170      // Find unused address171      const zeroBalance = await findUnusedAddress(api);172173      // Add zeroBalance address to allow list174      await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);175176      // Mint token using unused address as signer177      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);178179      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();180181      expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;182    });183  });184185  it('NFT: Sponsoring of transfers is rate limited', async () => {186    const collectionId = await createCollectionExpectSuccess();187    await setCollectionSponsorExpectSuccess(collectionId, bob.address);188    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');189190    await usingApi(async (api) => {191      // Find unused address192      const zeroBalance = await findUnusedAddress(api);193194      // Mint token for alice195      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);196197      // Transfer this token from Alice to unused address and back198      // Alice to Zero gets sponsored199      const aliceToZero = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);200      const events1 = await submitTransactionAsync(alice, aliceToZero);201      const result1 = getGenericResult(events1);202203      // Second transfer should fail204      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();205      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);206      const badTransaction = async function () {207        await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);208      };209      await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');210      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();211212      // Try again after Zero gets some balance - now it should succeed213      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);214      await submitTransactionAsync(alice, balancetx);215      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);216      const result2 = getGenericResult(events2);217218      expect(result1.success).to.be.true;219      expect(result2.success).to.be.true;220      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);221    });222  });223224  it('Fungible: Sponsoring is rate limited', async () => {225    const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});226    await setCollectionSponsorExpectSuccess(collectionId, bob.address);227    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');228229    await usingApi(async (api) => {230      // Find unused address231      const zeroBalance = await findUnusedAddress(api);232233      // Mint token for unused address234      const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);235236      // Transfer this tokens in parts from unused address to Alice237      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);238      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);239      const result1 = getGenericResult(events1);240      expect(result1.success).to.be.true;241242      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();243      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected;244      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();245246      // Try again after Zero gets some balance - now it should succeed247      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);248      await submitTransactionAsync(alice, balancetx);249      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);250      const result2 = getGenericResult(events2);251      expect(result2.success).to.be.true;252253      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);254    });255  });256257  it('ReFungible: Sponsoring is rate limited', async () => {258    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});259    await setCollectionSponsorExpectSuccess(collectionId, bob.address);260    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');261262    await usingApi(async (api) => {263      // Find unused address264      const zeroBalance = await findUnusedAddress(api);265266      // Mint token for alice267      const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);268269      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1);270271      // Zero to alice gets sponsored272      const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);273      const result1 = getGenericResult(events1);274      expect(result1.success).to.be.true;275276      // Second transfer should fail277      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();278      await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejectedWith('Inability to pay some fees');279      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();280      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);281282      // Try again after Zero gets some balance - now it should succeed283      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);284      await submitTransactionAsync(alice, balancetx);285      const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);286      const result2 = getGenericResult(events2);287      expect(result2.success).to.be.true;288    });289  });290291  it('NFT: Sponsoring of createItem is rate limited', async () => {292    const collectionId = await createCollectionExpectSuccess();293    await setCollectionSponsorExpectSuccess(collectionId, bob.address);294    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');295296    // Enable collection allow list297    await enableAllowListExpectSuccess(alice, collectionId);298299    // Enable public minting300    await enablePublicMintingExpectSuccess(alice, collectionId);301302    await usingApi(async (api) => {303      // Find unused address304      const zeroBalance = await findUnusedAddress(api);305306      // Add zeroBalance address to allow list307      await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);308309      // Mint token using unused address as signer - gets sponsored310      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);311312      // Second mint should fail313      const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();314315      const badTransaction = async function () {316        await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);317      };318      await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');319      const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();320321      // Try again after Zero gets some balance - now it should succeed322      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);323      await submitTransactionAsync(alice, balancetx);324      await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);325326      expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);327    });328  });329330});331332describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {333  before(async () => {334    await usingApi(async () => {335      const keyring = new Keyring({type: 'sr25519'});336      alice = keyring.addFromUri('//Alice');337      bob = keyring.addFromUri('//Bob');338      charlie = keyring.addFromUri('//Charlie');339    });340  });341342  it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => {343    // Find the collection that never existed344    let collectionId = 0;345    await usingApi(async (api) => {346      collectionId = await getCreatedCollectionCount(api) + 1;347    });348349    await confirmSponsorshipExpectFailure(collectionId, '//Bob');350  });351352  it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => {353    const collectionId = await createCollectionExpectSuccess();354    await setCollectionSponsorExpectSuccess(collectionId, bob.address);355356    await usingApi(async (api) => {357      const transfer = api.tx.balances.transfer(charlie.address, 1e15);358      await submitTransactionAsync(alice, transfer);359    });360361    await confirmSponsorshipExpectFailure(collectionId, '//Charlie');362  });363364  it('(!negative test!) Confirm sponsorship using owner address', async () => {365    const collectionId = await createCollectionExpectSuccess();366    await setCollectionSponsorExpectSuccess(collectionId, bob.address);367    await confirmSponsorshipExpectFailure(collectionId, '//Alice');368  });369370  it('(!negative test!) Confirm sponsorship by collection admin', async () => {371    const collectionId = await createCollectionExpectSuccess();372    await setCollectionSponsorExpectSuccess(collectionId, bob.address);373    await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address);374    await confirmSponsorshipExpectFailure(collectionId, '//Charlie');375  });376377  it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => {378    const collectionId = await createCollectionExpectSuccess();379    await confirmSponsorshipExpectFailure(collectionId, '//Bob');380  });381382  it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => {383    const collectionId = await createCollectionExpectSuccess();384    await destroyCollectionExpectSuccess(collectionId);385    await confirmSponsorshipExpectFailure(collectionId, '//Bob');386  });387388  it('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async () => {389    const collectionId = await createCollectionExpectSuccess();390    await setCollectionSponsorExpectSuccess(collectionId, bob.address);391    await confirmSponsorshipExpectSuccess(collectionId, '//Bob');392393    await usingApi(async (api) => {394      // Find unused address395      const ownerZeroBalance = await findUnusedAddress(api);396397      // Find another unused address398      const senderZeroBalance = await findUnusedAddress(api);399400      // Mint token for an unused address401      const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', ownerZeroBalance.address);402403      const sponsorBalanceBeforeTx = (await api.query.system.account(bob.address)).data.free.toBigInt();404405      // Try to transfer this token from an unsponsored unused adress to Alice406      const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);407      await expect(submitTransactionExpectFailAsync(senderZeroBalance, zeroToAlice)).to.be.rejected;408409      const sponsorBalanceAfterTx = (await api.query.system.account(bob.address)).data.free.toBigInt();410411      expect(sponsorBalanceAfterTx).to.equal(sponsorBalanceBeforeTx);412    });413  });414});