difftreelog
Add test for vesting pallet presence, cleanup other tests
in: master
12 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1228,6 +1228,26 @@
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
+name = "enumflags2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0"
+dependencies = [
+ "enumflags2_derive",
+]
+
+[[package]]
+name = "enumflags2_derive"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3541,6 +3561,7 @@
"pallet-transaction-payment",
"pallet-transaction-payment-rpc-runtime-api",
"pallet-treasury",
+ "pallet-vesting",
"parity-scale-codec",
"serde",
"sp-api",
@@ -4020,6 +4041,20 @@
]
[[package]]
+name = "pallet-vesting"
+version = "2.0.0"
+source = "git+https://github.com/usetech-llc/substrate.git?branch=release_flexi#59646c902484d9c5e8933a80cbed551228b81274"
+dependencies = [
+ "enumflags2",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
name = "parity-db"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
node/src/chain_spec.rsdiffbeforeafterboth--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -154,7 +154,8 @@
.collect(),
}),
pallet_treasury: Some(Default::default()),
- pallet_sudo: Some(SudoConfig { key: root_key }),
+ pallet_sudo: Some(SudoConfig { key: root_key }),
+ pallet_vesting: Some(Default::default()),
pallet_nft: Some(NftConfig {
collection: vec![(
1,
runtime/Cargo.tomldiffbeforeafterboth--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -45,6 +45,8 @@
pallet-timestamp = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
pallet-transaction-payment = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
+pallet-treasury = { version = "2.0.0", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
+pallet-vesting = { version = "2.0.0", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
sp-api = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
sp-block-builder = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
sp-consensus-aura = { default-features = false, version = '0.8.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
@@ -56,8 +58,6 @@
sp-std = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
sp-transaction-pool = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
sp-version = { default-features = false, version = '2.0.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
-
-pallet-treasury = { version = "2.0.0", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'release_flexi' }
[features]
default = ['std']
@@ -90,6 +90,9 @@
'pallet-timestamp/std',
'pallet-transaction-payment/std',
'pallet-transaction-payment-rpc-runtime-api/std',
+ 'pallet-treasury/std',
+ 'pallet-vesting/std',
+
'pallet-nft/std',
'sp-api/std',
'sp-block-builder/std',
@@ -103,5 +106,4 @@
'sp-transaction-pool/std',
'sp-version/std',
- 'pallet-treasury/std',
]
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -17,7 +17,7 @@
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{
- Convert, BlakeTwo256, Block as BlockT, IdentifyAccount,
+ Convert, ConvertInto, BlakeTwo256, Block as BlockT, IdentifyAccount,
IdentityLookup, NumberFor, Saturating, Verify,
},
transaction_validity::{TransactionSource, TransactionValidity},
@@ -412,6 +412,18 @@
type Call = Call;
}
+parameter_types! {
+ pub const MinVestedTransfer: Balance = 100 * DOLLARS;
+}
+
+impl pallet_vesting::Trait for Runtime {
+ type Event = Event;
+ type Currency = Balances;
+ type BlockNumberToBalance = ConvertInto;
+ type MinVestedTransfer = MinVestedTransfer;
+ type WeightInfo = ();
+}
+
/// Used for the module nft in `./nft.rs`
impl pallet_nft::Trait for Runtime {
type Event = Event;
@@ -435,6 +447,7 @@
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
Nft: pallet_nft::{Module, Call, Config<T>, Storage, Event<T>},
Treasury: pallet_treasury::{Module, Call, Storage, Config, Event<T>},
+ Vesting: pallet_vesting::{Module, Call, Config<T>, Storage, Event<T>},
}
);
tests/src/blocks-production.test.tsdiffbeforeafterboth--- a/tests/src/blocks-production.test.ts
+++ b/tests/src/blocks-production.test.ts
@@ -2,7 +2,7 @@
import promisifySubstrate from "./substrate/promisify-substrate";
import { expect } from "chai";
-describe('Blocks Production', () => {
+describe('Blocks Production smoke test', () => {
it('Node produces new blocks', async () => {
await usingApi(async api => {
const blocksPromise = promisifySubstrate(api, () => {
tests/src/connection.test.tsdiffbeforeafterboth--- a/tests/src/connection.test.ts
+++ b/tests/src/connection.test.ts
@@ -7,7 +7,7 @@
const expect = chai.expect;
-describe('Connection', () => {
+describe('Connection smoke test', () => {
it('Connection can be established', async () => {
await usingApi(async api => {
const health = await api.rpc.system.health();
@@ -16,11 +16,17 @@
});
it('Cannot connect to 255.255.255.255', async () => {
+ console.log = function () {};
+ console.error = function () {};
+
const neverConnectProvider = new WsProvider('ws://255.255.255.255:9944');
await expect((async () => {
await usingApi(async api => {
const health = await api.rpc.system.health();
}, { provider: neverConnectProvider });
})()).to.be.eventually.rejected;
+
+ delete console.log;
+ delete console.error;
});
});
\ No newline at end of file
tests/src/contracts.test.tsdiffbeforeafterboth--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -1,13 +1,17 @@
+import { ApiPromise } from "@polkadot/api";
import { expect } from "chai";
-import usingApi from "./substrate/substrate-api";
+import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";
import fs from "fs";
import { Abi, BlueprintPromise, CodePromise } from "@polkadot/api-contract";
import { IKeyringPair } from "@polkadot/types/types";
import { Keyring } from "@polkadot/api";
import { ApiTypes, SubmittableExtrinsic } from "@polkadot/api/types";
+import { BigNumber } from 'bignumber.js';
+import { findUnusedAddress } from './util/helpers'
const value = 0;
const gasLimit = 3000n * 1000000n;
+const endowment = `1000000000000000`;
function deployBlueprint(alice: IKeyringPair, code: CodePromise): Promise<BlueprintPromise> {
return new Promise<BlueprintPromise>(async (resolve, reject) => {
@@ -25,7 +29,6 @@
function deployContract(alice: IKeyringPair, blueprint: BlueprintPromise) : Promise<any> {
return new Promise<any>(async (resolve, reject) => {
- const endowment = 1000000000000000n;
const initValue = true;
const unsub = await blueprint.tx
@@ -39,28 +42,25 @@
});
}
-function runTransaction(privateKey: IKeyringPair, extrinsic: SubmittableExtrinsic<ApiTypes>) {
- return new Promise<void>(async (resolve, reject) => {
- extrinsic.signAndSend(privateKey, async result => {
- if(!result.isInBlock) {
- return;
- }
+async function prepareDeployer(api: ApiPromise) {
+ // Find unused address
+ const deployer = await findUnusedAddress(api);
+
+ // Transfer balance to it
+ const keyring = new Keyring({ type: 'sr25519' });
+ const alice = keyring.addFromUri(`//Alice`);
+ let amount = new BigNumber(endowment);
+ amount = amount.plus(1e15);
+ const tx = api.tx.balances.transfer(deployer.address, amount.toFixed());
+ await submitTransactionAsync(alice, tx);
- if(result.findRecord('system', 'ExtrinsicSuccess')) {
- resolve();
- }
- else {
- reject('Failed to flip value.');
- }
- })
- });
+ return deployer;
}
-describe('Contracts', () => {
+describe('Contracts smoke test', () => {
it(`Can deploy smart contract Flipper, instantiate it and call it's get and flip messages.`, async () => {
await usingApi(async api => {
- const keyring = new Keyring({ type: 'sr25519' });
- const alice = keyring.addFromUri("//Alice");
+ const deployer = await prepareDeployer(api);
const wasm = fs.readFileSync('./src/flipper/flipper.wasm');
@@ -69,11 +69,11 @@
const code = new CodePromise(api, abi, wasm);
- const blueprint = await deployBlueprint(alice, code);
- const contract = (await deployContract(alice, blueprint))['contract'];
+ const blueprint = await deployBlueprint(deployer, code);
+ const contract = (await deployContract(deployer, blueprint))['contract'];
const getFlipValue = async () => {
- const result = await contract.query.get(alice.address, value, gasLimit);
+ const result = await contract.query.get(deployer.address, value, gasLimit);
if(!result.result.isSuccess) {
throw `Failed to get flipper value`;
@@ -85,7 +85,7 @@
expect(initialGetResponse).to.be.true;
const flip = contract.exec('flip', value, gasLimit);
- await runTransaction(alice, flip);
+ await submitTransactionAsync(deployer, flip);
const afterFlipGetResponse = await getFlipValue();
@@ -112,7 +112,7 @@
// const bob = new GenericAccountId(api.registry, bobsPublicKey);
// const transfer = contractInstance.exec('balance_transfer', 0, 1000000000000n, [bob, new u128(api.registry, 1000000)]);
- // await runTransaction(alicesPrivateKey, transfer);
+ // await submitTransactionAsync(alicesPrivateKey, transfer);
// const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
tests/src/creditFeesToTreasury.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/creditFeesToTreasury.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/crefitFeesToTreasury.test.tsdiffbeforeafterbothno changes
tests/src/pallet-presence.test.tsdiffbeforeafterboth--- a/tests/src/pallet-presence.test.ts
+++ b/tests/src/pallet-presence.test.ts
@@ -6,20 +6,34 @@
return api.runtimeMetadata.asLatest.modules.map(m => m.name.toString().toLowerCase());
}
-describe('Pallet presence.', () => {
- it('NFT pallet is present.', async () => {
+// Pallets that must always be present
+const requiredPallets = [
+ 'nft', 'balances', 'contracts', 'randomnesscollectiveflip', 'system', 'timestamp', 'transactionpayment', 'treasury', 'vesting'
+];
+
+// Pallets that depend on consensus and governance configuration
+const consensusPallets = [
+ 'sudo', 'grandpa', 'aura'
+];
+
+describe('Pallet presence', () => {
+ it('Required pallets are present', async () => {
await usingApi(async api => {
- expect(getModuleNames(api)).to.include('nft');
+ for (let i=0; i<requiredPallets.length; i++) {
+ expect(getModuleNames(api)).to.include(requiredPallets[i]);
+ }
});
});
- it('Balances pallet is present.', async () => {
+ it('Governance and consensus pallets are present', async () => {
await usingApi(async api => {
- expect(getModuleNames(api)).to.include('balances');
+ for (let i=0; i<consensusPallets.length; i++) {
+ expect(getModuleNames(api)).to.include(consensusPallets[i]);
+ }
});
});
- it('Contracts pallet is present.', async () => {
+ it('No extra pallets are included', async () => {
await usingApi(async api => {
- expect(getModuleNames(api)).to.include('contracts');
+ expect(getModuleNames(api).length).to.be.equal(requiredPallets.length + consensusPallets.length);
});
});
});
tests/src/transfer.test.tsdiffbeforeafterboth--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -3,6 +3,8 @@
import { alicesPublicKey, bobsPublicKey, ferdiesPublicKey } from "./accounts";
import privateKey from "./substrate/privateKey";
import getBalance from "./substrate/get-balance";
+import { BigNumber } from 'bignumber.js';
+import { findUnusedAddress } from './util/helpers'
describe('Transfer', () => {
it('Balance transfers', async () => {
@@ -23,7 +25,8 @@
it('Inability to pay fees error message is correct', async () => {
await usingApi(async api => {
- const pk = privateKey('//Ferdie');
+ // Find unused address
+ const pk = await findUnusedAddress(api);
console.log = function () {};
console.error = function () {};
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -1,10 +1,13 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
-import type { EventRecord } from '@polkadot/types/interfaces';
+import type { AccountId, EventRecord } from '@polkadot/types/interfaces';
+import { ApiPromise, Keyring } from "@polkadot/api";
import { default as usingApi, submitTransactionAsync } from "../substrate/substrate-api";
import privateKey from '../substrate/privateKey';
import { alicesPublicKey } from "../accounts";
import { strToUTF16, utf16ToStr, hexToStr } from '../util/util';
+import { IKeyringPair } from "@polkadot/types/types";
+import { BigNumber } from 'bignumber.js';
chai.use(chaiAsPromised);
const expect = chai.expect;
@@ -98,3 +101,14 @@
});
}
+export async function findUnusedAddress(api: ApiPromise): Promise<IKeyringPair> {
+ let bal = new BigNumber(0);
+ let unused;
+ do {
+ const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000));
+ const keyring = new Keyring({ type: 'sr25519' });
+ unused = keyring.addFromUri(`//${randomSeed}`);
+ bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());
+ } while (bal.toFixed() != '0');
+ return unused;
+}
\ No newline at end of file