joyApi.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { ApiPromise, WsProvider } from "@polkadot/api";
  2. import { types } from "@joystream/types";
  3. import { AccountId, Hash } from "@polkadot/types/interfaces";
  4. import { config } from "dotenv";
  5. import BN from "bn.js";
  6. import { Option, Vec } from "@polkadot/types";
  7. import { wsLocation } from "./config";
  8. import { MemberId } from "@joystream/types/members";
  9. import { Member, IApplicant, IVote } from "./types";
  10. import { PromiseAllObj } from "./components/ValidatorReport/utils";
  11. import { IElectionStake, SealedVote } from "@joystream/types/council";
  12. config();
  13. export class JoyApi {
  14. endpoint: string;
  15. isReady: Promise<ApiPromise>;
  16. api!: ApiPromise;
  17. constructor() {
  18. this.endpoint = wsLocation;
  19. this.isReady = (async () =>
  20. await new ApiPromise({ provider: new WsProvider(wsLocation), types })
  21. .isReadyOrError)();
  22. }
  23. get init(): Promise<JoyApi> {
  24. return this.isReady.then((instance) => {
  25. this.api = instance;
  26. return this;
  27. });
  28. }
  29. async finalizedHash() {
  30. return this.api.rpc.chain.getFinalizedHead();
  31. }
  32. async councilRound(): Promise<Number> {
  33. return Number((await this.api.query.councilElection.round()).toJSON());
  34. }
  35. async councilSize(): Promise<Number> {
  36. return Number((await this.api.query.councilElection.councilSize()).toJSON());
  37. }
  38. async termEndsAt(): Promise<Number> {
  39. return Number((await this.api.query.council.termEndsAt()).toJSON());
  40. }
  41. async stage(): Promise<{ [key: string]: Number }> {
  42. const stage = (await this.api.query.councilElection.stage()).toJSON();
  43. return stage as unknown as { [key: string]: Number };
  44. }
  45. async getCouncilApplicants(): Promise<IApplicant[]> {
  46. const addresses: AccountId[] = (
  47. await this.api.query.councilElection.applicants()
  48. ).toJSON() as unknown as AccountId[];
  49. const members = await Promise.all(
  50. addresses.map(async (address) => {
  51. return PromiseAllObj({
  52. address: address,
  53. memberId: await this.api.query.members.memberIdsByRootAccountId(
  54. address as unknown as AccountId
  55. ),
  56. });
  57. })
  58. );
  59. return (await Promise.all(
  60. members.map(async (member) => {
  61. const { memberId, address } = member;
  62. const id = (memberId as unknown as MemberId[])[0] as MemberId;
  63. return PromiseAllObj({
  64. member: (await this.api.query.members.membershipById(
  65. id
  66. )) as unknown as Member,
  67. electionStake: (
  68. await this.api.query.councilElection.applicantStakes(address)
  69. ).toJSON() as unknown as IElectionStake,
  70. } as IApplicant);
  71. })
  72. )) as IApplicant[];
  73. }
  74. async getVotes(): Promise<IVote[]> {
  75. const commitments: AccountId[] = (
  76. await this.api.query.councilElection.commitments()
  77. ).toJSON() as unknown as AccountId[];
  78. const votes = await Promise.all(
  79. commitments.map(async (hash) => {
  80. const vote = (await this.api.query.councilElection.votes(
  81. hash
  82. )) as unknown as SealedVote;
  83. const newStake = vote.stake.new;
  84. const transferredStake = vote.stake.transferred;
  85. const voterId = await this.api.query.members.memberIdsByRootAccountId(
  86. vote.voter
  87. );
  88. const voterMembership = (await this.api.query.members.membershipById(
  89. voterId
  90. )) as unknown as Member;
  91. const voterHandle = voterMembership.handle;
  92. const candidateId = `${vote.vote}`;
  93. if (
  94. candidateId === "" ||
  95. candidateId === null ||
  96. candidateId === undefined
  97. ) {
  98. return {
  99. voterHandle: voterHandle,
  100. voterId: voterId as unknown as Number,
  101. newStake: newStake as unknown as Number,
  102. transferredStake: transferredStake as unknown as Number,
  103. } as IVote;
  104. } else {
  105. const voteId = await this.api.query.members.memberIdsByRootAccountId(
  106. candidateId
  107. );
  108. const voteMembership = (await this.api.query.members.membershipById(
  109. voteId
  110. )) as unknown as Member;
  111. const voteHandle = voteMembership.handle;
  112. return {
  113. voterHandle: voterHandle,
  114. voterId: voterId as unknown as Number,
  115. candidateHandle: voteHandle,
  116. candidateId: voteId as unknown as Number,
  117. newStake: newStake as unknown as Number,
  118. transferredStake: transferredStake as unknown as Number,
  119. } as IVote;
  120. }
  121. })
  122. );
  123. return votes;
  124. }
  125. async finalizedBlockHeight() {
  126. const finalizedHash = await this.finalizedHash();
  127. const { number } = await this.api.rpc.chain.getHeader(`${finalizedHash}`);
  128. return number.toNumber();
  129. }
  130. async findActiveValidators(
  131. hash: Hash,
  132. searchPreviousBlocks: boolean
  133. ): Promise<AccountId[]> {
  134. const block = await this.api.rpc.chain.getBlock(hash);
  135. let currentBlockNr = block.block.header.number.toNumber();
  136. let activeValidators;
  137. do {
  138. let currentHash = (await this.api.rpc.chain.getBlockHash(
  139. currentBlockNr
  140. )) as Hash;
  141. let allValidators = (await this.api.query.staking.snapshotValidators.at(
  142. currentHash
  143. )) as Option<Vec<AccountId>>;
  144. if (!allValidators.isEmpty) {
  145. let max = (
  146. await this.api.query.staking.validatorCount.at(currentHash)
  147. ).toNumber();
  148. activeValidators = Array.from(allValidators.unwrap()).slice(0, max);
  149. }
  150. if (searchPreviousBlocks) {
  151. --currentBlockNr;
  152. } else {
  153. ++currentBlockNr;
  154. }
  155. } while (activeValidators === undefined);
  156. return activeValidators;
  157. }
  158. async validatorsData() {
  159. const validators = await this.api.query.session.validators();
  160. const era = await this.api.query.staking.currentEra();
  161. const totalStake = era.isSome
  162. ? await this.api.query.staking.erasTotalStake(era.unwrap())
  163. : new BN(0);
  164. return {
  165. count: validators.length,
  166. validators: validators.toJSON(),
  167. total_stake: totalStake.toNumber(),
  168. };
  169. }
  170. }