瀏覽代碼

validator rewards

Joystream Stats 3 年之前
父節點
當前提交
b186689a97

+ 9 - 12
src/App.tsx

@@ -141,18 +141,9 @@ class App extends React.Component<IProps, IState> {
           era = currentEra;
           this.fetchStakes(api, era, this.state.validators);
           this.save("era", era);
-
-          const lastReward = await api.query.staking.erasValidatorReward(
-            era - 1
-          );
-          this.save("lastReward", Number(lastReward));
-        }
-        if (era > 0 && this.state.lastReward === 0) {
-          const lastReward = await api.query.staking.erasValidatorReward(
-            era - 1
-          );
-          this.save("lastReward", Number(lastReward));
-        }
+          this.fetchLastReward(api, era - 1);
+        } else if (this.state.lastReward === 0)
+          this.fetchLastReward(api, currentEra);
 
         this.fetchEraRewardPoints(api, Number(era));
 
@@ -177,6 +168,12 @@ class App extends React.Component<IProps, IState> {
     this.fetchNominators(api);
   }
 
+  async fetchLastReward(api: Api, era: number) {
+    const lastReward = Number(await api.query.staking.erasValidatorReward(era));
+    console.debug(`last reward`, lastReward);
+    this.save("lastReward", lastReward);
+  }
+
   async fetchTokenomics() {
     console.debug(`Updating tokenomics`);
     const { data } = await axios.get("https://status.joystream.org/status");

+ 2 - 1
src/components/Dashboard/index.tsx

@@ -9,7 +9,7 @@ const Dashboard = (props: IState) => {
 
   return (
     <div className="w-100 flex-grow-1 d-flex align-items-center justify-content-center d-flex flex-column">
-      <div className="box position-fixed " style={{ top: "0", right: "0" }}>
+      <div className="box position-abasolute" style={{ top: "0", right: "0" }}>
         <Link to="/mint">Tools</Link>
       </div>
 
@@ -68,6 +68,7 @@ const Dashboard = (props: IState) => {
         save={props.save}
         rewardPoints={props.rewardPoints}
         issued={tokenomics ? Number(tokenomics.totalIssuance) : 0}
+        price={tokenomics ? Number(tokenomics.price) : 0}
       />
     </div>
   );

+ 33 - 5
src/components/Validators/MinMax.tsx

@@ -1,14 +1,18 @@
 import React from "react";
 import { Stakes } from "../../types";
 
+const dollar = (d: number) => (d > 0 ? `$ ${Math.round(d * 100) / 100}` : "");
+
 const MinMax = (props: {
   stakes?: { [key: string]: Stakes };
   issued: number;
   validators: number;
   nominators: number;
   waiting: number;
+  reward: number;
+  price: number;
 }) => {
-  const { issued, stakes, validators, nominators, waiting } = props;
+  const { issued, stakes, validators, waiting, reward, price } = props;
   if (!stakes || !Object.values(stakes).length) return <span />;
 
   let sum = 0;
@@ -26,12 +30,12 @@ const MinMax = (props: {
     <div className="float-right text-right">
       <div className="mb-2">
         <div>
-          <div className="float-left mr-1">validators:</div>
-          {validators}
+          <div className="float-left mr-1">nominators:</div>
+          {props.nominators}
         </div>
         <div>
-          <div className="float-left mr-1">nominators:</div>
-          {nominators}
+          <div className="float-left mr-1">validators:</div>
+          {validators}
         </div>
         <div>
           <div className="float-left mr-1">waiting:</div>
@@ -51,6 +55,30 @@ const MinMax = (props: {
       <div>
         <div className="float-left mr-1">max:</div> {maxStake} JOY
       </div>
+
+      <Reward reward={reward} price={price} validators={validators} />
+    </div>
+  );
+};
+
+const Reward = (props: {
+  reward: number;
+  price: number;
+  validators: number;
+}) => {
+  const { reward, price, validators } = props;
+  if (!reward) return <div />;
+
+  return (
+    <div className="mt-2">
+      <b>total reward per hour</b>
+      <div>{reward} JOY</div>
+      <div>{dollar(price * reward)}</div>
+      <div className="mt-2">per validator:</div>
+      <div className="text-warning">
+        {Math.round(reward / validators)} JOY
+        <div>{dollar((price * reward) / validators)}</div>
+      </div>
     </div>
   );
 };

+ 15 - 2
src/components/Validators/Nominators.tsx

@@ -4,14 +4,22 @@ import { Handles, Stake } from "../../types";
 
 // TODO use MemberBox after refactor
 
+const Reward = (reward: number) =>
+  reward > 0 ? (
+    <span className="text-warning mx-1">+{Math.round(reward)}</span>
+  ) : (
+    <span />
+  );
+
 const Nominators = (props: {
   sortBy: (field: string) => void;
   toggleExpand: () => void;
   expand: boolean;
   handles: Handles;
   nominators?: Stake[];
+  reward: number;
 }) => {
-  const { sortBy, toggleExpand, expand, handles, nominators } = props;
+  const { sortBy, toggleExpand, expand, handles, nominators, reward } = props;
 
   if (!nominators || !nominators.length) return <div />;
 
@@ -22,6 +30,7 @@ const Nominators = (props: {
     return (
       <div className="d-flex flex-row">
         <div onClick={() => sortBy("othersStake")}>{nominators[0].value}</div>
+        {Reward(reward)}
         <User id={nominators[0].who} handle={handles[nominators[0].who]} />
       </div>
     );
@@ -34,6 +43,7 @@ const Nominators = (props: {
         {nominators.map((n) => (
           <div key={n.who} className="d-flex flex-row">
             <div>{n.value}</div>
+            {Reward(reward * (n.value / sum))}
             <User id={n.who} handle={handles[n.who]} />
           </div>
         ))}
@@ -46,7 +56,10 @@ const Nominators = (props: {
       {nominators
         .sort((a, b) => b.value - a.value)
         .map((n) => (
-          <User key={n.who} id={n.who} handle={handles[n.who]} />
+          <span key={n.who}>
+            {Reward(reward * (n.value / sum))}
+            <User id={n.who} handle={handles[n.who]} />
+          </span>
         ))}
       <span onClick={toggleExpand}> +</span>
     </div>

+ 27 - 5
src/components/Validators/Validator.tsx

@@ -27,6 +27,7 @@ interface IProps {
   starred: string | undefined;
   stakes?: { [key: string]: Stakes };
   rewardPoints?: RewardPoints;
+  reward?: number;
 }
 
 interface IState {
@@ -63,6 +64,7 @@ class Validator extends Component<IProps, IState> {
       starred,
       stakes,
       rewardPoints,
+      reward = 0,
     } = this.props;
     const { expandNominators, hidden } = this.state;
     if (hidden) return <div />;
@@ -70,9 +72,23 @@ class Validator extends Component<IProps, IState> {
     const handle = handles[validator] || validator;
     const points = rewardPoints ? rewardPoints.individual[validator] : "";
     const myStakes = stakes ? stakes[validator] : undefined;
-    const totalStake = myStakes ? myStakes.total : "";
-    const ownStake = myStakes ? myStakes.own : "";
-    const commission = myStakes ? `${myStakes.commission}%` : "";
+    let totalStake = 0;
+    let ownStake = 0;
+    let commission = "";
+    let ownReward = 0;
+    let othersReward = 0;
+
+    if (myStakes) {
+      totalStake = myStakes.total;
+      ownStake = myStakes.own;
+      commission = `${myStakes.commission}%`;
+
+      const own = ownStake / totalStake;
+      const others = 1 - own;
+      const commissionShare = myStakes.commission / 100;
+      othersReward = reward * others * (1 - commissionShare);
+      ownReward = reward * (own + others * commissionShare);
+    }
 
     return (
       <div className="mx-3 d-flex flex-row">
@@ -111,13 +127,19 @@ class Validator extends Component<IProps, IState> {
           {commission}
         </div>
         <div className="col-1 text-right" onClick={() => sortBy("totalStake")}>
-          {totalStake}
+          {totalStake > 0 && totalStake}
         </div>
         <div className="col-1 text-right" onClick={() => sortBy("ownStake")}>
-          {ownStake}
+          {ownStake > 0 && ownStake}
         </div>
+        {ownReward ? (
+          <div className="text-warning">+{Math.round(ownReward)}</div>
+        ) : (
+          <div />
+        )}
         <div className="col-3 mb-1 text-left">
           <Nominators
+            reward={othersReward}
             toggleExpand={this.toggleExpandNominators}
             sortBy={sortBy}
             expand={expandNominators}

+ 9 - 2
src/components/Validators/index.tsx

@@ -13,7 +13,6 @@ import {
 
 interface IProps {
   era: number;
-  issued: number;
   councils: Seat[][];
   handles: Handles;
   members: Member[];
@@ -29,6 +28,9 @@ interface IProps {
   stakes?: { [key: string]: Stakes };
   rewardPoints?: RewardPoints;
   lastReward: number;
+
+  issued: number;
+  price: number;
 }
 
 interface IState {
@@ -112,6 +114,7 @@ class Validators extends Component<IProps, IState> {
       rewardPoints,
       stakes,
       issued,
+      price,
     } = this.props;
     const { sortBy } = this.state;
     const startTime = now - block * 6000;
@@ -123,14 +126,16 @@ class Validators extends Component<IProps, IState> {
     return (
       <div className="box w-100">
         <div className="float-left">
-          last block: {block}, era {era}, last reward: {lastReward} JOY
+          last block: {block}, era {era}
         </div>
         <MinMax
           stakes={stakes}
           issued={issued}
+          price={price}
           validators={validators.length}
           nominators={nominators.length}
           waiting={waiting.length}
+          reward={lastReward}
         />
 
         <h3>Validators</h3>
@@ -144,6 +149,7 @@ class Validators extends Component<IProps, IState> {
               toggleStar={this.toggleStar}
               startTime={startTime}
               validator={v}
+              reward={lastReward / validators.length}
               councils={councils}
               handles={handles}
               members={members}
@@ -163,6 +169,7 @@ class Validators extends Component<IProps, IState> {
               toggleStar={this.toggleStar}
               startTime={startTime}
               validator={v}
+              reward={lastReward / validators.length}
               councils={councils}
               handles={handles}
               members={members}