-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
974 additions
and
49 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Dec } from "@everett-protocol/cosmosjs/common/decimal"; | ||
|
||
export class DecUtils { | ||
static decToStrWithoutTrailingZeros(dec: Dec): string { | ||
return DecUtils.removeTrailingZerosFromDecStr(dec.toString()); | ||
} | ||
|
||
static removeTrailingZerosFromDecStr(decStr: string): string { | ||
for (let i = decStr.length - 1; i >= 0; i--) { | ||
if (decStr[i] === "0") { | ||
decStr = decStr.slice(0, i); | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
if (decStr.length > 0) { | ||
if (decStr[decStr.length - 1] === ".") { | ||
decStr = decStr.slice(0, decStr.length - 1); | ||
} | ||
} | ||
|
||
return decStr; | ||
} | ||
|
||
private static precisions: { [precision: string]: Dec } = {}; | ||
|
||
static getPrecisionDec(precision: number): Dec { | ||
if (DecUtils.precisions[precision.toString()]) { | ||
return DecUtils.precisions[precision.toString()]; | ||
} | ||
|
||
let dec = new Dec(1); | ||
for (let i = 0; i < precision; i++) { | ||
dec = dec.mul(new Dec(10)); | ||
} | ||
DecUtils.precisions[precision.toString()] = dec; | ||
return dec; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { useState, useEffect } from "react"; | ||
import { useFetch } from "./use-fetch"; | ||
import { AccAddress } from "@everett-protocol/cosmosjs/common/address"; | ||
|
||
const Buffer = require("buffer/").Buffer; | ||
|
||
interface Result { | ||
height: string; | ||
result: string; | ||
} | ||
|
||
/** | ||
* @param baseUrl Url of rest endpoint | ||
*/ | ||
export const useInterstaking = ( | ||
baseUrl: string, | ||
sourcePort?: string, | ||
sourceChannel?: string, | ||
address: string | ||
) => { | ||
const [url, setUrl] = useState(""); | ||
|
||
const [registered, setRegistered] = useState<Buffer>(Buffer.from([])); | ||
|
||
const fetch = useFetch<Result>(url, "get"); | ||
|
||
useEffect(() => { | ||
setRegistered(Buffer.from([])); | ||
|
||
if (sourcePort && sourceChannel && address) { | ||
setUrl(baseUrl + `/registered/${sourcePort}/${sourceChannel}/${address}`); | ||
} | ||
}, [baseUrl, sourcePort, sourceChannel, address]); | ||
|
||
useEffect(() => { | ||
if (fetch.data && fetch.data.result) { | ||
const result = fetch.data.result; | ||
|
||
setRegistered(Buffer.from(result, "base64")); | ||
} | ||
}, [fetch.data]); | ||
|
||
return { | ||
url: fetch.url, | ||
registered, | ||
refresh: fetch.refresh, | ||
fetching: fetch.fetching | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { useState, useEffect } from "react"; | ||
import { useFetch } from "./use-fetch"; | ||
import { Dec } from "@everett-protocol/cosmosjs/common/decimal"; | ||
import Axios from "axios"; | ||
|
||
export interface Validator { | ||
operator_address: string; | ||
consensus_pubkey: string; | ||
jailed: boolean; | ||
status: number; | ||
tokens: string; | ||
delegator_shares: string; | ||
description: { | ||
moniker: string; | ||
identity: string; | ||
website: string; | ||
details: string; | ||
}; | ||
unbonding_height: string; | ||
unbonding_time: string; | ||
commission: { | ||
commission_rates: { | ||
rate: string; | ||
max_rate: string; | ||
max_change_rate: string; | ||
}; | ||
update_time: string; | ||
}; | ||
min_self_delegation: string; | ||
/** | ||
* The url of thumbnail image. | ||
* This is not the native field from validator but just helper field. | ||
* This may be the image from keybase with matched description.identity as keybase ID suffix. | ||
* This will be fetched gradually. | ||
* This field will be `undefined` if not yet fetched. | ||
* This field will be empty string "" if fetched but error ocurrs or not have keybase profile image. | ||
*/ | ||
thumbnail?: string; | ||
} | ||
|
||
export interface ValidatorHook { | ||
validators: Validator[]; | ||
refresh: (() => Promise<void> | undefined) | undefined; | ||
fetching: boolean; | ||
} | ||
|
||
/** | ||
* @param baseUrl Url of rest endpoint | ||
*/ | ||
export const useValidator = (baseUrl: string): ValidatorHook => { | ||
const [validators, setValidators] = useState<Validator[]>([]); | ||
|
||
const fetch = useFetch<{ result: Validator[] }>( | ||
baseUrl + "/staking/validators", | ||
"get" | ||
); | ||
|
||
useEffect(() => { | ||
if (fetch.data && fetch.data.result) { | ||
let validators = fetch.data.result; | ||
validators = validators.sort((v1, v2) => { | ||
return new Dec(v1.delegator_shares).gt(new Dec(v2.delegator_shares)) | ||
? -1 | ||
: 1; | ||
}); | ||
|
||
for (const val of validators) { | ||
const thunbnail = localStorage.getItem( | ||
`thumbnail-${val.operator_address}` | ||
); | ||
val.thumbnail = thunbnail ? thunbnail : undefined; | ||
} | ||
|
||
setValidators(validators); | ||
} | ||
}, [fetch.data]); | ||
|
||
useEffect(() => { | ||
/** | ||
* TODO: Name of variable is "isMounted". But this naming doesn't fully convey its meaning. | ||
* This means that it will be true until this props haven't be changed. | ||
* There will be a better naming. | ||
*/ | ||
let isMounted = true; | ||
|
||
// Fetch thumbnail. | ||
// Return whether there is a change | ||
const fetchThumbnail = async ( | ||
reminder: number, | ||
len: number | ||
): Promise<boolean> => { | ||
let validator: Validator | undefined; | ||
for (let i = 0; i < validators.length; i++) { | ||
if (i % len === reminder) { | ||
if (validators[i].thumbnail === undefined) { | ||
validator = validators[i]; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (validator) { | ||
validator.thumbnail = ""; | ||
try { | ||
const result = await Axios.get<{ | ||
status: { | ||
code: number; | ||
name: string; | ||
}; | ||
them: [ | ||
{ | ||
id: string; | ||
pictures: { | ||
primary: { | ||
url: string; | ||
}; | ||
}; | ||
} | ||
]; | ||
}>( | ||
`https://keybase.io/_/api/1.0/user/lookup.json?fields=pictures&key_suffix=${validator.description.identity}` | ||
); | ||
|
||
if (result.status === 200 && result.data?.status?.code === 0) { | ||
const them = result.data?.them; | ||
if (them && them.length > 0) { | ||
const pictureUrl = them[0].pictures?.primary?.url; | ||
if (pictureUrl) { | ||
validator.thumbnail = pictureUrl; | ||
localStorage.setItem( | ||
`thumbnail-${validator.operator_address}`, | ||
pictureUrl | ||
); | ||
} | ||
} | ||
} | ||
} catch (e) { | ||
console.log( | ||
`Error occurs during fetching thumbnail for validator: ${e.toString()}` | ||
); | ||
} | ||
return true; | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
(async () => { | ||
if (validators && validators.length > 0) { | ||
const fetches: Promise<boolean>[] = []; | ||
|
||
// Fetch 10 items at once. | ||
const len = 10; | ||
for (let i = 0; i < len; i++) { | ||
fetches.push(fetchThumbnail(i, len)); | ||
} | ||
|
||
const result = await Promise.all(fetches); | ||
|
||
for (const r of result) { | ||
if (r && isMounted) { | ||
// If their is change, re-render the validators. | ||
setValidators(validators.slice()); | ||
return; | ||
} | ||
} | ||
} | ||
})(); | ||
|
||
return () => { | ||
isMounted = false; | ||
}; | ||
}, [validators]); | ||
|
||
return { | ||
validators, | ||
refresh: fetch.refresh, | ||
fetching: fetch.fetching | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.