123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- import { ApiPromise } from "@polkadot/api";
- // types
- import { Bounty, CacheEvent, WorkerReward, SpendingProposal } from "./types";
- import { AccountId, Balance } from "@polkadot/types/interfaces";
- import { Hash } from "@polkadot/types/interfaces";
- import { Membership } from "@joystream/types/members";
- import { Mint, MintId } from "@joystream/types/mint";
- import {
- Proposal,
- ProposalId,
- SpendingParams,
- } from "@joystream/types/proposals";
- import { ProposalDetails, ProposalOf } from "@joystream/types/augment/types";
- import { Stake } from "@joystream/types/stake";
- import {
- RewardRelationship,
- RewardRelationshipId,
- } from "@joystream/types/recurring-rewards";
- // lib
- import { getPercent, getTotalMinted } from "./";
- import {
- getBlock,
- getBlockHash,
- getMint,
- getNextWorker,
- getMember,
- getWorker,
- getWorkerReward,
- getProposalInfo,
- getProposalDetails,
- getStake,
- getValidators,
- getValidatorCount,
- } from "./api";
- import { WorkerOf } from "@joystream/types/augment-codec/all";
- import { ProposalDetailsOf } from "@joystream/types/augment/types";
- export const filterMethods = {
- getBurnedTokens: ({ section, method }: CacheEvent) =>
- section === "balances" && method === "Transfer",
- newValidatorsRewards: ({ section, method }: CacheEvent) =>
- section === "staking" && method === "Reward",
- finalizedSpendingProposals: ({ section, method }: CacheEvent) =>
- section === "proposalsEngine" && method === "ProposalStatusUpdated",
- sudoSetBalance: ({ section, method }: CacheEvent) =>
- section === "balances" && method === "BalanceSet",
- proposalStatusUpdated: ({ section, method }: CacheEvent) =>
- section === "proposalsEngine" && method === "ProposalStatusUpdated",
- };
- export const getWorkerRewards = async (
- api: ApiPromise,
- group: string,
- hash: Hash
- ): Promise<WorkerReward[]> => {
- let workers = Array<WorkerReward>();
- const nextWorkerId = await getNextWorker(api, group, hash);
- for (let id = 0; id < nextWorkerId; ++id) {
- const worker: WorkerOf = await getWorker(api, group, hash, id);
- const account = worker.role_account_id as AccountId;
- const memberId = worker.member_id;
- const member: Membership = await getMember(api, memberId, hash);
- const handle = member ? String(member.handle) : account.toString();
- const status = worker.is_active ? `active` : `inactive`;
- let stake: Stake;
- let reward: RewardRelationship;
- if (worker.role_stake_profile.isSome) {
- const roleStakeProfile = worker.role_stake_profile.unwrap();
- stake = await getStake(api, roleStakeProfile.stake_id, hash);
- }
- if (worker.reward_relationship.isSome) {
- // TODO changing salaries are not reflected
- const rewardId: RewardRelationshipId =
- worker.reward_relationship.unwrap();
- reward = await getWorkerReward(api, hash, rewardId);
- }
- workers.push({ id, stake, reward, status, handle, account, memberId });
- }
- return workers;
- };
- export const getWorkerRow = (
- worker: WorkerReward,
- earnedStart: number
- ): string => {
- const mtjoy = (mtjoy: number): string => (mtjoy / 1000000).toFixed(1);
- const { id, memberId, account, handle, status, reward } = worker;
- const earnedEnd = Number(reward.total_reward_received.toBigInt());
- if (!earnedEnd) return ``;
- const totalEarned = mtjoy(earnedEnd);
- const earnedTerm = mtjoy(earnedEnd - earnedStart);
- const amount = Number(reward.amount_per_payout.toBigInt());
- const rewardPerBlock = (amount / Number(reward.payout_interval)).toFixed();
- const url = `https://pioneer.joystreamstats.live/#/members/${handle}`; // TODO
- return `| ${id} | [@${handle}](${url}) | ${status} | ${rewardPerBlock} | ${earnedTerm} | ${totalEarned} |\n`;
- };
- export const getBurnedTokens = (
- burnAddress: string,
- blocks: [number, CacheEvent[]][]
- ): number => {
- let tokensBurned = 0;
- blocks.forEach(([key, transfers]) =>
- transfers.forEach((transfer) => {
- let receiver = transfer.data[1] as AccountId;
- let amount = transfer.data[2] as Balance;
- if (receiver.toString() === burnAddress) tokensBurned += Number(amount);
- })
- );
- return tokensBurned;
- };
- export const getFinalizedSpendingProposals = async (
- api: ApiPromise,
- blocks: [number, CacheEvent[]][]
- ): Promise<SpendingProposal[]> => {
- const selectedEvents: CacheEvent[] = [];
- blocks.map(([key, proposalEvents]) =>
- proposalEvents.map((proposalEvent) => selectedEvents.push(proposalEvent))
- );
- let spendingProposals: SpendingProposal[] = [];
- for (const proposalEvent of selectedEvents) {
- let statusUpdateData = proposalEvent.data[1] as any;
- const finalizedAt = statusUpdateData.finalized.finalizedAt;
- if (!(statusUpdateData.finalized && finalizedAt)) continue;
- const proposalId = proposalEvent.data[0] as ProposalId;
- const proposalInfo: ProposalOf = await getProposalInfo(api, proposalId);
- if (!proposalInfo) continue;
- try {
- const finalizedData = proposalInfo.status.asFinalized;
- const details: ProposalDetailsOf = await getProposalDetails(
- api,
- proposalId
- );
- if (finalizedData.proposalStatus.isApproved && details.isSpending) {
- let approvedData = finalizedData.proposalStatus.asApproved;
- if (!approvedData.isExecuted) continue;
- if (
- !spendingProposals.some((proposal) => proposal.id === +proposalId)
- ) {
- const title = proposalInfo.title.toString();
- const amount = +details.asSpending[0];
- spendingProposals.push({ id: +proposalId, title, amount });
- }
- }
- } catch (e) {
- console.error(`Failed to fetch proposal info: ${e.message}`);
- continue;
- }
- }
- return spendingProposals;
- };
- export const getValidatorsRewards = (
- blocks: [number, CacheEvent[]][]
- ): number => {
- let newValidatorRewards = 0;
- blocks.forEach(([key, validatorRewards]) =>
- validatorRewards.forEach(
- (reward: CacheEvent) => (newValidatorRewards += Number(reward.data[1]))
- )
- );
- return newValidatorRewards;
- };
- export const getActiveValidators = async (
- api: ApiPromise,
- hash: Hash,
- searchPreviousBlocks: boolean = false
- ): Promise<AccountId[]> => {
- const block = await getBlock(api, hash);
- let currentBlockNr = block.block.header.number.toNumber();
- let activeValidators: AccountId[];
- do {
- const hash: Hash = await getBlockHash(api, currentBlockNr);
- const validators: AccountId[] = await getValidators(api, hash);
- if (validators.length) {
- let max = await getValidatorCount(api, hash);
- activeValidators = validators.slice(0, max);
- }
- if (searchPreviousBlocks) --currentBlockNr;
- else ++currentBlockNr;
- } while (!activeValidators);
- return activeValidators;
- };
|