diff --git a/src/lib/utils.server.ts b/src/lib/utils.server.ts new file mode 100644 index 0000000..96a47ee --- /dev/null +++ b/src/lib/utils.server.ts @@ -0,0 +1,88 @@ +import type { Address } from 'viem' +import type { Contract } from './types' +import consola from 'consola' +import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite' +import { contracts } from '../schema' +import { and, eq } from 'drizzle-orm' + +export const getContractInformation = async ( + address: Address, + chainId: number, +): Promise => { + try { + const response = await fetch(`https://anyabi.xyz/api/get-abi/${chainId}/${address}`) + if (!response.ok) { + consola.info('ABI not found.') + return { name: 'Unverified', address, abi: [] } + } + const contractData = await response.json() + + return { + ...contractData, + address, + } + } catch (e) { + consola.error(e) + consola.info('ABI not found.') + return { name: 'Unverified', address, abi: [] } + } +} + +export const getCachedContractInformation = async ( + address: Address, + chainId: number, + db: BunSQLiteDatabase, +): Promise => { + try { + consola.info('Fetching contract information for', address, 'on chain', chainId) + consola.info('Checking for cached ABI...') + const result = await db + .select() + .from(contracts) + .where(and(eq(contracts.address, address), eq(contracts.chainId, chainId))) + + if (result.length) { + consola.info('Found in db cache') + return { + name: result[0].name, + abi: [...JSON.parse(result[0].abi)], + address, + } + } + consola.info('Not found in cache. Fetching from anyabi.xyz...') + const contract = await getContractInformation(address, chainId) + + // Don't cache unverified contracts + if (contract.name === 'Unverified') { + return contract + } + + // Update the database + consola.info('Updating db cache...') + await db.insert(contracts).values({ + id: `${chainId}:${address}`, + name: contract.name, + address, + abi: JSON.stringify(contract.abi), + chainId, + }) + + return contract + } catch (e) { + consola.error(e) + throw new Error('Failed to fetch contract information') + } +} + +export const getFuncSigBySelector = async (selector: string): Promise => { + const response = await fetch( + `https://api.openchain.xyz/signature-database/v1/lookup?function=${selector}&filter=true`, + ) + const data = await response.json() + + if (data && data.result && data.result.function && data.result.function[selector]) { + return data.result.function[selector][0].name + } + + return 'unknown()' +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 361be22..64aac73 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -3,12 +3,8 @@ import { twMerge } from 'tailwind-merge' import { cubicOut } from 'svelte/easing' import type { TransitionConfig } from 'svelte/transition' import { type Abi, type AbiFunction, type Address } from 'viem' -import type { Contract } from './types' import toast from 'svelte-french-toast' -import Database from 'bun:sqlite' -import { drizzle, type BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite' -import { contracts } from '../schema' -import { and, eq } from 'drizzle-orm' +import type { Contract } from './types' import consola from 'consola' export function cn(...inputs: ClassValue[]) { @@ -63,6 +59,16 @@ export const flyAndScale = ( } } +export const copyToClipboard = async (text: string) => { + await navigator.clipboard.writeText(text) + toast.success('Copied to clipboard!') +} + +export const abiMethods = (abi: Abi): AbiFunction[] => + abi.filter((i) => i.type === 'function') as AbiFunction[] + +export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) + export const getContractInformation = async ( address: Address, chainId: number, @@ -85,72 +91,3 @@ export const getContractInformation = async ( return { name: 'Unverified', address, abi: [] } } } - -export const getCachedContractInformation = async ( - address: Address, - chainId: number, - db: BunSQLiteDatabase, -): Promise => { - try { - consola.info('Fetching contract information for', address, 'on chain', chainId) - consola.info('Checking for cached ABI...') - const result = await db - .select() - .from(contracts) - .where(and(eq(contracts.address, address), eq(contracts.chainId, chainId))) - - if (result.length) { - consola.info('Found in db cache') - return { - name: result[0].name, - abi: [...JSON.parse(result[0].abi)], - address, - } - } - consola.info('Not found in cache. Fetching from anyabi.xyz...') - const contract = await getContractInformation(address, chainId) - - // Don't cache unverified contracts - if (contract.name === 'Unverified') { - return contract - } - - // Update the database - consola.info('Updating db cache...') - await db.insert(contracts).values({ - id: `${chainId}:${address}`, - name: contract.name, - address, - abi: JSON.stringify(contract.abi), - chainId, - }) - - return contract - } catch (e) { - consola.error(e) - throw new Error('Failed to fetch contract information') - } -} - -export const copyToClipboard = async (text: string) => { - await navigator.clipboard.writeText(text) - toast.success('Copied to clipboard!') -} - -export const getFuncSigBySelector = async (selector: string): Promise => { - const response = await fetch( - `https://api.openchain.xyz/signature-database/v1/lookup?function=${selector}&filter=true`, - ) - const data = await response.json() - - if (data && data.result && data.result.function && data.result.function[selector]) { - return data.result.function[selector][0].name - } - - return 'unknown()' -} - -export const abiMethods = (abi: Abi): AbiFunction[] => - abi.filter((i) => i.type === 'function') as AbiFunction[] - -export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) diff --git a/src/routes/diamond/[address]/+page.server.ts b/src/routes/diamond/[address]/+page.server.ts index fd47753..84c13a5 100644 --- a/src/routes/diamond/[address]/+page.server.ts +++ b/src/routes/diamond/[address]/+page.server.ts @@ -1,5 +1,5 @@ import type { FacetData, Contract, Diamond } from '$lib/types' -import { getCachedContractInformation, getFuncSigBySelector } from '$lib/utils' +import { getCachedContractInformation, getFuncSigBySelector } from '$lib/utils.server' import { error } from '@sveltejs/kit' import type { PageServerLoad } from './$types' import { diff --git a/src/routes/diamond/[address]/json/+server.ts b/src/routes/diamond/[address]/json/+server.ts index f317c99..8dc4b22 100644 --- a/src/routes/diamond/[address]/json/+server.ts +++ b/src/routes/diamond/[address]/json/+server.ts @@ -1,9 +1,5 @@ import type { FacetData, Contract, Diamond } from '$lib/types' -import { - getCachedContractInformation, - getContractInformation, - getFuncSigBySelector, -} from '$lib/utils' +import { getCachedContractInformation, getFuncSigBySelector } from '$lib/utils.server' import { error, json } from '@sveltejs/kit' import type { RequestHandler } from './$types' import {