Bläddra i källkod

tokenomics-generator: refactor Working Groups + template

Joystream Stats 3 år sedan
förälder
incheckning
5f76d61c9f

+ 1 - 1
scripts/report-generator/src/council.ts

@@ -9,6 +9,7 @@ import {
   ProposalType,
   ReportData,
 } from "./types/council";
+import { sum } from "./lib";
 import { getCouncilAt } from "./lib/api";
 import { StorageKey, U32, u32, Vec } from "@polkadot/types";
 import { Backer, Seats } from "@joystream/types/council";
@@ -246,7 +247,6 @@ async function getCouncilMembersInfo(
       )) as Membership;
       info.username = membership.handle.toString();
       info.ownStake = Number(seat.stake.toBigInt());
-      const sum = (a: number[]) => a.reduce((s: number, i: number) => s + i, 0);
       info.backersStake = sum(seat.backers.map((b: Backer) => +b.stake));
       return info;
     })

+ 4 - 2
scripts/report-generator/src/generator.ts

@@ -109,8 +109,10 @@ const tokenomicsReport = async (
 
   console.log(`-> Writing report to ${fileName}`);
   for (const entry of Object.entries(stats)) {
-    const regex = new RegExp("{" + entry[0] + "}", "g");
-    fileData = fileData.replace(regex, entry[1].toString());
+    if (entry[1] !== null) {
+      let regex = new RegExp("{" + entry[0] + "}", "g");
+      fileData = fileData.replace(regex, entry[1]?.toString());
+    } else console.warn(`empty value:`, entry[0]);
   }
   fs.writeFileSync(`${dir}/${fileName}`, fileData);
   return true;

+ 155 - 229
scripts/report-generator/src/tokenomics.ts

@@ -9,12 +9,8 @@ import {
   EventRecord,
   Hash,
 } from "@polkadot/types/interfaces";
-import {
-  Config,
-  MintStatistics,
-  Statistics,
-  WorkersInfo,
-} from "./types/tokenomics";
+import { Config, MintStats, Statistics, WorkersInfo } from "./types/tokenomics";
+import { sum } from "./lib";
 import {
   CacheEvent,
   Bounty,
@@ -22,11 +18,9 @@ import {
   SpendingProposal,
   StatusData,
 } from "./lib/types";
-
 import { Option, u32, Vec } from "@polkadot/types";
 import { ElectionStake, SealedVote, Seats } from "@joystream/types/council";
 import { Mint, MintId } from "@joystream/types/mint";
-import { ContentId, DataObjectType } from "@joystream/types/legacy"; //@joystream/types/storage
 import { CategoryId } from "@joystream/types/forum";
 import { MemberId, Membership } from "@joystream/types/members";
 import {
@@ -108,6 +102,16 @@ export class StatisticsCollector {
   private api?: ApiPromise;
   private blocksEventsCache: Map<number, CacheEvent[]>;
   private statistics: Statistics;
+  private groups = [
+    // map chain prefix to group tag
+    ["contentWorkingGroup", "Curators", "curators"],
+    ["storageWorkingGroup", "Storage Providers", "storageProviders"],
+    ["distributionWorkingGroup", "Distribution", "distribution"],
+    //["gatewayWorkingGroup", "Gateways", "gateways"],
+    ["operationsWorkingGroupAlpha", "Operations", "operationsGroupAlpha"],
+    ["operationsWorkingGroupBeta", "Marketing", "operationsGroupBeta"],
+    ["operationsWorkingGroupGamma", "Gamma", "operationsGroupGamma"],
+  ];
 
   constructor() {
     this.blocksEventsCache = new Map<number, CacheEvent[]>();
@@ -115,6 +119,7 @@ export class StatisticsCollector {
   }
 
   saveStats(data: any) {
+    console.debug(`saving`, Object.keys(data));
     Object.keys(data).map((key: string) => (this.statistics[key] = data[key]));
   }
 
@@ -180,15 +185,13 @@ export class StatisticsCollector {
     eventStats(this.blocksEventsCache); // print event stats
     return Promise.all([
       this.fillTokenInfo(startBlock, endBlock, startHash, endHash, config),
-      this.fillMintsInfo(startHash, endHash),
+      this.fillMintsInfo([startHash, endHash]),
       this.fillCouncilInfo(startHash, endHash, config.councilRoundOffset),
       this.fillCouncilElectionInfo(startBlock),
       this.fillValidatorInfo(startHash, endHash),
-      this.fillStorageProviderInfo(startBlock, endBlock, startHash, endHash),
-      this.fillCuratorInfo(startHash, endHash),
-      this.fillOperationsInfo(startBlock, endBlock, startHash, endHash),
       this.fillMembershipInfo(startHash, endHash),
       this.fillForumInfo(startHash, endHash),
+      this.fillWorkingGroupsInfo([startHash, endHash]),
     ]);
   }
 
@@ -198,8 +201,12 @@ export class StatisticsCollector {
     } catch {
       console.warn("File with spending proposal categories not found: ${file}");
     }
-    const fileContent = await fs.readFile(file);
-    const proposals = parse(fileContent).slice(1);
+    const proposals = fsSync
+      .readFileSync(file, "utf-8")
+      .split("\n")
+      .map((line: string) => line.split(","))
+      .filter((fields: string[]) => fields.length === 12)
+      .slice(1);
     console.log(`Loaded ${proposals.length} proposals.`);
     return proposals
       .filter(
@@ -286,35 +293,13 @@ export class StatisticsCollector {
       endBlock - startBlock,
       endHash
     );
-    const newCuratorInfo = await this.computeWorkingGroupReward(
-      startHash,
-      endHash,
-      "contentDirectory"
-    );
-
     this.saveStats({
       spendingProposalsTotal,
       newCouncilRewards: newCouncilRewards.toFixed(2),
-      newCuratorRewards: newCuratorInfo.rewards.toFixed(2),
     });
   }
 
-  async getMintInfo(
-    api: ApiPromise,
-    mintId: MintId,
-    startHash: Hash,
-    endHash: Hash
-  ): Promise<MintStatistics> {
-    const startMint: Mint = await getMint(api, startHash, mintId);
-    const endMint: Mint = await getMint(api, endHash, mintId);
-    let stats = new MintStatistics();
-    stats.startMinted = getTotalMinted(startMint);
-    stats.endMinted = getTotalMinted(endMint);
-    stats.diffMinted = stats.endMinted - stats.startMinted;
-    stats.percMinted = getPercent(stats.startMinted, stats.endMinted);
-    return stats;
-  }
-
+  //
   async computeCouncilReward(
     roundNrBlocks: number,
     endHash: Hash
@@ -353,79 +338,77 @@ export class StatisticsCollector {
     return avgCouncilRewardPerBlock * roundNrBlocks;
   }
 
+  // Generate mint stats and WG sections
+  fillWorkingGroupsInfo(range: Hash[]) {
+    const promises = this.groups.map((group: string[], i: number) =>
+      this.groupStats(group, range, i).then((stats) => this.groupSection(stats))
+    );
+    Promise.all(promises).then((sections) =>
+      this.saveStats({ workingGroups: sections.join() })
+    );
+  }
+
+  // Generate WG markdown
+  groupSection({ workers, stakes, workersTable, index, labels }: WorkersInfo) {
+    const [chainName, tag, pioneerName] = labels;
+    return `
+
+### 4.${index} ${tag}
+* [*${chainName}*](https://testnet.joystream.org/#/working-groups/opportunities/${pioneerName})
+| Property                | Start Block | End Block | % Change |
+|-------------------------|--------------|--------------|----------|
+| Number of  Workers | ${workers.start} | ${workers.end} | ${workers.change} |
+| Total  Stake | ${stakes.start} | ${stakes.end} | ${stakes.change} |
+
+${workersTable}
+`;
+  }
+
   // Summarize stakes and rewards at start and end
-  async computeWorkingGroupReward(
-    startHash: Hash,
-    endHash: Hash,
-    workingGroup: string
+  async groupStats(
+    labels: string[],
+    range: Hash[],
+    index: number
   ): Promise<WorkersInfo> {
-    const group = workingGroup + "WorkingGroup";
-    let info = new WorkersInfo();
-
-    // stakes at start
+    const [startHash, endHash] = range;
+    const [group, tag] = labels;
+    let workers = { start: 0, end: 0, change: 0 };
+    let stakes = { start: 0, end: 0, change: 0 };
     const workersStart: WorkerReward[] = await getWorkerRewards(
       this.api,
       group,
       startHash
     );
-    workersStart.forEach(({ stake }) => {
-      if (stake) info.startStake += stake.value.toNumber();
-    });
-
-    // stakes at end
+    workers.start = workersStart.length;
+    stakes.start = sum(workersStart.map(({ stake }) => +stake?.value || 0));
     const workersEnd: WorkerReward[] = await getWorkerRewards(
       this.api,
       group,
       endHash
     );
-    let workers = ``;
+    workers.end = workersEnd.length;
+    workers.change = getPercent(workers.start, workers.end);
+    let workerRows = ``; // rewards table
     workersEnd.forEach(async (worker) => {
-      if (worker.stake) info.endStake += worker.stake.value.toNumber();
+      if (worker.stake) stakes.end += worker.stake.value.toNumber();
       if (!worker.reward) return;
       let earnedBefore = 0;
       const hired = workersStart.find((w) => w.id === worker.id);
       if (hired) earnedBefore = hired.reward.total_reward_received.toNumber();
-      workers += getWorkerRow(worker, earnedBefore);
+      workerRows += getWorkerRow(worker, earnedBefore);
     });
-    const groupTag =
-      workingGroup === `storage`
-        ? `storageProviders`
-        : workingGroup === `contentDirectory`
-        ? `curators`
-        : workingGroup === `operations`
-        ? `operations`
-        : ``;
-    if (workers.length) {
-      const header = `| # | Member | Status | tJOY / Block | M tJOY Term | M tJOY total |\n|--|--|--|--|--|--|\n`;
-      this.saveStats({ [groupTag]: header + workers });
-    } else this.saveStats({ [groupTag]: `` });
-
-    const mintId = await getGroupMint(this.api, group);
-    const mintStart: Mint = await getMint(this.api, startHash, mintId);
-    const mintEnd: Mint = await getMint(this.api, endHash, mintId);
-    const totalMinted = (m: Mint) => Number(m.total_minted);
-    info.rewards = totalMinted(mintEnd) - totalMinted(mintStart);
-    info.endNrOfWorkers = workersEnd.length;
-    return info;
+    stakes.change = getPercent(stakes.start, stakes.end);
+    const workersTable = this.workersTable(workerRows);
+    return { labels, index, workers, stakes, workersTable };
   }
 
-  async computeGroupMintStats(
-    [label, tag]: string[],
-    startHash: Hash,
-    endHash: Hash
-  ) {
-    const group = label + "WorkingGroup";
-    const mint = await getGroupMint(this.api, group);
-    const info = await this.getMintInfo(this.api, mint, startHash, endHash);
-    let stats: { [key: string]: number } = {};
-    stats[`start${tag}Minted`] = info.startMinted;
-    stats[`end${tag}Minted`] = info.endMinted;
-    stats[`new${tag}Minted`] = info.diffMinted;
-    stats[`perc${tag}Minted`] = info.percMinted;
-    this.saveStats(stats);
+  workersTable(rows: string) {
+    if (!rows.length) return ``;
+    return `| # | Member | Status | tJOY / Block | M tJOY Term | M tJOY total |\n|--|--|--|--|--|--|\n${rows}`;
   }
 
-  async fillMintsInfo(startHash: Hash, endHash: Hash): Promise<void> {
+  async fillMintsInfo(range: Hash[]): Promise<void> {
+    const [startHash, endHash] = range;
     const startNrMints = await getMintsCreated(this.api, startHash);
     const endNrMints = await getMintsCreated(this.api, endHash);
     const newMints = endNrMints - startNrMints;
@@ -453,24 +436,36 @@ export class StatisticsCollector {
     this.saveStats({ newMints, totalMinted, totalMintCapacityIncrease });
 
     // council
-    const councilInfo = await this.getMintInfo(
-      this.api,
-      await getCouncilMint(this.api, endHash),
-      startHash,
-      endHash
+    const councilStats = await getCouncilMint(this.api, endHash).then(
+      async (id) => this.mintStats(this.api, id, range)
     );
-    this.saveStats({
-      startCouncilMinted: councilInfo.startMinted,
-      endCouncilMinted: councilInfo.endMinted,
-      newCouncilMinted: councilInfo.diffMinted,
-      percNewCouncilMinted: councilInfo.percMinted,
+    const { start, end, diff, change } = councilStats;
+    let tokenomics = `| Council | ${diff} |\n`;
+    let mintStats = `| Council Total Minted | ${start} | ${end} | ${diff} | ${change} |\n`;
+
+    // Calculate WG Mint Growth
+    const promises = this.groups.map(async ([group, tag]: string[]) => {
+      const id = await getGroupMint(this.api, group);
+      const stats = await this.mintStats(this.api, id, range);
+      const { start, end, diff, change } = stats;
+      tokenomics += `| ${tag} | ${diff} |\n`;
+      mintStats += `| ${tag} Minted | ${start} | ${end} | ${diff} | ${change} |\n`;
     });
-    // working groups
-    const groups = [
-      ["contentDirectory", "Curator"],
-      ["storage", "Storage"],
-      ["operations", "Operations"],
-    ].forEach((group) => this.computeGroupMintStats(group, startHash, endHash));
+    Promise.all(promises).then(() => this.saveStats({ mintStats, tokenomics }));
+  }
+
+  // Calculate growth
+  async mintStats(
+    api: ApiPromise,
+    mintId: MintId,
+    range: Hash[]
+  ): Promise<MintStats> {
+    const [startHash, endHash] = range;
+    const startMint: Mint = await getMint(api, startHash, mintId);
+    const endMint: Mint = await getMint(api, endHash, mintId);
+    const start = getTotalMinted(startMint);
+    const end = getTotalMinted(endMint);
+    return this.formatChange(start, end);
   }
 
   async fillCouncilInfo(
@@ -514,10 +509,17 @@ export class StatisticsCollector {
         event.section == "councilElection" && event.method == "CouncilElected"
     );
 
-    if (!isStartBlockFirstCouncilBlock)
+    let election = {
+      electionApplicants: 0,
+      electionApplicantsStakes: 0,
+      electionVotes: 0,
+    };
+    if (!isStartBlockFirstCouncilBlock) {
+      this.saveStats(election);
       return console.warn(
         "Note: The given start block is not the first block of the council round so council election information will be empty"
       );
+    }
 
     let lastBlockHash = await getBlockHash(this.api, startBlock - 1);
     let applicants: Vec<AccountId> = await getCouncilApplicants(
@@ -533,18 +535,12 @@ export class StatisticsCollector {
       );
       electionApplicantsStakes += applicantStakes.new.toNumber();
     }
-    // let seats = await getCouncil(this.api,startBlockHash) as Seats;
-    //TODO: Find a more accurate way of getting the votes
-    const votes: Vec<Hash> = await getCouncilCommitments(
+    election.electionApplicants = applicants.length;
+    election.electionVotes = await getCouncilCommitments(
       this.api,
       lastBlockHash
-    );
-
-    this.saveStats({
-      electionApplicants: applicants.length,
-      electionApplicantsStakes,
-      electionVotes: votes.length,
-    });
+    ).then((votes: Vec<Hash>) => votes.length);
+    this.saveStats(election);
   }
 
   async fillValidatorInfo(startHash: Hash, endHash: Hash): Promise<void> {
@@ -576,89 +572,6 @@ export class StatisticsCollector {
     });
   }
 
-  async fillStorageProviderInfo(
-    startBlock: number,
-    endBlock: number,
-    startHash: Hash,
-    endHash: Hash
-  ): Promise<void> {
-    let storageProvidersRewards = await this.computeWorkingGroupReward(
-      startHash,
-      endHash,
-      "storage"
-    );
-    const newStorageProviderReward = Number(
-      storageProvidersRewards.rewards.toFixed(2)
-    );
-    const startStorageProvidersStake = storageProvidersRewards.startStake;
-    const endStorageProvidersStake = storageProvidersRewards.endStake;
-
-    const group = "storageWorkingGroup";
-    const startStorageProviders = await getWorkers(this.api, group, startHash);
-    const endStorageProviders = await getWorkers(this.api, group, endHash);
-
-    this.saveStats({
-      newStorageProviderReward,
-      startStorageProvidersStake,
-      endStorageProvidersStake,
-      percNewStorageProviderStake: getPercent(
-        startStorageProvidersStake,
-        endStorageProvidersStake
-      ),
-      startStorageProviders,
-      endStorageProviders,
-      percNewStorageProviders: getPercent(
-        startStorageProviders,
-        endStorageProviders
-      ),
-    });
-  }
-
-  async fillCuratorInfo(startHash: Hash, endHash: Hash): Promise<void> {
-    const group = "contentDirectoryWorkingGroup";
-    const startCurators = await getWorkers(this.api, group, startHash);
-    const endCurators = await getWorkers(this.api, group, endHash);
-
-    this.saveStats({
-      startCurators,
-      endCurators,
-      percNewCurators: getPercent(startCurators, endCurators),
-    });
-  }
-
-  async fillOperationsInfo(
-    startBlock: number,
-    endBlock: number,
-    startHash: Hash,
-    endHash: Hash
-  ): Promise<void> {
-    const operationsRewards = await this.computeWorkingGroupReward(
-      startHash,
-      endHash,
-      "operations"
-    );
-    const newOperationsReward = operationsRewards.rewards.toFixed(2);
-    const startOperationsStake = operationsRewards.startStake;
-    const endOperationsStake = operationsRewards.endStake;
-
-    const group = "operationsWorkingGroup";
-    const startWorkers = await getWorkers(this.api, group, startHash);
-    const endWorkers = await getWorkers(this.api, group, endHash);
-
-    this.saveStats({
-      newOperationsReward: Number(newOperationsReward),
-      startOperationsWorkers: startWorkers,
-      endOperationsWorkers: endWorkers,
-      percNewOperationsWorkers: getPercent(startWorkers, endWorkers),
-      startOperationsStake,
-      endOperationsStake,
-      percNewOperationstake: getPercent(
-        startOperationsStake,
-        endOperationsStake
-      ),
-    });
-  }
-
   async fillMembershipInfo(startHash: Hash, endHash: Hash): Promise<void> {
     const startMembers = await getNextMember(this.api, startHash);
     const endMembers = await getNextMember(this.api, endHash);
@@ -797,49 +710,62 @@ export class StatisticsCollector {
       }
 
       // calculate inflation
-      let startTermExchangeRate = 0;
-      let endTermExchangeRate = 0;
+      let [rateStart, rateEnd, fiatStart, fiatEnd] = [0, 0, 0, 0];
       if (filteredExchanges.length) {
         const lastExchangeEvent =
           filteredExchanges[filteredExchanges.length - 1];
-        startTermExchangeRate = filteredExchanges[0].price * 1000000;
-        endTermExchangeRate = lastExchangeEvent.price * 1000000;
-      } else {
-        startTermExchangeRate =
-          filteredDollarPoolChanges[0].rateAfter * 1000000;
+        rateStart = filteredExchanges[0].price * 1000000;
+        rateEnd = lastExchangeEvent.price * 1000000;
+      } else if (filteredDollarPoolChanges.length) {
+        rateStart = filteredDollarPoolChanges[0].rateAfter * 1000000;
         const lastEvent =
           filteredDollarPoolChanges[filteredDollarPoolChanges.length - 1];
-        endTermExchangeRate = lastEvent.rateAfter * 1000000;
+        rateEnd = lastEvent.rateAfter * 1000000;
+      }
+
+      // dollar pool size
+      if (allDollarPoolChanges.length) {
+        fiatStart =
+          allDollarPoolChanges[0].change > 0
+            ? allDollarPoolChanges[0].valueAfter -
+              allDollarPoolChanges[0].change
+            : allDollarPoolChanges[0].valueAfter;
+        const endDollarEvent =
+          allDollarPoolChanges[allDollarPoolChanges.length - 1];
+        fiatEnd = endDollarEvent.valueAfter;
       }
-      let inflationPct = getPercent(endTermExchangeRate, startTermExchangeRate);
+      const fiat = this.formatChangePrefix(fiatStart, fiatEnd, "fiat");
+      const rate = this.formatChangePrefix(rateStart, rateEnd, "price");
       console.log(
         "# USD / 1M tJOY Rate\n",
-        `@ Term start (block #${startBlockHeight}: ${startTermExchangeRate}\n`,
-        `@ Term end (block #${endBlockHeight}: ${endTermExchangeRate}\n`,
-        `Inflation: ${inflationPct}`
+        `@ Term start (block #${startBlockHeight}: ${rate.start}\n`,
+        `@ Term end (block #${endBlockHeight}: ${rate.end}\n`,
+        `Inflation: ${rate.change}`
       );
-
-      const startDollarPool =
-        allDollarPoolChanges[0].change > 0
-          ? allDollarPoolChanges[0].valueAfter - allDollarPoolChanges[0].change
-          : allDollarPoolChanges[0].valueAfter;
-      const endDollarEvent =
-        allDollarPoolChanges[allDollarPoolChanges.length - 1];
-      const endDollarPool = endDollarEvent.valueAfter;
-      const dollarPoolPctChange = getPercent(startDollarPool, endDollarPool);
-
-      this.saveStats({
-        startTermExchangeRate: startTermExchangeRate.toFixed(2),
-        endTermExchangeRate: endTermExchangeRate.toFixed(2),
-        inflationPct,
-        startDollarPool: startDollarPool.toFixed(2),
-        endDollarPool: endDollarPool.toFixed(2),
-        dollarPoolPctChange,
-        dollarPoolRefills,
-      });
+      this.saveStats({ ...fiat, ...rate, dollarPoolRefills });
     });
   }
 
+  formatChange(input: number, output: number): MintStats {
+    const diff = output - input;
+    const change = getPercent(output, input);
+    return { start: input.toFixed(2), end: output.toFixed(2), diff, change };
+  }
+  formatChangePrefix(
+    input: number,
+    output: number,
+    pre: string
+  ): { [key: string]: string | number } {
+    const diff = output - input;
+    const change = getPercent(output, input);
+    return {
+      [`${pre}Start`]: input.toFixed(2),
+      [`${pre}End`]: output.toFixed(2),
+      [`${pre}Diff`]: diff,
+      [`${pre}Change`]: change,
+    };
+  }
+
   async buildBlocksEventCache(
     startBlock: number,
     endBlock: number,

+ 15 - 73
scripts/report-generator/src/types/tokenomics.ts

@@ -15,17 +15,13 @@ export interface Config {
 }
 
 export class Statistics {
-  [key: string]: number | string;
+  [key: string]: number | string | { [key: string]: number | string };
   councilRound: number = 0;
   councilMembers: number = 0;
 
-  electionApplicants: number = 0;
-  electionAvgApplicants: number = 0;
-  perElectionApplicants: number = 0;
-
-  electionApplicantsStakes: number = 0;
-  electionVotes: number = 0;
-  avgVotePerApplicant: number = 0;
+  tokenomics: string;
+  mintStats: string;
+  workingGroups: string;
 
   dateStart: string = "";
   dateEnd: string = "";
@@ -81,26 +77,6 @@ export class Statistics {
 
   totalMintCapacityIncrease: number = 0;
 
-  startCouncilMinted: number = 0;
-  endCouncilMinted: number = 0;
-  newCouncilMinted: number = 0;
-  percNewCouncilMinted: number = 0;
-
-  startCuratorMinted: number = 0;
-  endCuratorMinted: number = 0;
-  newCuratorMinted: number = 0;
-  percCuratorMinted: number = 0;
-
-  startStorageMinted: number = 0;
-  endStorageMinted: number = 0;
-  newStorageMinted: number = 0;
-  percStorageMinted: number = 0;
-
-  startOperationsMinted: number = 0;
-  endOperationsMinted: number = 0;
-  newOperationsMinted: number = 0;
-  percOperationsMinted: number = 0;
-
   startIssuance: number = 0;
   endIssuance: number = 0;
   newIssuance: number = 0;
@@ -116,29 +92,7 @@ export class Statistics {
   endValidatorsStake: number = 0;
   percNewValidatorsStake: number = 0;
 
-  startStorageProviders: number = 0;
-  endStorageProviders: number = 0;
-  percNewStorageProviders: number = 0;
-  newStorageProviderReward: number = 0;
-  startStorageProvidersStake: number = 0;
-  endStorageProvidersStake: number = 0;
-  percNewStorageProviderStake: number = 0;
-
-  startOperationsWorkers: number = 0;
-  endOperationsWorkers: number = 0;
-  percNewOperationsWorkers: number = 0;
-  newOperationsReward: number = 0;
-  startOperationsStake: number = 0;
-  endOperationsStake: number = 0;
-  percNewOperationstake: number = 0;
-
   newCouncilRewards: number = 0;
-
-  startCurators: number = 0;
-  endCurators: number = 0;
-  percNewCurators: number = 0;
-  newCuratorRewards: number = 0;
-
   startUsedSpace: number = 0;
   newUsedSpace: number = 0;
   endUsedSpace: number = 0;
@@ -179,12 +133,12 @@ export class ValidatorReward {
   blockNumber: number = 0;
 }
 
-export class WorkersInfo {
-  rewards: number = 0;
-  startStake: number = 0;
-  endStake: number = 0;
-  startNrOfWorkers: number = 0;
-  endNrOfWorkers: number = 0;
+export interface WorkersInfo {
+  index: number;
+  labels: string[];
+  stakes: { start: number; end: number; change: number };
+  workers: { start: number; end: number; change: number };
+  workersTable: string;
 }
 
 export class Exchange {
@@ -206,23 +160,11 @@ export enum ProposalTypes {
   SetStorageRoleParameters = "SetStorageRoleParameters",
 }
 
-export class MintStatistics {
-  startMinted: number;
-  endMinted: number;
-  diffMinted: number;
-  percMinted: number;
-
-  constructor(
-    startMinted: number = 0,
-    endMinted: number = 0,
-    diffMinted: number = 0,
-    percMinted: number = 0
-  ) {
-    this.startMinted = startMinted;
-    this.endMinted = endMinted;
-    this.diffMinted = diffMinted;
-    this.percMinted = percMinted;
-  }
+export interface MintStats {
+  start: string;
+  end: string;
+  diff: number;
+  change: number;
 }
 
 export class Media {

+ 10 - 38
scripts/report-generator/templates/tokenomics.md

@@ -11,39 +11,33 @@ This is a report which explains the current state of the Joystream network in nu
 | Property            | Start Block | End Block | % Change |
 |---------------------|--------------|--------------|----------|
 | Total Tokens Minted |  {startIssuance} | {endIssuance} | {percNewIssuance} |
-| USD Pool |  {startDollarPool} | {endDollarPool} | {dollarPoolPctChange} |
+| USD Pool |  {fiatStart} | {fiatEnd} | {fiatChange} |
 
-| Property            | Value        |
+| Role                | Value        |
 |---------------------|--------------|
 | Total Tokens Burned | {newTokensBurn} |
 | Spending Proposals (Executed) | {spendingProposalsTotal} |
 | Bounties paid       | {bountiesTotalPaid} |
 | Validator Role      | {newValidatorRewards} |
-| Storage Role        | {newStorageProviderReward} |
-| Curator Role        | {newCuratorRewards} |
-| Operations Role     | {newOperationsReward} |
+{tokenomics}
 
 ### 2.2 Fiat Pool
 | Property            | Start Block, USD | End Block, USD | % Change |
 |---------------------|--------------|--------------|----------|
-| USD Pool | {startDollarPool} | {endDollarPool} | {dollarPoolPctChange} |
+| USD Pool |  {fiatStart} | {fiatEnd} | {fiatChange} |
 
 {dollarPoolRefills}
 
 ### 2.3 Mints
-| Property                    | Start Block           | End Block | % Change |
+| Minted per Role             | Start Block           | End Block | Difference | % Change |
 |-----------------------------|-----------------------|--------------|----------|
-| Council Mint Total Minted   | {startCouncilMinted}  | {endCouncilMinted} |{percNewCouncilMinted} |
-| Curator Mint Total Minted   | {startCuratorMinted} | {endCuratorMinted} | {percCuratorMinted} |
-| Storage Mint Total Minted   | {startStorageMinted} | {endStorageMinted} | {percStorageMinted} |
-| Operations Mint Total Minted | {startOperationsMinted} | {endOperationsMinted} | {percOperationsMinted} |
-
+{mintStats}
 
 ### 2.4 tJOY Inflation
 
-* Start Block Exchange Rate, USD/1M tJOY: {startTermExchangeRate}
-* End Block Exchange Rate, USD/1M tJOY: {endTermExchangeRate}
-* Inflation, %: {inflationPct}
+* Start Block Exchange Rate, USD/1M tJOY: {priceStart}
+* End Block Exchange Rate, USD/1M tJOY: {priceEnd}
+* Inflation, %: {priceChange}
 
 Negative value indicates deflation
 
@@ -69,29 +63,7 @@ Negative value indicates deflation
 | Number of Validators       | {startValidators} | {endValidators} | {percValidators} |
 | Validator Total Stake      | {startValidatorsStake} | {endValidatorsStake} | {percNewValidatorsStake} |
 
-
-### 4.2 Storage Role
-| Property                | Start Block | End Block | % Change |
-|-------------------------|--------------|--------------|----------|
-| Number of Storage Workers | {startStorageProviders} | {endStorageProviders} | {percNewStorageProviders} |
-| Total Storage Stake (workers + lead) | {startStorageProvidersStake} | {endStorageProvidersStake} | {percNewStorageProviderStake} |
-
-{storageProviders}
-
-### 4.3 Curator Role
-| Property                | Start Block | End Block | % Change |
-|-------------------------|--------------|--------------|----------|
-| Number of Curators      | {startCurators} | {endCurators} | {percNewCurators} |
-
-{curators}
-
-### 4.4 Operations Role
-| Property                | Start Block | End Block | % Change |
-|-------------------------|--------------|--------------|----------|
-| Number of Operations Workers      | {startOperationsWorkers} | {endOperationsWorkers} | {percNewOperationsWorkers} |
-| Total Operations Stake (workers + lead) | {startOperationsStake} | {endOperationsStake} | {percNewOperationstake} |
-
-{operations}
+{workingGroups}
 
 ## 5.0 User Generated Content
 ### 5.1 Membership Information