rewards.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { ApiPromise } from "@polkadot/api";
  2. // types
  3. import { Bounty, CacheEvent, WorkerReward } from "./types";
  4. import { AccountId, Balance } from "@polkadot/types/interfaces";
  5. import { Hash } from "@polkadot/types/interfaces";
  6. import { Membership } from "@joystream/types/members";
  7. import { Mint, MintId } from "@joystream/types/mint";
  8. import { Stake } from "@joystream/types/stake";
  9. import {
  10. RewardRelationship,
  11. RewardRelationshipId,
  12. } from "@joystream/types/recurring-rewards";
  13. // lib
  14. import { getPercent, getTotalMinted } from "./";
  15. import {
  16. getBlock,
  17. getBlockHash,
  18. getMint,
  19. getNextWorker,
  20. getMember,
  21. getWorker,
  22. getWorkerReward,
  23. getStake,
  24. getValidators,
  25. getValidatorCount,
  26. } from "./api";
  27. import {WorkerOf} from "@joystream/types/augment-codec/all";
  28. export const filterMethods = {
  29. getBurnedTokens: ({ section, method }: CacheEvent) =>
  30. section === "balances" && method === "Transfer",
  31. newValidatorsRewards: ({ section, method }: CacheEvent) =>
  32. section === "staking" && method === "Reward",
  33. };
  34. export const getWorkerRewards = async (
  35. api: ApiPromise,
  36. group: string,
  37. hash: Hash
  38. ): Promise<WorkerReward[]> => {
  39. let workers = Array<WorkerReward>();
  40. const nextWorkerId = await getNextWorker(api, group, hash);
  41. for (let id = 0; id < nextWorkerId; ++id) {
  42. const worker: WorkerOf = await getWorker(api, group, hash, id);
  43. const account = worker.role_account_id;
  44. const memberId = worker.member_id;
  45. const member: Membership = await getMember(api, memberId, hash);
  46. const handle = member ? String(member.handle) : account.toString();
  47. const status = worker.is_active ? `active` : `inactive`;
  48. let stake: Stake, reward: RewardRelationship;
  49. if (worker.role_stake_profile.isSome) {
  50. const roleStakeProfile = worker.role_stake_profile.unwrap();
  51. stake = await getStake(api, roleStakeProfile.stake_id);
  52. }
  53. if (worker.reward_relationship.isSome) {
  54. // TODO changing salaries are not reflected
  55. const rewardId: RewardRelationshipId = worker.reward_relationship.unwrap();
  56. reward = await getWorkerReward(api, hash, rewardId);
  57. }
  58. workers.push({ id, stake, reward, status, handle, account, memberId });
  59. }
  60. return workers;
  61. };
  62. export const getWorkerRow = (
  63. worker: WorkerReward,
  64. earnedStart: number
  65. ): string => {
  66. const mtjoy = (mtjoy: number): string => (mtjoy / 1000000).toFixed(1);
  67. const { id, memberId, account, handle, status, reward } = worker;
  68. const earnedEnd = Number(reward.total_reward_received.toBigInt());
  69. if (!earnedEnd) return ``;
  70. const totalEarned = mtjoy(earnedEnd);
  71. const earnedTerm = mtjoy(earnedEnd - earnedStart);
  72. const amount = Number(reward.amount_per_payout.toBigInt());
  73. const rewardPerBlock = (amount / Number(reward.payout_interval)).toFixed();
  74. const url = `https://pioneer.joystreamstats.live/#/members/${handle}`; // TODO
  75. // TODO compare earning to term start and show difference
  76. return `| ${id} | [@${handle}](${url}) | ${status} | ${rewardPerBlock} | ${earnedTerm} | ${totalEarned} |\n`;
  77. };
  78. export const getBurnedTokens = (
  79. burnAddress: string,
  80. blocks: [number, CacheEvent[]][]
  81. ): number => {
  82. let tokensBurned = 0;
  83. blocks.forEach(([key, transfers]) =>
  84. transfers.forEach((transfer) => {
  85. let receiver = transfer.data[1] as AccountId;
  86. let amount = transfer.data[2] as Balance;
  87. if (receiver.toString() === burnAddress) tokensBurned = Number(amount);
  88. })
  89. );
  90. return tokensBurned;
  91. };
  92. export const getValidatorsRewards = (
  93. blocks: [number, CacheEvent[]][]
  94. ): number => {
  95. let newValidatorRewards = 0;
  96. blocks.forEach(([key, validatorRewards]) =>
  97. validatorRewards.forEach(
  98. (reward: CacheEvent) => (newValidatorRewards += Number(reward.data[1]))
  99. )
  100. );
  101. return newValidatorRewards;
  102. };
  103. export const getActiveValidators = async (
  104. api: ApiPromise,
  105. hash: Hash,
  106. searchPreviousBlocks: boolean = false
  107. ): Promise<AccountId[]> => {
  108. const block = await getBlock(api, hash);
  109. let currentBlockNr = block.block.header.number.toNumber();
  110. let activeValidators: AccountId[];
  111. do {
  112. const hash: Hash = await getBlockHash(api, currentBlockNr);
  113. const validators: AccountId[] = await getValidators(api, hash);
  114. if (validators.length) {
  115. let max = await getValidatorCount(api, hash);
  116. activeValidators = validators.slice(0, max);
  117. }
  118. if (searchPreviousBlocks) --currentBlockNr;
  119. else ++currentBlockNr;
  120. } while (activeValidators == undefined);
  121. return activeValidators;
  122. };