difftreelog
sending fees to treasury + integration test
in: master
5 files changed
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -315,7 +315,7 @@
type Balance = Balance;
/// The ubiquitous event type.
type Event = Event;
- type DustRemoval = ();
+ type DustRemoval = Treasury;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
@@ -357,7 +357,7 @@
impl pallet_transaction_payment::Trait for Runtime {
type Currency = pallet_balances::Module<Runtime>;
- type OnTransactionPayment = ();
+ type OnTransactionPayment = Treasury;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
tests/package-lock.jsondiffbeforeafterboth--- a/tests/package-lock.json
+++ b/tests/package-lock.json
@@ -13,13 +13,12 @@
"@polkadot/api-contract": "^2.3.1",
"@polkadot/types": "^2.3.1",
"@polkadot/util": "^3.4.1",
- "@types/bn.js": "^4.11.6",
+ "bignumber.js": "^9.0.0",
"chai-as-promised": "^7.1.1"
},
"devDependencies": {
"@polkadot/dev": "^0.52.11",
"@polkadot/ts": "^0.3.41",
- "@types/bn.js": "^4.11.6",
"@types/chai": "^4.2.12",
"@types/chai-as-promised": "^7.1.3",
"@types/mocha": "^8.0.3",
@@ -7114,6 +7113,14 @@
"node": "*"
}
},
+ "node_modules/bignumber.js": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz",
+ "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
@@ -34960,6 +34967,11 @@
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"dev": true
},
+ "bignumber.js": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz",
+ "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA=="
+ },
"binary-extensions": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -6,7 +6,6 @@
"devDependencies": {
"@polkadot/dev": "^0.52.11",
"@polkadot/ts": "^0.3.41",
- "@types/bn.js": "^4.11.6",
"@types/chai": "^4.2.12",
"@types/chai-as-promised": "^7.1.3",
"@types/mocha": "^8.0.3",
@@ -27,7 +26,7 @@
"@polkadot/api-contract": "^2.3.1",
"@polkadot/types": "^2.3.1",
"@polkadot/util": "^3.4.1",
- "@types/bn.js": "^4.11.6",
+ "bignumber.js": "^9.0.0",
"chai-as-promised": "^7.1.1"
},
"standard": {
tests/src/crefitFeesToTreasury.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/crefitFeesToTreasury.test.ts
@@ -0,0 +1,107 @@
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";
+import { alicesPublicKey, bobsPublicKey } from "./accounts";
+import privateKey from "./substrate/privateKey";
+import { BigNumber } from 'bignumber.js';
+import { createCollectionExpectSuccess, getGenericResult } from './util/helpers';
+
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+const Treasury = "5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z";
+const saneMinimumFee = 0.0001;
+const saneMaximumFee = 0.01;
+
+describe('integration test: Fees must be credited to Treasury:', () => {
+ it('Total issuance does not change', async () => {
+ await usingApi(async (api) => {
+ const totalBefore = new BigNumber((await api.query.balances.totalIssuance()).toString());
+
+ const alicePrivateKey = privateKey('//Alice');
+ const amount = new BigNumber(1);
+ const transfer = api.tx.balances.transfer(bobsPublicKey, amount.toFixed());
+
+ const result = getGenericResult(await submitTransactionAsync(alicePrivateKey, transfer));
+
+ const totalAfter = new BigNumber((await api.query.balances.totalIssuance()).toString());
+
+ expect(result.success).to.be.true;
+ expect(totalAfter.toFixed()).to.be.equal(totalBefore.toFixed());
+ });
+ });
+
+ it('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async () => {
+ await usingApi(async (api) => {
+ const alicePrivateKey = privateKey('//Alice');
+ const treasuryBalanceBefore = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const aliceBalanceBefore = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString());
+
+ const amount = new BigNumber(1);
+ const transfer = api.tx.balances.transfer(bobsPublicKey, amount.toFixed());
+ const result = getGenericResult(await submitTransactionAsync(alicePrivateKey, transfer));
+
+ const treasuryBalanceAfter = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const aliceBalanceAfter = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString());
+ const fee = aliceBalanceBefore.minus(aliceBalanceAfter).minus(amount);
+ const treasuryIncrease = treasuryBalanceAfter.minus(treasuryBalanceBefore);
+
+ expect(result.success).to.be.true;
+ expect(treasuryIncrease.toFixed()).to.be.equal(fee.toFixed());
+ });
+ });
+
+ it('Treasury balance increased by failed tx fee', async () => {
+ await usingApi(async (api) => {
+ const bobPrivateKey = privateKey('//Bob');
+ const treasuryBalanceBefore = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const bobBalanceBefore = new BigNumber((await api.query.system.account(bobsPublicKey)).data.free.toString());
+
+ const badTx = api.tx.balances.setBalance(alicesPublicKey, 0, 0);
+ const result = getGenericResult(await submitTransactionAsync(bobPrivateKey, badTx));
+
+ const treasuryBalanceAfter = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const bobBalanceAfter = new BigNumber((await api.query.system.account(bobsPublicKey)).data.free.toString());
+ const fee = bobBalanceBefore.minus(bobBalanceAfter);
+ const treasuryIncrease = treasuryBalanceAfter.minus(treasuryBalanceBefore);
+
+ expect(result.success).to.be.false;
+ expect(treasuryIncrease.toFixed()).to.be.equal(fee.toFixed());
+ });
+ });
+
+ it('NFT Transactions also send fees to Treasury', async () => {
+ await usingApi(async (api) => {
+ const treasuryBalanceBefore = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const aliceBalanceBefore = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString());
+
+ await createCollectionExpectSuccess('A', 'B', 'C', 'NFT');
+
+ const treasuryBalanceAfter = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const aliceBalanceAfter = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString());
+ const fee = aliceBalanceBefore.minus(aliceBalanceAfter);
+ const treasuryIncrease = treasuryBalanceAfter.minus(treasuryBalanceBefore);
+
+ expect(treasuryIncrease.toFixed()).to.be.equal(fee.toFixed());
+ });
+ });
+
+ it('Fees are sane', async () => {
+ await usingApi(async (api) => {
+ const treasuryBalanceBefore = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const aliceBalanceBefore = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString());
+
+ await createCollectionExpectSuccess('A', 'B', 'C', 'NFT');
+
+ const treasuryBalanceAfter = new BigNumber((await api.query.system.account(Treasury)).data.free.toString());
+ const aliceBalanceAfter = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString());
+ const fee = aliceBalanceBefore.minus(aliceBalanceAfter);
+ const treasuryIncrease = treasuryBalanceAfter.minus(treasuryBalanceBefore);
+
+ expect(fee.dividedBy(1e15).toNumber()).to.be.lessThan(0.01);
+ expect(fee.dividedBy(1e15).toNumber()).to.be.greaterThan(0.0001);
+ });
+ });
+
+});
+
tests/src/util/helpers.tsdiffbeforeafterboth1import chai from 'chai';2import chaiAsPromised from 'chai-as-promised';3import type { EventRecord } from '@polkadot/types/interfaces';4import { default as usingApi, submitTransactionAsync } from "../substrate/substrate-api";5import privateKey from '../substrate/privateKey';6import { alicesPublicKey } from "../accounts";7import { strToUTF16, utf16ToStr, hexToStr } from '../util/util';89chai.use(chaiAsPromised);10const expect = chai.expect;1112type CreateCollectionResult = {13 success: boolean,14 collectionId: number15};1617function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {18 let success = false;19 let collectionId: number = 0;20 events.forEach(({ phase, event: { data, method, section } }) => {21 // console.log(` ${phase}: ${section}.${method}:: ${data}`);22 if (method == 'ExtrinsicSuccess') {23 success = true;24 } else if ((section == 'nft') && (method == 'Created')) {25 collectionId = parseInt(data[0].toString());26 }27 });28 let result: CreateCollectionResult = {29 success,30 collectionId31 }32 return result;33}3435export async function createCollectionExpectSuccess(name: string, description: string, tokenPrefix: string, mode: string) {36 await usingApi(async (api) => {37 // Get number of collections before the transaction38 const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());3940 // Run the CreateCollection transaction41 const alicePrivateKey = privateKey('//Alice');42 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), mode);43 const events = await submitTransactionAsync(alicePrivateKey, tx);44 const result = getCreateCollectionResult(events);4546 // Get number of collections after the transaction47 const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());4849 // Get the collection 50 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();5152 // What to expect53 expect(result.success).to.be.true;54 expect(result.collectionId).to.be.equal(BcollectionCount);55 expect(collection).to.be.not.null;56 expect(BcollectionCount).to.be.equal(AcollectionCount+1, 'Error: NFT collection NOT created.');57 expect(collection.Owner).to.be.equal(alicesPublicKey);58 expect(utf16ToStr(collection.Name)).to.be.equal(name);59 expect(utf16ToStr(collection.Description)).to.be.equal(description);60 expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);61 });62}63 64export async function createCollectionExpectFailure(name: string, description: string, tokenPrefix: string, mode: string) {65 await usingApi(async (api) => {66 // Get number of collections before the transaction67 const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());6869 // Run the CreateCollection transaction70 const alicePrivateKey = privateKey('//Alice');71 const tx = api.tx.nft.createCollection(name, description, tokenPrefix, mode);72 const events = await submitTransactionAsync(alicePrivateKey, tx);73 const result = getCreateCollectionResult(events);7475 // Get number of collections after the transaction76 const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());7778 // What to expect79 expect(result.success).to.be.false;80 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');81 });82}83 1import chai from 'chai';2import chaiAsPromised from 'chai-as-promised';3import type { EventRecord } from '@polkadot/types/interfaces';4import { default as usingApi, submitTransactionAsync } from "../substrate/substrate-api";5import privateKey from '../substrate/privateKey';6import { alicesPublicKey } from "../accounts";7import { strToUTF16, utf16ToStr, hexToStr } from '../util/util';89chai.use(chaiAsPromised);10const expect = chai.expect;1112type GenericResult = {13 success: boolean,14};1516type CreateCollectionResult = {17 success: boolean,18 collectionId: number19};2021export function getGenericResult(events: EventRecord[]): GenericResult {22 let result: GenericResult = {23 success: false24 }25 events.forEach(({ phase, event: { data, method, section } }) => {26 // console.log(` ${phase}: ${section}.${method}:: ${data}`);27 if (method == 'ExtrinsicSuccess') {28 result.success = true;29 }30 });31 return result;32}3334function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {35 let success = false;36 let collectionId: number = 0;37 events.forEach(({ phase, event: { data, method, section } }) => {38 // console.log(` ${phase}: ${section}.${method}:: ${data}`);39 if (method == 'ExtrinsicSuccess') {40 success = true;41 } else if ((section == 'nft') && (method == 'Created')) {42 collectionId = parseInt(data[0].toString());43 }44 });45 let result: CreateCollectionResult = {46 success,47 collectionId48 }49 return result;50}5152export async function createCollectionExpectSuccess(name: string, description: string, tokenPrefix: string, mode: string) {53 await usingApi(async (api) => {54 // Get number of collections before the transaction55 const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());5657 // Run the CreateCollection transaction58 const alicePrivateKey = privateKey('//Alice');59 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), mode);60 const events = await submitTransactionAsync(alicePrivateKey, tx);61 const result = getCreateCollectionResult(events);6263 // Get number of collections after the transaction64 const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());6566 // Get the collection 67 const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();6869 // What to expect70 expect(result.success).to.be.true;71 expect(result.collectionId).to.be.equal(BcollectionCount);72 expect(collection).to.be.not.null;73 expect(BcollectionCount).to.be.equal(AcollectionCount+1, 'Error: NFT collection NOT created.');74 expect(collection.Owner).to.be.equal(alicesPublicKey);75 expect(utf16ToStr(collection.Name)).to.be.equal(name);76 expect(utf16ToStr(collection.Description)).to.be.equal(description);77 expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);78 });79}80 81export async function createCollectionExpectFailure(name: string, description: string, tokenPrefix: string, mode: string) {82 await usingApi(async (api) => {83 // Get number of collections before the transaction84 const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());8586 // Run the CreateCollection transaction87 const alicePrivateKey = privateKey('//Alice');88 const tx = api.tx.nft.createCollection(name, description, tokenPrefix, mode);89 const events = await submitTransactionAsync(alicePrivateKey, tx);90 const result = getCreateCollectionResult(events);9192 // Get number of collections after the transaction93 const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString());9495 // What to expect96 expect(result.success).to.be.false;97 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');98 });99}100