123456import chai from 'chai';7import chaiAsPromised from 'chai-as-promised';8import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';9import {alicesPublicKey, bobsPublicKey} from './accounts';10import privateKey from './substrate/privateKey';11import {IKeyringPair} from '@polkadot/types/types';12import {13 createCollectionExpectSuccess,14 createItemExpectSuccess,15 getGenericResult,16 transferExpectSuccess,17} from './util/helpers';1819import {default as waitNewBlocks} from './substrate/wait-new-blocks';20import {ApiPromise} from '@polkadot/api';2122chai.use(chaiAsPromised);23const expect = chai.expect;2425const TREASURY = '5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z';26const saneMinimumFee = 0.05;27const saneMaximumFee = 0.5;28const createCollectionDeposit = 100;2930let alice: IKeyringPair;31let bob: IKeyringPair;3233343536function skipInflationBlock(api: ApiPromise): Promise<void> {37 const promise = new Promise<void>(async (resolve) => {38 const blockInterval = (await api.consts.inflation.inflationBlockInterval).toNumber();39 const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => {40 const currentBlock = head.number.toNumber();41 if (currentBlock % blockInterval < blockInterval - 10) {42 unsubscribe();43 resolve();44 } else {45 console.log(`Skipping inflation block, current block: ${currentBlock}`);46 }47 });48 });4950 return promise;51}5253describe('integration test: Fees must be credited to Treasury:', () => {54 before(async () => {55 await usingApi(async () => {56 alice = privateKey('//Alice');57 bob = privateKey('//Bob');58 });59 });6061 it('Total issuance does not change', async () => {62 await usingApi(async (api) => {63 await skipInflationBlock(api);64 await waitNewBlocks(api, 1);6566 const totalBefore = (await api.query.balances.totalIssuance()).toBigInt();6768 const alicePrivateKey = privateKey('//Alice');69 const amount = 1n;70 const transfer = api.tx.balances.transfer(bobsPublicKey, amount);7172 const result = getGenericResult(await submitTransactionAsync(alicePrivateKey, transfer));7374 const totalAfter = (await api.query.balances.totalIssuance()).toBigInt();7576 expect(result.success).to.be.true;77 expect(totalAfter).to.be.equal(totalBefore);78 });79 });8081 it('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async () => {82 await usingApi(async (api) => {83 await skipInflationBlock(api);84 await waitNewBlocks(api, 1);8586 const alicePrivateKey = privateKey('//Alice');87 const treasuryBalanceBefore: bigint = (await api.query.system.account(TREASURY)).data.free.toBigInt();88 const aliceBalanceBefore: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();8990 const amount = 1n;91 const transfer = api.tx.balances.transfer(bobsPublicKey, amount);92 const result = getGenericResult(await submitTransactionAsync(alicePrivateKey, transfer));9394 const treasuryBalanceAfter: bigint = (await api.query.system.account(TREASURY)).data.free.toBigInt();95 const aliceBalanceAfter: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();96 const fee = aliceBalanceBefore - aliceBalanceAfter - amount;97 const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;9899 expect(result.success).to.be.true;100 expect(treasuryIncrease).to.be.equal(fee);101 });102 });103104 it('Treasury balance increased by failed tx fee', async () => {105 await usingApi(async (api) => {106 await skipInflationBlock(api);107 await waitNewBlocks(api, 1);108109 const bobPrivateKey = privateKey('//Bob');110 const treasuryBalanceBefore = (await api.query.system.account(TREASURY)).data.free.toBigInt();111 const bobBalanceBefore = (await api.query.system.account(bobsPublicKey)).data.free.toBigInt();112113 const badTx = api.tx.balances.setBalance(alicesPublicKey, 0, 0);114 await expect(submitTransactionExpectFailAsync(bobPrivateKey, badTx)).to.be.rejected;115116 const treasuryBalanceAfter = (await api.query.system.account(TREASURY)).data.free.toBigInt();117 const bobBalanceAfter = (await api.query.system.account(bobsPublicKey)).data.free.toBigInt();118 const fee = bobBalanceBefore - bobBalanceAfter;119 const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;120121 expect(treasuryIncrease).to.be.equal(fee);122 });123 });124125 it('NFT Transactions also send fees to Treasury', async () => {126 await usingApi(async (api) => {127 await skipInflationBlock(api);128 await waitNewBlocks(api, 1);129130 const treasuryBalanceBefore = (await api.query.system.account(TREASURY)).data.free.toBigInt();131 const aliceBalanceBefore = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();132133 await createCollectionExpectSuccess();134135 const treasuryBalanceAfter = (await api.query.system.account(TREASURY)).data.free.toBigInt();136 const aliceBalanceAfter = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();137 const fee = aliceBalanceBefore - aliceBalanceAfter;138 const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore;139140 expect(treasuryIncrease).to.be.equal(fee);141 });142 });143144 it('Fees are sane', async () => {145 await usingApi(async (api) => {146 await skipInflationBlock(api);147 await waitNewBlocks(api, 1);148149 const aliceBalanceBefore: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();150151 await createCollectionExpectSuccess();152153 const aliceBalanceAfter: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();154 const fee = aliceBalanceBefore - aliceBalanceAfter;155156 expect(fee / 10n ** 15n < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true;157 expect(fee / 10n ** 15n < BigInt(Math.ceil(saneMinimumFee + createCollectionDeposit))).to.be.true;158 });159 });160161 it('NFT Transfer fee is close to 0.1 Unique', async () => {162 await usingApi(async (api) => {163 await skipInflationBlock(api);164 await waitNewBlocks(api, 1);165166 const collectionId = await createCollectionExpectSuccess();167 const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT');168169 const aliceBalanceBefore: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();170 await transferExpectSuccess(collectionId, tokenId, alice, bob, 1, 'NFT');171 const aliceBalanceAfter: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();172 const fee = aliceBalanceBefore - aliceBalanceAfter;173174 175 const expectedTransferFee = 0.1;176 const toleranceMaxBound = 0.0012;177 const toleranceMinBound = -0.0012;178 const fact = Number(fee) / 1e15 - expectedTransferFee;179 expect(fact).to.be.lessThan(toleranceMaxBound);180 expect(fact).to.be.greaterThan(toleranceMinBound);181 });182 });183184});