Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add create bounty script #4416

Merged
merged 29 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7b84fde
Add bounty script INIT
MiZiet Dec 31, 2020
50afa1d
Finish flow and extract methods
MiZiet Dec 31, 2020
307fce7
Add empty readme file
MiZiet Dec 31, 2020
a5a6b1c
extract functions and constants to different files
MiZiet Dec 31, 2020
426dba3
Make voting parallel
MiZiet Dec 31, 2020
e4830d0
Add proposeCurator and approveBounty
MiZiet Dec 31, 2020
99e07a1
Move helpers to new file
MiZiet Dec 31, 2020
19ef067
Add waitFor functions
MiZiet Jan 5, 2021
4dd9671
Remove sleep from closedBounty
MiZiet Jan 5, 2021
8bfeea6
Use motions hashes and ids
MiZiet Jan 5, 2021
8115edb
Use bounty index
MiZiet Jan 5, 2021
2a7bd4b
Extract methods from waitFor utils
ekowalsk Jan 5, 2021
8abc56c
[WIP] Create bounties async
MiZiet Jan 5, 2021
16b5ba8
Merge branch 'master' into mz-add-create-bounty-script
MiZiet Jan 7, 2021
4f9cb1a
Add approveBounties
MiZiet Jan 7, 2021
4e1b94d
Finish flow for multi bounties
MiZiet Jan 7, 2021
f842327
Extract multi functions to separate file
MiZiet Jan 7, 2021
eec7f3e
Clear import
MiZiet Jan 7, 2021
594d173
Create one bounty in each status
MiZiet Jan 7, 2021
f4a6e78
Add content to the readme
MiZiet Jan 7, 2021
2f194a6
Correct path in readme
MiZiet Jan 7, 2021
582683c
Correct lint warnings
MiZiet Jan 7, 2021
deb6456
Apply review suggestions
MiZiet Jan 7, 2021
c5f5a93
add ts-node
Jan 13, 2021
5774529
move tsconfig-paths dependency
Jan 14, 2021
e638d80
Refactor wait functions.
Jan 14, 2021
88fcc7e
Simplify bounty name
Jan 14, 2021
e719b3f
Update readme.md
Jan 14, 2021
412c983
Merge branch 'master' into mz-add-create-bounty-script
MiZiet Jan 14, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/test-support/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@
"dependencies": {
"@testing-library/react": "^11.2.3",
"testcontainers": "^6.4.1"
},
"devDependencies": {
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0"
}
}
48 changes: 48 additions & 0 deletions packages/test-support/scripts/createBounties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { createApi } from '@polkadot/test-support/api';
import { aliceSigner,
bobSigner,
charlieSigner,
daveSigner,
eveSigner,
ferdieSigner } from '@polkadot/test-support/keyring';

import { multiAcceptCurator,
multiApproveBounty,
multiAwardBounty,
multiClaimBounty,
multiProposeBounty,
multiProposeCurator,
multiWaitForBountyFunded,
multiWaitForClaim } from './lib/multiFunctions';

(async () => {
const api = await createApi(9944);

const SIGNERS = [aliceSigner(), bobSigner(), charlieSigner(), daveSigner(), eveSigner(), ferdieSigner()];

const indexes = await multiProposeBounty(api, 6);

indexes.pop();
await multiApproveBounty(api, indexes);

await multiWaitForBountyFunded(api, indexes);

indexes.pop();
await multiProposeCurator(api, indexes, SIGNERS);

indexes.pop();
await multiAcceptCurator(api, indexes, SIGNERS);

indexes.pop();
await multiAwardBounty(api, indexes, SIGNERS);

await multiWaitForClaim(api, indexes);

indexes.pop();
await multiClaimBounty(api, indexes, SIGNERS);

await api.disconnect();
})().catch((err) => console.error(err));
34 changes: 34 additions & 0 deletions packages/test-support/scripts/lib/bountyWaitFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { ApiPromise } from '@polkadot/api';
import { DeriveBounty } from '@polkadot/api-derive/types';
import { waitFor, WaitOptions } from '@polkadot/test-support/utils/waitFor';

type bStatus = 'isFunded' | 'isActive';

async function getBounty (api: ApiPromise, bountyIndex: number): Promise<DeriveBounty> {
const bounties = await api.derive.bounties.bounties();

return bounties.find((bounty) => (bounty.index.toNumber() === bountyIndex)) as DeriveBounty;
}

export async function waitForBountyState (api: ApiPromise, expectedState: bStatus, index: number, { interval = 500,
timeout = 10000 } = {}): Promise<boolean> {
return waitFor(async () => {
const bounty = await getBounty(api, index);

return bounty.bounty.status[expectedState];
}, { interval, timeout });
}

export async function waitForClaim (api: ApiPromise, index: number, { interval = 500, timeout = 10000 }: WaitOptions): Promise<boolean> {
return waitFor(async () => {
const bounty = await getBounty(api, index);
const unlockAt = bounty.bounty.status.asPendingPayout.unlockAt;

const bestNumber = await api.derive.chain.bestNumber();

return unlockAt.lt(bestNumber);
}, { interval, timeout });
}
47 changes: 47 additions & 0 deletions packages/test-support/scripts/lib/changeBountyStateFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { KeyringPair } from '@polkadot/keyring/types';

import BN from 'bn.js';

import { ApiPromise } from '@polkadot/api';
import { execute } from '@polkadot/test-support/transaction';

import { acceptMotion, fillTreasury, getMotion, proposeMotion } from './helpers';

export async function acceptCurator (api: ApiPromise, id: number, signer: KeyringPair): Promise<void> {
await execute(api.tx.bounties.acceptCurator(id), signer);
}

export async function awardBounty (api: ApiPromise, index: number, signer: KeyringPair): Promise<void> {
await execute(api.tx.bounties.awardBounty(index, signer.address), signer);
}

export async function claimBounty (api: ApiPromise, index: number, signer: KeyringPair): Promise<void> {
await execute(api.tx.bounties.claimBounty(index), signer);
}

export async function proposeBounty (api: ApiPromise, value: BN, title: string, signer: KeyringPair): Promise<number> {
await execute(api.tx.bounties.proposeBounty(value, title), signer);
const index = await api.query.bounties.bountyCount();

return index.toNumber() - 1;
}

export async function proposeCurator (api: ApiPromise, index: number, signer: KeyringPair): Promise<void> {
await proposeMotion(api, api.tx.bounties.proposeCurator(index, signer.address, 10), signer);

const bountyProposal = await getMotion(api, index);

await acceptMotion(api, bountyProposal.hash, bountyProposal.votes?.index.toNumber() ?? 0);
}

export async function approveBounty (api: ApiPromise, index: number, signer: KeyringPair): Promise<void> {
await proposeMotion(api, api.tx.bounties.approveBounty(index), signer);

const bountyProposal = await getMotion(api, index);

await acceptMotion(api, bountyProposal.hash, bountyProposal.votes?.index.toNumber() ?? 0);
await fillTreasury(api, signer);
}
10 changes: 10 additions & 0 deletions packages/test-support/scripts/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import BN from 'bn.js';

export const TREASURY_ADDRESS = '13UVJyLnbVp9RBZYFwFGyDvVd1y27Tt8tkntv6Q7JVPhFsTB';
export const FUNDING_TIME = 150000;
export const PAYOUT_TIME = 150000;
export const WEIGHT_BOUND = new BN('10000000000');
export const LENGTH_BOUND = 100000;
42 changes: 42 additions & 0 deletions packages/test-support/scripts/lib/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import BN from 'bn.js';

import { ApiPromise } from '@polkadot/api';
import { SubmittableExtrinsic } from '@polkadot/api/types';
import { DeriveCollectiveProposal } from '@polkadot/api-derive/types';
import { KeyringPair } from '@polkadot/keyring/types';
import { charlieSigner,
daveSigner,
eveSigner,
ferdieSigner } from '@polkadot/test-support/keyring';
import { execute } from '@polkadot/test-support/transaction';
import { Hash } from '@polkadot/types/interfaces';

import { LENGTH_BOUND, TREASURY_ADDRESS, WEIGHT_BOUND } from './constants';

export async function acceptMotion (api: ApiPromise, hash: Hash, index: number): Promise<void> {
const charlieVote = execute(api.tx.council.vote(hash, index, true), charlieSigner());
const daveVote = execute(api.tx.council.vote(hash, index, true), daveSigner());
const eveVote = execute(api.tx.council.vote(hash, index, true), eveSigner());
const ferdieVote = execute(api.tx.council.vote(hash, index, true), ferdieSigner());

await Promise.all([charlieVote, daveVote, eveVote, ferdieVote]);
await execute(api.tx.council.close(hash, index, WEIGHT_BOUND, LENGTH_BOUND), charlieSigner());
}

export async function fillTreasury (api: ApiPromise, signer: KeyringPair): Promise<void> {
await execute(api.tx.balances.transfer(TREASURY_ADDRESS, new BN(5_000_000_000_000_000)), signer);
}

export async function proposeMotion (api: ApiPromise, submittableExtrinsic: SubmittableExtrinsic<'promise'>, signer: KeyringPair): Promise<void> {
await execute(api.tx.council.propose(4, submittableExtrinsic, LENGTH_BOUND), signer);
}

export async function getMotion (api: ApiPromise, index: number): Promise<DeriveCollectiveProposal> {
const bounties = await api.derive.bounties.bounties();
const bountyProposals = bounties.find((bounty) => (bounty.index.toNumber() === index))?.proposals as DeriveCollectiveProposal[];

return bountyProposals[0];
}
68 changes: 68 additions & 0 deletions packages/test-support/scripts/lib/multiFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import BN from 'bn.js';

import { ApiPromise } from '@polkadot/api';
import { KeyringPair } from '@polkadot/keyring/types';
import { aliceSigner } from '@polkadot/test-support/keyring';

import { waitForBountyState, waitForClaim } from './bountyWaitFunctions';
import { acceptCurator, approveBounty, awardBounty, claimBounty, proposeBounty, proposeCurator } from './changeBountyStateFunctions';
import { FUNDING_TIME, PAYOUT_TIME } from './constants';

export async function multiProposeBounty (api: ApiPromise, numberOfBounties: number): Promise<number[]> {
const indexes = [];

for (let i = 0; i < numberOfBounties; i++) {
indexes.push(await proposeBounty(api, new BN(500_000_000_000_000), `new bounty no ${i}`, aliceSigner()));
}

return indexes;
}

export async function multiApproveBounty (api: ApiPromise, bountyIndexes: number[]): Promise<void> {
for (const bountyIndex of bountyIndexes) {
await approveBounty(api, bountyIndex, aliceSigner());
}
}

export async function multiWaitForBountyFunded (api: ApiPromise, bountyIndexes: number[]): Promise<void> {
const waitFunctions = bountyIndexes.map((bountyIndex) =>
waitForBountyState(api, 'isFunded', bountyIndex, { interval: 2000, timeout: FUNDING_TIME }));

await Promise.all(waitFunctions);
}

export async function multiProposeCurator (api: ApiPromise, bountyIndexes: number[], signers: KeyringPair[]): Promise<void> {
for (let i = 0; i < bountyIndexes.length; i++) {
await proposeCurator(api, bountyIndexes[i], signers[i]);
}
}

export async function multiAcceptCurator (api: ApiPromise, bountyIndexes: number[], signers: KeyringPair[]): Promise<void> {
const acceptFunctions = bountyIndexes.map((bountyIndex, index) =>
acceptCurator(api, bountyIndex, signers[index]));

await Promise.all(acceptFunctions);
}

export async function multiAwardBounty (api: ApiPromise, bountyIndexes: number[], signers: KeyringPair[]): Promise<void> {
const awardFunctions = bountyIndexes.map((bountyIndex, index) =>
awardBounty(api, bountyIndex, signers[index]));

await Promise.all(awardFunctions);
}

export async function multiWaitForClaim (api: ApiPromise, bountyIndexes: number[]): Promise<void> {
for (const index of bountyIndexes) {
await waitForClaim(api, index, { interval: 2000, timeout: PAYOUT_TIME });
}
}

export async function multiClaimBounty (api: ApiPromise, bountyIndexes: number[], signers: KeyringPair[]): Promise<void> {
const awardFunctions = bountyIndexes.map((bountyIndex, index) =>
claimBounty(api, bountyIndex, signers[index]));

await Promise.all(awardFunctions);
}
18 changes: 18 additions & 0 deletions packages/test-support/scripts/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Scripts for bounty testing

The scripts are prepared to run on a local, development version of substrate with following changes:
- `bin/node/runtime/src/lib.rs`
```
pub const SpendPeriod: BlockNumber = 1 * MINUTES;
pub const BountyDepositPayoutDelay: BlockNumber = 1 * MINUTES
```

To run a script enter the `packages/test-support` directory and run:
```
ts-node scripts/<script-name>
```

Available scripts:
- `createBounties` - creates a list of bounties,
one in each status ( Proposed, Funded, Curator Proposed, Active, Pending Payout, Closed )

4 changes: 2 additions & 2 deletions packages/test-support/src/api/createApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { ApiPromise } from '@polkadot/api/promise';
import { WsProvider } from '@polkadot/rpc-provider';
import { SUBSTRATE_PORT } from '@polkadot/test-support/substrate';

export async function createApi (): Promise<ApiPromise> {
export async function createApi (port: number = SUBSTRATE_PORT): Promise<ApiPromise> {
process.env.NODE_ENV = 'test';

const provider = new WsProvider(`ws://127.0.0.1:${SUBSTRATE_PORT}`);
const provider = new WsProvider(`ws://127.0.0.1:${port}`);

const api = await ApiPromise.create({ provider });

Expand Down
30 changes: 30 additions & 0 deletions packages/test-support/src/keyring/signers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,33 @@ export function aliceSigner (): KeyringPair {

return keyring.addFromUri('//Alice');
}

export function bobSigner (): KeyringPair {
const keyring = new Keyring({ type: 'sr25519' });

return keyring.addFromUri('//Bob');
}

export function charlieSigner (): KeyringPair {
const keyring = new Keyring({ type: 'sr25519' });

return keyring.addFromUri('//Charlie');
}

export function daveSigner (): KeyringPair {
const keyring = new Keyring({ type: 'sr25519' });

return keyring.addFromUri('//Dave');
}

export function eveSigner (): KeyringPair {
const keyring = new Keyring({ type: 'sr25519' });

return keyring.addFromUri('//Eve');
}

export function ferdieSigner (): KeyringPair {
const keyring = new Keyring({ type: 'sr25519' });

return keyring.addFromUri('//Ferdie');
}
6 changes: 3 additions & 3 deletions packages/test-support/src/transaction/execute.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { waitFor } from '@testing-library/react';

import { SubmittableExtrinsic } from '@polkadot/api/types';
import { KeyringPair } from '@polkadot/keyring/types';
import { EventRecord, ExtrinsicStatus } from '@polkadot/types/interfaces';

import { waitFor } from '../utils/waitFor';

export async function execute (extrinsic: SubmittableExtrinsic<'promise'>, singer: KeyringPair, logger = { info: console.log }): Promise<void> {
let currentTxDone = false;

Expand Down Expand Up @@ -36,5 +36,5 @@ export async function execute (extrinsic: SubmittableExtrinsic<'promise'>, singe
}

await extrinsic.signAndSend(singer, sendStatusCb);
await waitFor(() => expect(currentTxDone).toBeTruthy(), { timeout: 20000 });
await waitFor(() => currentTxDone, { timeout: 20000 });
}
27 changes: 27 additions & 0 deletions packages/test-support/src/utils/waitFor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2017-2021 @polkadot/test-support authors & contributors
// SPDX-License-Identifier: Apache-2.0

export type WaitOptions = { interval?: number, timeout?: number };

export async function waitFor (predicate: () => boolean, { interval, timeout }: WaitOptions): Promise<boolean>;
export async function waitFor (predicate: () => Promise<boolean>, { interval, timeout }: WaitOptions): Promise<boolean>;

export async function waitFor (predicate: () => Promise<boolean> | boolean, { interval = 500, timeout = 10000 } = {}): Promise<boolean> {
const asyncPredicate = () => Promise.resolve(predicate());

let elapsed = 0;

while (!(await asyncPredicate())) {
if (elapsed > timeout) {
throw Error('Timeout');
}

await sleep(interval);
elapsed += interval;
}

return true;
}

export const sleep = (ms: number):Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));
10 changes: 10 additions & 0 deletions packages/test-support/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "CommonJS",
"target": "es2018"
},
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
Loading