add utils package + move get tokens to lib folder

This commit is contained in:
2026-05-11 23:16:26 +08:00
parent d2c2a46e54
commit f47491ad86
18 changed files with 482 additions and 54 deletions
+1
View File
@@ -12,6 +12,7 @@
"build:stable": "vite build && electrobun build --env=stable"
},
"dependencies": {
"@koins/utils": "workspace:*",
"@alchemy/wallet-apis": "^5.0.0-beta.28",
"electrobun": "^1.18.1",
"ethers": "^6.16.0",
+31 -38
View File
@@ -8,6 +8,8 @@ import {
Utils,
} from 'electrobun/bun'
import { inspect } from 'util'
import { getTokenMetadata, getTokensBalances } from './lib/alchemy'
import { tryCatch } from '@koins/utils'
const DEV_SERVER_PORT = 5173
const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}`
@@ -196,46 +198,33 @@ async function fetchAlchemyTokenBalances(
chainid: string,
address: string,
): Promise<TokenBalanceResult[]> {
const network = ALCHEMY_NETWORKS[chainid]
if (!network) return []
const url = `https://${network}.g.alchemy.com/v2/${key}`
const post = (body: any) =>
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}).then((r) => r.json())
const balRes = await post({
jsonrpc: '2.0',
id: 0,
method: 'alchemy_getTokenBalances',
params: [address, 'erc20'],
})
// console.log(inspect(balRes, { depth: null }))
const tokens: any[] = balRes.result?.tokenBalances ?? []
const nonZero = tokens.filter(
(t: any) => t.tokenBalance !== '0x0' && !t.error,
const [balRes, balResError] = await tryCatch(
getTokensBalances(key, chainid, address),
)
if (balResError) {
console.log('Get Tokens Balance', balResError)
return []
}
if (!balRes) return []
const tokens = balRes.result?.tokenBalances ?? []
const nonZero = tokens.filter((t) => t.tokenBalance !== '0x0')
const metas = await Promise.allSettled(
nonZero.map((t: any) =>
post({
jsonrpc: '2.0',
id: 0,
method: 'alchemy_getTokenMetadata',
params: [t.contractAddress],
}),
nonZero.map((t) =>
getTokenMetadata(key, chainid, t.contractAddress),
),
)
console.log(inspect(metas, { depth: null }))
if (!metas) return []
return nonZero
.map((t: any, i: number) => {
const meta =
metas[i].status === 'fulfilled' ? metas[i].value.result : null
metas[i].status === 'fulfilled' && metas[i].value
? metas[i].value.result
: null
return {
symbol: meta?.symbol ?? 'Unknown',
decimals: meta?.decimals ?? 0,
@@ -371,13 +360,17 @@ const rpc = BrowserView.defineRPC<RPC>({
name: 'alchemy_key',
})
if (!key) return []
const result = await fetchAlchemyTokenBalances(
key,
chainid,
address,
)
// console.log(inspect(result, { depth: null }))
return result
try {
const result = await fetchAlchemyTokenBalances(
key,
chainid,
address,
)
return result
} catch (error) {
console.log(error)
return []
}
},
},
messages: {},
+30
View File
@@ -0,0 +1,30 @@
import { tryCatch } from '@koins/utils'
export const post = async <T>(
url: string,
body: any,
): Promise<{ jsonrpc: '2.0'; id: number; result: T }> => {
const [response, error] = await tryCatch(
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}),
)
if (error) {
console.log(error)
throw error
}
console.log('data', await response.text())
const [data, dataError] = await tryCatch(response.json())
if (dataError) {
console.log(dataError)
throw dataError
}
return data
}
@@ -0,0 +1,34 @@
import { post } from './call'
import { getChainID, getURL } from './network'
import { inspect } from 'util'
export const getTokensBalances = async (
key: string,
chainid: string,
address: string,
) => {
const chainId = getChainID(chainid)
if (!chainId) return
const url = getURL({
chainId,
key,
})
const balRes = await post<{
address: `0x${string}`
tokenBalances: {
contractAddress: `0x${string}`
tokenBalance: string
}[]
}>(url, {
jsonrpc: '2.0',
id: 0,
method: 'alchemy_getTokenBalances',
params: [address, 'erc20'],
})
console.log(inspect(balRes, { depth: null, colors: true }))
return balRes
}
@@ -0,0 +1,30 @@
import { post } from './call'
import { getChainID, getURL } from './network'
export const getTokenMetadata = async (
key: string,
chainid: string,
tokenAddress: string,
) => {
const chainId = getChainID(chainid)
if (!chainId) return
const url = getURL({
chainId,
key,
})
const result = await post<{
name: string | null
symbol: string | null
decimals: number | null
logo: string | null
}>(url, {
jsonrpc: '2.0',
id: 0,
method: 'alchemy_getTokenMetadata',
params: [tokenAddress],
})
return result
}
@@ -0,0 +1,3 @@
export * from './get-token-balances'
export * from './get-token-metadata'
export * from './types'
@@ -0,0 +1,31 @@
export const ALCHEMY_NETWORKS = {
'1': 'eth-mainnet',
'137': 'polygon-mainnet',
'56': 'bnb-mainnet',
} as const
export type ChainID = keyof typeof ALCHEMY_NETWORKS
export const CHAIN_ID = Object.keys(
ALCHEMY_NETWORKS,
) as Array<ChainID>
export const getChainID = (id: string) => {
if (CHAIN_ID.includes(id as ChainID)) {
return id as ChainID
}
return null
}
export const getURL = ({
key,
chainId,
}: {
chainId: ChainID
key: string
}) => {
const network = ALCHEMY_NETWORKS[chainId]
const url = `https://${network}.g.alchemy.com/v2/${key}`
return url
}
@@ -0,0 +1,3 @@
export type Token = {}
export type TokenBalance = {}