apiWrapper.ts 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326
  1. import { ApiPromise, WsProvider } from '@polkadot/api';
  2. import { Option, Vec, Bytes, u32 } from '@polkadot/types';
  3. import { Codec } from '@polkadot/types/types';
  4. import { KeyringPair } from '@polkadot/keyring/types';
  5. import { UserInfo, PaidMembershipTerms, MemberId } from '@nicaea/types/members';
  6. import { Mint, MintId } from '@nicaea/types/mint';
  7. import { Lead, LeadId } from '@nicaea/types/content-working-group';
  8. import { Application, WorkerId, Worker, ApplicationIdToWorkerIdMap, Opening } from '@nicaea/types/working-group';
  9. import { Application as HiringApplication } from '@nicaea/types/hiring';
  10. import { RoleParameters } from '@nicaea/types/roles';
  11. import { Seat } from '@nicaea/types/lib/council';
  12. import { Balance, EventRecord, AccountId, BlockNumber, BalanceOf } from '@polkadot/types/interfaces';
  13. import BN from 'bn.js';
  14. import { SubmittableExtrinsic } from '@polkadot/api/types';
  15. import { Sender } from './sender';
  16. import { Utils } from './utils';
  17. import { Stake, StakedState } from '@nicaea/types/stake';
  18. import { RewardRelationship } from '@nicaea/types/recurring-rewards';
  19. import { Opening as HiringOpening, ApplicationId } from '@nicaea/types/hiring';
  20. export class ApiWrapper {
  21. private readonly api: ApiPromise;
  22. private readonly sender: Sender;
  23. public static async create(provider: WsProvider): Promise<ApiWrapper> {
  24. const api = await ApiPromise.create({ provider });
  25. return new ApiWrapper(api);
  26. }
  27. constructor(api: ApiPromise) {
  28. this.api = api;
  29. this.sender = new Sender(api);
  30. }
  31. public close() {
  32. this.api.disconnect();
  33. }
  34. public async buyMembership(
  35. account: KeyringPair,
  36. paidTermsId: number,
  37. name: string,
  38. expectFailure = false
  39. ): Promise<void> {
  40. return this.sender.signAndSend(
  41. this.api.tx.members.buyMembership(paidTermsId, new UserInfo({ handle: name, avatar_uri: '', about: '' })),
  42. account,
  43. expectFailure
  44. );
  45. }
  46. public getMemberIds(address: string): Promise<MemberId[]> {
  47. return this.api.query.members.memberIdsByControllerAccountId<Vec<MemberId>>(address);
  48. }
  49. public getBalance(address: string): Promise<Balance> {
  50. return this.api.query.balances.freeBalance<Balance>(address);
  51. }
  52. public async transferBalance(from: KeyringPair, to: string, amount: BN): Promise<void> {
  53. return this.sender.signAndSend(this.api.tx.balances.transfer(to, amount), from);
  54. }
  55. public getPaidMembershipTerms(paidTermsId: number): Promise<Option<PaidMembershipTerms>> {
  56. return this.api.query.members.paidMembershipTermsById<Option<PaidMembershipTerms>>(paidTermsId);
  57. }
  58. public getMembershipFee(paidTermsId: number): Promise<BN> {
  59. return this.getPaidMembershipTerms(paidTermsId).then(terms => terms.unwrap().fee.toBn());
  60. }
  61. public async transferBalanceToAccounts(from: KeyringPair, to: KeyringPair[], amount: BN): Promise<void[]> {
  62. return Promise.all(
  63. to.map(async keyPair => {
  64. await this.transferBalance(from, keyPair.address, amount);
  65. })
  66. );
  67. }
  68. private getBaseTxFee(): BN {
  69. return this.api.createType('BalanceOf', this.api.consts.transactionPayment.transactionBaseFee).toBn();
  70. }
  71. private estimateTxFee(tx: SubmittableExtrinsic<'promise'>): BN {
  72. const baseFee: BN = this.getBaseTxFee();
  73. const byteFee: BN = this.api.createType('BalanceOf', this.api.consts.transactionPayment.transactionByteFee).toBn();
  74. return Utils.calcTxLength(tx).mul(byteFee).add(baseFee);
  75. }
  76. public estimateBuyMembershipFee(account: KeyringPair, paidTermsId: number, name: string): BN {
  77. return this.estimateTxFee(
  78. this.api.tx.members.buyMembership(paidTermsId, new UserInfo({ handle: name, avatar_uri: '', about: '' }))
  79. );
  80. }
  81. public estimateApplyForCouncilFee(amount: BN): BN {
  82. return this.estimateTxFee(this.api.tx.councilElection.apply(amount));
  83. }
  84. public estimateVoteForCouncilFee(nominee: string, salt: string, stake: BN): BN {
  85. const hashedVote: string = Utils.hashVote(nominee, salt);
  86. return this.estimateTxFee(this.api.tx.councilElection.vote(hashedVote, stake));
  87. }
  88. public estimateRevealVoteFee(nominee: string, salt: string): BN {
  89. const hashedVote: string = Utils.hashVote(nominee, salt);
  90. return this.estimateTxFee(this.api.tx.councilElection.reveal(hashedVote, nominee, salt));
  91. }
  92. public estimateProposeRuntimeUpgradeFee(stake: BN, name: string, description: string, runtime: Bytes | string): BN {
  93. return this.estimateTxFee(
  94. this.api.tx.proposalsCodex.createRuntimeUpgradeProposal(stake, name, description, stake, runtime)
  95. );
  96. }
  97. public estimateProposeTextFee(stake: BN, name: string, description: string, text: string): BN {
  98. return this.estimateTxFee(this.api.tx.proposalsCodex.createTextProposal(stake, name, description, stake, text));
  99. }
  100. public estimateProposeSpendingFee(
  101. title: string,
  102. description: string,
  103. stake: BN,
  104. balance: BN,
  105. destination: string
  106. ): BN {
  107. return this.estimateTxFee(
  108. this.api.tx.proposalsCodex.createSpendingProposal(stake, title, description, stake, balance, destination)
  109. );
  110. }
  111. public estimateProposeWorkingGroupMintCapacityFee(title: string, description: string, stake: BN, balance: BN): BN {
  112. return this.estimateTxFee(
  113. this.api.tx.proposalsCodex.createSetContentWorkingGroupMintCapacityProposal(
  114. stake,
  115. title,
  116. description,
  117. stake,
  118. balance
  119. )
  120. );
  121. }
  122. public estimateProposeValidatorCountFee(title: string, description: string, stake: BN): BN {
  123. return this.estimateTxFee(
  124. this.api.tx.proposalsCodex.createSetValidatorCountProposal(stake, title, description, stake, stake)
  125. );
  126. }
  127. public estimateProposeLeadFee(title: string, description: string, stake: BN, address: string): BN {
  128. return this.estimateTxFee(
  129. this.api.tx.proposalsCodex.createSetLeadProposal(stake, title, description, stake, { stake, address })
  130. );
  131. }
  132. public estimateProposeEvictStorageProviderFee(title: string, description: string, stake: BN, address: string): BN {
  133. return this.estimateTxFee(
  134. this.api.tx.proposalsCodex.createEvictStorageProviderProposal(stake, title, description, stake, address)
  135. );
  136. }
  137. public estimateProposeStorageRoleParametersFee(
  138. title: string,
  139. description: string,
  140. stake: BN,
  141. minStake: BN,
  142. minActors: BN,
  143. maxActors: BN,
  144. reward: BN,
  145. rewardPeriod: BN,
  146. bondingPeriod: BN,
  147. unbondingPeriod: BN,
  148. minServicePeriod: BN,
  149. startupGracePeriod: BN,
  150. entryRequestFee: BN
  151. ): BN {
  152. return this.estimateTxFee(
  153. this.api.tx.proposalsCodex.createSetStorageRoleParametersProposal(stake, title, description, stake, [
  154. minStake,
  155. minActors,
  156. maxActors,
  157. reward,
  158. rewardPeriod,
  159. bondingPeriod,
  160. unbondingPeriod,
  161. minServicePeriod,
  162. startupGracePeriod,
  163. entryRequestFee,
  164. ])
  165. );
  166. }
  167. public estimateProposeElectionParametersFee(
  168. title: string,
  169. description: string,
  170. stake: BN,
  171. announcingPeriod: BN,
  172. votingPeriod: BN,
  173. revealingPeriod: BN,
  174. councilSize: BN,
  175. candidacyLimit: BN,
  176. newTermDuration: BN,
  177. minCouncilStake: BN,
  178. minVotingStake: BN
  179. ): BN {
  180. return this.estimateTxFee(
  181. this.api.tx.proposalsCodex.createSetElectionParametersProposal(stake, title, description, stake, [
  182. announcingPeriod,
  183. votingPeriod,
  184. revealingPeriod,
  185. councilSize,
  186. candidacyLimit,
  187. newTermDuration,
  188. minCouncilStake,
  189. minVotingStake,
  190. ])
  191. );
  192. }
  193. public estimateVoteForProposalFee(): BN {
  194. return this.estimateTxFee(this.api.tx.proposalsEngine.vote(0, 0, 'Approve'));
  195. }
  196. public estimateAddOpeningFee(): BN {
  197. return this.estimateTxFee(
  198. this.api.tx.storageWorkingGroup.addOpening(
  199. 'CurrentBlock',
  200. {
  201. application_rationing_policy: { max_active_applicants: '32' },
  202. max_review_period_length: 32,
  203. application_staking_policy: {
  204. amount: 0,
  205. amount_mode: 'AtLeast',
  206. crowded_out_unstaking_period_length: 0,
  207. review_period_expired_unstaking_period_length: 0,
  208. },
  209. role_staking_policy: {
  210. amount: 0,
  211. amount_mode: 'AtLeast',
  212. crowded_out_unstaking_period_length: 0,
  213. review_period_expired_unstaking_period_length: 0,
  214. },
  215. role_slashing_terms: {
  216. Slashable: {
  217. max_count: 0,
  218. max_percent_pts_per_time: 0,
  219. },
  220. },
  221. fill_opening_successful_applicant_application_stake_unstaking_period: 0,
  222. fill_opening_failed_applicant_application_stake_unstaking_period: 0,
  223. fill_opening_failed_applicant_role_stake_unstaking_period: 0,
  224. terminate_curator_application_stake_unstaking_period: 0,
  225. terminate_curator_role_stake_unstaking_period: 0,
  226. exit_curator_role_application_stake_unstaking_period: 0,
  227. exit_curator_role_stake_unstaking_period: 0,
  228. },
  229. 'Opening readable text',
  230. 'Worker'
  231. )
  232. );
  233. }
  234. public estimateProposeCreateWorkingGroupLeaderOpening(): BN {
  235. return this.estimateTxFee(
  236. this.api.tx.proposalsCodex.createAddWorkingGroupLeaderOpeningProposal(
  237. 0,
  238. 'some long title for the purpose of testing',
  239. 'some long description for the purpose of testing',
  240. 0,
  241. {
  242. activate_at: 'CurrentBlock',
  243. commitment: {
  244. application_rationing_policy: { max_active_applicants: '32' },
  245. max_review_period_length: 32,
  246. application_staking_policy: {
  247. amount: 0,
  248. amount_mode: 'AtLeast',
  249. crowded_out_unstaking_period_length: 0,
  250. review_period_expired_unstaking_period_length: 0,
  251. },
  252. role_staking_policy: {
  253. amount: 0,
  254. amount_mode: 'AtLeast',
  255. crowded_out_unstaking_period_length: 0,
  256. review_period_expired_unstaking_period_length: 0,
  257. },
  258. role_slashing_terms: {
  259. Slashable: {
  260. max_count: 0,
  261. max_percent_pts_per_time: 0,
  262. },
  263. },
  264. fill_opening_successful_applicant_application_stake_unstaking_period: 0,
  265. fill_opening_failed_applicant_application_stake_unstaking_period: 0,
  266. fill_opening_failed_applicant_role_stake_unstaking_period: 0,
  267. terminate_curator_application_stake_unstaking_period: 0,
  268. terminate_curator_role_stake_unstaking_period: 0,
  269. exit_curator_role_application_stake_unstaking_period: 0,
  270. exit_curator_role_stake_unstaking_period: 0,
  271. },
  272. human_readable_text: 'Opening readable text',
  273. working_group: 'Storage',
  274. }
  275. )
  276. );
  277. }
  278. public estimateAcceptApplicationsFee(): BN {
  279. return this.estimateTxFee(this.api.tx.storageWorkingGroup.acceptApplications(0));
  280. }
  281. public estimateApplyOnOpeningFee(account: KeyringPair): BN {
  282. return this.estimateTxFee(
  283. this.api.tx.storageWorkingGroup.applyOnOpening(
  284. 0,
  285. 0,
  286. account.address,
  287. 0,
  288. 0,
  289. 'Some testing text used for estimation purposes which is longer than text expected during the test'
  290. )
  291. );
  292. }
  293. public estimateBeginApplicantReviewFee(): BN {
  294. return this.estimateTxFee(this.api.tx.storageWorkingGroup.beginApplicantReview(0));
  295. }
  296. public estimateFillOpeningFee(): BN {
  297. return this.estimateTxFee(
  298. this.api.tx.storageWorkingGroup.fillOpening(0, [0], {
  299. amount_per_payout: 0,
  300. next_payment_at_block: 0,
  301. payout_interval: 0,
  302. })
  303. );
  304. }
  305. public estimateIncreaseStakeFee(): BN {
  306. return this.estimateTxFee(this.api.tx.storageWorkingGroup.increaseStake(0, 0));
  307. }
  308. public estimateDecreaseStakeFee(): BN {
  309. return this.estimateTxFee(this.api.tx.storageWorkingGroup.decreaseStake(0, 0));
  310. }
  311. public estimateUpdateRoleAccountFee(address: string): BN {
  312. return this.estimateTxFee(this.api.tx.storageWorkingGroup.updateRoleAccount(0, address));
  313. }
  314. public estimateUpdateRewardAccountFee(address: string): BN {
  315. return this.estimateTxFee(this.api.tx.storageWorkingGroup.updateRewardAccount(0, address));
  316. }
  317. public estimateLeaveRoleFee(): BN {
  318. return this.estimateTxFee(this.api.tx.storageWorkingGroup.leaveRole(0, 'Long justification text'));
  319. }
  320. public estimateWithdrawApplicationFee(): BN {
  321. return this.estimateTxFee(this.api.tx.storageWorkingGroup.withdrawApplication(0));
  322. }
  323. public estimateTerminateApplicationFee(): BN {
  324. return this.estimateTxFee(this.api.tx.storageWorkingGroup.terminateApplication(0));
  325. }
  326. public estimateSlashStakeFee(): BN {
  327. return this.estimateTxFee(this.api.tx.storageWorkingGroup.slashStake(0, 0));
  328. }
  329. public estimateTerminateRoleFee(): BN {
  330. return this.estimateTxFee(
  331. this.api.tx.storageWorkingGroup.terminateRole(
  332. 0,
  333. 'Long justification text explaining why the worker role will be terminated',
  334. false
  335. )
  336. );
  337. }
  338. private applyForCouncilElection(account: KeyringPair, amount: BN): Promise<void> {
  339. return this.sender.signAndSend(this.api.tx.councilElection.apply(amount), account, false);
  340. }
  341. public batchApplyForCouncilElection(accounts: KeyringPair[], amount: BN): Promise<void[]> {
  342. return Promise.all(
  343. accounts.map(async keyPair => {
  344. await this.applyForCouncilElection(keyPair, amount);
  345. })
  346. );
  347. }
  348. public async getCouncilElectionStake(address: string): Promise<BN> {
  349. // TODO alter then `applicantStake` type will be introduced
  350. return this.api.query.councilElection.applicantStakes(address).then(stake => {
  351. const parsed = JSON.parse(stake.toString());
  352. return new BN(parsed.new);
  353. });
  354. }
  355. private voteForCouncilMember(account: KeyringPair, nominee: string, salt: string, stake: BN): Promise<void> {
  356. const hashedVote: string = Utils.hashVote(nominee, salt);
  357. return this.sender.signAndSend(this.api.tx.councilElection.vote(hashedVote, stake), account, false);
  358. }
  359. public batchVoteForCouncilMember(
  360. accounts: KeyringPair[],
  361. nominees: KeyringPair[],
  362. salt: string[],
  363. stake: BN
  364. ): Promise<void[]> {
  365. return Promise.all(
  366. accounts.map(async (keyPair, index) => {
  367. await this.voteForCouncilMember(keyPair, nominees[index].address, salt[index], stake);
  368. })
  369. );
  370. }
  371. private revealVote(account: KeyringPair, commitment: string, nominee: string, salt: string): Promise<void> {
  372. return this.sender.signAndSend(this.api.tx.councilElection.reveal(commitment, nominee, salt), account, false);
  373. }
  374. public batchRevealVote(accounts: KeyringPair[], nominees: KeyringPair[], salt: string[]): Promise<void[]> {
  375. return Promise.all(
  376. accounts.map(async (keyPair, index) => {
  377. const commitment = Utils.hashVote(nominees[index].address, salt[index]);
  378. await this.revealVote(keyPair, commitment, nominees[index].address, salt[index]);
  379. })
  380. );
  381. }
  382. // TODO consider using configurable genesis instead
  383. public sudoStartAnnouncingPerion(sudo: KeyringPair, endsAtBlock: BN): Promise<void> {
  384. return this.sender.signAndSend(
  385. this.api.tx.sudo.sudo(this.api.tx.councilElection.setStageAnnouncing(endsAtBlock)),
  386. sudo,
  387. false
  388. );
  389. }
  390. public sudoStartVotingPerion(sudo: KeyringPair, endsAtBlock: BN): Promise<void> {
  391. return this.sender.signAndSend(
  392. this.api.tx.sudo.sudo(this.api.tx.councilElection.setStageVoting(endsAtBlock)),
  393. sudo,
  394. false
  395. );
  396. }
  397. public sudoStartRevealingPerion(sudo: KeyringPair, endsAtBlock: BN): Promise<void> {
  398. return this.sender.signAndSend(
  399. this.api.tx.sudo.sudo(this.api.tx.councilElection.setStageRevealing(endsAtBlock)),
  400. sudo,
  401. false
  402. );
  403. }
  404. public sudoSetCouncilMintCapacity(sudo: KeyringPair, capacity: BN): Promise<void> {
  405. return this.sender.signAndSend(
  406. this.api.tx.sudo.sudo(this.api.tx.council.setCouncilMintCapacity(capacity)),
  407. sudo,
  408. false
  409. );
  410. }
  411. public sudoSetWorkingGroupMintCapacity(sudo: KeyringPair, capacity: BN): Promise<void> {
  412. return this.sender.signAndSend(
  413. this.api.tx.sudo.sudo(this.api.tx.storageWorkingGroup.setMintCapacity(capacity)),
  414. sudo,
  415. false
  416. );
  417. }
  418. public getBestBlock(): Promise<BN> {
  419. return this.api.derive.chain.bestNumber();
  420. }
  421. public getCouncil(): Promise<Seat[]> {
  422. return this.api.query.council.activeCouncil<Vec<Codec>>().then(seats => {
  423. return (seats as unknown) as Seat[];
  424. });
  425. }
  426. public getRuntime(): Promise<Bytes> {
  427. return this.api.query.substrate.code<Bytes>();
  428. }
  429. public async proposeRuntime(
  430. account: KeyringPair,
  431. stake: BN,
  432. name: string,
  433. description: string,
  434. runtime: Bytes | string
  435. ): Promise<void> {
  436. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  437. return this.sender.signAndSend(
  438. this.api.tx.proposalsCodex.createRuntimeUpgradeProposal(memberId, name, description, stake, runtime),
  439. account,
  440. false
  441. );
  442. }
  443. public async proposeText(
  444. account: KeyringPair,
  445. stake: BN,
  446. name: string,
  447. description: string,
  448. text: string
  449. ): Promise<void> {
  450. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  451. return this.sender.signAndSend(
  452. this.api.tx.proposalsCodex.createTextProposal(memberId, name, description, stake, text),
  453. account,
  454. false
  455. );
  456. }
  457. public async proposeSpending(
  458. account: KeyringPair,
  459. title: string,
  460. description: string,
  461. stake: BN,
  462. balance: BN,
  463. destination: string
  464. ): Promise<void> {
  465. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  466. return this.sender.signAndSend(
  467. this.api.tx.proposalsCodex.createSpendingProposal(memberId, title, description, stake, balance, destination),
  468. account,
  469. false
  470. );
  471. }
  472. public async proposeWorkingGroupMintCapacity(
  473. account: KeyringPair,
  474. title: string,
  475. description: string,
  476. stake: BN,
  477. balance: BN
  478. ): Promise<void> {
  479. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  480. return this.sender.signAndSend(
  481. this.api.tx.proposalsCodex.createSetContentWorkingGroupMintCapacityProposal(
  482. memberId,
  483. title,
  484. description,
  485. stake,
  486. balance
  487. ),
  488. account,
  489. false
  490. );
  491. }
  492. public async proposeValidatorCount(
  493. account: KeyringPair,
  494. title: string,
  495. description: string,
  496. stake: BN,
  497. validatorCount: BN
  498. ): Promise<void> {
  499. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  500. return this.sender.signAndSend(
  501. this.api.tx.proposalsCodex.createSetValidatorCountProposal(memberId, title, description, stake, validatorCount),
  502. account,
  503. false
  504. );
  505. }
  506. public async proposeLead(
  507. account: KeyringPair,
  508. title: string,
  509. description: string,
  510. stake: BN,
  511. leadAccount: KeyringPair
  512. ): Promise<void> {
  513. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  514. const leadMemberId: BN = (await this.getMemberIds(leadAccount.address))[0].toBn();
  515. const addressString: string = leadAccount.address;
  516. return this.sender.signAndSend(
  517. this.api.tx.proposalsCodex.createSetLeadProposal(memberId, title, description, stake, [
  518. leadMemberId,
  519. addressString,
  520. ]),
  521. account,
  522. false
  523. );
  524. }
  525. public async proposeEvictStorageProvider(
  526. account: KeyringPair,
  527. title: string,
  528. description: string,
  529. stake: BN,
  530. storageProvider: string
  531. ): Promise<void> {
  532. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  533. return this.sender.signAndSend(
  534. this.api.tx.proposalsCodex.createEvictStorageProviderProposal(
  535. memberId,
  536. title,
  537. description,
  538. stake,
  539. storageProvider
  540. ),
  541. account,
  542. false
  543. );
  544. }
  545. public async proposeStorageRoleParameters(
  546. account: KeyringPair,
  547. title: string,
  548. description: string,
  549. stake: BN,
  550. minStake: BN,
  551. minActors: BN,
  552. maxActors: BN,
  553. reward: BN,
  554. rewardPeriod: BN,
  555. bondingPeriod: BN,
  556. unbondingPeriod: BN,
  557. minServicePeriod: BN,
  558. startupGracePeriod: BN,
  559. entryRequestFee: BN
  560. ): Promise<void> {
  561. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  562. return this.sender.signAndSend(
  563. this.api.tx.proposalsCodex.createSetStorageRoleParametersProposal(memberId, title, description, stake, [
  564. minStake,
  565. minActors,
  566. maxActors,
  567. reward,
  568. rewardPeriod,
  569. bondingPeriod,
  570. unbondingPeriod,
  571. minServicePeriod,
  572. startupGracePeriod,
  573. entryRequestFee,
  574. ]),
  575. account,
  576. false
  577. );
  578. }
  579. public async proposeElectionParameters(
  580. account: KeyringPair,
  581. title: string,
  582. description: string,
  583. stake: BN,
  584. announcingPeriod: BN,
  585. votingPeriod: BN,
  586. revealingPeriod: BN,
  587. councilSize: BN,
  588. candidacyLimit: BN,
  589. newTermDuration: BN,
  590. minCouncilStake: BN,
  591. minVotingStake: BN
  592. ): Promise<void> {
  593. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  594. return this.sender.signAndSend(
  595. this.api.tx.proposalsCodex.createSetElectionParametersProposal(memberId, title, description, stake, [
  596. announcingPeriod,
  597. votingPeriod,
  598. revealingPeriod,
  599. councilSize,
  600. candidacyLimit,
  601. newTermDuration,
  602. minCouncilStake,
  603. minVotingStake,
  604. ]),
  605. account,
  606. false
  607. );
  608. }
  609. public approveProposal(account: KeyringPair, memberId: BN, proposal: BN): Promise<void> {
  610. return this.sender.signAndSend(this.api.tx.proposalsEngine.vote(memberId, proposal, 'Approve'), account, false);
  611. }
  612. public batchApproveProposal(council: KeyringPair[], proposal: BN): Promise<void[]> {
  613. return Promise.all(
  614. council.map(async keyPair => {
  615. const memberId: BN = (await this.getMemberIds(keyPair.address))[0].toBn();
  616. await this.approveProposal(keyPair, memberId, proposal);
  617. })
  618. );
  619. }
  620. public getBlockDuration(): BN {
  621. return this.api.createType('Moment', this.api.consts.babe.expectedBlockTime).toBn();
  622. }
  623. public expectProposalCreated(): Promise<BN> {
  624. return new Promise(async resolve => {
  625. await this.api.query.system.events<Vec<EventRecord>>(events => {
  626. events.forEach(record => {
  627. if (record.event.method && record.event.method.toString() === 'ProposalCreated') {
  628. resolve(new BN(record.event.data[1].toString()));
  629. }
  630. });
  631. });
  632. });
  633. }
  634. public expectRuntimeUpgraded(): Promise<void> {
  635. return new Promise(async resolve => {
  636. await this.api.query.system.events<Vec<EventRecord>>(events => {
  637. events.forEach(record => {
  638. if (record.event.method.toString() === 'RuntimeUpdated') {
  639. resolve();
  640. }
  641. });
  642. });
  643. });
  644. }
  645. public expectProposalFinalized(): Promise<void> {
  646. return new Promise(async resolve => {
  647. await this.api.query.system.events<Vec<EventRecord>>(events => {
  648. events.forEach(record => {
  649. if (
  650. record.event.method &&
  651. record.event.method.toString() === 'ProposalStatusUpdated' &&
  652. record.event.data[1].toString().includes('Executed')
  653. ) {
  654. resolve();
  655. }
  656. });
  657. });
  658. });
  659. }
  660. public expectOpeningFilled(): Promise<ApplicationIdToWorkerIdMap> {
  661. return new Promise(async resolve => {
  662. await this.api.query.system.events<Vec<EventRecord>>(events => {
  663. events.forEach(record => {
  664. if (record.event.method && record.event.method.toString() === 'OpeningFilled') {
  665. resolve((record.event.data[1] as unknown) as ApplicationIdToWorkerIdMap);
  666. }
  667. });
  668. });
  669. });
  670. }
  671. public expectOpeningAdded(): Promise<BN> {
  672. return new Promise(async resolve => {
  673. await this.api.query.system.events<Vec<EventRecord>>(events => {
  674. events.forEach(record => {
  675. if (record.event.method && record.event.method.toString() === 'OpeningAdded') {
  676. resolve((record.event.data as unknown) as BN);
  677. }
  678. });
  679. });
  680. });
  681. }
  682. public expectApplicationReviewBegan(): Promise<void> {
  683. return new Promise(async resolve => {
  684. await this.api.query.system.events<Vec<EventRecord>>(events => {
  685. events.forEach(record => {
  686. if (record.event.method && record.event.method.toString() === 'BeganApplicationReview') {
  687. resolve();
  688. }
  689. });
  690. });
  691. });
  692. }
  693. public getTotalIssuance(): Promise<BN> {
  694. return this.api.query.balances.totalIssuance<Balance>();
  695. }
  696. public async getRequiredProposalStake(numerator: number, denominator: number): Promise<BN> {
  697. const issuance: number = await (await this.getTotalIssuance()).toNumber();
  698. const stake = (issuance * numerator) / denominator;
  699. return new BN(stake.toFixed(0));
  700. }
  701. public getProposalCount(): Promise<BN> {
  702. return this.api.query.proposalsEngine.proposalCount<u32>();
  703. }
  704. public async getWorkingGroupMintCapacity(): Promise<BN> {
  705. const mintId: MintId = await this.api.query.contentWorkingGroup.mint<MintId>();
  706. const mintCodec = await this.api.query.minting.mints<Codec[]>(mintId);
  707. const mint: Mint = (mintCodec[0] as unknown) as Mint;
  708. return mint.getField<Balance>('capacity');
  709. }
  710. public getValidatorCount(): Promise<BN> {
  711. return this.api.query.staking.validatorCount<u32>();
  712. }
  713. public async getCurrentLeadAddress(): Promise<string> {
  714. const leadId: Option<LeadId> = await this.api.query.contentWorkingGroup.currentLeadId<Option<LeadId>>();
  715. const leadCodec = await this.api.query.contentWorkingGroup.leadById<Codec[]>(leadId.unwrap());
  716. const lead = (leadCodec[0] as unknown) as Lead;
  717. return lead.role_account.toString();
  718. }
  719. public async createStorageProvider(account: KeyringPair): Promise<void> {
  720. const memberId: BN = (await this.getMemberIds(account.address))[0].toBn();
  721. await this.sender.signAndSend(this.api.tx.actors.roleEntryRequest('StorageProvider', memberId), account, false);
  722. await this.sender.signAndSend(this.api.tx.actors.stake('StorageProvider', account.address), account, false);
  723. return;
  724. }
  725. public async isStorageProvider(address: string): Promise<boolean> {
  726. const storageProviders: Vec<AccountId> = await this.api.query.actors.accountIdsByRole<Vec<AccountId>>(
  727. 'StorageProvider'
  728. );
  729. return storageProviders.map(accountId => accountId.toString()).includes(address);
  730. }
  731. public async sudoSetLead(sudo: KeyringPair, lead: KeyringPair): Promise<void> {
  732. const leadMemberId: BN = (await this.getMemberIds(lead.address))[0].toBn();
  733. return this.sender.signAndSend(
  734. this.api.tx.sudo.sudo(this.api.tx.storageWorkingGroup.setLead(leadMemberId, lead.address)),
  735. sudo,
  736. false
  737. );
  738. }
  739. public async sudoUnsetLead(sudo: KeyringPair): Promise<void> {
  740. return this.sender.signAndSend(this.api.tx.sudo.sudo(this.api.tx.storageWorkingGroup.unsetLead()), sudo, false);
  741. }
  742. public async addOpening(
  743. activateAtBlock: BN | undefined,
  744. account: KeyringPair,
  745. maxActiveApplicants: BN,
  746. maxReviewPeriodLength: BN,
  747. applicationStakingPolicyAmount: BN,
  748. applicationCrowdedOutUnstakingPeriodLength: BN,
  749. applicationExpiredUnstakingPeriodLength: BN,
  750. roleStakingPolicyAmount: BN,
  751. roleCrowdedOutUnstakingPeriodLength: BN,
  752. roleExpiredUnstakingPeriodLength: BN,
  753. slashableMaxCount: BN,
  754. slashableMaxPercentPtsPerTime: BN,
  755. successfulApplicantApplicationStakeUnstakingPeriod: BN,
  756. failedApplicantApplicationStakeUnstakingPeriod: BN,
  757. failedApplicantRoleStakeUnstakingPeriod: BN,
  758. terminateCuratorApplicationStakeUnstakingPeriod: BN,
  759. terminateCuratorRoleStakeUnstakingPeriod: BN,
  760. exitCuratorRoleApplicationStakeUnstakingPeriod: BN,
  761. exitCuratorRoleStakeUnstakingPeriod: BN,
  762. text: string,
  763. openingType: string
  764. ): Promise<void> {
  765. const activateAt = activateAtBlock == undefined ? 'CurrentBlock' : { ExactBlock: activateAtBlock };
  766. const commitment = {
  767. application_rationing_policy: { max_active_applicants: maxActiveApplicants },
  768. max_review_period_length: maxReviewPeriodLength,
  769. application_staking_policy: {
  770. amount: applicationStakingPolicyAmount,
  771. amount_mode: 'AtLeast',
  772. crowded_out_unstaking_period_length: applicationCrowdedOutUnstakingPeriodLength,
  773. review_period_expired_unstaking_period_length: applicationExpiredUnstakingPeriodLength,
  774. },
  775. role_staking_policy: {
  776. amount: roleStakingPolicyAmount,
  777. amount_mode: 'AtLeast',
  778. crowded_out_unstaking_period_length: roleCrowdedOutUnstakingPeriodLength,
  779. review_period_expired_unstaking_period_length: roleExpiredUnstakingPeriodLength,
  780. },
  781. role_slashing_terms: {
  782. Slashable: {
  783. max_count: slashableMaxCount,
  784. max_percent_pts_per_time: slashableMaxPercentPtsPerTime,
  785. },
  786. },
  787. fill_opening_successful_applicant_application_stake_unstaking_period: successfulApplicantApplicationStakeUnstakingPeriod,
  788. fill_opening_failed_applicant_application_stake_unstaking_period: failedApplicantApplicationStakeUnstakingPeriod,
  789. fill_opening_failed_applicant_role_stake_unstaking_period: failedApplicantRoleStakeUnstakingPeriod,
  790. terminate_curator_application_stake_unstaking_period: terminateCuratorApplicationStakeUnstakingPeriod,
  791. terminate_curator_role_stake_unstaking_period: terminateCuratorRoleStakeUnstakingPeriod,
  792. exit_curator_role_application_stake_unstaking_period: exitCuratorRoleApplicationStakeUnstakingPeriod,
  793. exit_curator_role_stake_unstaking_period: exitCuratorRoleStakeUnstakingPeriod,
  794. };
  795. await this.sender.signAndSend(
  796. this.api.tx.storageWorkingGroup.addOpening(activateAt, commitment, text, openingType),
  797. account,
  798. false
  799. );
  800. }
  801. public async sudoAddOpening(
  802. activateAtBlock: BN | undefined,
  803. sudo: KeyringPair,
  804. maxActiveApplicants: BN,
  805. maxReviewPeriodLength: BN,
  806. applicationStakingPolicyAmount: BN,
  807. applicationCrowdedOutUnstakingPeriodLength: BN,
  808. applicationExpiredUnstakingPeriodLength: BN,
  809. roleStakingPolicyAmount: BN,
  810. roleCrowdedOutUnstakingPeriodLength: BN,
  811. roleExpiredUnstakingPeriodLength: BN,
  812. slashableMaxCount: BN,
  813. slashableMaxPercentPtsPerTime: BN,
  814. successfulApplicantApplicationStakeUnstakingPeriod: BN,
  815. failedApplicantApplicationStakeUnstakingPeriod: BN,
  816. failedApplicantRoleStakeUnstakingPeriod: BN,
  817. terminateCuratorApplicationStakeUnstakingPeriod: BN,
  818. terminateCuratorRoleStakeUnstakingPeriod: BN,
  819. exitCuratorRoleApplicationStakeUnstakingPeriod: BN,
  820. exitCuratorRoleStakeUnstakingPeriod: BN,
  821. text: string,
  822. openingType: string
  823. ): Promise<void> {
  824. const activateAt = activateAtBlock == undefined ? 'CurrentBlock' : { ExactBlock: activateAtBlock };
  825. const commitment = {
  826. application_rationing_policy: { max_active_applicants: maxActiveApplicants },
  827. max_review_period_length: maxReviewPeriodLength,
  828. application_staking_policy: {
  829. amount: applicationStakingPolicyAmount,
  830. amount_mode: 'AtLeast',
  831. crowded_out_unstaking_period_length: applicationCrowdedOutUnstakingPeriodLength,
  832. review_period_expired_unstaking_period_length: applicationExpiredUnstakingPeriodLength,
  833. },
  834. role_staking_policy: {
  835. amount: roleStakingPolicyAmount,
  836. amount_mode: 'AtLeast',
  837. crowded_out_unstaking_period_length: roleCrowdedOutUnstakingPeriodLength,
  838. review_period_expired_unstaking_period_length: roleExpiredUnstakingPeriodLength,
  839. },
  840. role_slashing_terms: {
  841. Slashable: {
  842. max_count: slashableMaxCount,
  843. max_percent_pts_per_time: slashableMaxPercentPtsPerTime,
  844. },
  845. },
  846. fill_opening_successful_applicant_application_stake_unstaking_period: successfulApplicantApplicationStakeUnstakingPeriod,
  847. fill_opening_failed_applicant_application_stake_unstaking_period: failedApplicantApplicationStakeUnstakingPeriod,
  848. fill_opening_failed_applicant_role_stake_unstaking_period: failedApplicantRoleStakeUnstakingPeriod,
  849. terminate_curator_application_stake_unstaking_period: terminateCuratorApplicationStakeUnstakingPeriod,
  850. terminate_curator_role_stake_unstaking_period: terminateCuratorRoleStakeUnstakingPeriod,
  851. exit_curator_role_application_stake_unstaking_period: exitCuratorRoleApplicationStakeUnstakingPeriod,
  852. exit_curator_role_stake_unstaking_period: exitCuratorRoleStakeUnstakingPeriod,
  853. };
  854. await this.sender.signAndSend(
  855. this.api.tx.sudo.sudo(this.api.tx.storageWorkingGroup.addOpening(activateAt, commitment, text, openingType)),
  856. sudo,
  857. false
  858. );
  859. }
  860. public async proposeCreateWorkingGroupLeaderOpening(
  861. account: KeyringPair,
  862. title: string,
  863. description: string,
  864. proposalStake: BN,
  865. activateAtBlock: BN,
  866. maxActiveApplicants: BN,
  867. maxReviewPeriodLength: BN,
  868. applicationStakingPolicyAmount: BN,
  869. applicationCrowdedOutUnstakingPeriodLength: BN,
  870. applicationExpiredUnstakingPeriodLength: BN,
  871. roleStakingPolicyAmount: BN,
  872. roleCrowdedOutUnstakingPeriodLength: BN,
  873. roleExpiredUnstakingPeriodLength: BN,
  874. slashableMaxCount: BN,
  875. slashableMaxPercentPtsPerTime: BN,
  876. successfulApplicantApplicationStakeUnstakingPeriod: BN,
  877. failedApplicantApplicationStakeUnstakingPeriod: BN,
  878. failedApplicantRoleStakeUnstakingPeriod: BN,
  879. terminateCuratorApplicationStakeUnstakingPeriod: BN,
  880. terminateCuratorRoleStakeUnstakingPeriod: BN,
  881. exitCuratorRoleApplicationStakeUnstakingPeriod: BN,
  882. exitCuratorRoleStakeUnstakingPeriod: BN,
  883. text: string
  884. ): Promise<void> {
  885. const memberId: BN = (await this.getMemberIds(account.address))[0];
  886. const commitment = {
  887. application_rationing_policy: { max_active_applicants: maxActiveApplicants },
  888. max_review_period_length: maxReviewPeriodLength,
  889. application_staking_policy: {
  890. amount: applicationStakingPolicyAmount,
  891. amount_mode: 'AtLeast',
  892. crowded_out_unstaking_period_length: applicationCrowdedOutUnstakingPeriodLength,
  893. review_period_expired_unstaking_period_length: applicationExpiredUnstakingPeriodLength,
  894. },
  895. role_staking_policy: {
  896. amount: roleStakingPolicyAmount,
  897. amount_mode: 'AtLeast',
  898. crowded_out_unstaking_period_length: roleCrowdedOutUnstakingPeriodLength,
  899. review_period_expired_unstaking_period_length: roleExpiredUnstakingPeriodLength,
  900. },
  901. role_slashing_terms: {
  902. Slashable: {
  903. max_count: slashableMaxCount,
  904. max_percent_pts_per_time: slashableMaxPercentPtsPerTime,
  905. },
  906. },
  907. fill_opening_successful_applicant_application_stake_unstaking_period: successfulApplicantApplicationStakeUnstakingPeriod,
  908. fill_opening_failed_applicant_application_stake_unstaking_period: failedApplicantApplicationStakeUnstakingPeriod,
  909. fill_opening_failed_applicant_role_stake_unstaking_period: failedApplicantRoleStakeUnstakingPeriod,
  910. terminate_curator_application_stake_unstaking_period: terminateCuratorApplicationStakeUnstakingPeriod,
  911. terminate_curator_role_stake_unstaking_period: terminateCuratorRoleStakeUnstakingPeriod,
  912. exit_curator_role_application_stake_unstaking_period: exitCuratorRoleApplicationStakeUnstakingPeriod,
  913. exit_curator_role_stake_unstaking_period: exitCuratorRoleStakeUnstakingPeriod,
  914. };
  915. await this.sender.signAndSend(
  916. this.api.tx.proposalsCodex.createAddWorkingGroupLeaderOpeningProposal(
  917. memberId,
  918. title,
  919. description,
  920. proposalStake,
  921. {
  922. activate_at: 'CurrentBlock',
  923. commitment: commitment,
  924. human_readable_text: text,
  925. working_group: 'Storage',
  926. }
  927. ),
  928. account,
  929. false
  930. );
  931. }
  932. public async acceptApplications(account: KeyringPair, openingId: BN): Promise<void> {
  933. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.acceptApplications(openingId), account, false);
  934. }
  935. public async beginApplicantReview(account: KeyringPair, openingId: BN): Promise<void> {
  936. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.beginApplicantReview(openingId), account, false);
  937. }
  938. public async sudoBeginApplicantReview(sudo: KeyringPair, openingId: BN): Promise<void> {
  939. return this.sender.signAndSend(
  940. this.api.tx.sudo.sudo(this.api.tx.storageWorkingGroup.beginApplicantReview(openingId)),
  941. sudo,
  942. false
  943. );
  944. }
  945. public async applyOnOpening(
  946. account: KeyringPair,
  947. openingId: BN,
  948. roleStake: BN,
  949. applicantStake: BN,
  950. text: string,
  951. expectFailure: boolean
  952. ): Promise<void> {
  953. const memberId: BN = (await this.getMemberIds(account.address))[0];
  954. return this.sender.signAndSend(
  955. this.api.tx.storageWorkingGroup.applyOnOpening(
  956. memberId,
  957. openingId,
  958. account.address,
  959. roleStake,
  960. applicantStake,
  961. text
  962. ),
  963. account,
  964. expectFailure
  965. );
  966. }
  967. public async batchApplyOnOpening(
  968. accounts: KeyringPair[],
  969. openingId: BN,
  970. roleStake: BN,
  971. applicantStake: BN,
  972. text: string,
  973. expectFailure: boolean
  974. ): Promise<void[]> {
  975. return Promise.all(
  976. accounts.map(async keyPair => {
  977. await this.applyOnOpening(keyPair, openingId, roleStake, applicantStake, text, expectFailure);
  978. })
  979. );
  980. }
  981. public async fillOpening(
  982. account: KeyringPair,
  983. openingId: BN,
  984. applicationId: BN[],
  985. amountPerPayout: BN,
  986. nextPaymentBlock: BN,
  987. payoutInterval: BN
  988. ): Promise<void> {
  989. return this.sender.signAndSend(
  990. this.api.tx.storageWorkingGroup.fillOpening(openingId, applicationId, {
  991. amount_per_payout: amountPerPayout,
  992. next_payment_at_block: nextPaymentBlock,
  993. payout_interval: payoutInterval,
  994. }),
  995. account,
  996. false
  997. );
  998. }
  999. public async sudoFillOpening(
  1000. sudo: KeyringPair,
  1001. openingId: BN,
  1002. applicationId: BN[],
  1003. amountPerPayout: BN,
  1004. nextPaymentBlock: BN,
  1005. payoutInterval: BN
  1006. ): Promise<void> {
  1007. return this.sender.signAndSend(
  1008. this.api.tx.sudo.sudo(
  1009. this.api.tx.storageWorkingGroup.fillOpening(openingId, applicationId, {
  1010. amount_per_payout: amountPerPayout,
  1011. next_payment_at_block: nextPaymentBlock,
  1012. payout_interval: payoutInterval,
  1013. })
  1014. ),
  1015. sudo,
  1016. false
  1017. );
  1018. }
  1019. public async increaseStake(account: KeyringPair, workerId: BN, stake: BN): Promise<void> {
  1020. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.increaseStake(workerId, stake), account, false);
  1021. }
  1022. public async decreaseStake(account: KeyringPair, workerId: BN, stake: BN, expectFailure: boolean): Promise<void> {
  1023. return this.sender.signAndSend(
  1024. this.api.tx.storageWorkingGroup.decreaseStake(workerId, stake),
  1025. account,
  1026. expectFailure
  1027. );
  1028. }
  1029. public async slashStake(account: KeyringPair, workerId: BN, stake: BN, expectFailure: boolean): Promise<void> {
  1030. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.slashStake(workerId, stake), account, expectFailure);
  1031. }
  1032. public async updateRoleAccount(account: KeyringPair, workerId: BN, newRoleAccount: string): Promise<void> {
  1033. return this.sender.signAndSend(
  1034. this.api.tx.storageWorkingGroup.updateRoleAccount(workerId, newRoleAccount),
  1035. account,
  1036. false
  1037. );
  1038. }
  1039. public async updateRewardAccount(account: KeyringPair, workerId: BN, newRewardAccount: string): Promise<void> {
  1040. return this.sender.signAndSend(
  1041. this.api.tx.storageWorkingGroup.updateRewardAccount(workerId, newRewardAccount),
  1042. account,
  1043. false
  1044. );
  1045. }
  1046. public async withdrawApplication(account: KeyringPair, workerId: BN): Promise<void> {
  1047. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.withdrawApplication(workerId), account, false);
  1048. }
  1049. public async batchWithdrawApplication(accounts: KeyringPair[]): Promise<void[]> {
  1050. return Promise.all(
  1051. accounts.map(async keyPair => {
  1052. const applicationIds: BN[] = await this.getApplicationsIdsByRoleAccount(keyPair.address);
  1053. await this.withdrawApplication(keyPair, applicationIds[0]);
  1054. })
  1055. );
  1056. }
  1057. public async terminateApplication(account: KeyringPair, applicationId: BN): Promise<void> {
  1058. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.terminateApplication(applicationId), account, false);
  1059. }
  1060. public async batchTerminateApplication(account: KeyringPair, roleAccounts: KeyringPair[]): Promise<void[]> {
  1061. return Promise.all(
  1062. roleAccounts.map(async keyPair => {
  1063. const applicationIds: BN[] = await this.getActiveApplicationsIdsByRoleAccount(keyPair.address);
  1064. await this.terminateApplication(account, applicationIds[0]);
  1065. })
  1066. );
  1067. }
  1068. public async terminateRole(
  1069. account: KeyringPair,
  1070. applicationId: BN,
  1071. text: string,
  1072. expectFailure: boolean
  1073. ): Promise<void> {
  1074. return this.sender.signAndSend(
  1075. this.api.tx.storageWorkingGroup.terminateRole(applicationId, text, false),
  1076. account,
  1077. expectFailure
  1078. );
  1079. }
  1080. public async leaveRole(account: KeyringPair, text: string, expectFailure: boolean): Promise<void> {
  1081. const workerId: BN = await this.getWorkerIdByRoleAccount(account.address);
  1082. return this.sender.signAndSend(this.api.tx.storageWorkingGroup.leaveRole(workerId, text), account, expectFailure);
  1083. }
  1084. public async batchLeaveRole(roleAccounts: KeyringPair[], text: string, expectFailure: boolean): Promise<void[]> {
  1085. return Promise.all(
  1086. roleAccounts.map(async keyPair => {
  1087. await this.leaveRole(keyPair, text, expectFailure);
  1088. })
  1089. );
  1090. }
  1091. public async getStorageRoleParameters(): Promise<RoleParameters> {
  1092. return (await this.api.query.actors.parameters<Option<RoleParameters>>('StorageProvider')).unwrap();
  1093. }
  1094. public async getAnnouncingPeriod(): Promise<BN> {
  1095. return this.api.query.councilElection.announcingPeriod<BlockNumber>();
  1096. }
  1097. public async getVotingPeriod(): Promise<BN> {
  1098. return this.api.query.councilElection.votingPeriod<BlockNumber>();
  1099. }
  1100. public async getRevealingPeriod(): Promise<BN> {
  1101. return this.api.query.councilElection.revealingPeriod<BlockNumber>();
  1102. }
  1103. public async getCouncilSize(): Promise<BN> {
  1104. return this.api.query.councilElection.councilSize<u32>();
  1105. }
  1106. public async getCandidacyLimit(): Promise<BN> {
  1107. return this.api.query.councilElection.candidacyLimit<u32>();
  1108. }
  1109. public async getNewTermDuration(): Promise<BN> {
  1110. return this.api.query.councilElection.newTermDuration<BlockNumber>();
  1111. }
  1112. public async getMinCouncilStake(): Promise<BN> {
  1113. return this.api.query.councilElection.minCouncilStake<BalanceOf>();
  1114. }
  1115. public async getMinVotingStake(): Promise<BN> {
  1116. return this.api.query.councilElection.minVotingStake<BalanceOf>();
  1117. }
  1118. public async getNextOpeningId(): Promise<BN> {
  1119. return this.api.query.storageWorkingGroup.nextOpeningId<u32>();
  1120. }
  1121. public async getNextApplicationId(): Promise<BN> {
  1122. return this.api.query.storageWorkingGroup.nextApplicationId<u32>();
  1123. }
  1124. public async getOpening(id: BN): Promise<Opening> {
  1125. return ((await this.api.query.storageWorkingGroup.openingById<Codec[]>(id))[0] as unknown) as Opening;
  1126. }
  1127. public async getHiringOpening(id: BN): Promise<HiringOpening> {
  1128. return ((await this.api.query.hiring.openingById<Codec[]>(id))[0] as unknown) as HiringOpening;
  1129. }
  1130. public async getWorkers(): Promise<Worker[]> {
  1131. return ((await this.api.query.storageWorkingGroup.workerById<Codec[]>())[1] as unknown) as Worker[];
  1132. }
  1133. public async getWorkerById(id: BN): Promise<Worker> {
  1134. return ((await this.api.query.storageWorkingGroup.workerById<Codec[]>(id))[0] as unknown) as Worker;
  1135. }
  1136. public async getWorkerIdByRoleAccount(address: string): Promise<BN> {
  1137. const workersAndIds = await this.api.query.storageWorkingGroup.workerById<Codec[]>();
  1138. const workers: Worker[] = (workersAndIds[1] as unknown) as Worker[];
  1139. const ids: WorkerId[] = (workersAndIds[0] as unknown) as WorkerId[];
  1140. let index: number;
  1141. workers.forEach((worker, i) => {
  1142. if (worker.role_account_id.toString() === address) index = i;
  1143. });
  1144. return ids[index!];
  1145. }
  1146. public async getApplicationsIdsByRoleAccount(address: string): Promise<BN[]> {
  1147. const applicationsAndIds = await this.api.query.storageWorkingGroup.applicationById<Codec[]>();
  1148. const applications: Application[] = (applicationsAndIds[1] as unknown) as Application[];
  1149. const ids: ApplicationId[] = (applicationsAndIds[0] as unknown) as ApplicationId[];
  1150. return applications
  1151. .map((application, index) => (application.role_account_id.toString() === address ? ids[index] : undefined))
  1152. .filter(index => index !== undefined) as BN[];
  1153. }
  1154. public async getHiringApplicationById(id: BN): Promise<HiringApplication> {
  1155. return ((await this.api.query.hiring.applicationById<Codec[]>(id))[0] as unknown) as HiringApplication;
  1156. }
  1157. public async getApplicationById(id: BN): Promise<Application> {
  1158. return ((await this.api.query.storageWorkingGroup.applicationById<Codec[]>(id))[0] as unknown) as Application;
  1159. }
  1160. public async getActiveApplicationsIdsByRoleAccount(address: string): Promise<BN[]> {
  1161. const applicationsAndIds = await this.api.query.storageWorkingGroup.applicationById<Codec[]>();
  1162. const applications: Application[] = (applicationsAndIds[1] as unknown) as Application[];
  1163. const ids: ApplicationId[] = (applicationsAndIds[0] as unknown) as ApplicationId[];
  1164. return (
  1165. await Promise.all(
  1166. applications.map(async (application, index) => {
  1167. if (
  1168. application.role_account_id.toString() === address &&
  1169. (await this.getHiringApplicationById(application.application_id)).stage.type === 'Active'
  1170. ) {
  1171. return ids[index];
  1172. } else {
  1173. return undefined;
  1174. }
  1175. })
  1176. )
  1177. ).filter(index => index !== undefined) as BN[];
  1178. }
  1179. public async getStake(id: BN): Promise<Stake> {
  1180. return ((await this.api.query.stake.stakes<Codec[]>(id))[0] as unknown) as Stake;
  1181. }
  1182. public async getWorkerStakeAmount(workerId: BN): Promise<BN> {
  1183. let stakeId: BN = (await this.getWorkerById(workerId)).role_stake_profile.unwrap().stake_id;
  1184. return (((await this.getStake(stakeId)).staking_status.value as unknown) as StakedState).staked_amount;
  1185. }
  1186. public async getRewardRelationship(id: BN): Promise<RewardRelationship> {
  1187. return ((
  1188. await this.api.query.recurringRewards.rewardRelationships<Codec[]>(id)
  1189. )[0] as unknown) as RewardRelationship;
  1190. }
  1191. public async getWorkerRewardAccount(workerId: BN): Promise<string> {
  1192. let rewardRelationshipId: BN = (await this.getWorkerById(workerId)).reward_relationship.unwrap();
  1193. return (await this.getRewardRelationship(rewardRelationshipId)).getField('account').toString();
  1194. }
  1195. }