From d2c2a46e54d3b5ed3706c8f0196e113f4a9e3f93 Mon Sep 17 00:00:00 2001
From: TZGyn
Date: Mon, 11 May 2026 16:31:48 +0800
Subject: [PATCH] filter out tokens without logo on tokens list
---
apps/desktop/src/bun/index.ts | 352 ++++++++++++-------
apps/desktop/src/lib/electrobun.ts | 19 +-
apps/desktop/src/lib/states/wallet.svelte.ts | 189 +---------
apps/desktop/src/routes/index.svelte | 120 ++++---
4 files changed, 324 insertions(+), 356 deletions(-)
diff --git a/apps/desktop/src/bun/index.ts b/apps/desktop/src/bun/index.ts
index dbe6e16..a9096e7 100644
--- a/apps/desktop/src/bun/index.ts
+++ b/apps/desktop/src/bun/index.ts
@@ -7,6 +7,7 @@ import {
type RPCSchema,
Utils,
} from 'electrobun/bun'
+import { inspect } from 'util'
const DEV_SERVER_PORT = 5173
const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}`
@@ -56,7 +57,18 @@ ApplicationMenu.setApplicationMenu([
const url = await getMainViewUrl()
-const ETHERSCAN_API = 'https://api.etherscan.io/v2/api'
+const ALCHEMY_NETWORKS: Record = {
+ '1': 'eth-mainnet',
+ '137': 'polygon-mainnet',
+ '56': 'bnb-mainnet',
+}
+
+type TokenBalanceResult = {
+ symbol: string
+ balance: string
+ contractAddress: string
+ logo?: string
+}
type TxEntry = {
hash: string
@@ -64,10 +76,7 @@ type TxEntry = {
from: string
to: string
value: string
- input?: string
- isError?: string
tokenSymbol?: string
- tokenName?: string
tokenDecimal?: string
contractAddress?: string
pairedValue?: string
@@ -97,11 +106,16 @@ type RPC = {
params: {
address: string
chainid: string
- page?: number
- offset?: number
}
response: Promise
}
+ fetchTokenBalances: {
+ params: {
+ address: string
+ chainid: string
+ }
+ response: Promise
+ }
openExternal: {
params: {
url: string
@@ -117,32 +131,148 @@ type RPC = {
}>
}
-async function fetchEtherscan(
+async function fetchAlchemyTransfers(
key: string,
chainid: string,
- action: string,
address: string,
- page: number,
- offset: number,
): Promise {
- const params = new URLSearchParams({
- module: 'account',
- action,
- address,
- page: String(page),
- offset: String(offset),
- sort: 'desc',
- apikey: key,
- chainid,
+ const network = ALCHEMY_NETWORKS[chainid]
+ if (!network) return []
+ const url = `https://${network}.g.alchemy.com/v2/${key}`
+
+ const body = (fromAddress?: string, toAddress?: string) => ({
+ jsonrpc: '2.0',
+ id: 0,
+ method: 'alchemy_getAssetTransfers',
+ params: [
+ {
+ ...(fromAddress ? { fromAddress } : {}),
+ ...(toAddress ? { toAddress } : {}),
+ category: ['external', 'erc20'],
+ withMetadata: true,
+ maxCount: '0x3E8',
+ },
+ ],
})
- const res = await fetch(`${ETHERSCAN_API}?${params}`)
- const data = await res.json()
- if (data.status !== '1') return []
- return data.result
+
+ const [outRes, inRes] = await Promise.all([
+ fetch(url, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body(address, undefined)),
+ }).then((r) => r.json()),
+ fetch(url, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body(undefined, address)),
+ }).then((r) => r.json()),
+ ])
+
+ const outgoing: any[] = outRes.result?.transfers ?? []
+ const incoming: any[] = inRes.result?.transfers ?? []
+
+ const seen = new Set()
+ return [...outgoing, ...incoming].filter((t) => {
+ if (seen.has(t.hash)) return false
+ seen.add(t.hash)
+ return true
+ })
+}
+
+function formatUnits(balance: string, decimals: number): string {
+ const bal = BigInt(balance)
+ if (bal === 0n) return '0'
+ const divisor = 10n ** BigInt(decimals)
+ const intPart = bal / divisor
+ const fracPart = (bal % divisor)
+ .toString()
+ .padStart(decimals, '0')
+ .replace(/0+$/, '')
+ return fracPart ? `${intPart}.${fracPart}` : `${intPart}`
+}
+
+async function fetchAlchemyTokenBalances(
+ key: string,
+ chainid: string,
+ address: string,
+): Promise {
+ 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 metas = await Promise.allSettled(
+ nonZero.map((t: any) =>
+ post({
+ jsonrpc: '2.0',
+ id: 0,
+ method: 'alchemy_getTokenMetadata',
+ params: [t.contractAddress],
+ }),
+ ),
+ )
+ console.log(inspect(metas, { depth: null }))
+
+ return nonZero
+ .map((t: any, i: number) => {
+ const meta =
+ metas[i].status === 'fulfilled' ? metas[i].value.result : null
+ return {
+ symbol: meta?.symbol ?? 'Unknown',
+ decimals: meta?.decimals ?? 0,
+ balance: formatUnits(t.tokenBalance, meta?.decimals ?? 18),
+ contractAddress: t.contractAddress,
+ logo: meta?.logo ?? undefined,
+ }
+ })
+ .filter((t) => t.logo && t.decimals !== 0)
+}
+
+function mapTransfer(t: any): TxEntry {
+ const isExternal = t.category === 'external'
+ return {
+ hash: t.hash,
+ timeStamp: String(
+ Math.floor(
+ new Date(t.metadata.blockTimestamp).getTime() / 1000,
+ ),
+ ),
+ from: t.from,
+ to: t.to,
+ value: String(t.value),
+ ...(isExternal
+ ? {}
+ : {
+ tokenSymbol: t.asset,
+ tokenDecimal: t.rawContract?.decimal
+ ? String(parseInt(t.rawContract.decimal, 16))
+ : undefined,
+ contractAddress: t.rawContract?.address ?? undefined,
+ }),
+ }
}
const rpc = BrowserView.defineRPC({
- maxRequestTime: 20000,
+ maxRequestTime: 200000,
handlers: {
requests: {
getSecret: async ({ name, service }) => {
@@ -154,140 +284,78 @@ const rpc = BrowserView.defineRPC({
openExternal: async ({ url }) => {
Utils.openExternal(url)
},
- fetchTxHistory: async ({
- address,
- chainid,
- page = 1,
- offset = 1000,
- }) => {
+ fetchTxHistory: async ({ address, chainid }) => {
const key = await Bun.secrets.get({
service: 'koins',
- name: 'etherscan_key',
+ name: 'alchemy_key',
})
if (!key) return []
- const [nativeTxs, tokenTxs] = await Promise.all([
- fetchEtherscan(
- key,
- chainid,
- 'txlist',
- address,
- page,
- offset,
- ),
- fetchEtherscan(
- key,
- chainid,
- 'tokentx',
- address,
- page,
- offset,
- ),
- ])
+ const all = await fetchAlchemyTransfers(key, chainid, address)
const addrLower = address.toLowerCase()
- const byHash = new Map<
- string,
- { native?: any; token: any[] }
- >()
- for (const t of nativeTxs) {
+ const byHash = new Map()
+ for (const t of all) {
const h = t.hash
- if (!byHash.has(h)) byHash.set(h, { token: [] })
- byHash.get(h)!.native = t
- }
- for (const t of tokenTxs) {
- const h = t.hash
- if (!byHash.has(h)) byHash.set(h, { token: [] })
- byHash.get(h)!.token.push(t)
+ if (!byHash.has(h)) byHash.set(h, [])
+ byHash.get(h)!.push(t)
}
const combined: TxEntry[] = []
for (const [, group] of byHash) {
- console.log(group)
- const { native, token } = group
- const nv = native?.value ?? '0'
+ const external = group.filter(
+ (t: any) => t.category === 'external',
+ )
+ const tokens = group.filter(
+ (t: any) => t.category === 'erc20',
+ )
- const incoming = token.filter(
+ const extOut = external.filter(
+ (t: any) => t.from.toLowerCase() === addrLower,
+ )
+ const extIn = external.filter(
(t: any) => t.to.toLowerCase() === addrLower,
)
- const outgoing = token.filter(
+ const tokIn = tokens.filter(
+ (t: any) => t.to.toLowerCase() === addrLower,
+ )
+ const tokOut = tokens.filter(
(t: any) => t.from.toLowerCase() === addrLower,
)
- if (native && nv !== '0' && incoming.length > 0) {
+ if (extOut.length > 0 && tokIn.length > 0) {
combined.push({
- hash: native.hash,
- timeStamp: native.timeStamp,
- from: native.from,
- to: native.to,
- value: native.value,
- input: native.input,
- isError: native.isError,
- tokenSymbol: incoming[0].tokenSymbol,
- tokenDecimal: incoming[0].tokenDecimal,
- contractAddress: incoming[0].contractAddress,
- pairedValue: incoming[0].value,
- pairedSymbol: incoming[0].tokenSymbol,
- pairedDecimals: incoming[0].tokenDecimal,
+ ...mapTransfer(extOut[0]),
+ tokenSymbol: tokIn[0].asset,
+ tokenDecimal: tokIn[0].rawContract?.decimal
+ ? String(parseInt(tokIn[0].rawContract.decimal, 16))
+ : undefined,
+ contractAddress:
+ tokIn[0].rawContract?.address ?? undefined,
+ pairedValue: String(tokIn[0].value),
+ pairedSymbol: tokIn[0].asset,
+ pairedDecimals: tokIn[0].rawContract?.decimal
+ ? String(parseInt(tokIn[0].rawContract.decimal, 16))
+ : undefined,
})
- } else if (native && nv !== '0') {
+ } else if (extOut.length > 0) {
+ combined.push(mapTransfer(extOut[0]))
+ } else if (extIn.length > 0) {
+ combined.push(mapTransfer(extIn[0]))
+ } else if (tokOut.length > 0 && tokIn.length > 0) {
combined.push({
- hash: native.hash,
- timeStamp: native.timeStamp,
- from: native.from,
- to: native.to,
- value: native.value,
- input: native.input,
- isError: native.isError,
- })
- } else if (incoming.length > 0 && outgoing.length > 0) {
- combined.push({
- hash: incoming[0].hash,
- timeStamp: incoming[0].timeStamp,
- from: incoming[0].from,
- to: incoming[0].to,
- value: outgoing[0].value,
- tokenSymbol: outgoing[0].tokenSymbol,
- tokenDecimal: outgoing[0].tokenDecimal,
- contractAddress: outgoing[0].contractAddress,
- pairedValue: incoming[0].value,
- pairedSymbol: incoming[0].tokenSymbol,
- pairedDecimals: incoming[0].tokenDecimal,
- })
- } else if (outgoing.length > 0) {
- combined.push({
- hash: outgoing[0].hash,
- timeStamp: outgoing[0].timeStamp,
- from: outgoing[0].from,
- to: outgoing[0].to,
- value: outgoing[0].value,
- tokenSymbol: outgoing[0].tokenSymbol,
- tokenDecimal: outgoing[0].tokenDecimal,
- contractAddress: outgoing[0].contractAddress,
- isError: '0',
- })
- } else if (incoming.length > 0) {
- combined.push({
- hash: incoming[0].hash,
- timeStamp: incoming[0].timeStamp,
- from: incoming[0].from,
- to: incoming[0].to,
- value: incoming[0].value,
- tokenSymbol: incoming[0].tokenSymbol,
- tokenDecimal: incoming[0].tokenDecimal,
- contractAddress: incoming[0].contractAddress,
- })
- } else if (native) {
- combined.push({
- hash: native.hash,
- timeStamp: native.timeStamp,
- from: native.from,
- to: native.to,
- value: native.value,
- input: native.input,
- isError: native.isError,
+ ...mapTransfer(tokOut[0]),
+ pairedValue: String(tokIn[0].value),
+ pairedSymbol: tokIn[0].asset,
+ pairedDecimals: tokIn[0].rawContract?.decimal
+ ? String(parseInt(tokIn[0].rawContract.decimal, 16))
+ : undefined,
})
+ } else if (tokOut.length > 0) {
+ combined.push(mapTransfer(tokOut[0]))
+ } else if (tokIn.length > 0) {
+ combined.push(mapTransfer(tokIn[0]))
}
}
@@ -297,6 +365,20 @@ const rpc = BrowserView.defineRPC({
return combined
},
+ fetchTokenBalances: async ({ address, chainid }) => {
+ const key = await Bun.secrets.get({
+ service: 'koins',
+ name: 'alchemy_key',
+ })
+ if (!key) return []
+ const result = await fetchAlchemyTokenBalances(
+ key,
+ chainid,
+ address,
+ )
+ // console.log(inspect(result, { depth: null }))
+ return result
+ },
},
messages: {},
},
diff --git a/apps/desktop/src/lib/electrobun.ts b/apps/desktop/src/lib/electrobun.ts
index ac3930f..9d95225 100644
--- a/apps/desktop/src/lib/electrobun.ts
+++ b/apps/desktop/src/lib/electrobun.ts
@@ -6,10 +6,7 @@ export type TxEntry = {
from: string
to: string
value: string
- input?: string
- isError?: string
tokenSymbol?: string
- tokenName?: string
tokenDecimal?: string
contractAddress?: string
pairedValue?: string
@@ -17,6 +14,13 @@ export type TxEntry = {
pairedDecimals?: string
}
+export type TokenBalanceResult = {
+ symbol: string
+ balance: string
+ contractAddress: string
+ logo?: string
+}
+
type RPC = {
bun: {
requests: {
@@ -39,11 +43,16 @@ type RPC = {
params: {
address: string
chainid: string
- page?: number
- offset?: number
}
response: Promise
}
+ fetchTokenBalances: {
+ params: {
+ address: string
+ chainid: string
+ }
+ response: Promise
+ }
openExternal: {
params: {
url: string
diff --git a/apps/desktop/src/lib/states/wallet.svelte.ts b/apps/desktop/src/lib/states/wallet.svelte.ts
index 0191d51..10ac106 100644
--- a/apps/desktop/src/lib/states/wallet.svelte.ts
+++ b/apps/desktop/src/lib/states/wallet.svelte.ts
@@ -2,23 +2,9 @@ import {
JsonRpcProvider,
HDNodeWallet,
formatEther,
- formatUnits,
- Contract,
} from 'ethers'
import { electrobun, type TxEntry } from '$lib/electrobun'
-const ERC20_ABI = [
- 'function balanceOf(address) view returns (uint256)',
- 'function symbol() view returns (string)',
- 'function decimals() view returns (uint8)',
-]
-
-type DiscoveredToken = {
- address: string
- symbol: string
- decimals: number
-}
-
export const networks = [
{
id: 'bsc',
@@ -27,18 +13,6 @@ export const networks = [
symbol: 'BNB',
chainid: '56',
explorerUrl: 'https://bscscan.com/tx/',
- tokens: [
- {
- symbol: 'USDC',
- address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',
- decimals: 18,
- },
- {
- symbol: 'USDT',
- address: '0x55d398326f99059fF775485246999027B3197955',
- decimals: 18,
- },
- ],
},
{
id: 'polygon',
@@ -47,18 +21,6 @@ export const networks = [
symbol: 'POL',
chainid: '137',
explorerUrl: 'https://polygonscan.com/tx/',
- tokens: [
- {
- symbol: 'USDC',
- address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
- decimals: 6,
- },
- {
- symbol: 'USDT',
- address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
- decimals: 6,
- },
- ],
},
{
id: 'eth',
@@ -67,23 +29,6 @@ export const networks = [
symbol: 'ETH',
chainid: '1',
explorerUrl: 'https://etherscan.io/tx/',
- tokens: [
- {
- symbol: 'USDC',
- address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
- decimals: 6,
- },
- {
- symbol: 'USDT',
- address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
- decimals: 6,
- },
- {
- symbol: 'BAT',
- address: '0x0D8775F648430679A709E98d2b0Cb6250d2887EF',
- decimals: 18,
- },
- ],
},
] as const
@@ -92,7 +37,8 @@ export type NetworkId = (typeof networks)[number]['id']
export type TokenBalance = {
symbol: string
balance: string
- address?: string
+ contractAddress: string
+ logo?: string
}
export const Wallet = () => {
@@ -105,9 +51,8 @@ export const Wallet = () => {
let error = $state('')
let vaultExists = $state(false)
let ready = $state(false)
- let etherscanKey = $state('')
+ let apiKey = $state('')
let transactions = $state([])
- let discoveredTokens = $state([])
const net = () => networks.find((n) => n.id === network)!
@@ -120,9 +65,9 @@ export const Wallet = () => {
vaultExists = raw !== null && raw !== undefined
const key = await electrobun.rpc?.request.getSecret({
service: 'koins',
- name: 'etherscan_key',
+ name: 'alchemy_key',
})
- if (key) etherscanKey = key
+ if (key) apiKey = key
if (raw) {
seed = raw
await refresh()
@@ -138,7 +83,6 @@ export const Wallet = () => {
const switchNetwork = async (id: NetworkId) => {
network = id
- discoveredTokens = []
if (seed) await refresh()
}
@@ -169,7 +113,6 @@ export const Wallet = () => {
error = ''
tokenBalances = []
transactions = []
- discoveredTokens = []
}
const refresh = async () => {
@@ -184,39 +127,12 @@ export const Wallet = () => {
const nativeBal = await provider.getBalance(wallet.address)
balance = formatEther(nativeBal)
- const [hardcodedBals, discoveredBals] = await Promise.all([
- Promise.all(
- net().tokens.map(async (t) => {
- try {
- const c = new Contract(t.address, ERC20_ABI, provider)
- const bal = await c.balanceOf(wallet.address)
- return {
- symbol: t.symbol,
- balance: formatUnits(bal, t.decimals),
- address: t.address,
- }
- } catch {
- return { symbol: t.symbol, balance: '0', address: t.address }
- }
- }),
- ),
- Promise.all(
- discoveredTokens.map(async (t) => {
- try {
- const c = new Contract(t.address, ERC20_ABI, provider)
- const bal = await c.balanceOf(wallet.address)
- return {
- symbol: t.symbol,
- balance: formatUnits(bal, t.decimals),
- address: t.address,
- }
- } catch {
- return { symbol: t.symbol, balance: '0', address: t.address }
- }
- }),
- ),
- ])
- tokenBalances = [...hardcodedBals, ...discoveredBals]
+ const bals = await electrobun.rpc?.request.fetchTokenBalances({
+ address: wallet.address,
+ chainid: net().chainid,
+ })
+ tokenBalances = bals ?? []
+
fetchTxHistory()
} catch (e) {
error =
@@ -226,18 +142,18 @@ export const Wallet = () => {
}
}
- const saveEtherscanKey = async (key: string) => {
+ const saveApiKey = async (key: string) => {
await electrobun.rpc?.request.setSecret({
service: 'koins',
- name: 'etherscan_key',
+ name: 'alchemy_key',
value: key,
})
- etherscanKey = key
+ apiKey = key
if (address) await fetchTxHistory()
}
const fetchTxHistory = async () => {
- if (!address || !etherscanKey) {
+ if (!address || !apiKey) {
transactions = []
return
}
@@ -246,69 +162,6 @@ export const Wallet = () => {
chainid: net().chainid,
})
transactions = txs ?? []
-
- const seen = new Set(
- net().tokens.map((t) => t.address.toLowerCase()),
- )
- discoveredTokens.forEach((d) => seen.add(d.address.toLowerCase()))
-
- const newAddrs = [
- ...new Set(
- (txs ?? [])
- .filter(
- (t) =>
- t.contractAddress &&
- !seen.has(t.contractAddress.toLowerCase()),
- )
- .map((t) => t.contractAddress!.toLowerCase()),
- ),
- ]
- if (newAddrs.length === 0) return
-
- const provider = new JsonRpcProvider(net().rpc)
- const newTokens: DiscoveredToken[] = []
-
- for (const addr of newAddrs) {
- try {
- const c = new Contract(addr, ERC20_ABI, provider)
- const [symbol, decimals] = await Promise.all([
- c.symbol(),
- c.decimals(),
- ])
- if (
- typeof symbol !== 'string' ||
- symbol.length > 12 ||
- /[\s.:/]/.test(symbol)
- ) {
- continue
- }
- newTokens.push({ address: addr, symbol, decimals })
- } catch {
- // not ERC-20, skip
- }
- }
-
- console.log(newTokens)
-
- if (newTokens.length > 0) {
- discoveredTokens = [...discoveredTokens, ...newTokens]
- const newBals = await Promise.all(
- newTokens.map(async (t) => {
- try {
- const c = new Contract(t.address, ERC20_ABI, provider)
- const bal = await c.balanceOf(address)
- return {
- symbol: t.symbol,
- balance: formatUnits(bal, t.decimals),
- address: t.address,
- }
- } catch {
- return { symbol: t.symbol, balance: '0', address: t.address }
- }
- }),
- )
- tokenBalances = [...tokenBalances, ...newBals]
- }
}
return {
@@ -342,9 +195,6 @@ export const Wallet = () => {
get explorerUrl() {
return net().explorerUrl
},
- get tokens() {
- return net().tokens
- },
get loading() {
return loading
},
@@ -360,21 +210,18 @@ export const Wallet = () => {
get networks() {
return networks
},
- get etherscanKey() {
- return etherscanKey
+ get apiKey() {
+ return apiKey
},
get transactions() {
return transactions
},
- get discoveredTokens() {
- return discoveredTokens
- },
refresh,
init,
lock,
saveVault,
switchNetwork,
- saveEtherscanKey,
+ saveApiKey,
fetchTxHistory,
}
}
diff --git a/apps/desktop/src/routes/index.svelte b/apps/desktop/src/routes/index.svelte
index 9732dec..4238fc5 100644
--- a/apps/desktop/src/routes/index.svelte
+++ b/apps/desktop/src/routes/index.svelte
@@ -10,9 +10,9 @@
CardHeader,
CardTitle,
} from '$lib/components/ui/card/index.js'
- import { formatEther, formatUnits } from 'ethers'
- const CDN = 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains'
+ const CDN =
+ 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains'
const chainDir: Record = {
eth: 'ethereum',
@@ -29,26 +29,14 @@
return `${CDN}/${chainDir[id]}/assets/${address}/logo.png`
}
- const SELECTORS: Record = {
- '0x': 'Send',
- '0xa9059cbb': 'Transfer',
- '0x095ea7b3': 'Approve',
- '0x23b872dd': 'TransferFrom',
- '0x38ed1739': 'Swap',
- '0x7ff36ab5': 'Swap',
- '0x18cbafe5': 'Swap',
- '0x022c0d9f': 'Swap',
- '0x3593564c': 'Swap',
- '0x49404b7c': 'Swap',
- '0x414bf389': 'Swap',
- }
-
function txAction(tx: TxEntry, address: string): string {
if (tx.pairedValue) return 'Swap'
- const dir = tx.from.toLowerCase() === address.toLowerCase() ? 'Sent' : 'Received'
+ const dir =
+ tx.from.toLowerCase() === address.toLowerCase()
+ ? 'Sent'
+ : 'Received'
if (tx.tokenSymbol) return `${dir} ${tx.tokenSymbol}`
- const sel = tx.input?.slice(0, 10) ?? '0x'
- return SELECTORS[sel] ?? 'Contract Interaction'
+ return dir
}
let w = Wallet()
@@ -132,19 +120,25 @@
src={nativeIcon(w.network)}
alt=""
class="size-4 rounded-full"
- onerror={(e) => (e.target as HTMLElement).style.display = 'none'} />
- {w.balance} {w.symbol}
+ onerror={(e) =>
+ ((e.target as HTMLElement).style.display =
+ 'none')} />
+ {w.balance}
+ {w.symbol}
Tokens
{#each w.tokenBalances as t}
-
+
(e.target as HTMLElement).style.display = 'none'} />
+ onerror={(e) =>
+ ((e.target as HTMLElement).style.display =
+ 'none')} />
{Number(t.balance) < 0.0001 && Number(t.balance) > 0
? '<0.0001'
: Number(t.balance).toFixed(4)}
@@ -174,15 +168,15 @@
Transactions
- {#if !w.etherscanKey}
+ {#if !w.apiKey}
@@ -199,24 +193,62 @@
-
+
{#if tx.pairedValue}
-
(e.target as HTMLElement).style.display = 'none'} />
- {Number(formatEther(tx.value)).toFixed(4)} {w.symbol}
+
+ ((e.target as HTMLElement).style.display =
+ 'none')} />
+ {Number(tx.value).toFixed(4)}
+ {w.symbol}
→
-
(e.target as HTMLElement).style.display = 'none'} />
- {Number(formatUnits(tx.pairedValue, Number(tx.pairedDecimals ?? 18))).toFixed(4)} {tx.pairedSymbol}
+
+ ((e.target as HTMLElement).style.display =
+ 'none')} />
+ {Number(tx.pairedValue).toFixed(4)}
+ {tx.pairedSymbol}
{:else if tx.tokenSymbol}
-
(e.target as HTMLElement).style.display = 'none'} />
- {Number(formatUnits(tx.value, Number(tx.tokenDecimal ?? 18))).toFixed(4)} {tx.tokenSymbol}
+
+ ((e.target as HTMLElement).style.display =
+ 'none')} />
+ {Number(tx.value).toFixed(4)}
+ {tx.tokenSymbol}
{:else}
-
(e.target as HTMLElement).style.display = 'none'} />
- {Number(formatEther(tx.value)).toFixed(4)} {w.symbol}
+
+ ((e.target as HTMLElement).style.display =
+ 'none')} />
+ {Number(tx.value).toFixed(4)}
+ {w.symbol}
{/if}
@@ -230,20 +262,18 @@
minute: '2-digit',
})}
-
+
- {#if !tx.tokenSymbol || tx.pairedValue}
-
- {tx.isError === '0' ? '✓' : '✗'}
-
- {/if}
{/each}