Skip to content

Commit

Permalink
feat: fetch Dune Safe numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
DiogoSoaress committed Aug 16, 2023
1 parent 474a044 commit 0065bd4
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 8 deletions.
7 changes: 5 additions & 2 deletions src/components/Home/Stats/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Container, Grid, Typography } from '@mui/material'
import type { ReactElement } from 'react'
import { type ReactElement } from 'react'

import css from './styles.module.css'
import layoutCss from '@/components/common/styles.module.css'
import type { BaseBlock } from '@/components/Home/types'
import { useSafeNumbers } from '@/hooks/useSafeNumbers'

const Stats = ({ caption, title, text, items }: BaseBlock): ReactElement => {
const stats = useSafeNumbers()

return (
<Container>
<Grid container className={layoutCss.containerShort} spacing={{ xs: '30px', xl: '50px' }}>
Expand All @@ -28,7 +31,7 @@ const Stats = ({ caption, title, text, items }: BaseBlock): ReactElement => {
items.map((item, index) => {
const textBlock = (
<>
<p className={css.metric}>{item.title}</p>
<p className={css.metric}>{stats[index]}</p>
<Typography variant="caption">{item.text}</Typography>
</>
)
Expand Down
1 change: 1 addition & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const LS_NAMESPACE = 'SAFE__'
export const IS_PRODUCTION = process.env.NEXT_PUBLIC_IS_PRODUCTION
export const GOOGLE_ANALYTICS_TRACKING_ID = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_TRACKING_ID || ''
export const GOOGLE_ANALYTICS_DOMAIN = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_DOMAIN || 'safe.global'
export const DUNE_API_KEY = process.env.NEXT_PUBLIC_DUNE_API_KEY || ''

// Links
export const WALLET_LINK = 'https://app.safe.global'
Expand Down
18 changes: 12 additions & 6 deletions src/content/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,22 @@
"text": "Previously called Gnosis Safe, <i>Safe</i> spun out with a mission to build a better standard for ownership with smart contract accounts. Since 2018, Safe has grown to support several EVM chains",
"items": [
{
"title": "16M",
"text": "Total transactions"
"text": "Total transactions",
"link": {
"href": "https://dune.com/queries/2093960/3449499"
}
},
{
"title": "$56B",
"text": "Total assets stored"
"text": "Total assets stored",
"link": {
"href": "https://dune.com/queries/2771785/4614463"
}
},
{
"title": "4.3M",
"text": "Safe accounts deployed"
"text": "Safe accounts deployed",
"link": {
"href": "https://dune.com/queries/2459401/4044167"
}
}
],
"component": "Home/Stats"
Expand Down
40 changes: 40 additions & 0 deletions src/hooks/useSafeNumbers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import useSWR from 'swr'
import { formatValue } from '@/lib/formatValue'
import { DUNE_API_KEY } from '@/config/constants'

const QUERY_ID_TOTAL_TRANSACTIONS = 2093960
const QUERY_ID_TOTAL_ASSETS = 2771785
const QUERY_ID_TOTAL_SAFES_DEPOLOYED = 2459401

const fallbackStats = ['16M', '$56B', '4.3M']

const fetcher = (url: string) =>
fetch(url)
.then((res) => res.json())
.then((data) => data.result.rows[0])

function totalAssetsEndpoint(queryId: number): string {
return `https://api.dune.com/api/v1/query/${queryId}/results?api_key=${DUNE_API_KEY}`
}

export const useSafeNumbers = (): Array<string> => {
const { data: totalTransactions, isLoading: isLoadingTransactions } = useSWR(
totalAssetsEndpoint(QUERY_ID_TOTAL_TRANSACTIONS),
fetcher,
)
const { data: totalAssets, isLoading: isLoadingAssets } = useSWR(totalAssetsEndpoint(QUERY_ID_TOTAL_ASSETS), fetcher)
const { data: totalSafesDeployed, isLoading: isLoadingSafesDeployed } = useSWR(
totalAssetsEndpoint(QUERY_ID_TOTAL_SAFES_DEPOLOYED),
fetcher,
)

if (isLoadingTransactions || isLoadingAssets || isLoadingSafesDeployed) {
return fallbackStats
}

const formattedTotalAssets = '$' + formatValue(totalAssets.usd_value)
const formattedTotalSafesDeployed = formatValue(totalSafesDeployed.num_safes)
const formattedTotalTransactions = formatValue(totalTransactions.num_txs)

return [formattedTotalTransactions, formattedTotalAssets, formattedTotalSafesDeployed]
}
34 changes: 34 additions & 0 deletions src/lib/formatValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const hasSingleIntegerDigit = (value: number): boolean => value < 10

/**
* Formats a numeric value into its thousands order of magnitude.
* If it rounds to a single integer digit, keep one decimal place.
*
* @param {number} value - The numeric value to format.
* @returns {string} The formatted value with the order of magnitude suffix.
*/
export function formatValue(value: number): string {
if (value >= 1e12) {
const valueInTrillions = value / 1e12
const isSingleDigitInteger = hasSingleIntegerDigit(valueInTrillions)
const formattedValue = isSingleDigitInteger ? valueInTrillions.toFixed(1) : Math.floor(valueInTrillions).toString()
return formattedValue + 'T'
} else if (value >= 1e9) {
const valueInBillions = value / 1e9
const isSingleDigitInteger = hasSingleIntegerDigit(valueInBillions)
const formattedValue = isSingleDigitInteger ? valueInBillions.toFixed(1) : Math.floor(valueInBillions).toString()
return formattedValue + 'B'
} else if (value >= 1e6) {
const valueInMillions = value / 1e6
const isSingleDigitInteger = hasSingleIntegerDigit(valueInMillions)
const formattedValue = isSingleDigitInteger ? valueInMillions.toFixed(1) : Math.floor(valueInMillions).toString()
return formattedValue + 'M'
} else if (value >= 1e3) {
const valueInThousands = value / 1e3
const isSingleDigitInteger = hasSingleIntegerDigit(valueInThousands)
const formattedValue = isSingleDigitInteger ? valueInThousands.toFixed(1) : Math.floor(valueInThousands).toString()
return formattedValue + 'K'
} else {
return `${value}`
}
}

0 comments on commit 0065bd4

Please sign in to comment.