Skip to content

Commit

Permalink
use dune api to get the total eth staked to simplify and reduce the c…
Browse files Browse the repository at this point in the history
…alls we currently do
  • Loading branch information
pettinarip committed Jul 14, 2024
1 parent 407ef79 commit a7607b3
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 59 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
# GOOGLE_API_KEY=
# GOOGLE_CALENDAR_ID=

# Dune Analytics API key (required for total eth staked)
# DUNE_API_KEY=

# Matomo environment (URL and site ID required for analytics)
NEXT_PUBLIC_MATOMO_URL=
NEXT_PUBLIC_MATOMO_SITE_ID=
Expand Down
4 changes: 2 additions & 2 deletions src/components/StatsBoxGrid/useStatsBoxGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export const useStatsBoxGrid = ({

const metrics: StatsBoxMetric[] = [
{
apiProvider: "Beaconcha.in",
apiUrl: "https://beaconcha.in/",
apiProvider: "Dune Analytics",
apiUrl: "https://dune.com/",
title: t("page-index-network-stats-total-eth-staked"),
description: t("page-index-network-stats-total-eth-staked-explainer"),
buttonContainer: (
Expand Down
84 changes: 29 additions & 55 deletions src/lib/api/fetchTotalEthStaked.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,47 @@
import type {
EthStoreResponse,
MetricReturnData,
TimestampedData,
} from "@/lib/types"
import type { EthStakedResponse, MetricReturnData } from "@/lib/types"

import { weiToRoundedEther } from "@/lib/utils/weiToRoundedEther"
import { DUNE_API_URL } from "../constants"

import { BEACONCHA_IN_URL, DAYS_TO_FETCH } from "@/lib/constants"

const MS_PER_DAY = 1000 * 60 * 60 * 24
const DAY_DELTA = 5
const DUNE_API_KEY = process.env.DUNE_API_KEY

export const fetchTotalEthStaked = async (): Promise<MetricReturnData> => {
const { href: ethstoreLatest } = new URL(
"api/v1/ethstore/latest",
BEACONCHA_IN_URL
if (!DUNE_API_KEY) {
console.error("Dune API key not found")
return { error: "Dune API key not found" }
}

const url = new URL(
"api/v1/endpoints/pablop/eth-staked/results",
DUNE_API_URL
)

try {
// 1- Use initial call to `latest` to fetch current Beacon Chain "day" (for use in secondary fetches)
const ethstoreLatestResponse = await fetch(ethstoreLatest)
if (!ethstoreLatestResponse.ok) {
console.log(
ethstoreLatestResponse.status,
ethstoreLatestResponse.statusText
)
throw new Error("Failed to fetch Ethstore latest data")
const ethStakedResponse = await fetch(url, {
headers: { "X-Dune-API-Key": DUNE_API_KEY },
})
if (!ethStakedResponse.ok) {
console.log(ethStakedResponse.status, ethStakedResponse.statusText)
throw new Error("Failed to fetch eth staked data")
}

const ethstoreJson: EthStoreResponse = await ethstoreLatestResponse.json()
const ethStakedJson: EthStakedResponse = await ethStakedResponse.json()
const {
data: { day, effective_balances_sum_wei },
} = ethstoreJson
const valueTotalEth = weiToRoundedEther(effective_balances_sum_wei)

const data: TimestampedData<number>[] = [
{ timestamp: new Date().getTime(), value: valueTotalEth },
]

// 2- Perform multiple API calls to fetch data for the last 90 days, `getData` for caching
for (let i = DAY_DELTA; i <= DAYS_TO_FETCH; i += DAY_DELTA) {
const lookupDay = day - i
const timestamp = new Date().getTime() - i * MS_PER_DAY
result: { rows = [] },
} = ethStakedJson

const { href: ethstoreDay } = new URL(
`api/v1/ethstore/${lookupDay}`,
BEACONCHA_IN_URL
)

const ethstoreDayResponse = await fetch(ethstoreDay)
if (!ethstoreDayResponse.ok) {
console.log(ethstoreDayResponse.status, ethstoreDayResponse.statusText)
throw new Error("Failed to fetch Ethstore day data")
}

const ethstoreDayJson: EthStoreResponse = await ethstoreDayResponse.json()
const {
data: { effective_balances_sum_wei: sumWei },
} = ethstoreDayJson
const value = weiToRoundedEther(sumWei)

data.push({ timestamp, value })
}
const data = rows.map((row) => ({
timestamp: new Date(row.time).getTime(),
value: row.cum_deposited_eth,
}))

// data is already sorted...but just in case
data.sort((a, b) => a.timestamp - b.timestamp)

const { value } = data[data.length - 1]

return {
data, // historical data: { timestamp: unix-milliseconds, value }
value: valueTotalEth, // current value (number, unformatted)
data,
value,
}
} catch (error: unknown) {
console.error((error as Error).message)
Expand Down
3 changes: 2 additions & 1 deletion src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const DAYS_TO_FETCH = 90
export const RANGES = ["30d", "90d"] as const
export const BEACONCHA_IN_URL = "https://beaconcha.in/"
export const ETHERSCAN_API_URL = "https://api.etherscan.io"
export const DUNE_API_URL = "https://api.dune.com"

// Wallets
export const NUMBER_OF_SUPPORTED_LANGUAGES_SHOWN = 5
Expand Down Expand Up @@ -152,4 +153,4 @@ export const MOBILE_LANGUAGE_BUTTON_NAME = "mobile-language-button"
export const DESKTOP_LANGUAGE_BUTTON_NAME = "desktop-language-button"

// Codeblock
export const LINES_BEFORE_COLLAPSABLE = 8
export const LINES_BEFORE_COLLAPSABLE = 8
11 changes: 10 additions & 1 deletion src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ type HeroButtonProps = Omit<CallToActionProps, "index">
* or a string. (defaults to `StaticImageData`)
*/
export type CommonHeroProps<
HeroImg extends StaticImageData | string = StaticImageData
HeroImg extends StaticImageData | string = StaticImageData,
> = {
/**
* Decorative image displayed as the full background or an aside to
Expand Down Expand Up @@ -485,6 +485,15 @@ export type EthStoreResponse = Data<{
effective_balances_sum_wei: number
}>

export type EthStakedResponse = {
result: {
rows?: {
cum_deposited_eth: number
time: string
}[]
}
}

export type EpochResponse = Data<{
validatorscount: number
}>
Expand Down

0 comments on commit a7607b3

Please sign in to comment.