-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix/stake-sheet-validaton-after-submission
- Loading branch information
Showing
16 changed files
with
231 additions
and
131 deletions.
There are no files selected for viewing
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
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
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
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
97 changes: 59 additions & 38 deletions
97
apps/portal/src/domains/staking/subtensor/atoms/taostats.ts
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 |
---|---|---|
@@ -1,54 +1,75 @@ | ||
import { ValidatorsData } from '../types' | ||
import { delegatesAtom } from './delegates' | ||
import { atom } from 'jotai' | ||
import { atomFamily } from 'jotai/utils' | ||
|
||
const TAOSTATS_DATA_URL = 'https://taostats.io/data.json' | ||
|
||
// The taostats endpoint has a `network` field, which is the name of the network. | ||
// This field is the only way to tell which network a given set of stats is for. | ||
// This map lets us identify which `network` value to use as an id for each given genesisHash. | ||
const TaostatsNetworkByGenesisHash = new Map([ | ||
['0x2f0555cc76fc2840a25a6ea3b9637146806f1f44b090c175ffde2a7e5ab36c03', 'Bittensor'], | ||
]) | ||
|
||
type Taostats = Array<{ | ||
network?: string // 'Bittensor' | ||
token?: string // 'TAO' | ||
price?: string // '365.73' | ||
'24h_change'?: string // '12.69' | ||
'24h_volume'?: string // '66990486.579526' | ||
current_supply?: string // '6923726' | ||
total_supply?: string // '21000000' | ||
delegated_supply?: string // '5744443' | ||
market_cap?: string // '2532203699' | ||
next_halvening?: string // '22 October 2025' | ||
daily_return_per_1000t?: string // '0.0010277758870616' | ||
validating_apy?: string // '18.77' | ||
staking_apy?: string // '17.08' | ||
last_updated?: string // '12 June 2024 16:54:08 GMT' | ||
}> | ||
const TAOSTATS_API_KEY = import.meta.env.REACT_APP_TAOSTATS_API_KEY | ||
const TAOSTATS_API_URL = 'https://api.taostats.io/api/v1' | ||
|
||
export const taostatsAtom = atom(async () => { | ||
const fetchTaoStats = async ({ page = 1, limit = 200 }: { page: number; limit: number }): Promise<ValidatorsData> => { | ||
try { | ||
const stats = await (await fetch(TAOSTATS_DATA_URL)).json() | ||
return Array.isArray(stats) ? (stats as Taostats) : [] | ||
return await ( | ||
await fetch(`${TAOSTATS_API_URL}/validator?page=${page}&limit=${limit}`, { | ||
method: 'GET', | ||
headers: { | ||
Authorization: TAOSTATS_API_KEY, | ||
'Content-Type': 'application/json', | ||
}, | ||
}) | ||
).json() | ||
} catch (cause) { | ||
console.error('Failed to fetch TAO stats', { cause }) | ||
return [] | ||
throw new Error('Failed to fetch TAO stats', { cause }) | ||
} | ||
} | ||
|
||
export const taostatsAtom = atom(async () => { | ||
const stats: ValidatorsData = { count: 0, validators: [] } | ||
|
||
let page = 1 | ||
while (stats.count === 0 || stats.count > stats.validators.length) { | ||
const taoStats = await fetchTaoStats({ page: page, limit: 200 }) | ||
stats.count = taoStats.count | ||
stats.validators.push(...taoStats.validators) | ||
page++ | ||
} | ||
|
||
return stats | ||
}) | ||
|
||
export const taostatsByChainAtomFamily = atomFamily((genesisHash: string | undefined) => { | ||
if (!genesisHash) return atom(() => Promise.resolve(undefined)) | ||
export const activeTaoDelegatesStatsAtom = atom(async get => { | ||
const taostats = await get(taostatsAtom) | ||
const delegates = await get(delegatesAtom) | ||
|
||
const activeDelegatesHotKeys = Object.keys(delegates) | ||
|
||
const networkName = TaostatsNetworkByGenesisHash.get(genesisHash) | ||
if (!networkName) return atom(() => Promise.resolve(undefined)) | ||
const activeDelegates = taostats.validators.filter(validator => | ||
activeDelegatesHotKeys.includes(validator.hot_key.ss58) | ||
) | ||
|
||
return atom(async get => (await get(taostatsAtom))?.find(stats => stats.network === networkName)) | ||
return activeDelegates | ||
}) | ||
|
||
export const stakingAprByChainAtomFamily = atomFamily((genesisHash: string | undefined) => | ||
export const highestAprTaoValidatorAtom = atom(async get => { | ||
const activeDelegatesStats = await get(activeTaoDelegatesStatsAtom) | ||
const highestAprValidatorStats = activeDelegatesStats.reduce((acc, validator) => { | ||
if (parseFloat(validator.apr) > parseFloat(acc.apr)) { | ||
acc = validator | ||
} | ||
return acc | ||
}) | ||
|
||
return highestAprValidatorStats | ||
}) | ||
|
||
export const taoDelegateStatsAtomFamily = atomFamily((hotKey: string) => | ||
atom(async get => { | ||
const taostats = await get(taostatsByChainAtomFamily(genesisHash)) | ||
return parseFloat(taostats?.staking_apy ?? '0.0') / 100 | ||
const activeDelegatesStats = await get(activeTaoDelegatesStatsAtom) | ||
return activeDelegatesStats.find(validator => validator.hot_key.ss58 === hotKey) | ||
}) | ||
) | ||
|
||
export const taoTotalStakedTaoAtom = atom(async get => { | ||
const { system_total_stake } = await get(highestAprTaoValidatorAtom) | ||
|
||
return system_total_stake | ||
}) |
Oops, something went wrong.