123456import chai from 'chai';7import chaiAsPromised from 'chai-as-promised';8import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';9import {10 createCollectionExpectSuccess,11 setCollectionSponsorExpectSuccess,12 destroyCollectionExpectSuccess,13 confirmSponsorshipExpectSuccess,14 confirmSponsorshipExpectFailure,15 createItemExpectSuccess,16 findUnusedAddress,17 getGenericResult,18 enableAllowListExpectSuccess,19 enablePublicMintingExpectSuccess,20 addToAllowListExpectSuccess,21 normalizeAccountId,22 addCollectionAdminExpectSuccess,23} from './util/helpers';24import {Keyring} from '@polkadot/api';25import {IKeyringPair} from '@polkadot/types/types';2627chai.use(chaiAsPromised);28const expect = chai.expect;2930let alice: IKeyringPair;31let bob: IKeyringPair;32let charlie: IKeyringPair;3334describe('integration test: ext. confirmSponsorship():', () => {3536 before(async () => {37 await usingApi(async () => {38 const keyring = new Keyring({type: 'sr25519'});39 alice = keyring.addFromUri('//Alice');40 bob = keyring.addFromUri('//Bob');41 charlie = keyring.addFromUri('//Charlie');42 });43 });4445 it('Confirm collection sponsorship', async () => {46 const collectionId = await createCollectionExpectSuccess();47 await setCollectionSponsorExpectSuccess(collectionId, bob.address);48 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');49 });50 it('Add sponsor to a collection after the same sponsor was already added and confirmed', async () => {51 const collectionId = await createCollectionExpectSuccess();52 await setCollectionSponsorExpectSuccess(collectionId, bob.address);53 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');54 await setCollectionSponsorExpectSuccess(collectionId, bob.address);55 });56 it('Add new sponsor to a collection after another sponsor was already added and confirmed', async () => {57 const collectionId = await createCollectionExpectSuccess();58 await setCollectionSponsorExpectSuccess(collectionId, bob.address);59 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');60 await setCollectionSponsorExpectSuccess(collectionId, charlie.address);61 });6263 it('NFT: Transfer fees are paid by the sponsor after confirmation', async () => {64 const collectionId = await createCollectionExpectSuccess();65 await setCollectionSponsorExpectSuccess(collectionId, bob.address);66 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');6768 await usingApi(async (api) => {69 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();7071 72 const zeroBalance = await findUnusedAddress(api);7374 75 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', zeroBalance.address);7677 78 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);79 const events = await submitTransactionAsync(zeroBalance, zeroToAlice);80 const result = getGenericResult(events);81 expect(result.success).to.be.true;8283 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();8485 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;86 });8788 });8990 it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => {91 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});92 await setCollectionSponsorExpectSuccess(collectionId, bob.address);93 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');9495 await usingApi(async (api) => {96 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();9798 99 const zeroBalance = await findUnusedAddress(api);100101 102 const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);103104 105 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);106 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);107 const result1 = getGenericResult(events1);108 expect(result1.success).to.be.true;109110 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();111112 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;113 });114 });115116 it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {117 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});118 await setCollectionSponsorExpectSuccess(collectionId, bob.address);119 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');120121 await usingApi(async (api) => {122 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();123124 125 const zeroBalance = await findUnusedAddress(api);126127 128 const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);129130 131 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);132 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);133 const result1 = getGenericResult(events1);134135 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();136137 expect(result1.success).to.be.true;138 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;139 });140 });141142 it('CreateItem fees are paid by the sponsor after confirmation', async () => {143 const collectionId = await createCollectionExpectSuccess();144 await setCollectionSponsorExpectSuccess(collectionId, bob.address);145 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');146147 148 await enableAllowListExpectSuccess(alice, collectionId);149150 151 await enablePublicMintingExpectSuccess(alice, collectionId);152153 154 await usingApi(async (api) => {155 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();156157 158 const zeroBalance = await findUnusedAddress(api);159160 161 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);162163 164 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);165166 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();167168 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;169 });170 });171172 it('NFT: Sponsoring of transfers is rate limited', async () => {173 const collectionId = await createCollectionExpectSuccess();174 await setCollectionSponsorExpectSuccess(collectionId, bob.address);175 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');176177 await usingApi(async (api) => {178 179 const zeroBalance = await findUnusedAddress(api);180181 182 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);183184 185 186 const aliceToZero = api.tx.nft.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);187 const events1 = await submitTransactionAsync(alice, aliceToZero);188 const result1 = getGenericResult(events1);189190 191 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();192 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);193 const badTransaction = async function () {194 await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);195 };196 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');197 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();198199 200 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);201 await submitTransactionAsync(alice, balancetx);202 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);203 const result2 = getGenericResult(events2);204205 expect(result1.success).to.be.true;206 expect(result2.success).to.be.true;207 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);208 });209 });210211 it('Fungible: Sponsoring is rate limited', async () => {212 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});213 await setCollectionSponsorExpectSuccess(collectionId, bob.address);214 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');215216 await usingApi(async (api) => {217 218 const zeroBalance = await findUnusedAddress(api);219220 221 const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);222223 224 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);225 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);226 const result1 = getGenericResult(events1);227 expect(result1.success).to.be.true;228229 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();230 await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected;231 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();232233 234 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);235 await submitTransactionAsync(alice, balancetx);236 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);237 const result2 = getGenericResult(events2);238 expect(result2.success).to.be.true;239240 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);241 });242 });243244 it('ReFungible: Sponsoring is rate limited', async () => {245 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});246 await setCollectionSponsorExpectSuccess(collectionId, bob.address);247 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');248249 await usingApi(async (api) => {250 251 const zeroBalance = await findUnusedAddress(api);252253 254 const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', alice.address);255256 257 258 const aliceToZero = api.tx.nft.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);259 const events1 = await submitTransactionAsync(alice, aliceToZero);260 const result1 = getGenericResult(events1);261 expect(result1.success).to.be.true;262263 264 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();265 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1);266 const badTransaction = async function () {267 await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);268 };269 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');270 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();271272 273 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);274 await submitTransactionAsync(alice, balancetx);275 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);276 const result2 = getGenericResult(events2);277 expect(result2.success).to.be.true;278279 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);280 });281 });282283 it('NFT: Sponsoring of createItem is rate limited', async () => {284 const collectionId = await createCollectionExpectSuccess();285 await setCollectionSponsorExpectSuccess(collectionId, bob.address);286 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');287288 289 await enableAllowListExpectSuccess(alice, collectionId);290291 292 await enablePublicMintingExpectSuccess(alice, collectionId);293294 await usingApi(async (api) => {295 296 const zeroBalance = await findUnusedAddress(api);297298 299 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);300301 302 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);303304 305 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();306307 const badTransaction = async function () {308 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);309 };310 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');311 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();312313 314 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);315 await submitTransactionAsync(alice, balancetx);316 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);317318 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);319 });320 });321322});323324describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {325 before(async () => {326 await usingApi(async () => {327 const keyring = new Keyring({type: 'sr25519'});328 alice = keyring.addFromUri('//Alice');329 bob = keyring.addFromUri('//Bob');330 charlie = keyring.addFromUri('//Charlie');331 });332 });333334 it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => {335 336 let collectionId = 0;337 await usingApi(async (api) => {338 collectionId = (await api.query.common.createdCollectionCount()).toNumber() + 1;339 });340341 await confirmSponsorshipExpectFailure(collectionId, '//Bob');342 });343344 it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => {345 const collectionId = await createCollectionExpectSuccess();346 await setCollectionSponsorExpectSuccess(collectionId, bob.address);347348 await usingApi(async (api) => {349 const transfer = api.tx.balances.transfer(charlie.address, 1e15);350 await submitTransactionAsync(alice, transfer);351 });352353 await confirmSponsorshipExpectFailure(collectionId, '//Charlie');354 });355356 it('(!negative test!) Confirm sponsorship using owner address', async () => {357 const collectionId = await createCollectionExpectSuccess();358 await setCollectionSponsorExpectSuccess(collectionId, bob.address);359 await confirmSponsorshipExpectFailure(collectionId, '//Alice');360 });361362 it('(!negative test!) Confirm sponsorship by collection admin', async () => {363 const collectionId = await createCollectionExpectSuccess();364 await setCollectionSponsorExpectSuccess(collectionId, bob.address);365 await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address);366 await confirmSponsorshipExpectFailure(collectionId, '//Charlie');367 });368369 it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => {370 const collectionId = await createCollectionExpectSuccess();371 await confirmSponsorshipExpectFailure(collectionId, '//Bob');372 });373374 it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => {375 const collectionId = await createCollectionExpectSuccess();376 await destroyCollectionExpectSuccess(collectionId);377 await confirmSponsorshipExpectFailure(collectionId, '//Bob');378 });379});