council.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { WsProvider, ApiPromise } from "@polkadot/api";
  2. import { types } from "@joystream/types";
  3. import { Announcing, ElectionStage, Revealing, Seats, Voting } from "@joystream/types/council";
  4. import { Null, Option, u32 } from "@polkadot/types";
  5. import { CouncilData, CouncilMemberData, Participant, VoterData } from "./interfaces";
  6. import { getParticipantAt } from "./functions";
  7. import { BalanceOf, BlockNumber, Hash } from "@polkadot/types/interfaces";
  8. import { Mint, MintId } from "@joystream/types/mint";
  9. async function main() {
  10. // Initialise the provider to connect to the local node
  11. const provider = new WsProvider('ws://127.0.0.1:9944');
  12. /*
  13. If you want to play around on our staging network, go ahead and connect to this staging network instead.
  14. const provider = new WsProvider('wss://alexandria-testing-1.joystream.app/staging/rpc:9944');
  15. There's a bunch of tokens on the account: 5HdYzMVpJv3c4omqwKKr7SpBgzrdRRYBwoNVhJB2Y8xhUbfK,
  16. with seed: "emotion soul hole loan journey what sport inject dwarf cherry ankle lesson"
  17. please transfer (what you need only) to your own account, and don't test runtime upgrades :D
  18. */
  19. // Create the API and wait until ready
  20. const api = await ApiPromise.create({ provider, types })
  21. // made this example with historical data, so you can check different councils/stages
  22. const blocks :number[] = [259200, 259201]
  23. // discounting this voter
  24. const joystreamVoter = "5CJzTaCp5fuqG7NdJQ6oUCwdmFHKichew8w4RZ3zFHM8qSe6"
  25. const councils: CouncilData[] = []
  26. for (let i=0; i<blocks.length; i++) {
  27. const councilMembers: CouncilMemberData[] = []
  28. const blockHash = await api.rpc.chain.getBlockHash(blocks[i]) as Hash
  29. const electionStatus = await api.query.councilElection.stage.at(blockHash) as Option<ElectionStage>
  30. const electionRound = await api.query.councilElection.round.at(blockHash) as u32
  31. console.log(`
  32. at block: ${blocks[i]},
  33. the election stage was: ${electionStatus.value.toString()},
  34. of election round: ${electionRound.toNumber()},
  35. `)
  36. if (electionStatus.value instanceof ElectionStage) {
  37. const electionStage = electionStatus.unwrap()
  38. if (electionStage.value instanceof Announcing) {
  39. console.log("In 'Announcing' stage - ends at block", electionStage.value.toNumber())
  40. } else if (electionStage.value instanceof Voting) {
  41. console.log("In 'Voting' stage - ends at block", electionStage.value.toNumber())
  42. } else if (electionStage.value instanceof Revealing) {
  43. console.log("In 'Revealing' stage - ends at block", electionStage.value.toNumber())
  44. } else {
  45. }
  46. }
  47. const activeCouncil = await api.query.council.activeCouncil.at(blockHash) as Seats
  48. if (!activeCouncil.isEmpty) {
  49. const elected: Participant[] = []
  50. for (let member of activeCouncil) {
  51. let otherStake = 0
  52. let jsgStake = 0
  53. const councilMemberId = await getParticipantAt(api, member.member, blockHash)
  54. const voters: VoterData[] = []
  55. elected.push(councilMemberId)
  56. for (let backer of member.backers) {
  57. const voterId = await getParticipantAt(api, backer.member, blockHash)
  58. const voter: VoterData = {
  59. voterId,
  60. voterStake: backer.stake.toNumber(),
  61. stakeRatioExJSGvotes: 0,
  62. kpiRewardRatio: 0,
  63. }
  64. otherStake += backer.stake.toNumber()
  65. if (backer.member.toString() === joystreamVoter) {
  66. jsgStake += backer.stake.toNumber()
  67. }
  68. voters.push(voter)
  69. }
  70. const ownStake = member.stake.toNumber()
  71. const totalStakeExJSGvotes = member.stake.toNumber() + otherStake - jsgStake
  72. const totalStake = member.stake.toNumber() + otherStake
  73. const councilMember: CouncilMemberData = {
  74. councilMemberId,
  75. totalStake,
  76. totalStakeExJSGvotes,
  77. ownStake,
  78. otherStake,
  79. otherStakeExJSGvotes: otherStake - jsgStake,
  80. stakeRatioExJSGvotes: ownStake/totalStakeExJSGvotes,
  81. voters,
  82. }
  83. councilMembers.push(councilMember)
  84. }
  85. let totalStakes = 0
  86. let totalStakesExJSGvotes = 0
  87. let ownStakes = 0
  88. let otherStakes = 0
  89. let otherStakesExJSGvotes = 0
  90. for (let councilMember of councilMembers) {
  91. totalStakes += councilMember.totalStake
  92. totalStakesExJSGvotes += councilMember.totalStakeExJSGvotes
  93. ownStakes += councilMember.ownStake
  94. otherStakes += councilMember.otherStake
  95. otherStakesExJSGvotes += councilMember.otherStakeExJSGvotes
  96. }
  97. for (let councilMember of councilMembers) {
  98. councilMember.kpiRewardRatio = councilMember.ownStake/totalStakesExJSGvotes
  99. for (let voter of councilMember.voters) {
  100. if (voter.voterId.accountId != joystreamVoter) {
  101. voter.stakeRatioExJSGvotes = voter.voterStake/councilMember.totalStakeExJSGvotes
  102. voter.kpiRewardRatio = voter.voterStake/totalStakesExJSGvotes
  103. }
  104. }
  105. }
  106. const termEnd = (await api.query.council.termEndsAt.at(blockHash) as BlockNumber).toNumber()
  107. const announcing = (await api.query.councilElection.announcingPeriod.at(blockHash) as BlockNumber).toNumber()
  108. const voting = (await api.query.councilElection.votingPeriod.at(blockHash) as BlockNumber).toNumber()
  109. const revealing = (await api.query.councilElection.votingPeriod.at(blockHash) as BlockNumber).toNumber()
  110. const term = (await api.query.councilElection.newTermDuration.at(blockHash) as BlockNumber).toNumber()
  111. // this will not always be correct...
  112. const electedAtBlock = termEnd-term
  113. const newCouncilStartsAt = termEnd+announcing+voting+revealing
  114. const electedHash = await api.rpc.chain.getBlockHash(electedAtBlock) as Hash
  115. const getRewardInterval = await api.query.council.payoutInterval.at(electedHash) as Option<BlockNumber>
  116. const councilMint = await api.query.council.councilMint.at(electedHash) as MintId
  117. const mintAtStart = await api.query.minting.mints.at(electedHash,councilMint) as Mint
  118. const mintCapacityAtStart = mintAtStart.capacity.toNumber()
  119. let rewardInterval = 3600
  120. if (!(getRewardInterval.value instanceof Null)) {
  121. rewardInterval = getRewardInterval.unwrap().toNumber()
  122. }
  123. const rewardamountPerPayout = (await api.query.council.amountPerPayout.at(electedHash) as BalanceOf).toNumber()
  124. const expectedIndividualRewards = rewardamountPerPayout*term/rewardInterval
  125. const council: CouncilData = {
  126. electionCycle: electionRound.toNumber(),
  127. electedAtBlock,
  128. mintCapacityAtStart,
  129. rewardamountPerPayout,
  130. rewardInterval,
  131. termEnd: termEnd,
  132. expectedIndividualRewards,
  133. newCouncilStartsAt,
  134. totalStakes,
  135. totalStakesExJSGvotes,
  136. ownStakes,
  137. otherStakes,
  138. otherStakesExJSGvotes,
  139. elected,
  140. electionData: councilMembers,
  141. }
  142. const bestHeight = (await api.derive.chain.bestNumber()).toNumber()
  143. if (bestHeight>newCouncilStartsAt) {
  144. const endHash = await api.rpc.chain.getBlockHash(newCouncilStartsAt) as Hash
  145. const mintAtEnd = await api.query.minting.mints.at(endHash,councilMint) as Mint
  146. council.mintCapacityAtEnd = mintAtEnd.capacity.toNumber()
  147. council.councilSpending = mintAtEnd.total_minted.toNumber() - mintAtStart.total_minted.toNumber()
  148. }
  149. councils.push(council)
  150. }
  151. }
  152. console.log("councils",JSON.stringify(councils, null, 4))
  153. api.disconnect()
  154. }
  155. main()