Skip to content

Commit

Permalink
db update
Browse files Browse the repository at this point in the history
  • Loading branch information
wslyvh committed Aug 4, 2024
1 parent 1fe989a commit 0db98d3
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 156 deletions.
4 changes: 0 additions & 4 deletions src/components/charts/trend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ export function TrendChart(props: Props) {
},
}
const series = [
{
name: 'median',
data: props.data.map((item) => Math.round(item.median * 100) / 100),
},
{
name: 'baseFee',
data: props.data.map((item) => Math.round(item.baseFee * 100) / 100),
Expand Down
8 changes: 8 additions & 0 deletions src/components/featured.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@
}
}

.double {
grid-template-columns: 1fr 1fr;

@media (max-width: $screen-640) {
grid-template-columns: 1fr;
}
}

.rows {
display: grid;
gap: $gap-16;
Expand Down
2 changes: 2 additions & 0 deletions src/components/featured.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ interface Props {
type?: 'grid' | 'rows'
className?: string
children: ReactNode
double?: boolean
}

export function Featured(props: Props) {
let className = `${styles.container}`
if (props.className) className += ` ${props.className}`
let type = styles.grid
if (props.double) type += ` ${styles.double}`
if (props.type) type = styles[props.type]

return (
Expand Down
1 change: 0 additions & 1 deletion src/hooks/useGasPrice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export function useGasPrice(network: string = '', interval: number = 12000) {
try {
const provider = !network ? getDefaultProvider() : GetRpcProvider(network as any)
const feeData = await provider.getFeeData()
console.log('FEE DATA', feeData)

if (feeData.gasPrice && feeData.maxPriorityFeePerGas) {
const gasPrice = Math.round(Number(formatUnits(feeData.gasPrice, 'gwei')) * 100) / 100
Expand Down
25 changes: 10 additions & 15 deletions src/pages/gas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function Index(props: Props) {
<SEO title={title} divider="⛽" description="Monitor and track the Ethereum gas price to reduce transaction fees save money." />
<TopnavLayout className={styles.container} title="Ethereum Gas tracker" action={{ href: '/gas/api', text: 'Get API Access' }}>
<section>
<Featured className={styles.featured}>
<Featured className={styles.featured} double>
<Panel type="primary" fill stretch>
<div style={{ padding: '8px' }}>
<h4>⛽ Current</h4>
Expand All @@ -49,18 +49,7 @@ export default function Index(props: Props) {
<div style={{ padding: '8px' }}>
<h4>🕘 Avg/last hour</h4>
<br />
<span>baseFee: {Math.round(props.gasData.lastHour.baseFee * 100) / 100}</span>
<br />
<span>median: {Math.round(props.gasData.lastHour.median * 100) / 100}</span>
</div>
</Panel>
<Panel type="neutral" stretch>
<div style={{ padding: '8px' }}>
<h4>📅 Avg/24 hours</h4>
<br />
<span>baseFee: {Math.round(props.gasData.lastDay.baseFee * 100) / 100}</span>
<br />
<span>median: {Math.round(props.gasData.lastDay.median * 100) / 100}</span>
<span>baseFee: {props.gasData.lastHour}</span>
</div>
</Panel>
</Featured>
Expand Down Expand Up @@ -96,12 +85,18 @@ export default function Index(props: Props) {
<li>
<Link href="/gas">Ethereum Gas Tracker</Link>
</li>
<li>
<Link href="/gas/arbitrum">Arbitrum Gas Tracker</Link>
</li>
<li>
<Link href="/gas/optimism">Optimism Gas Tracker</Link>
</li>
<li>
<Link href="/gas/polygon">Polygon Gas Tracker</Link>
</li>
<li>
<Link href="/gas/base">Base Gas Tracker</Link>
</li>
</ul>
</article>

Expand Down Expand Up @@ -155,13 +150,13 @@ export const getStaticProps: GetStaticProps<Props> = async () => {
const categories = await service.GetCategories()

const gasData = await GetGasData()
const hourlyAverages = await GetAverage('hour', 168)
const averages = await GetAverage('hour', 168)

return {
props: {
categories,
gasData,
heatmap: hourlyAverages ?? [],
heatmap: averages ?? [],
},
revalidate: DEFAULT_REVALIDATE_PERIOD,
}
Expand Down
33 changes: 14 additions & 19 deletions src/pages/gas/[network].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function Index(props: Props) {
<SEO title={title} divider="⛽" description={`Monitor and track the ${networkName} gas price to reduce transaction fees save money.`} />
<TopnavLayout className={styles.container} title={defaultTitle} action={{ href: '/gas/api', text: 'Get API Access' }}>
<section>
<Featured className={styles.featured}>
<Featured className={styles.featured} double>
<Panel type="primary" fill stretch>
<div style={{ padding: '8px' }}>
<h4>⛽ Current</h4>
Expand All @@ -58,18 +58,7 @@ export default function Index(props: Props) {
<div style={{ padding: '8px' }}>
<h4>🕘 Avg/last hour</h4>
<br />
<span>baseFee: {Math.round(props.gasData.lastHour.baseFee * 100) / 100}</span>
<br />
<span>median: {Math.round(props.gasData.lastHour.median * 100) / 100}</span>
</div>
</Panel>
<Panel type="neutral" stretch>
<div style={{ padding: '8px' }}>
<h4>📅 Avg/24 hours</h4>
<br />
<span>baseFee: {Math.round(props.gasData.lastDay.baseFee * 100) / 100}</span>
<br />
<span>median: {Math.round(props.gasData.lastDay.median * 100) / 100}</span>
<span>baseFee: {props.gasData.lastHour}</span>
</div>
</Panel>
</Featured>
Expand Down Expand Up @@ -105,15 +94,18 @@ export default function Index(props: Props) {
<li>
<Link href="/gas">Ethereum Gas Tracker</Link>
</li>
{/* <li>
<li>
<Link href="/gas/arbitrum">Arbitrum Gas Tracker</Link>
</li> */}
</li>
<li>
<Link href="/gas/optimism">Optimism Gas Tracker</Link>
</li>
<li>
<Link href="/gas/polygon">Polygon Gas Tracker</Link>
</li>
<li>
<Link href="/gas/base">Base Gas Tracker</Link>
</li>
</ul>
</article>

Expand Down Expand Up @@ -171,9 +163,12 @@ export const getStaticPaths: GetStaticPaths = async () => {
{
params: { network: 'optimism' },
},
// {
// params: { network: 'arbitrum' },
// },
{
params: { network: 'arbitrum' },
},
{
params: { network: 'base' },
},
],
fallback: false,
}
Expand All @@ -184,7 +179,7 @@ export const getStaticProps: GetStaticProps<Props, Params> = async (context) =>
const service = new MarkdownContentService()
const categories = await service.GetCategories()

if (!network || !['polygon', 'optimism'].includes(network)) {
if (!network || !['polygon', 'optimism', 'base', 'arbitrum'].includes(network)) {
return {
props: null,
notFound: true,
Expand Down
135 changes: 20 additions & 115 deletions src/services/indexer.ts
Original file line number Diff line number Diff line change
@@ -1,137 +1,42 @@
import * as dotenv from 'dotenv'
import { createClient } from '@supabase/supabase-js'
import { getMin, getMax, getAverage, getMedian, toRoundedGwei, getEthPrice } from 'utils/gas'
import { GasFee } from 'types/gas'
import { GetRpcProvider } from 'utils/providers'

dotenv.config()

const defaultBlockLimit = 10
export type NETWORKS = 'mainnet' | 'polygon' | 'optimism' | 'arbitrum'

if (!process.env.SUPABASE_URL || !process.env.SUPABASE_KEY) {
console.warn('SUPABASE_URL or SUPABASE_KEY env variables are not set.')
}

if (!process.env.INFURA_KEY) {
console.warn('INFURA_KEY env variable is not set.')
}

if (!process.env.NEXT_PUBLIC_ALCHEMY_API_KEY) {
console.warn('NEXT_PUBLIC_ALCHEMY_API_KEY env variable is not set.')
}

export async function Index(network: NETWORKS = 'mainnet') {
console.log(`[${network}] Start indexing..`)

const db = CreateDbClient()
const provider = GetRpcProvider(network)

const currentBlock = await provider.getBlockNumber()
const lastProcessedBlock = await db.from(network).select('*').order('blockNr', { ascending: false }).limit(1)
const runUntil =
lastProcessedBlock.data && lastProcessedBlock.data.length > 0 ? lastProcessedBlock.data[0].blockNr : null || currentBlock - defaultBlockLimit
console.log(`[${network}] Process blocks # ${runUntil} / ${currentBlock}`)

let blockNr = currentBlock
while (blockNr >= runUntil) {
console.log(`[${network}] # ${blockNr}`)

const block = await provider.getBlockWithTransactions(blockNr)
const fees = block.transactions.map((i) => toRoundedGwei(i.maxFeePerGas)).filter((i) => i > 0)
const ethPrice = await getEthPrice()

const record = {
blockNr: block.number,
baseFee: toRoundedGwei(block.baseFeePerGas),
gasLimit: block.gasLimit.toNumber(),
gasUsed: block.gasUsed.toNumber(),
txCount: block.transactions.length,
min: getMin(fees),
max: getMax(fees),
avg: getAverage(fees),
median: getMedian(fees),
ethPrice: ethPrice,
}

// console.log(`[${network}] Add to db`, record)
const response = await db.from(network).upsert([record])
if (response.error) {
console.log(`[${network}] Unable to save block # ${blockNr}`, record)
throw new Error(response.error.message)
}

blockNr--
}

console.log(`[${network}] Completed.`)
return
}

export async function Cleanup(network: NETWORKS = 'mainnet') {
console.log(`[${network}] Start cleanup..`)

const db = CreateDbClient()
try {
// delete all records where created_at is older than 14 days
const since = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000).toISOString()
console.log(`[${network}] Delete records older than ${since}`)
const { data, error } = await db.from(network).delete().lte('created_at', since)

if (error) {
console.error('Error:', error)
throw new Error(error.message)
}

console.log('Data deleted!')
return data
} catch (error) {
console.error('Error:', error)
}
}
export type NETWORKS = 'mainnet' | 'polygon' | 'optimism' | 'arbitrum' | 'base'

export async function GetGasData(network: NETWORKS = 'mainnet') {
console.log('Get GasData', network)
const daily = await GetAverage('day', 1, network)
const hourly = await GetAverage('hour', 24, network)

if (!daily || daily.length === 0) {
throw new Error('Unable to fetch daily average')
try {
const res = await fetch(`https://www.ethgastracker.com/api/gas/history/${network}`)
const body = await res.json()
const blocks = body.data.blocks
const average = blocks.map((i: GasFee) => i.baseFee).reduce((a: number, b: number) => a + b, 0) / blocks.length

return {
lastHour: Math.round(average * 100) / 100,
fees: body.data.blocks,
}
}
if (!hourly || hourly.length === 0) {
throw new Error('Unable to fetch hourly average')
catch (error) {
console.error('Error:', error)
}

return {
lastDay: daily[0],
lastHour: hourly[0],
fees: hourly,
lastHour: 0,
fees: [],
}
}

export async function GetAverage(period: 'hour' | 'day', limit: number = 24, network: NETWORKS = 'mainnet') {
console.log(`[${network}] Get average by ${period}`)

const db = CreateDbClient()

try {
const { data, error } = await db.from(`gasdata_${network}_${period}`).select('*').limit(limit)

if (error) {
console.error('Error:', error)
throw new Error(error.message)
}

return data as GasFee[]
} catch (error) {
console.error('Error:', error)
const res = await fetch(`https://www.ethgastracker.com/api/gas/average/${network}`)
const body = await res.json()
return body.data.data
}
}

export function CreateDbClient() {
if (!process.env.SUPABASE_URL || !process.env.SUPABASE_KEY) {
throw new Error('SUPABASE_URL or SUPABASE_KEY env variables are not set.')
catch (error) {
console.error('Error:', error)
}

return createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY)
}
3 changes: 1 addition & 2 deletions src/types/gas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ export interface Heatmap {
}

export interface GasData {
lastDay: GasFee
lastHour: GasFee
lastHour: number
fees: GasFee[]
}

Expand Down

0 comments on commit 0db98d3

Please sign in to comment.