123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806 |
- import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'
- import { Bytes, Option, u32, Vec, StorageKey } from '@polkadot/types'
- import { Codec, ISubmittableResult } from '@polkadot/types/types'
- import { KeyringPair } from '@polkadot/keyring/types'
- import { MemberId, PaidMembershipTerms, PaidTermId } from '@joystream/types/members'
- import { Mint, MintId } from '@joystream/types/mint'
- import {
- Application,
- ApplicationIdToWorkerIdMap,
- Worker,
- WorkerId,
- OpeningPolicyCommitment,
- Opening as WorkingGroupOpening,
- } from '@joystream/types/working-group'
- import { ElectionStake, Seat } from '@joystream/types/council'
- import { AccountInfo, Balance, BalanceOf, BlockNumber, Event, EventRecord } from '@polkadot/types/interfaces'
- import BN from 'bn.js'
- import { SubmittableExtrinsic } from '@polkadot/api/types'
- import { Sender, LogLevel } from './sender'
- import { Utils } from './utils'
- import { Stake, StakedState, StakeId } from '@joystream/types/stake'
- import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards'
- import { types } from '@joystream/types'
- import {
- ActivateOpeningAt,
- Application as HiringApplication,
- ApplicationId,
- Opening as HiringOpening,
- OpeningId,
- } from '@joystream/types/hiring'
- import { FillOpeningParameters, ProposalId } from '@joystream/types/proposals'
- import { v4 as uuid } from 'uuid'
- import { ChannelEntity } from '@joystream/cd-schemas/types/entities/ChannelEntity'
- import { VideoEntity } from '@joystream/cd-schemas/types/entities/VideoEntity'
- import { initializeContentDir, InputParser } from '@joystream/cd-schemas'
- import { OperationType } from '@joystream/types/content-directory'
- import { ContentId, DataObject } from '@joystream/types/media'
- import Debugger from 'debug'
- export enum WorkingGroups {
- StorageWorkingGroup = 'storageWorkingGroup',
- ContentDirectoryWorkingGroup = 'contentDirectoryWorkingGroup',
- }
- export class ApiFactory {
- private readonly api: ApiPromise
- private readonly keyring: Keyring
-
- private readonly treasuryAccount: string
- public static async create(
- provider: WsProvider,
- treasuryAccountUri: string,
- sudoAccountUri: string
- ): Promise<ApiFactory> {
- const debug = Debugger('api-factory')
- let connectAttempts = 0
- while (true) {
- connectAttempts++
- debug(`Connecting to chain, attempt ${connectAttempts}..`)
- try {
- const api = await ApiPromise.create({ provider, types })
-
- await api.isReady
-
-
- await Utils.wait(5000)
- return new ApiFactory(api, treasuryAccountUri, sudoAccountUri)
- } catch (err) {
- if (connectAttempts === 3) {
- throw new Error('Unable to connect to chain')
- }
- }
- await Utils.wait(5000)
- }
- }
- constructor(api: ApiPromise, treasuryAccountUri: string, sudoAccountUri: string) {
- this.api = api
- this.keyring = new Keyring({ type: 'sr25519' })
- this.treasuryAccount = this.keyring.addFromUri(treasuryAccountUri).address
- this.keyring.addFromUri(sudoAccountUri)
- }
- public getApi(label: string): Api {
- return new Api(this.api, this.treasuryAccount, this.keyring, label)
- }
- public close(): void {
- this.api.disconnect()
- }
- }
- export class Api {
- private readonly api: ApiPromise
- private readonly sender: Sender
- private readonly keyring: Keyring
-
- private readonly treasuryAccount: string
- constructor(api: ApiPromise, treasuryAccount: string, keyring: Keyring, label: string) {
- this.api = api
- this.keyring = keyring
- this.treasuryAccount = treasuryAccount
- this.sender = new Sender(api, keyring, label)
- }
- public enableDebugTxLogs(): void {
- this.sender.setLogLevel(LogLevel.Debug)
- }
- public enableVerboseTxLogs(): void {
- this.sender.setLogLevel(LogLevel.Verbose)
- }
- public createKeyPairs(n: number): KeyringPair[] {
- const nKeyPairs: KeyringPair[] = []
- for (let i = 0; i < n; i++) {
- nKeyPairs.push(this.keyring.addFromUri(i + uuid().substring(0, 8)))
- }
- return nKeyPairs
- }
-
- public getWorkingGroupString(workingGroup: WorkingGroups): string {
- switch (workingGroup) {
- case WorkingGroups.StorageWorkingGroup:
- return 'Storage'
- case WorkingGroups.ContentDirectoryWorkingGroup:
- return 'Content'
- default:
- throw new Error(`Invalid working group string representation: ${workingGroup}`)
- }
- }
- public async makeSudoCall(tx: SubmittableExtrinsic<'promise'>): Promise<ISubmittableResult> {
- const sudo = await this.api.query.sudo.key()
- return this.sender.signAndSend(this.api.tx.sudo.sudo(tx), sudo)
- }
- public createPaidTermId(value: BN): PaidTermId {
- return this.api.createType('PaidTermId', value)
- }
- public async buyMembership(account: string, paidTermsId: PaidTermId, name: string): Promise<ISubmittableResult> {
- return this.sender.signAndSend(
- this.api.tx.members.buyMembership(paidTermsId, name, '', ''),
- account
- )
- }
- public getMemberIds(address: string): Promise<MemberId[]> {
- return this.api.query.members.memberIdsByControllerAccountId<Vec<MemberId>>(address)
- }
- public async getBalance(address: string): Promise<Balance> {
- const accountData: AccountInfo = await this.api.query.system.account<AccountInfo>(address)
- return accountData.data.free
- }
- public async transferBalance(from: string, to: string, amount: BN): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx.balances.transfer(to, amount), from)
- }
- public async treasuryTransferBalance(to: string, amount: BN): Promise<ISubmittableResult> {
- return this.transferBalance(this.treasuryAccount, to, amount)
- }
- public treasuryTransferBalanceToAccounts(to: string[], amount: BN): Promise<ISubmittableResult[]> {
- return Promise.all(to.map((account) => this.transferBalance(this.treasuryAccount, account, amount)))
- }
- public getPaidMembershipTerms(paidTermsId: PaidTermId): Promise<PaidMembershipTerms> {
- return this.api.query.members.paidMembershipTermsById<PaidMembershipTerms>(paidTermsId)
- }
- public async getMembershipFee(paidTermsId: PaidTermId): Promise<BN> {
- const terms: PaidMembershipTerms = await this.getPaidMembershipTerms(paidTermsId)
- return terms.fee
- }
-
- private estimateTxFee(tx: SubmittableExtrinsic<'promise'>): BN {
- const byteFee: BN = this.api.createType('BalanceOf', this.api.consts.transactionPayment.transactionByteFee)
- return Utils.calcTxLength(tx).mul(byteFee)
- }
- public estimateBuyMembershipFee(account: string, paidTermsId: PaidTermId, name: string): BN {
- return this.estimateTxFee(
- this.api.tx.members.buyMembership(paidTermsId, name, '', '')
- )
- }
- public estimateApplyForCouncilFee(amount: BN): BN {
- return this.estimateTxFee(this.api.tx.councilElection.apply(amount))
- }
- public estimateVoteForCouncilFee(nominee: string, salt: string, stake: BN): BN {
- const hashedVote: string = Utils.hashVote(nominee, salt)
- return this.estimateTxFee(this.api.tx.councilElection.vote(hashedVote, stake))
- }
- public estimateRevealVoteFee(nominee: string, salt: string): BN {
- const hashedVote: string = Utils.hashVote(nominee, salt)
- return this.estimateTxFee(this.api.tx.councilElection.reveal(hashedVote, nominee, salt))
- }
- public estimateProposeRuntimeUpgradeFee(stake: BN, name: string, description: string, runtime: Bytes | string): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createRuntimeUpgradeProposal(stake, name, description, stake, runtime)
- )
- }
- public estimateProposeTextFee(stake: BN, name: string, description: string, text: string): BN {
- return this.estimateTxFee(this.api.tx.proposalsCodex.createTextProposal(stake, name, description, stake, text))
- }
- public estimateProposeSpendingFee(
- title: string,
- description: string,
- stake: BN,
- balance: BN,
- destination: string
- ): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createSpendingProposal(stake, title, description, stake, balance, destination)
- )
- }
- public estimateProposeValidatorCountFee(title: string, description: string, stake: BN): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createSetValidatorCountProposal(stake, title, description, stake, stake)
- )
- }
- public estimateProposeElectionParametersFee(
- title: string,
- description: string,
- stake: BN,
- announcingPeriod: BN,
- votingPeriod: BN,
- revealingPeriod: BN,
- councilSize: BN,
- candidacyLimit: BN,
- newTermDuration: BN,
- minCouncilStake: BN,
- minVotingStake: BN
- ): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createSetElectionParametersProposal(stake, title, description, stake, {
- announcing_period: announcingPeriod,
- voting_period: votingPeriod,
- revealing_period: revealingPeriod,
- council_size: councilSize,
- candidacy_limit: candidacyLimit,
- new_term_duration: newTermDuration,
- min_council_stake: minCouncilStake,
- min_voting_stake: minVotingStake,
- })
- )
- }
- public estimateVoteForProposalFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsEngine.vote(
- this.api.createType('MemberId', 0),
- this.api.createType('ProposalId', 0),
- 'Approve'
- )
- )
- }
- public estimateAddOpeningFee(module: WorkingGroups): BN {
- const commitment: OpeningPolicyCommitment = this.api.createType('OpeningPolicyCommitment', {
- application_rationing_policy: this.api.createType('Option<ApplicationRationingPolicy>', {
- max_active_applicants: new BN(32) as u32,
- }),
- max_review_period_length: new BN(32) as u32,
- application_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: new BN(1),
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: new BN(1),
- review_period_expired_unstaking_period_length: new BN(1),
- }),
- role_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: new BN(1),
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: new BN(1),
- review_period_expired_unstaking_period_length: new BN(1),
- }),
- role_slashing_terms: this.api.createType('SlashingTerms', {
- Slashable: {
- max_count: new BN(0),
- max_percent_pts_per_time: new BN(0),
- },
- }),
- fill_opening_successful_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- new BN(1)
- ),
- fill_opening_failed_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- new BN(1)
- ),
- fill_opening_failed_applicant_role_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- terminate_application_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- terminate_role_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- exit_role_application_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- exit_role_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- })
- return this.estimateTxFee(
- this.api.tx[module].addOpening('CurrentBlock', commitment, 'Human readable text', 'Worker')
- )
- }
- public estimateAcceptApplicationsFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- (this.api.tx[module].acceptApplications(this.api.createType('OpeningId', 0)) as unknown) as SubmittableExtrinsic<
- 'promise'
- >
- )
- }
- public estimateApplyOnOpeningFee(account: string, module: WorkingGroups): BN {
- return this.estimateTxFee(
- this.api.tx[module].applyOnOpening(
- this.api.createType('MemberId', 0),
- this.api.createType('OpeningId', 0),
- account,
- null,
- null,
- 'Some testing text used for estimation purposes which is longer than text expected during the test'
- )
- )
- }
- public estimateBeginApplicantReviewFee(module: WorkingGroups): BN {
- return this.estimateTxFee(this.api.tx[module].beginApplicantReview(0))
- }
- public estimateFillOpeningFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- this.api.tx[module].fillOpening(0, this.api.createType('ApplicationIdSet', [0]), {
- 'amount_per_payout': 0,
- 'next_payment_at_block': 0,
- 'payout_interval': 0,
- })
- )
- }
- public estimateIncreaseStakeFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- (this.api.tx[module].increaseStake(this.api.createType('WorkerId', 0), 0) as unknown) as SubmittableExtrinsic<
- 'promise'
- >
- )
- }
- public estimateDecreaseStakeFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- (this.api.tx[module].decreaseStake(this.api.createType('WorkerId', 0), 0) as unknown) as SubmittableExtrinsic<
- 'promise'
- >
- )
- }
- public estimateUpdateRoleAccountFee(address: string, module: WorkingGroups): BN {
- return this.estimateTxFee(this.api.tx[module].updateRoleAccount(this.api.createType('WorkerId', 0), address))
- }
- public estimateUpdateRewardAccountFee(address: string, module: WorkingGroups): BN {
- return this.estimateTxFee(this.api.tx[module].updateRewardAccount(this.api.createType('WorkerId', 0), address))
- }
- public estimateLeaveRoleFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- this.api.tx[module].leaveRole(this.api.createType('WorkerId', 0), 'Long justification text')
- )
- }
- public estimateWithdrawApplicationFee(module: WorkingGroups): BN {
- return this.estimateTxFee(this.api.tx[module].withdrawApplication(this.api.createType('ApplicationId', 0)))
- }
- public estimateTerminateApplicationFee(module: WorkingGroups): BN {
- return this.estimateTxFee(this.api.tx[module].terminateApplication(this.api.createType('ApplicationId', 0)))
- }
- public estimateSlashStakeFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- (this.api.tx[module].slashStake(this.api.createType('WorkerId', 0), 0) as unknown) as SubmittableExtrinsic<
- 'promise'
- >
- )
- }
- public estimateTerminateRoleFee(module: WorkingGroups): BN {
- return this.estimateTxFee(
- this.api.tx[module].terminateRole(
- this.api.createType('WorkerId', 0),
- 'Long justification text explaining why the worker role will be terminated',
- false
- )
- )
- }
- public estimateProposeCreateWorkingGroupLeaderOpeningFee(): BN {
- const commitment: OpeningPolicyCommitment = this.api.createType('OpeningPolicyCommitment', {
- application_rationing_policy: this.api.createType('Option<ApplicationRationingPolicy>', {
- max_active_applicants: new BN(32) as u32,
- }),
- max_review_period_length: new BN(32) as u32,
- application_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: new BN(1),
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: new BN(1),
- review_period_expired_unstaking_period_length: new BN(1),
- }),
- role_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: new BN(1),
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: new BN(1),
- review_period_expired_unstaking_period_length: new BN(1),
- }),
- role_slashing_terms: this.api.createType('SlashingTerms', {
- Slashable: {
- max_count: new BN(0),
- max_percent_pts_per_time: new BN(0),
- },
- }),
- fill_opening_successful_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- new BN(1)
- ),
- fill_opening_failed_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- new BN(1)
- ),
- fill_opening_failed_applicant_role_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- terminate_application_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- terminate_role_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- exit_role_application_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- exit_role_stake_unstaking_period: this.api.createType('Option<BlockNumber>', new BN(1)),
- })
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createAddWorkingGroupLeaderOpeningProposal(
- 0,
- 'some long title for the purpose of testing',
- 'some long description for the purpose of testing',
- null,
- {
- activate_at: 'CurrentBlock',
- commitment: commitment,
- human_readable_text: 'Opening readable text',
- working_group: 'Storage',
- }
- )
- )
- }
- public estimateProposeBeginWorkingGroupLeaderApplicationReviewFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createBeginReviewWorkingGroupLeaderApplicationsProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- this.api.createType('OpeningId', 0),
- 'Storage'
- )
- )
- }
- public estimateProposeFillLeaderOpeningFee(): BN {
- const fillOpeningParameters: FillOpeningParameters = this.api.createType('FillOpeningParameters', {
- opening_id: this.api.createType('OpeningId', 0),
- successful_application_id: this.api.createType('ApplicationId', 0),
- reward_policy: this.api.createType('Option<RewardPolicy>', {
- amount_per_payout: new BN(1) as Balance,
- next_payment_at_block: new BN(99999) as BlockNumber,
- payout_interval: this.api.createType('Option<u32>', new BN(99999)),
- }),
- working_group: this.api.createType('WorkingGroup', 'Storage'),
- })
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createFillWorkingGroupLeaderOpeningProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- fillOpeningParameters
- )
- )
- }
- public estimateProposeTerminateLeaderRoleFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createTerminateWorkingGroupLeaderRoleProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- {
- 'worker_id': this.api.createType('WorkerId', 0),
- 'rationale': 'Exceptionaly long and extraordinary descriptive rationale',
- 'slash': true,
- 'working_group': 'Storage',
- }
- )
- )
- }
- public estimateProposeLeaderRewardFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createSetWorkingGroupLeaderRewardProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- this.api.createType('WorkerId', 0),
- 0,
- 'Storage'
- )
- )
- }
- public estimateProposeDecreaseLeaderStakeFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createDecreaseWorkingGroupLeaderStakeProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- this.api.createType('WorkerId', 0),
- 0,
- 'Storage'
- )
- )
- }
- public estimateProposeSlashLeaderStakeFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createSlashWorkingGroupLeaderStakeProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- this.api.createType('WorkerId', 0),
- 0,
- 'Storage'
- )
- )
- }
- public estimateProposeWorkingGroupMintCapacityFee(): BN {
- return this.estimateTxFee(
- this.api.tx.proposalsCodex.createSetWorkingGroupMintCapacityProposal(
- this.api.createType('MemberId', 0),
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- 'Some testing text used for estimation purposes which is longer than text expected during the test',
- null,
- 0,
- 'Storage'
- )
- )
- }
- private applyForCouncilElection(account: string, amount: BN): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx.councilElection.apply(amount), account)
- }
- public batchApplyForCouncilElection(accounts: string[], amount: BN): Promise<ISubmittableResult[]> {
- return Promise.all(accounts.map(async (account) => this.applyForCouncilElection(account, amount)))
- }
- public async getCouncilElectionStake(address: string): Promise<BN> {
- return (((await this.api.query.councilElection.applicantStakes(address)) as unknown) as ElectionStake).new
- }
- private voteForCouncilMember(account: string, nominee: string, salt: string, stake: BN): Promise<ISubmittableResult> {
- const hashedVote: string = Utils.hashVote(nominee, salt)
- return this.sender.signAndSend(this.api.tx.councilElection.vote(hashedVote, stake), account)
- }
- public batchVoteForCouncilMember(
- accounts: string[],
- nominees: string[],
- salt: string[],
- stake: BN
- ): Promise<ISubmittableResult[]> {
- return Promise.all(
- accounts.map(async (account, index) => this.voteForCouncilMember(account, nominees[index], salt[index], stake))
- )
- }
- private revealVote(account: string, commitment: string, nominee: string, salt: string): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx.councilElection.reveal(commitment, nominee, salt), account)
- }
- public batchRevealVote(accounts: string[], nominees: string[], salt: string[]): Promise<ISubmittableResult[]> {
- return Promise.all(
- accounts.map(async (account, index) => {
- const commitment = Utils.hashVote(nominees[index], salt[index])
- return this.revealVote(account, commitment, nominees[index], salt[index])
- })
- )
- }
- public sudoStartAnnouncingPeriod(endsAtBlock: BN): Promise<ISubmittableResult> {
- return this.makeSudoCall(this.api.tx.councilElection.setStageAnnouncing(endsAtBlock))
- }
- public sudoStartVotingPeriod(endsAtBlock: BN): Promise<ISubmittableResult> {
- return this.makeSudoCall(this.api.tx.councilElection.setStageVoting(endsAtBlock))
- }
- public sudoStartRevealingPeriod(endsAtBlock: BN): Promise<ISubmittableResult> {
- return this.makeSudoCall(this.api.tx.councilElection.setStageRevealing(endsAtBlock))
- }
- public sudoSetCouncilMintCapacity(capacity: BN): Promise<ISubmittableResult> {
- return this.makeSudoCall(this.api.tx.council.setCouncilMintCapacity(capacity))
- }
- public getBestBlock(): Promise<BN> {
- return this.api.derive.chain.bestNumber()
- }
- public getCouncil(): Promise<Seat[]> {
- return this.api.query.council.activeCouncil<Vec<Codec>>().then((seats) => {
- return (seats as unknown) as Seat[]
- })
- }
- public async getCouncilAccounts(): Promise<string[]> {
- const council = await this.getCouncil()
- return council.map((seat) => seat.member.toString())
- }
- public async proposeRuntime(
- account: string,
- stake: BN,
- name: string,
- description: string,
- runtime: Bytes | string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createRuntimeUpgradeProposal(memberId, name, description, stake, runtime),
- account
- )
- }
- public async proposeText(
- account: string,
- stake: BN,
- name: string,
- description: string,
- text: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createTextProposal(memberId, name, description, stake, text),
- account
- )
- }
- public async proposeSpending(
- account: string,
- title: string,
- description: string,
- stake: BN,
- balance: BN,
- destination: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createSpendingProposal(memberId, title, description, stake, balance, destination),
- account
- )
- }
- public async proposeValidatorCount(
- account: string,
- title: string,
- description: string,
- stake: BN,
- validatorCount: BN
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createSetValidatorCountProposal(memberId, title, description, stake, validatorCount),
- account
- )
- }
- public async proposeElectionParameters(
- account: string,
- title: string,
- description: string,
- stake: BN,
- announcingPeriod: BN,
- votingPeriod: BN,
- revealingPeriod: BN,
- councilSize: BN,
- candidacyLimit: BN,
- newTermDuration: BN,
- minCouncilStake: BN,
- minVotingStake: BN
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createSetElectionParametersProposal(memberId, title, description, stake, {
- announcing_period: announcingPeriod,
- voting_period: votingPeriod,
- revealing_period: revealingPeriod,
- council_size: councilSize,
- candidacy_limit: candidacyLimit,
- new_term_duration: newTermDuration,
- min_council_stake: minCouncilStake,
- min_voting_stake: minVotingStake,
- }),
- account
- )
- }
- public async proposeBeginWorkingGroupLeaderApplicationReview(
- account: string,
- title: string,
- description: string,
- stake: BN,
- openingId: OpeningId,
- workingGroup: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createBeginReviewWorkingGroupLeaderApplicationsProposal(
- memberId,
- title,
- description,
- stake,
- openingId,
- this.api.createType('WorkingGroup', workingGroup)
- ),
- account
- )
- }
- public approveProposal(account: string, memberId: MemberId, proposal: ProposalId): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx.proposalsEngine.vote(memberId, proposal, 'Approve'), account)
- }
- public async batchApproveProposal(proposal: ProposalId): Promise<ISubmittableResult[]> {
- const councilAccounts = await this.getCouncilAccounts()
- return Promise.all(
- councilAccounts.map(async (account) => {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.approveProposal(account, memberId, proposal)
- })
- )
- }
- public getBlockDuration(): BN {
- return this.api.createType('Moment', this.api.consts.babe.expectedBlockTime)
- }
- public durationInMsFromBlocks(durationInBlocks: number): number {
- return this.getBlockDuration().muln(durationInBlocks).toNumber()
- }
- public findEventRecord(events: EventRecord[], section: string, method: string): EventRecord | undefined {
- return events.find((record) => record.event.section === section && record.event.method === method)
- }
- public findMemberRegisteredEvent(events: EventRecord[]): MemberId | undefined {
- const record = this.findEventRecord(events, 'members', 'MemberRegistered')
- if (record) {
- return record.event.data[0] as MemberId
- }
- }
- public findProposalCreatedEvent(events: EventRecord[]): ProposalId | undefined {
- const record = this.findEventRecord(events, 'proposalsEngine', 'ProposalCreated')
- if (record) {
- return record.event.data[1] as ProposalId
- }
- }
- public findOpeningAddedEvent(events: EventRecord[], workingGroup: WorkingGroups): OpeningId | undefined {
- const record = this.findEventRecord(events, workingGroup, 'OpeningAdded')
- if (record) {
- return record.event.data[0] as OpeningId
- }
- }
- public findLeaderSetEvent(events: EventRecord[], workingGroup: WorkingGroups): WorkerId | undefined {
- const record = this.findEventRecord(events, workingGroup, 'LeaderSet')
- if (record) {
- return (record.event.data as unknown) as WorkerId
- }
- }
- public findBeganApplicationReviewEvent(
- events: EventRecord[],
- workingGroup: WorkingGroups
- ): ApplicationId | undefined {
- const record = this.findEventRecord(events, workingGroup, 'BeganApplicationReview')
- if (record) {
- return (record.event.data as unknown) as ApplicationId
- }
- }
- public findTerminatedLeaderEvent(events: EventRecord[], workingGroup: WorkingGroups): EventRecord | undefined {
- return this.findEventRecord(events, workingGroup, 'TerminatedLeader')
- }
- public findWorkerRewardAmountUpdatedEvent(
- events: EventRecord[],
- workingGroup: WorkingGroups,
- workerId: WorkerId
- ): WorkerId | undefined {
- const record = this.findEventRecord(events, workingGroup, 'WorkerRewardAmountUpdated')
- if (record) {
- const id = (record.event.data[0] as unknown) as WorkerId
- if (id.eq(workerId)) {
- return workerId
- }
- }
- }
- public findStakeDecreasedEvent(events: EventRecord[], workingGroup: WorkingGroups): EventRecord | undefined {
- return this.findEventRecord(events, workingGroup, 'StakeDecreased')
- }
- public findStakeSlashedEvent(events: EventRecord[], workingGroup: WorkingGroups): EventRecord | undefined {
- return this.findEventRecord(events, workingGroup, 'StakeSlashed')
- }
- public findMintCapacityChangedEvent(events: EventRecord[], workingGroup: WorkingGroups): BN | undefined {
- const record = this.findEventRecord(events, workingGroup, 'MintCapacityChanged')
- if (record) {
- return (record.event.data[1] as unknown) as BN
- }
- }
- // Resolves to true when proposal finalized and executed successfully
- // Resolved to false when proposal finalized and execution fails
- public waitForProposalToFinalize(id: ProposalId): Promise<[boolean, EventRecord[]]> {
- return new Promise(async (resolve) => {
- const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>((events) => {
- events.forEach((record) => {
- if (
- record.event.method &&
- record.event.method.toString() === 'ProposalStatusUpdated' &&
- record.event.data[0].eq(id) &&
- record.event.data[1].toString().includes('Executed')
- ) {
- unsubscribe()
- resolve([true, events])
- } else if (
- record.event.method &&
- record.event.method.toString() === 'ProposalStatusUpdated' &&
- record.event.data[0].eq(id) &&
- record.event.data[1].toString().includes('ExecutionFailed')
- ) {
- unsubscribe()
- resolve([false, events])
- }
- })
- })
- })
- }
- public findOpeningFilledEvent(
- events: EventRecord[],
- workingGroup: WorkingGroups
- ): ApplicationIdToWorkerIdMap | undefined {
- const record = this.findEventRecord(events, workingGroup, 'OpeningFilled')
- if (record) {
- return (record.event.data[1] as unknown) as ApplicationIdToWorkerIdMap
- }
- }
- // Looks for the first occurance of an expected event, and resolves.
- // Use this when the event we are expecting is not particular to a specific extrinsic
- public waitForSystemEvent(eventName: string): Promise<Event> {
- return new Promise(async (resolve) => {
- const unsubscribe = await this.api.query.system.events<Vec<EventRecord>>((events) => {
- events.forEach((record) => {
- if (record.event.method && record.event.method.toString() === eventName) {
- unsubscribe()
- resolve(record.event)
- }
- })
- })
- })
- }
- public findApplicationReviewBeganEvent(
- events: EventRecord[],
- workingGroup: WorkingGroups
- ): ApplicationId | undefined {
- const record = this.findEventRecord(events, workingGroup, 'BeganApplicationReview')
- if (record) {
- return (record.event.data as unknown) as ApplicationId
- }
- }
- public async getWorkingGroupMintCapacity(module: WorkingGroups): Promise<BN> {
- const mintId: MintId = await this.api.query[module].mint<MintId>()
- const mint: Mint = await this.api.query.minting.mints<Mint>(mintId)
- return mint.capacity
- }
- public getValidatorCount(): Promise<BN> {
- return this.api.query.staking.validatorCount<u32>()
- }
- public async addOpening(
- lead: string,
- openingParameters: {
- activationDelay: BN
- maxActiveApplicants: BN
- maxReviewPeriodLength: BN
- applicationStakingPolicyAmount: BN
- applicationCrowdedOutUnstakingPeriodLength: BN
- applicationReviewPeriodExpiredUnstakingPeriodLength: BN
- roleStakingPolicyAmount: BN
- roleCrowdedOutUnstakingPeriodLength: BN
- roleReviewPeriodExpiredUnstakingPeriodLength: BN
- slashableMaxCount: BN
- slashableMaxPercentPtsPerTime: BN
- fillOpeningSuccessfulApplicantApplicationStakeUnstakingPeriod: BN
- fillOpeningFailedApplicantApplicationStakeUnstakingPeriod: BN
- fillOpeningFailedApplicantRoleStakeUnstakingPeriod: BN
- terminateApplicationStakeUnstakingPeriod: BN
- terminateRoleStakeUnstakingPeriod: BN
- exitRoleApplicationStakeUnstakingPeriod: BN
- exitRoleStakeUnstakingPeriod: BN
- text: string
- type: string
- },
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- const activateAt: ActivateOpeningAt = this.api.createType(
- 'ActivateOpeningAt',
- openingParameters.activationDelay.eqn(0)
- ? 'CurrentBlock'
- : { ExactBlock: (await this.getBestBlock()).add(openingParameters.activationDelay) }
- )
- const commitment: OpeningPolicyCommitment = this.api.createType('OpeningPolicyCommitment', {
- application_rationing_policy: this.api.createType('Option<ApplicationRationingPolicy>', {
- max_active_applicants: openingParameters.maxActiveApplicants as u32,
- }),
- max_review_period_length: openingParameters.maxReviewPeriodLength as u32,
- application_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: openingParameters.applicationStakingPolicyAmount,
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: openingParameters.applicationCrowdedOutUnstakingPeriodLength,
- review_period_expired_unstaking_period_length:
- openingParameters.applicationReviewPeriodExpiredUnstakingPeriodLength,
- }),
- role_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: openingParameters.roleStakingPolicyAmount,
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: openingParameters.roleCrowdedOutUnstakingPeriodLength,
- review_period_expired_unstaking_period_length: openingParameters.roleReviewPeriodExpiredUnstakingPeriodLength,
- }),
- role_slashing_terms: this.api.createType('SlashingTerms', {
- Slashable: {
- max_count: openingParameters.slashableMaxCount,
- max_percent_pts_per_time: openingParameters.slashableMaxPercentPtsPerTime,
- },
- }),
- fill_opening_successful_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.fillOpeningSuccessfulApplicantApplicationStakeUnstakingPeriod
- ),
- fill_opening_failed_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.fillOpeningFailedApplicantApplicationStakeUnstakingPeriod
- ),
- fill_opening_failed_applicant_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.fillOpeningFailedApplicantRoleStakeUnstakingPeriod
- ),
- terminate_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.terminateApplicationStakeUnstakingPeriod
- ),
- terminate_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.terminateRoleStakeUnstakingPeriod
- ),
- exit_role_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.exitRoleApplicationStakeUnstakingPeriod
- ),
- exit_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.exitRoleStakeUnstakingPeriod
- ),
- })
- return this.sender.signAndSend(
- this.createAddOpeningTransaction(activateAt, commitment, openingParameters.text, openingParameters.type, module),
- lead
- )
- }
- public async sudoAddOpening(
- openingParameters: {
- activationDelay: BN
- maxActiveApplicants: BN
- maxReviewPeriodLength: BN
- applicationStakingPolicyAmount: BN
- applicationCrowdedOutUnstakingPeriodLength: BN
- applicationReviewPeriodExpiredUnstakingPeriodLength: BN
- roleStakingPolicyAmount: BN
- roleCrowdedOutUnstakingPeriodLength: BN
- roleReviewPeriodExpiredUnstakingPeriodLength: BN
- slashableMaxCount: BN
- slashableMaxPercentPtsPerTime: BN
- fillOpeningSuccessfulApplicantApplicationStakeUnstakingPeriod: BN
- fillOpeningFailedApplicantApplicationStakeUnstakingPeriod: BN
- fillOpeningFailedApplicantRoleStakeUnstakingPeriod: BN
- terminateApplicationStakeUnstakingPeriod: BN
- terminateRoleStakeUnstakingPeriod: BN
- exitRoleApplicationStakeUnstakingPeriod: BN
- exitRoleStakeUnstakingPeriod: BN
- text: string
- type: string
- },
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- const activateAt: ActivateOpeningAt = this.api.createType(
- 'ActivateOpeningAt',
- openingParameters.activationDelay.eqn(0)
- ? 'CurrentBlock'
- : { ExactBlock: (await this.getBestBlock()).add(openingParameters.activationDelay) }
- )
- const commitment: OpeningPolicyCommitment = this.api.createType('OpeningPolicyCommitment', {
- application_rationing_policy: this.api.createType('Option<ApplicationRationingPolicy>', {
- max_active_applicants: openingParameters.maxActiveApplicants as u32,
- }),
- max_review_period_length: openingParameters.maxReviewPeriodLength as u32,
- application_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: openingParameters.applicationStakingPolicyAmount,
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: openingParameters.applicationCrowdedOutUnstakingPeriodLength,
- review_period_expired_unstaking_period_length:
- openingParameters.applicationReviewPeriodExpiredUnstakingPeriodLength,
- }),
- role_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: openingParameters.roleStakingPolicyAmount,
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: openingParameters.roleCrowdedOutUnstakingPeriodLength,
- review_period_expired_unstaking_period_length: openingParameters.roleReviewPeriodExpiredUnstakingPeriodLength,
- }),
- role_slashing_terms: this.api.createType('SlashingTerms', {
- Slashable: {
- max_count: openingParameters.slashableMaxCount,
- max_percent_pts_per_time: openingParameters.slashableMaxPercentPtsPerTime,
- },
- }),
- fill_opening_successful_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.fillOpeningSuccessfulApplicantApplicationStakeUnstakingPeriod
- ),
- fill_opening_failed_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.fillOpeningFailedApplicantApplicationStakeUnstakingPeriod
- ),
- fill_opening_failed_applicant_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.fillOpeningFailedApplicantRoleStakeUnstakingPeriod
- ),
- terminate_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.terminateApplicationStakeUnstakingPeriod
- ),
- terminate_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.terminateRoleStakeUnstakingPeriod
- ),
- exit_role_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.exitRoleApplicationStakeUnstakingPeriod
- ),
- exit_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- openingParameters.exitRoleStakeUnstakingPeriod
- ),
- })
- return this.makeSudoCall(
- this.createAddOpeningTransaction(activateAt, commitment, openingParameters.text, openingParameters.type, module)
- )
- }
- public async proposeCreateWorkingGroupLeaderOpening(leaderOpening: {
- account: string
- title: string
- description: string
- proposalStake: BN
- actiavteAt: string
- maxActiveApplicants: BN
- maxReviewPeriodLength: BN
- applicationStakingPolicyAmount: BN
- applicationCrowdedOutUnstakingPeriodLength: BN
- applicationReviewPeriodExpiredUnstakingPeriodLength: BN
- roleStakingPolicyAmount: BN
- roleCrowdedOutUnstakingPeriodLength: BN
- roleReviewPeriodExpiredUnstakingPeriodLength: BN
- slashableMaxCount: BN
- slashableMaxPercentPtsPerTime: BN
- fillOpeningSuccessfulApplicantApplicationStakeUnstakingPeriod: BN
- fillOpeningFailedApplicantApplicationStakeUnstakingPeriod: BN
- fillOpeningFailedApplicantRoleStakeUnstakingPeriod: BN
- terminateApplicationStakeUnstakingPeriod: BN
- terminateRoleStakeUnstakingPeriod: BN
- exitRoleApplicationStakeUnstakingPeriod: BN
- exitRoleStakeUnstakingPeriod: BN
- text: string
- workingGroup: string
- }): Promise<ISubmittableResult> {
- const commitment: OpeningPolicyCommitment = this.api.createType('OpeningPolicyCommitment', {
- application_rationing_policy: this.api.createType('Option<ApplicationRationingPolicy>', {
- max_active_applicants: leaderOpening.maxActiveApplicants as u32,
- }),
- max_review_period_length: leaderOpening.maxReviewPeriodLength as u32,
- application_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: leaderOpening.applicationStakingPolicyAmount,
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: leaderOpening.applicationCrowdedOutUnstakingPeriodLength,
- review_period_expired_unstaking_period_length:
- leaderOpening.applicationReviewPeriodExpiredUnstakingPeriodLength,
- }),
- role_staking_policy: this.api.createType('Option<StakingPolicy>', {
- amount: leaderOpening.roleStakingPolicyAmount,
- amount_mode: 'AtLeast',
- crowded_out_unstaking_period_length: leaderOpening.roleCrowdedOutUnstakingPeriodLength,
- review_period_expired_unstaking_period_length: leaderOpening.roleReviewPeriodExpiredUnstakingPeriodLength,
- }),
- role_slashing_terms: this.api.createType('SlashingTerms', {
- Slashable: {
- max_count: leaderOpening.slashableMaxCount,
- max_percent_pts_per_time: leaderOpening.slashableMaxPercentPtsPerTime,
- },
- }),
- fill_opening_successful_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.fillOpeningSuccessfulApplicantApplicationStakeUnstakingPeriod
- ),
- fill_opening_failed_applicant_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.fillOpeningFailedApplicantApplicationStakeUnstakingPeriod
- ),
- fill_opening_failed_applicant_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.fillOpeningFailedApplicantRoleStakeUnstakingPeriod
- ),
- terminate_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.terminateApplicationStakeUnstakingPeriod
- ),
- terminate_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.terminateRoleStakeUnstakingPeriod
- ),
- exit_role_application_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.exitRoleApplicationStakeUnstakingPeriod
- ),
- exit_role_stake_unstaking_period: this.api.createType(
- 'Option<BlockNumber>',
- leaderOpening.exitRoleStakeUnstakingPeriod
- ),
- })
- const memberId: MemberId = (await this.getMemberIds(leaderOpening.account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createAddWorkingGroupLeaderOpeningProposal(
- memberId,
- leaderOpening.title,
- leaderOpening.description,
- leaderOpening.proposalStake,
- {
- activate_at: leaderOpening.actiavteAt,
- commitment: commitment,
- human_readable_text: leaderOpening.text,
- working_group: leaderOpening.workingGroup,
- }
- ),
- leaderOpening.account
- )
- }
- public async proposeFillLeaderOpening(fillOpening: {
- account: string
- title: string
- description: string
- proposalStake: BN
- openingId: OpeningId
- successfulApplicationId: ApplicationId
- amountPerPayout: BN
- nextPaymentAtBlock: BN
- payoutInterval: BN
- workingGroup: string
- }): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(fillOpening.account))[0]
- const fillOpeningParameters: FillOpeningParameters = this.api.createType('FillOpeningParameters', {
- opening_id: fillOpening.openingId,
- successful_application_id: fillOpening.successfulApplicationId,
- reward_policy: this.api.createType('Option<RewardPolicy>', {
- amount_per_payout: fillOpening.amountPerPayout as Balance,
- next_payment_at_block: fillOpening.nextPaymentAtBlock as BlockNumber,
- payout_interval: this.api.createType('Option<u32>', fillOpening.payoutInterval),
- }),
- working_group: this.api.createType('WorkingGroup', fillOpening.workingGroup),
- })
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createFillWorkingGroupLeaderOpeningProposal(
- memberId,
- fillOpening.title,
- fillOpening.description,
- fillOpening.proposalStake,
- fillOpeningParameters
- ),
- fillOpening.account
- )
- }
- public async proposeTerminateLeaderRole(
- account: string,
- title: string,
- description: string,
- proposalStake: BN,
- leadWorkerId: WorkerId,
- rationale: string,
- slash: boolean,
- workingGroup: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createTerminateWorkingGroupLeaderRoleProposal(
- memberId,
- title,
- description,
- proposalStake,
- {
- 'worker_id': leadWorkerId,
- rationale,
- slash,
- 'working_group': workingGroup,
- }
- ),
- account
- )
- }
- public async proposeLeaderReward(
- account: string,
- title: string,
- description: string,
- proposalStake: BN,
- workerId: WorkerId,
- rewardAmount: BN,
- workingGroup: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createSetWorkingGroupLeaderRewardProposal(
- memberId,
- title,
- description,
- proposalStake,
- workerId,
- rewardAmount,
- this.api.createType('WorkingGroup', workingGroup)
- ),
- account
- )
- }
- public async proposeDecreaseLeaderStake(
- account: string,
- title: string,
- description: string,
- proposalStake: BN,
- workerId: WorkerId,
- rewardAmount: BN,
- workingGroup: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createDecreaseWorkingGroupLeaderStakeProposal(
- memberId,
- title,
- description,
- proposalStake,
- workerId,
- rewardAmount,
- this.api.createType('WorkingGroup', workingGroup)
- ),
- account
- )
- }
- public async proposeSlashLeaderStake(
- account: string,
- title: string,
- description: string,
- proposalStake: BN,
- workerId: WorkerId,
- rewardAmount: BN,
- workingGroup: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createSlashWorkingGroupLeaderStakeProposal(
- memberId,
- title,
- description,
- proposalStake,
- workerId,
- rewardAmount,
- this.api.createType('WorkingGroup', workingGroup)
- ),
- account
- )
- }
- public async proposeWorkingGroupMintCapacity(
- account: string,
- title: string,
- description: string,
- proposalStake: BN,
- mintCapacity: BN,
- workingGroup: string
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx.proposalsCodex.createSetWorkingGroupMintCapacityProposal(
- memberId,
- title,
- description,
- proposalStake,
- mintCapacity,
- this.api.createType('WorkingGroup', workingGroup)
- ),
- account
- )
- }
- private createAddOpeningTransaction(
- actiavteAt: ActivateOpeningAt,
- commitment: OpeningPolicyCommitment,
- text: string,
- type: string,
- module: WorkingGroups
- ): SubmittableExtrinsic<'promise'> {
- return this.api.tx[module].addOpening(actiavteAt, commitment, text, this.api.createType('OpeningType', type))
- }
- public async acceptApplications(
- leader: string,
- openingId: OpeningId,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].acceptApplications(openingId), leader)
- }
- public async beginApplicantReview(
- leader: string,
- openingId: OpeningId,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].beginApplicantReview(openingId), leader)
- }
- public async sudoBeginApplicantReview(openingId: OpeningId, module: WorkingGroups): Promise<ISubmittableResult> {
- return this.makeSudoCall(this.api.tx[module].beginApplicantReview(openingId))
- }
- public async applyOnOpening(
- account: string,
- roleAccountAddress: string,
- openingId: OpeningId,
- roleStake: BN,
- applicantStake: BN,
- text: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- const memberId: MemberId = (await this.getMemberIds(account))[0]
- return this.sender.signAndSend(
- this.api.tx[module].applyOnOpening(memberId, openingId, roleAccountAddress, roleStake, applicantStake, text),
- account
- )
- }
- public async batchApplyOnOpening(
- accounts: string[],
- openingId: OpeningId,
- roleStake: BN,
- applicantStake: BN,
- text: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult[]> {
- return Promise.all(
- accounts.map(async (account) =>
- this.applyOnOpening(account, account, openingId, roleStake, applicantStake, text, module)
- )
- )
- }
- public async fillOpening(
- leader: string,
- openingId: OpeningId,
- applicationIds: ApplicationId[],
- amountPerPayout: BN,
- nextPaymentBlock: BN,
- payoutInterval: BN,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(
- this.api.tx[module].fillOpening(openingId, this.api.createType('ApplicationIdSet', applicationIds), {
- amount_per_payout: amountPerPayout,
- next_payment_at_block: nextPaymentBlock,
- payout_interval: payoutInterval,
- }),
- leader
- )
- }
- public async sudoFillOpening(
- openingId: OpeningId,
- applicationIds: ApplicationId[],
- amountPerPayout: BN,
- nextPaymentBlock: BN,
- payoutInterval: BN,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.makeSudoCall(
- this.api.tx[module].fillOpening(openingId, this.api.createType('ApplicationIdSet', applicationIds), {
- 'amount_per_payout': amountPerPayout,
- 'next_payment_at_block': nextPaymentBlock,
- 'payout_interval': payoutInterval,
- })
- )
- }
- public async increaseStake(
- worker: string,
- workerId: WorkerId,
- stake: BN,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].increaseStake(workerId, stake), worker)
- }
- public async decreaseStake(
- leader: string,
- workerId: WorkerId,
- stake: BN,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].decreaseStake(workerId, stake), leader)
- }
- public async slashStake(
- leader: string,
- workerId: WorkerId,
- stake: BN,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].slashStake(workerId, stake), leader)
- }
- public async updateRoleAccount(
- worker: string,
- workerId: WorkerId,
- newRoleAccount: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].updateRoleAccount(workerId, newRoleAccount), worker)
- }
- public async updateRewardAccount(
- worker: string,
- workerId: WorkerId,
- newRewardAccount: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].updateRewardAccount(workerId, newRewardAccount), worker)
- }
- public async withdrawApplication(
- account: string,
- applicationId: ApplicationId,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].withdrawApplication(applicationId), account)
- }
- public async batchWithdrawActiveApplications(
- applicationIds: ApplicationId[],
- module: WorkingGroups
- ): Promise<ISubmittableResult[]> {
- const entries: [StorageKey, Application][] = await this.api.query[module].applicationById.entries<Application>()
- return Promise.all(
- entries
- .filter(([idKey]) => {
- return applicationIds.includes(idKey.args[0] as ApplicationId)
- })
- .map(([idKey, application]) => ({
- id: idKey.args[0] as ApplicationId,
- account: application.role_account_id.toString(),
- }))
- .map(({ id, account }) => this.withdrawApplication(account, id, module))
- )
- }
- public async terminateApplication(
- leader: string,
- applicationId: ApplicationId,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].terminateApplication(applicationId), leader)
- }
- public async batchTerminateApplication(
- leader: string,
- applicationIds: ApplicationId[],
- module: WorkingGroups
- ): Promise<ISubmittableResult[]> {
- return Promise.all(applicationIds.map((id) => this.terminateApplication(leader, id, module)))
- }
- public async terminateRole(
- leader: string,
- workerId: WorkerId,
- text: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].terminateRole(workerId, text, false), leader)
- }
- public async leaveRole(
- account: string,
- workerId: WorkerId,
- text: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult> {
- return this.sender.signAndSend(this.api.tx[module].leaveRole(workerId, text), account)
- }
- public async batchLeaveRole(
- workerIds: WorkerId[],
- text: string,
- module: WorkingGroups
- ): Promise<ISubmittableResult[]> {
- return Promise.all(
- workerIds.map(async (workerId) => {
-
- const worker = await this.getWorkerById(workerId, module)
- return this.leaveRole(worker.role_account_id.toString(), workerId, text, module)
- })
- )
- }
- public async getAnnouncingPeriod(): Promise<BN> {
- return this.api.query.councilElection.announcingPeriod<BlockNumber>()
- }
- public async getVotingPeriod(): Promise<BN> {
- return this.api.query.councilElection.votingPeriod<BlockNumber>()
- }
- public async getRevealingPeriod(): Promise<BN> {
- return this.api.query.councilElection.revealingPeriod<BlockNumber>()
- }
- public async getCouncilSize(): Promise<BN> {
- return this.api.query.councilElection.councilSize<u32>()
- }
- public async getCandidacyLimit(): Promise<BN> {
- return this.api.query.councilElection.candidacyLimit<u32>()
- }
- public async getNewTermDuration(): Promise<BN> {
- return this.api.query.councilElection.newTermDuration<BlockNumber>()
- }
- public async getMinCouncilStake(): Promise<BN> {
- return this.api.query.councilElection.minCouncilStake<BalanceOf>()
- }
- public async getMinVotingStake(): Promise<BN> {
- return this.api.query.councilElection.minVotingStake<BalanceOf>()
- }
- public async getHiringOpening(id: OpeningId): Promise<HiringOpening> {
- return await this.api.query.hiring.openingById<HiringOpening>(id)
- }
- public async getWorkingGroupOpening(id: OpeningId, group: WorkingGroups): Promise<WorkingGroupOpening> {
- return await this.api.query[group].openingById<WorkingGroupOpening>(id)
- }
- public async getWorkers(module: WorkingGroups): Promise<Worker[]> {
- return (await this.api.query[module].workerById.entries<Worker>()).map((workerWithId) => workerWithId[1])
- }
- public async getWorkerById(id: WorkerId, module: WorkingGroups): Promise<Worker> {
- return await this.api.query[module].workerById<Worker>(id)
- }
- public async isWorker(workerId: WorkerId, module: WorkingGroups): Promise<boolean> {
- const workersAndIds: [StorageKey, Worker][] = await this.api.query[module].workerById.entries<Worker>()
- const index: number = workersAndIds.findIndex((workersAndId) => workersAndId[0].args[0].eq(workerId))
- return index !== -1
- }
- public async getApplicationsIdsByRoleAccount(address: string, module: WorkingGroups): Promise<ApplicationId[]> {
- const applicationsAndIds: [StorageKey, Application][] = await this.api.query[module].applicationById.entries<
- Application
- >()
- return applicationsAndIds
- .map((applicationWithId) => {
- const application: Application = applicationWithId[1]
- return application.role_account_id.toString() === address
- ? (applicationWithId[0].args[0] as ApplicationId)
- : undefined
- })
- .filter((id) => id !== undefined) as ApplicationId[]
- }
- public async getHiringApplicationById(id: ApplicationId): Promise<HiringApplication> {
- return this.api.query.hiring.applicationById<HiringApplication>(id)
- }
- public async getApplicationById(id: ApplicationId, module: WorkingGroups): Promise<Application> {
- return this.api.query[module].applicationById<Application>(id)
- }
- public async getApplicantRoleAccounts(filterActiveIds: ApplicationId[], module: WorkingGroups): Promise<string[]> {
- const entries: [StorageKey, Application][] = await this.api.query[module].applicationById.entries<Application>()
- const applications = entries
- .filter(([idKey]) => {
- return filterActiveIds.includes(idKey.args[0] as ApplicationId)
- })
- .map(([, application]) => application)
- return (
- await Promise.all(
- applications.map(async (application) => {
- const active = (await this.getHiringApplicationById(application.application_id)).stage.type === 'Active'
- return active ? application.role_account_id.toString() : ''
- })
- )
- ).filter((addr) => addr !== '')
- }
- public async getWorkerRoleAccounts(workerIds: WorkerId[], module: WorkingGroups): Promise<string[]> {
- const entries: [StorageKey, Worker][] = await this.api.query[module].workerById.entries<Worker>()
- return entries
- .filter(([idKey]) => {
- return workerIds.includes(idKey.args[0] as WorkerId)
- })
- .map(([, worker]) => worker.role_account_id.toString())
- }
- public async getStake(id: StakeId): Promise<Stake> {
- return this.api.query.stake.stakes<Stake>(id)
- }
- public async getWorkerStakeAmount(workerId: WorkerId, module: WorkingGroups): Promise<BN> {
- const stakeId: StakeId = (await this.getWorkerById(workerId, module)).role_stake_profile.unwrap().stake_id
- return (((await this.getStake(stakeId)).staking_status.value as unknown) as StakedState).staked_amount
- }
- public async getRewardRelationship(id: RewardRelationshipId): Promise<RewardRelationship> {
- return this.api.query.recurringRewards.rewardRelationships<RewardRelationship>(id)
- }
- public async getWorkerRewardRelationship(workerId: WorkerId, module: WorkingGroups): Promise<RewardRelationship> {
- const rewardRelationshipId: RewardRelationshipId = (
- await this.getWorkerById(workerId, module)
- ).reward_relationship.unwrap()
- return this.getRewardRelationship(rewardRelationshipId)
- }
- public async getWorkerRewardAccount(workerId: WorkerId, module: WorkingGroups): Promise<string> {
- const rewardRelationshipId: RewardRelationshipId = (
- await this.getWorkerById(workerId, module)
- ).reward_relationship.unwrap()
- return (await this.getRewardRelationship(rewardRelationshipId)).getField('account').toString()
- }
- public async getLeadWorkerId(module: WorkingGroups): Promise<WorkerId | undefined> {
- return (await this.api.query[module].currentLead<Option<WorkerId>>()).unwrapOr(undefined)
- }
- public async getGroupLead(module: WorkingGroups): Promise<Worker | undefined> {
- const leadId = await this.getLeadWorkerId(module)
- return leadId ? this.getWorkerById(leadId, module) : undefined
- }
- public async getActiveWorkersCount(module: WorkingGroups): Promise<BN> {
- return this.api.query[module].activeWorkerCount<u32>()
- }
- public getMaxWorkersCount(module: WorkingGroups): BN {
- return this.api.createType('u32', this.api.consts[module].maxWorkerNumberLimit)
- }
- async sendContentDirectoryTransaction(operations: OperationType[]): Promise<ISubmittableResult> {
- const transaction = this.api.tx.contentDirectory.transaction(
- { Lead: null },
- operations
- )
- const lead = (await this.getGroupLead(WorkingGroups.ContentDirectoryWorkingGroup)) as Worker
- return this.sender.signAndSend(transaction, lead.role_account_id)
- }
- public async createChannelEntity(channel: ChannelEntity): Promise<ISubmittableResult> {
- // Create the parser with known entity schemas (the ones in content-directory-schemas/inputs)
- const parser = InputParser.createWithKnownSchemas(
- this.api,
-
- [
- {
- className: 'Channel',
- entries: [channel],
- },
- ]
- )
- // We parse the input into CreateEntity and AddSchemaSupportToEntity operations
- const operations = await parser.getEntityBatchOperations()
- return this.sendContentDirectoryTransaction(operations)
- }
- public async createVideoEntity(video: VideoEntity): Promise<ISubmittableResult> {
- // Create the parser with known entity schemas (the ones in content-directory-schemas/inputs)
- const parser = InputParser.createWithKnownSchemas(
- this.api,
-
- [
- {
- className: 'Video',
- entries: [video],
- },
- ]
- )
- // We parse the input into CreateEntity and AddSchemaSupportToEntity operations
- const operations = await parser.getEntityBatchOperations()
- return this.sendContentDirectoryTransaction(operations)
- }
- public async updateChannelEntity(
- channelUpdateInput: Record<string, any>,
- uniquePropValue: Record<string, any>
- ): Promise<ISubmittableResult> {
- // Create the parser with known entity schemas (the ones in content-directory-schemas/inputs)
- const parser = InputParser.createWithKnownSchemas(this.api)
- // We can reuse InputParser's `findEntityIdByUniqueQuery` method to find entityId of the channel we
- // created in ./createChannel.ts example (normally we would probably use some other way to do it, ie.: query node)
- const CHANNEL_ID = await parser.findEntityIdByUniqueQuery(uniquePropValue, 'Channel') // Use getEntityUpdateOperations to parse the update input
- const updateOperations = await parser.getEntityUpdateOperations(
- channelUpdateInput,
- 'Channel',
- CHANNEL_ID
- )
- return this.sendContentDirectoryTransaction(updateOperations)
- }
- async getDataByContentId(contentId: ContentId): Promise<DataObject | null> {
- const dataObject = await this.api.query.dataDirectory.DataByContentId<Option<DataObject>>(contentId)
- return dataObject.unwrapOr(null)
- }
- public async initializeContentDirectory(): Promise<void> {
- const lead = await this.getGroupLead(WorkingGroups.ContentDirectoryWorkingGroup)
- if (!lead) {
- throw new Error('No Lead is set for storage wokring group')
- }
- const leadKeyPair = this.keyring.getPair(lead.role_account_id.toString())
- return initializeContentDir(this.api, leadKeyPair)
- }
- }
|