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', zeroBalance.address);255256 const zeroToAlice = api.tx.nft.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1);257258 259 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);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 await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejectedWith('Inability to pay some fees');266 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();267 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);268269 270 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);271 await submitTransactionAsync(alice, balancetx);272 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);273 const result2 = getGenericResult(events2);274 expect(result2.success).to.be.true;275 });276 });277278 it('NFT: Sponsoring of createItem is rate limited', async () => {279 const collectionId = await createCollectionExpectSuccess();280 await setCollectionSponsorExpectSuccess(collectionId, bob.address);281 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');282283 284 await enableAllowListExpectSuccess(alice, collectionId);285286 287 await enablePublicMintingExpectSuccess(alice, collectionId);288289 await usingApi(async (api) => {290 291 const zeroBalance = await findUnusedAddress(api);292293 294 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);295296 297 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);298299 300 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();301302 const badTransaction = async function () {303 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);304 };305 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');306 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();307308 309 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);310 await submitTransactionAsync(alice, balancetx);311 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);312313 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);314 });315 });316317});318319describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {320 before(async () => {321 await usingApi(async () => {322 const keyring = new Keyring({type: 'sr25519'});323 alice = keyring.addFromUri('//Alice');324 bob = keyring.addFromUri('//Bob');325 charlie = keyring.addFromUri('//Charlie');326 });327 });328329 it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => {330 331 let collectionId = 0;332 await usingApi(async (api) => {333 collectionId = (await api.query.common.createdCollectionCount()).toNumber() + 1;334 });335336 await confirmSponsorshipExpectFailure(collectionId, '//Bob');337 });338339 it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => {340 const collectionId = await createCollectionExpectSuccess();341 await setCollectionSponsorExpectSuccess(collectionId, bob.address);342343 await usingApi(async (api) => {344 const transfer = api.tx.balances.transfer(charlie.address, 1e15);345 await submitTransactionAsync(alice, transfer);346 });347348 await confirmSponsorshipExpectFailure(collectionId, '//Charlie');349 });350351 it('(!negative test!) Confirm sponsorship using owner address', async () => {352 const collectionId = await createCollectionExpectSuccess();353 await setCollectionSponsorExpectSuccess(collectionId, bob.address);354 await confirmSponsorshipExpectFailure(collectionId, '//Alice');355 });356357 it('(!negative test!) Confirm sponsorship by collection admin', async () => {358 const collectionId = await createCollectionExpectSuccess();359 await setCollectionSponsorExpectSuccess(collectionId, bob.address);360 await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address);361 await confirmSponsorshipExpectFailure(collectionId, '//Charlie');362 });363364 it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => {365 const collectionId = await createCollectionExpectSuccess();366 await confirmSponsorshipExpectFailure(collectionId, '//Bob');367 });368369 it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => {370 const collectionId = await createCollectionExpectSuccess();371 await destroyCollectionExpectSuccess(collectionId);372 await confirmSponsorshipExpectFailure(collectionId, '//Bob');373 });374});