Skip to content

Commit

Permalink
Merge pull request #2946 from Joystream/staging
Browse files Browse the repository at this point in the history
Release Stabilisation Bugfixing 4
  • Loading branch information
thesan authored May 9, 2022
2 parents aa3b757 + bfd3a6e commit 6799dce
Show file tree
Hide file tree
Showing 203 changed files with 21,471 additions and 12,717 deletions.
1 change: 1 addition & 0 deletions .husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
1 change: 1 addition & 0 deletions docs/mocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Available commands:
- `yarn workspace ui node-mocks set-budget` - Set membership Working Group budget
- `yarn workspace ui node-mocks opening:create` - Create an opening
- `yarn workspace ui node-mocks opening:fill` - Fill existing opening
- `yarn workspace ui node-mocks upcoming-opening:create` - Create an upcoming opening
- `yarn workspace ui node-mocks transfer` - Transfer tokens between accounts

To show help:
Expand Down
16 changes: 13 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@
]
},
"scripts": {
"lint": "wsrun --package ui -c lint",
"lint": "wsrun --package ui -c lint:fix",
"build": "wsrun --fast-exit --stages -c --exclude @joystream/markdown-editor build",
"build:storybook": "wsrun --fast-exit --stages -c --exclude ui --exclude-missing build && wsrun --package ui -c build:storybook",
"storybook": "wsrun --exclude-missing -c storybook",
"test": "wsrun --fast-exit --package ui -c test",
"ci-test": "NODE_OPTIONS=--max_old_space_size=7000 wsrun --fast-exit --package ui -c test",
"start": "wsrun --package ui -c start"
"start": "wsrun --package ui -c start",
"prepare": "husky install"
},
"dependencies": {
"eslint-plugin-import": "^2.23.4",
"wsrun": "^5.2.4"
},
"devDependencies": {
"eslint": "^7.29.0"
"@typescript-eslint/parser": "^5.19.0",
"eslint": "^7.29.0",
"husky": ">=6",
"lint-staged": ">=10"
},
"resolutions": {
"@polkadot/api": "5.9.1",
Expand All @@ -47,5 +51,11 @@
"engines": {
"node": ">=14.0.0",
"yarn": "^1.22.0"
},
"lint-staged": {
"packages/ui/src/**/*.{js,ts,tsx,html}": [
"eslint --fix",
"prettier --write"
]
}
}
1 change: 1 addition & 0 deletions packages/ui/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ REACT_APP_TESTNET_NODE_SOCKET=wss://rpc.joystream.org:9944
REACT_APP_TESTNET_QUERY_NODE=https://query.joystream.org/graphql
REACT_APP_TESTNET_QUERY_NODE_SOCKET=wss://query.joystream.org/graphql
REACT_APP_TESTNET_MEMBERSHIP_FAUCET_URL=https://18.234.141.38.nip.io/member-faucet/register
REACT_APP_API_BENCHMARK=false
47 changes: 47 additions & 0 deletions packages/ui/dev/helpers/apiBenchmarking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { performance } from 'perf_hooks'

import { ApiPromise, ApiRx } from '@polkadot/api'
import { firstValueFrom, Observable } from 'rxjs'

import { benchmark } from '../../src/common/utils/benchmark'
import { ALICE } from '../node-mocks/data/addresses'
import { withPromiseApi, withRxApi } from '../node-mocks/lib/api'

const ENDPOINT = 'wss://rpc.joystream.org:9944' // TODO pass as a parameter
const DEFAULT_DURATION = 5_000

export const apiBenchmarking = {
command: 'api-benchmarking',
describe: 'Benchmark the chain api',
handler: () =>
benchmarkApi.rxjs(
{
title: 'PaymentInfo',
operation: (api) => api.tx.members.confirmStakingAccount(0, ALICE).paymentInfo(ALICE),
},
{
title: 'voteExistsByProposalByVoter',
operation: (api) => api.query.proposalsEngine.voteExistsByProposalByVoter.size(0, 0),
}
),
}

interface Operation<Api, R> {
title: string
operation: (api: Api, count: number) => R
duration?: number
}

const benchmarkApi = {
promise: (...operations: Operation<ApiPromise, Promise<any>>[]) =>
withPromiseApi(ENDPOINT)(async (api) => {
for (const { title, operation, duration = DEFAULT_DURATION } of operations)
await benchmark(title, (count) => operation(api, count), duration, performance)
}),

rxjs: (...operations: Operation<ApiRx, Observable<any>>[]) =>
withRxApi(ENDPOINT)(async (api) => {
for (const { title, operation, duration = DEFAULT_DURATION } of operations)
await benchmark(title, (count) => firstValueFrom(operation(api, count)), duration, performance)
}),
}
2 changes: 2 additions & 0 deletions packages/ui/dev/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import yargs from 'yargs'

import { apiBenchmarking } from './apiBenchmarking'
import { setChainSpecModule } from './chain-spec'
import { commitmentModule } from './commitment'
import { nextCouncilStageModule } from './nextCouncilStage'

yargs(process.argv.slice(2))
.usage('yarn helpers <command>')
.scriptName('')
.command(apiBenchmarking)
.command(setChainSpecModule)
.command(commitmentModule)
.command(nextCouncilStageModule)
Expand Down
30 changes: 16 additions & 14 deletions packages/ui/dev/node-mocks/commands/council/announce.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import { lockLookup } from '../../../../src/accounts/model/lockTypes'
import { flatMapP, mapP } from '../../../../src/common/utils'
import memberData from '../../../../src/mocks/data/raw/members.json'
import { accountsMap } from '../../data/addresses'
import { signAndSend, withApi } from '../../lib/api'
import { createMembersCommand } from '../members/create'

const announceCandidacies = () => {
const announceCandidacies = async () => {
await createMembersCommand()

withApi(async (api) => {
const candidateCount = api.consts.council.councilSize.toNumber() + 1
const announceStake = api.consts.council.minCandidateStake
const members = memberData.slice(0, candidateCount)

// Create accounts
const nextId = await api.query.members.nextMemberId()
if (Number(nextId) < candidateCount) {
await createMembersCommand()
}

// Fund the empty accounts
const accountToFund = ['charlie', 'dave', 'eve'] as const
const fundingTx = await flatMapP(accountToFund, async (name) => {
const address = accountsMap[name]
const requiredBalance = announceStake.add(api.consts.referendum.minimumStake).muln(1.5) // 1.5 extra margin for potential transaction fees
const memberToFund = members.filter(({ boundAccounts }) => !boundAccounts?.length)
const fundingTx = await flatMapP(memberToFund, async ({ controllerAccount: address }) => {
const { data } = await api.query.system.account(address)
return data.free.toNumber() < 30_000 ? [api.tx.balances.transfer(address, 100_000)] : []
return data.free.lt(requiredBalance) ? [api.tx.balances.transfer(address, requiredBalance)] : []
})

if (fundingTx.length > 0) {
Expand All @@ -37,12 +35,16 @@ const announceCandidacies = () => {
// Confirm staking account
await signAndSend(api.tx.members.confirmStakingAccount(id, address), address)
} else {
// Release stakes
await signAndSend(api.tx.council.releaseCandidacyStake(id), address)
const locks = await api.query.balances.locks(address)

if (locks.some(({ id }) => lockLookup(id) === 'Council Candidate')) {
// Release stakes
await signAndSend(api.tx.council.releaseCandidacyStake(id), address)
}
}

// Announce candidacy
await signAndSend(api.tx.council.announceCandidacy(id, address, address, 15_000), address)
await signAndSend(api.tx.council.announceCandidacy(id, address, address, announceStake), address)
})
})
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/dev/node-mocks/commands/council/reveal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { votes } from './vote'

const revealVotes = () =>
withApi(async (api) => {
await mapP(votes, ({ accountId, optionsId, salt }) =>
await mapP(votes(api), ({ accountId, optionsId, salt }) =>
signAndSend(api.tx.referendum.revealVote(salt, optionsId), accountId)
)
})
Expand Down
20 changes: 9 additions & 11 deletions packages/ui/dev/node-mocks/commands/council/vote.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { ApiPromise } from '@polkadot/api'

import { mapP } from '../../../../src/common/utils'
import { calculateCommitment } from '../../../../src/council/model/calculateCommitment'
import memberData from '../../../../src/mocks/data/raw/members.json'
import { accountsMap } from '../../data/addresses'
import { signAndSend, withApi } from '../../lib/api'

const SALT = '0x0000000000000000000000000000000000000000000000000000000000000001'
export const votes = ([
{ by: 'alice', voteFor: 'alice' },
{ by: 'bob', voteFor: 'bob' },
{ by: 'charlie', voteFor: 'charlie' },
] as const).map(({ by, voteFor }) => ({
accountId: accountsMap[by],
optionsId: memberData.find(({ handle }) => handle === voteFor)?.id as string,
salt: SALT,
}))
export const votes = (api: ApiPromise) => {
const councilSize = api.consts.council.councilSize.toNumber()
return memberData
.slice(0, councilSize)
.map(({ id: optionsId, controllerAccount: accountId }) => ({ accountId, optionsId, salt: SALT }))
}

const castVotes = () =>
withApi(async (api) => {
const stage = await api.query.referendum.stage()
const cycleId = stage.asVoting.current_cycle_id.toNumber()
await mapP(votes, async ({ accountId, optionsId, salt }) => {
await mapP(votes(api), async ({ accountId, optionsId, salt }) => {
const commitment = calculateCommitment(accountId, optionsId, salt, cycleId)
await signAndSend(api.tx.referendum.vote(commitment, 10_000), accountId)
})
Expand Down
9 changes: 7 additions & 2 deletions packages/ui/dev/node-mocks/commands/members/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
import { MembershipMetadata } from '@joystream/metadata-protobuf'

import { metadataToBytes } from '../../../../src/common/model/JoystreamNode'
import memberData from '../../../../src/mocks/data/raw/members.json'
import members from '../../../../src/mocks/data/raw/members.json'
import { getSudoAccount } from '../../data/addresses'
import { signAndSend, withApi } from '../../lib/api'

export const createMembersCommand = async () => {
await withApi(async (api) => {
const members = memberData
const nextId = await api.query.members.nextMemberId()

if (Number(nextId) > 0) {
console.log('Some members were already added')
return
}

const createMembers = members.map((member) => {
return api.tx.members.buyMembership({
Expand Down
35 changes: 35 additions & 0 deletions packages/ui/dev/node-mocks/commands/opening/apply.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ApplicationMetadata } from '@joystream/metadata-protobuf'
import { AnyNumber } from '@polkadot/types/types'

import { getDataFromEvent, metadataToBytes } from '../../../../src/common/model/JoystreamNode'
import memberData from '../../../../src/mocks/data/raw/members.json'
import { GroupIdName } from '../../../../src/working-groups/types'
import { signAndSend, withApi } from '../../lib/api'

const GROUP = 'membershipWorkingGroup'

interface Params {
openingId?: AnyNumber
group?: GroupIdName
}

export const applyOnOpeningCommand = async ({ openingId = 0, group = GROUP }: Params = {}) =>
await withApi(async (api) => {
const alice = memberData[0]

const tx = api.tx[GROUP].applyOnOpening({
member_id: alice.id,
opening_id: openingId,
role_account_id: alice.controllerAccount,
reward_account_id: alice.controllerAccount,
description: metadataToBytes(ApplicationMetadata, {}),
stake_parameters: {
stake: api.consts[group].minimumApplicationStake,
staking_account_id: alice.controllerAccount,
},
})

const events = await signAndSend(tx, alice.controllerAccount)

return String(getDataFromEvent(events, group, 'AppliedOnOpening', 1))
})
52 changes: 31 additions & 21 deletions packages/ui/dev/node-mocks/commands/opening/create.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
/* eslint-disable no-console */
import { OpeningMetadata } from '@joystream/metadata-protobuf'

import { metadataToBytes } from '../../../../src/common/model/JoystreamNode'
import { getDataFromEvent, metadataToBytes } from '../../../../src/common/model/JoystreamNode'
import { GroupIdName } from '../../../../src/working-groups/types'
import { getSudoAccount } from '../../data/addresses'
import { signAndSend, withApi } from '../../lib/api'

const opening = async () => {
await withApi(async (api) => {
const tx = api.tx.membershipWorkingGroup.addOpening(
metadataToBytes(OpeningMetadata, {
title: 'Test opening',
shortDescription: 'Test opening',
description: '# Test opening',
expectedEndingTimestamp: new Date().getTime() + 10000,
hiringLimit: 1,
applicationDetails: 'Details',
applicationFormQuestions: [
{ question: 'Question 1?', type: OpeningMetadata.ApplicationFormQuestion.InputType.TEXT },
{ question: 'Question 2?', type: OpeningMetadata.ApplicationFormQuestion.InputType.TEXTAREA },
],
}),
const GROUP = 'membershipWorkingGroup' // TODO pass as a parameter

export const addOpeningCommand = async ({ group = GROUP }: { group?: GroupIdName } = {}) => {
const title = `Test ${group} opening`

const openingMetadata = {
title,
shortDescription: title,
description: `# ${title}`,
expectedEndingTimestamp: new Date().getTime() + 10000,
hiringLimit: 1,
applicationDetails: 'Details',
applicationFormQuestions: [
{ question: 'Question 1?', type: OpeningMetadata.ApplicationFormQuestion.InputType.TEXT },
{ question: 'Question 2?', type: OpeningMetadata.ApplicationFormQuestion.InputType.TEXTAREA },
],
}

return await withApi(async (api) => {
const tx = api.tx[group].addOpening(
metadataToBytes(OpeningMetadata, openingMetadata),
'Leader',
{ stake_amount: 10_000, leaving_unstaking_period: 360_000 },
{ stake_amount: api.consts[group].minimumApplicationStake, leaving_unstaking_period: 360_000 },
'1337'
)

await signAndSend(api.tx.sudo.sudo(tx), getSudoAccount())
const events = await signAndSend(api.tx.sudo.sudo(tx), getSudoAccount())

return String(getDataFromEvent(events, group, 'OpeningAdded'))
})
}

export const createOpeningModule = {
command: 'opening:create',
describe: 'Create new opening in Membership Working Group',
handler: opening,
describe: 'Create new opening',
handler: async () => {
await addOpeningCommand()
},
}
13 changes: 9 additions & 4 deletions packages/ui/dev/node-mocks/commands/opening/fill.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
/* eslint-disable no-console */
import { registry } from '@joystream/types'
import { ApplicationId } from '@joystream/types/working-group'
import { BTreeSet } from '@polkadot/types'
import yargs from 'yargs'

import { GroupIdName } from '../../../../src/working-groups/types'
import { getSudoAccount } from '../../data/addresses'
import { signAndSend, withApi } from '../../lib/api'

const GROUP = 'membershipWorkingGroup' // TODO pass as a parameter

const options = {
applicationId: {
type: 'string',
Expand All @@ -21,12 +23,15 @@ const options = {
} as const

type CommandOptions = yargs.InferredOptionTypes<typeof options>
export type FillOpeningArgs = yargs.Arguments<CommandOptions>
type FillOpeningArgs = { group?: GroupIdName } & (
| yargs.Arguments<CommandOptions>
| { applicationId: string; openingId: string }
)

const fillOpeningCommand = async ({ applicationId, openingId }: FillOpeningArgs) => {
export const fillOpeningCommand = async ({ applicationId, openingId, group = GROUP }: FillOpeningArgs) => {
await withApi(async (api) => {
const applicationsSet = new (BTreeSet.with(ApplicationId))(registry, [String(applicationId)])
const fillOpening = api.tx.membershipWorkingGroup.fillOpening(String(openingId), applicationsSet)
const fillOpening = api.tx[group].fillOpening(String(openingId), applicationsSet)

await signAndSend(api.tx.sudo.sudo(fillOpening), getSudoAccount())
})
Expand Down
Loading

1 comment on commit 6799dce

@vercel
Copy link

@vercel vercel bot commented on 6799dce May 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

dao – ./

dao.joystream.org
dao-joystream.vercel.app
dao-git-olympia-joystream.vercel.app

Please sign in to comment.