Jelajahi Sumber

20230223: Integrated some Chain apis

mkbeefcake 1 tahun lalu
induk
melakukan
0944573c20

+ 174 - 10
src/App.tsx

@@ -59,12 +59,15 @@ const App = (props: {}) => {
   const [openings, setOpenings] = useState(initialState.openings);
   const [tokenomics, setTokenomics] = useState({});
   const [transactions, setTransactions] = useState([]);
-  const [reports, setReports] = useState({});
-  const [validators, setValidators] = useState({});
-  const [nominators, setNominators] = useState([]);
-  const [stashes, setStashes] = useState([]);
-  const [stakes, setStakes] = useState({});
-  const [rewardPoints, setRewardPoints] = useState({});
+  const [reports, setReports] = useState(initialState.reports);
+  const [validators, setValidators] = useState(initialState.validators);
+  const [nominators, setNominators] = useState(initialState.nominators);
+  const [stashes, setStashes] = useState(initialState.stashes);
+  const [stakes, setStakes] = useState(initialState.stakes);
+  const [rewardPoints, setRewardPoints] = useState(initialState.rewardPoints);
+  const [blocks, setBlocks] = useState(initialState.blocks);
+
+  const [initialized, setInitialized] = useState(false);
 
   const childProps = {
     stars,
@@ -98,7 +101,9 @@ const App = (props: {}) => {
     rewardPoints
   }
 
-  // Loading process
+  // ----------------------------------------------
+  // Loading progress
+  // ----------------------------------------------
   const { data } = useElectedCouncils({});
 
 	useEffect(() => {
@@ -112,9 +117,50 @@ const App = (props: {}) => {
     setCouncil(data[0]) 
 	}, [data])
 
-  // useEffect(() => {
-  //   loadData();
-  // }, [])
+  useEffect(() => {
+    loadData();
+    joyApi();
+  }, [])
+
+
+  // ----------------------------------------------
+  // Joystream Chain API
+  // ----------------------------------------------
+  const joyApi = () => {
+    console.debug(`Connecting to ${wsLocation}`);
+    const provider = new WsProvider(wsLocation);
+
+    ApiPromise.create({ provider }).then(async (api) => {
+      await api.isReady;
+      console.log(`Connected to ${wsLocation}`);
+      
+      setConnected(true);
+      // this.updateWorkingGroups(api);
+
+      api.rpc.chain.subscribeNewHeads(async (header: Header) => {
+        const id = header.number.toNumber();
+
+        // period call per 1 min for updates
+        const elapsedOneMin = id % 10 === 0;
+        if (elapsedOneMin /*|| status.block.id + 10 < id*/) {
+          updateStatus(api, id);
+        } 
+
+        // if (blocks.find((b) => b.id === id)) 
+        //   return;
+
+        // const timestamp = (await api.query.timestamp.now()).toNumber();
+        // const duration = status.block
+        //   ? timestamp - status.block.timestamp
+        //   : 6000;
+        // status.block = { id, timestamp, duration };
+        // this.save("status", status);
+
+        // blocks = blocks.filter((i) => i.id !== id).concat(status.block);
+        // this.setState({ blocks });
+      });
+    });    
+  }
 
   const loadData = async () => {
     console.debug(`Loading data`)
@@ -153,6 +199,124 @@ const App = (props: {}) => {
     // this.updateCouncils();
   }
 
+  // ---------------------------------------------------
+  // Polkadot api functions
+  // --------------------------------------------------
+  const updateStatus = async (api: ApiPromise, id: number): Promise<any> => {
+    console.debug(`#${id}: Updating status`);
+
+    // updateActiveProposals();
+    // getMints(api).then((mints) => {
+    //   setMints(mints) 
+    //   save(`mints`, mints) 
+    // });
+    // getTokenomics().then((tokenomics) => save(`tokenomics`, tokenomics));
+
+    // let { status, councils } = this.state;
+    // status.election = await updateElection(api);
+    // if (status.election?.stage) getElectionStatus(api);
+    // councils.forEach((c) => {
+    //   if (c?.round > status.council) status.council = c;
+    // });
+
+    // let hash: string = await api.rpc.chain.getBlockHash(1);
+    // if (hash)
+    //   status.startTime = (await api.query.timestamp.now.at(hash)).toNumber();
+
+    const nextMemberId = await await api.query.members.nextMemberId();
+    // setMembers(nextMemberId - 1);
+    setProposals(await get.proposalCount(api));
+    setPosts(await get.currentPostId(api));
+    setThreads(await get.currentThreadId(api));
+    setCategories(await get.currentCategoryId(api));
+    // status.proposalPosts = await api.query.proposalsDiscussion.postCount();
+
+    await updateEra(api, status.era).then(async (era) => {
+      let _status = {era: 0, lastReward:0, validatorStake: 0}
+      _status.era = era;
+      _status.lastReward = await getLastReward(api, era);
+      _status.validatorStake = await getTotalStake(api, era);
+      
+      setStatus(_status)
+      save("status", _status);
+
+    });
+
+     // return status;
+  }  
+
+  const updateEra = async (api: ApiPromise, old: number) => {
+    const era = Number(await api.query.staking.currentEra());
+    if (era === old) 
+      return era;
+
+    // this.updateWorkingGroups(api);
+    updateValidatorPoints(api, era);
+    
+    if (era > status.era || !validators.length) 
+      updateValidators(api);
+
+    return era;
+  }
+
+  const updateValidatorPoints = async (api: ApiPromise, currentEra: number) => {
+    let points = rewardPoints;
+
+    const updateTotal = (eraTotals) => {
+      let total = 0;
+      Object.keys(eraTotals).forEach((era) => (total += eraTotals[era]));
+      return total;
+    };
+
+    for (let era = currentEra; era > currentEra - historyDepth; --era) {
+      if (era < 0 || (era < currentEra && points.eraTotals[era]))
+        continue;
+
+      const eraPoints = await getEraRewardPoints(api, era);
+      points.eraTotals[era] = eraPoints.total;
+      Object.keys(eraPoints.individual).forEach((validator: string) => {
+        if (!points.validators[validator]) points.validators[validator] = {};
+        points.validators[validator][era] = eraPoints.individual[validator];
+      });
+    }
+
+    points.total = updateTotal(points.eraTotals);
+    console.debug(`Reward Points: ${points.total} points`);
+
+    setRewardPoints(points);
+    save("rewardPoints", points);
+
+  }
+
+  const updateValidators = (api: ApiPromise) => {
+    getValidators(api).then((validators) => {
+      
+      setValidators(validators);
+      save("validators", validators);
+
+      getNominators(api).then((nominators) => {
+        
+        setNominators(nominators);
+        save("nominators", nominators);
+
+        getStashes(api).then((stashes) => {
+          
+          setStashes(stashes);
+          save("stashes", stashes);
+
+          const { era } = status;
+          getValidatorStakes(api, era, stashes, members, save).then(
+            (stakes) => { 
+              setStakes(stakes)
+              save("stakes", stakes)
+            }
+          );
+        });
+      });
+    });
+  }
+
+
   // Save & Load data to local storage
   const save = (key: string, data: any) => {
     const value = JSON.stringify(data);

+ 1 - 1
src/components/Dashboard/Status.tsx

@@ -12,7 +12,7 @@ const Status = (props: {
         Connecting ..
       </div>
     );
-  if (!fetching.length) return <div />;
+  if (!fetching?.length) return <div />;
   return (
     <div className="connecting" onClick={toggleShowStatus}>
       Fetching {fetching}

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

@@ -22,8 +22,6 @@ const Dashboard = (props: IProps) => {
   const { council } = props;
 	const [description1, setDescription1] = useState('');
 
-  console.log(`Dashboard: `, council)
-
 	useEffect(() => {
 		if (!council) 
       return

+ 4 - 3
src/lib/groups.ts

@@ -1,6 +1,7 @@
 import moment from "moment";
-import { Openings } from "./types";
-import { Mint } from "@joystream/types/mint";
+import { ApiPromise } from "@polkadot/api";
+// import { Openings } from "./types";
+// import { Mint } from "@joystream/types/mint";
 
 // mapping: key = pioneer route, value: chain section
 export const groups = {
@@ -12,7 +13,7 @@ export const groups = {
   operationsGroupGamma: "operationsWorkingGroupGamma",
 };
 
-export const getMints = async (api: Api): Promise<Mint[]> => {
+export const getMints = async (api: ApiPromise): Promise<[]> => {
   console.debug(`Fetching mints`);
   const getMint = (id: number) => api.query.minting.mints(id);
   const promises = Object.values(groups).map((group) =>

+ 1 - 1
src/lib/validators.ts

@@ -47,7 +47,7 @@ export const getValidatorStakes = async (
   return stakes;
 };
 
-export const getEraRewardPoints = async (api: Api, era: EraId | number) =>
+export const getEraRewardPoints = async (api: ApiPromise, era: number) =>
   (await api.query.staking.erasRewardPoints(era)).toJSON();
 
 export const findActiveValidators = async (

+ 1 - 0
src/state.ts

@@ -39,4 +39,5 @@ export const initialState = {
     eraTotals: {},
     validators: {},
   },
+  blocks: []
 };