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 getCreatedCollectionCount,24 UNIQUE,25} from './util/helpers';26import {Keyring} from '@polkadot/api';27import {IKeyringPair} from '@polkadot/types/types';2829chai.use(chaiAsPromised);30const expect = chai.expect;3132let alice: IKeyringPair;33let bob: IKeyringPair;34let charlie: IKeyringPair;3536describe('integration test: ext. confirmSponsorship():', () => {3738 before(async () => {39 await usingApi(async () => {40 const keyring = new Keyring({type: 'sr25519'});41 alice = keyring.addFromUri('//Alice');42 bob = keyring.addFromUri('//Bob');43 charlie = keyring.addFromUri('//Charlie');44 });45 });4647 it('Confirm collection sponsorship', async () => {48 const collectionId = await createCollectionExpectSuccess();49 await setCollectionSponsorExpectSuccess(collectionId, bob.address);50 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');51 });52 it('Add sponsor to a collection after the same sponsor was already added and confirmed', async () => {53 const collectionId = await createCollectionExpectSuccess();54 await setCollectionSponsorExpectSuccess(collectionId, bob.address);55 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');56 await setCollectionSponsorExpectSuccess(collectionId, bob.address);57 });58 it('Add new sponsor to a collection after another sponsor was already added and confirmed', async () => {59 const collectionId = await createCollectionExpectSuccess();60 await setCollectionSponsorExpectSuccess(collectionId, bob.address);61 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');62 await setCollectionSponsorExpectSuccess(collectionId, charlie.address);63 });6465 it('NFT: Transfer fees are paid by the sponsor after confirmation', async () => {66 const collectionId = await createCollectionExpectSuccess();67 await setCollectionSponsorExpectSuccess(collectionId, bob.address);68 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');6970 await usingApi(async (api) => {71 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();7273 74 const zeroBalance = await findUnusedAddress(api);7576 77 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', zeroBalance.address);7879 80 const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);81 const events = await submitTransactionAsync(zeroBalance, zeroToAlice);82 const result = getGenericResult(events);83 expect(result.success).to.be.true;8485 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();8687 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;88 });8990 });9192 it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => {93 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});94 await setCollectionSponsorExpectSuccess(collectionId, bob.address);95 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');9697 await usingApi(async (api) => {98 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();99100 101 const zeroBalance = await findUnusedAddress(api);102103 104 const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);105106 107 const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);108 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);109 const result1 = getGenericResult(events1);110 expect(result1.success).to.be.true;111112 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();113114 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;115 });116 });117118 it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {119 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});120 await setCollectionSponsorExpectSuccess(collectionId, bob.address);121 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');122123 await usingApi(async (api) => {124 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();125126 127 const zeroBalance = await findUnusedAddress(api);128129 130 const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);131132 133 const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);134 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);135 const result1 = getGenericResult(events1);136137 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();138139 expect(result1.success).to.be.true;140 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;141 });142 });143144 it('CreateItem fees are paid by the sponsor after confirmation', async () => {145 const collectionId = await createCollectionExpectSuccess();146 await setCollectionSponsorExpectSuccess(collectionId, bob.address);147 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');148149 150 await enableAllowListExpectSuccess(alice, collectionId);151152 153 await enablePublicMintingExpectSuccess(alice, collectionId);154155 156 await usingApi(async (api) => {157 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();158159 160 const zeroBalance = await findUnusedAddress(api);161162 163 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);164165 166 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);167168 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();169170 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;171 });172 });173174 it('NFT: Sponsoring of transfers is rate limited', async () => {175 const collectionId = await createCollectionExpectSuccess();176 await setCollectionSponsorExpectSuccess(collectionId, bob.address);177 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');178179 await usingApi(async (api) => {180 181 const zeroBalance = await findUnusedAddress(api);182183 184 const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address);185186 187 188 const aliceToZero = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0);189 const events1 = await submitTransactionAsync(alice, aliceToZero);190 const result1 = getGenericResult(events1);191192 193 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();194 const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0);195 const badTransaction = async function () {196 await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice);197 };198 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');199 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();200201 202 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);203 await submitTransactionAsync(alice, balancetx);204 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);205 const result2 = getGenericResult(events2);206207 expect(result1.success).to.be.true;208 expect(result2.success).to.be.true;209 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);210 });211 });212213 it('Fungible: Sponsoring is rate limited', async () => {214 const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});215 await setCollectionSponsorExpectSuccess(collectionId, bob.address);216 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');217218 await usingApi(async (api) => {219 220 const zeroBalance = await findUnusedAddress(api);221222 223 const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address);224225 226 const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1);227 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);228 const result1 = getGenericResult(events1);229 expect(result1.success).to.be.true;230231 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();232 await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected;233 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();234235 236 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);237 await submitTransactionAsync(alice, balancetx);238 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);239 const result2 = getGenericResult(events2);240 expect(result2.success).to.be.true;241242 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);243 });244 });245246 it('ReFungible: Sponsoring is rate limited', async () => {247 const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});248 await setCollectionSponsorExpectSuccess(collectionId, bob.address);249 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');250251 await usingApi(async (api) => {252 253 const zeroBalance = await findUnusedAddress(api);254255 256 const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address);257258 const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1);259260 261 const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice);262 const result1 = getGenericResult(events1);263 expect(result1.success).to.be.true;264265 266 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();267 await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejectedWith('Inability to pay some fees');268 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();269 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);270271 272 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);273 await submitTransactionAsync(alice, balancetx);274 const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);275 const result2 = getGenericResult(events2);276 expect(result2.success).to.be.true;277 });278 });279280 it('NFT: Sponsoring of createItem is rate limited', async () => {281 const collectionId = await createCollectionExpectSuccess();282 await setCollectionSponsorExpectSuccess(collectionId, bob.address);283 await confirmSponsorshipExpectSuccess(collectionId, '//Bob');284285 286 await enableAllowListExpectSuccess(alice, collectionId);287288 289 await enablePublicMintingExpectSuccess(alice, collectionId);290291 await usingApi(async (api) => {292 293 const zeroBalance = await findUnusedAddress(api);294295 296 await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);297298 299 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);300301 302 const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt();303304 const badTransaction = async function () {305 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);306 };307 await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');308 const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();309310 311 const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);312 await submitTransactionAsync(alice, balancetx);313 await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);314315 expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);316 });317 });318319});320321describe('(!negative test!) integration test: ext. confirmSponsorship():', () => {322 before(async () => {323 await usingApi(async () => {324 const keyring = new Keyring({type: 'sr25519'});325 alice = keyring.addFromUri('//Alice');326 bob = keyring.addFromUri('//Bob');327 charlie = keyring.addFromUri('//Charlie');328 });329 });330331 it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => {332 333 let collectionId = 0;334 await usingApi(async (api) => {335 collectionId = await getCreatedCollectionCount(api) + 1;336 });337338 await confirmSponsorshipExpectFailure(collectionId, '//Bob');339 });340341 it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => {342 const collectionId = await createCollectionExpectSuccess();343 await setCollectionSponsorExpectSuccess(collectionId, bob.address);344345 await usingApi(async (api) => {346 const transfer = api.tx.balances.transfer(charlie.address, 1e15);347 await submitTransactionAsync(alice, transfer);348 });349350 await confirmSponsorshipExpectFailure(collectionId, '//Charlie');351 });352353 it('(!negative test!) Confirm sponsorship using owner address', async () => {354 const collectionId = await createCollectionExpectSuccess();355 await setCollectionSponsorExpectSuccess(collectionId, bob.address);356 await confirmSponsorshipExpectFailure(collectionId, '//Alice');357 });358359 it('(!negative test!) Confirm sponsorship by collection admin', async () => {360 const collectionId = await createCollectionExpectSuccess();361 await setCollectionSponsorExpectSuccess(collectionId, bob.address);362 await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address);363 await confirmSponsorshipExpectFailure(collectionId, '//Charlie');364 });365366 it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => {367 const collectionId = await createCollectionExpectSuccess();368 await confirmSponsorshipExpectFailure(collectionId, '//Bob');369 });370371 it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => {372 const collectionId = await createCollectionExpectSuccess();373 await destroyCollectionExpectSuccess(collectionId);374 await confirmSponsorshipExpectFailure(collectionId, '//Bob');375 });376});