split data access into API-only (alchemy/viem) and DB-first wrappers (tokens/transactions)

alchemy/get-token-metadata: stripped DB logic, now pure API call
viem/get-transaction-details: stripped DB logic, now pure viem call
tokens/get-metadata: new DB-first wrapper for token metadata
transactions/get-details: new DB-first wrapper for tx details
transactions/get-history: stores individual Alchemy transfers in tx_history
  table with blockNum, from, to columns for searchable ordering
This commit is contained in:
2026-05-18 03:03:34 +08:00
parent 135d651622
commit 9e76bd54ce
10 changed files with 466 additions and 235 deletions
@@ -1,6 +1,3 @@
import { eq, and } from 'drizzle-orm'
import { db } from '../db'
import { tokenMetadata } from '../db/schema'
import { post } from './call'
import { getChainID, getURL } from './network'
@@ -12,36 +9,9 @@ export const getTokenMetadata = async (
const chainId = getChainID(chainid)
if (!chainId) return
const cached = db
.select()
.from(tokenMetadata)
.where(
and(
eq(tokenMetadata.chainId, chainId),
eq(tokenMetadata.contractAddress, tokenAddress.toLowerCase()),
),
)
.get()
const url = getURL({ chainId, key })
if (cached) {
return {
jsonrpc: '2.0' as const,
id: 0,
result: {
name: cached.name ?? null,
symbol: cached.symbol,
decimals: cached.decimals ?? null,
logo: cached.logo ?? null,
},
}
}
const url = getURL({
chainId,
key,
})
const result = await post<{
return await post<{
name: string | null
symbol: string | null
decimals: number | null
@@ -52,24 +22,4 @@ export const getTokenMetadata = async (
method: 'alchemy_getTokenMetadata',
params: [tokenAddress],
})
if (result?.result?.symbol) {
try {
await db
.insert(tokenMetadata)
.values({
name: result.result.name,
symbol: result.result.symbol,
decimals: result.result.decimals,
logo: result.result.logo,
contractAddress: tokenAddress.toLowerCase(),
chainId,
})
.onConflictDoNothing()
} catch (e) {
console.log('Failed to cache token metadata', e)
}
}
return result
}