Skip to content

Commit

Permalink
chore: polish
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Oct 10, 2023
1 parent 3c7d2b2 commit 4a333c0
Show file tree
Hide file tree
Showing 17 changed files with 26,878 additions and 789 deletions.
Binary file modified bun.lockb
Binary file not shown.
55 changes: 55 additions & 0 deletions src/actions/getAccountTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { type Address, parseAbiItem } from 'abitype'
import type { GetLogsParameters } from 'viem'

import { getLogsQueryOptions } from '~/hooks/useGetLogs'
import { queryClient } from '~/react-query'
import type { Client } from '~/viem'

export async function getAccountTokens(
client: Client,
{
address,
fromBlock,
toBlock,
}: {
address: Address
fromBlock: GetLogsParameters['fromBlock']
toBlock: GetLogsParameters['toBlock']
},
) {
const [transfersFrom, transfersTo] = await Promise.all([
queryClient.fetchQuery(
getLogsQueryOptions(client, {
event: parseAbiItem(
'event Transfer(address indexed from, address indexed to, uint256)',
),
args: {
from: address,
},
fromBlock,
toBlock,
}),
),
queryClient.fetchQuery(
getLogsQueryOptions(client, {
event: parseAbiItem(
'event Transfer(address indexed from, address indexed to, uint256)',
),
args: {
to: address,
},
fromBlock,
toBlock,
}),
),
])

// TODO: Check if log addresses are ERC20 tokens.

return [
...new Set([
...(transfersFrom?.map((t) => t.address) || []),
...(transfersTo?.map((t) => t.address) || []),
]),
]
}
1 change: 1 addition & 0 deletions src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { connect } from './connect'
export { disconnect } from './disconnect'
export { getAccountTokens } from './getAccountTokens'
18 changes: 1 addition & 17 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ import {
useAccountStore,
useNetworkStore,
useSessionsStore,
useTokensStore,
} from '~/zustand'

import { type AppMeta, AppMetaContext } from './contexts'
import { useImportTransferredTokens } from './hooks/useImportTransferredTokens'
import Layout from './screens/_layout'
import AccountDetails from './screens/account-details'
import BlockConfig from './screens/block-config'
Expand Down Expand Up @@ -128,7 +126,6 @@ export function init({ type = 'standalone' }: { type?: AppMeta['type'] } = {}) {
<AccountsChangedEmitter />
<NetworkChangedEmitter />
<SyncBlockNumber />
<SyncTransferredTokens />
<SyncJsonRpcAccounts />
<SyncNetwork />
<RouterProvider router={router} />
Expand Down Expand Up @@ -200,19 +197,6 @@ function SyncBlockNumber() {
return null
}

/** Keeps Transfer event imported tokens in sync. */
function SyncTransferredTokens() {
const { account } = useAccountStore()
const { addToken } = useTokensStore()
const tokens = useImportTransferredTokens()
if (account?.address) {
tokens.forEach((addr) => {
addToken(addr, account.address)
})
}
return null
}

/** Keeps accounts in sync with network. */
function SyncJsonRpcAccounts() {
const { data: chainId } = useNetworkStatus()
Expand All @@ -238,7 +222,7 @@ function SyncNetwork() {
const prevListening = usePrevious(listening)
useEffect(() => {
// Reset stale queries that are dependent on the client when node comes back online.
if (!prevListening && listening) {
if (prevListening === false && listening) {
queryClient.removeQueries({
predicate(query) {
return query.queryKey.includes(client.key)
Expand Down
46 changes: 46 additions & 0 deletions src/hooks/useAccountTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { queryOptions, useQuery } from '@tanstack/react-query'
import { type Address, stringify } from 'viem'

import { getAccountTokens } from '~/actions'
import { createQueryKey } from '~/react-query'
import type { Client } from '~/viem'
import { useNetworkStore, useTokensStore } from '~/zustand'

import { useClient } from './useClient'

type UseAccountTokensParameters = {
address?: Address
}

export const getAccountTokensQueryKey = createQueryKey<
'account-tokens',
[key: Client['key'], address: Address | undefined, args: string]
>('account-tokens')

export function useAccountTokensQueryOptions(args: UseAccountTokensParameters) {
const { address } = args

const { syncTokens } = useTokensStore()
const { network } = useNetworkStore()
const client = useClient()

return queryOptions({
enabled: Boolean(address && network.forkBlockNumber),
queryKey: getAccountTokensQueryKey([client.key, address, stringify(args)]),
async queryFn() {
if (!address) throw new Error('address is required')
const tokens = await getAccountTokens(client, {
address,
fromBlock: network.forkBlockNumber,
toBlock: 'latest',
})
syncTokens(tokens, address)
return tokens
},
})
}

export function useAccountTokens(args: UseAccountTokensParameters) {
const queryOptions = useAccountTokensQueryOptions(args)
return useQuery(queryOptions)
}
43 changes: 29 additions & 14 deletions src/hooks/useGetLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,73 @@ import { queryOptions, useQuery } from '@tanstack/react-query'
import {
type BlockNumber,
type BlockTag,
type Client,
type GetLogsParameters,
stringify,
} from 'viem'

import { createQueryKey } from '~/react-query'

import type { AbiEvent } from 'abitype'
import type { Client } from '../viem'
import { useClient } from './useClient'

type UseLogsParameters<
TAbiEvent extends AbiEvent,
TFromBlock extends BlockNumber | BlockTag,
TToBlock extends BlockNumber | BlockTag,
> = GetLogsParameters<TAbiEvent, TAbiEvent[], undefined, TFromBlock, TToBlock>
> = GetLogsParameters<
TAbiEvent,
TAbiEvent[],
undefined,
TFromBlock,
TToBlock
> & {
enabled?: boolean
}

export const getLogsQueryKey = createQueryKey<
'get-logs',
[key: Client['key'], args: string]
>('get-logs')

export function useGetLogsQueryOptions<
export function getLogsQueryOptions<
TAbiEvent extends AbiEvent,
TFromBlock extends BlockNumber | BlockTag,
TToBlock extends BlockNumber | BlockTag,
>(parameters: UseLogsParameters<TAbiEvent, TFromBlock, TToBlock>) {
const client = useClient()
>(client: Client, args: UseLogsParameters<TAbiEvent, TFromBlock, TToBlock>) {
const { enabled = true, fromBlock, toBlock } = args

return queryOptions({
enabled: Boolean(parameters),
enabled,
gcTime:
typeof parameters.fromBlock === 'bigint' &&
typeof parameters.toBlock === 'bigint'
typeof fromBlock === 'bigint' && typeof toBlock === 'bigint'
? Infinity
: undefined,
staleTime:
typeof parameters.fromBlock === 'bigint' &&
typeof parameters.toBlock === 'bigint'
typeof fromBlock === 'bigint' && typeof toBlock === 'bigint'
? Infinity
: undefined,
queryKey: getLogsQueryKey([client.key, stringify(parameters)]),
queryKey: getLogsQueryKey([client.key, stringify(args)]),
async queryFn() {
return await client.getLogs(parameters)
return await client.getLogs(args)
},
})
}

export function useGetLogsQueryOptions<
TAbiEvent extends AbiEvent,
TFromBlock extends BlockNumber | BlockTag,
TToBlock extends BlockNumber | BlockTag,
>(args: UseLogsParameters<TAbiEvent, TFromBlock, TToBlock>) {
const client = useClient()
return getLogsQueryOptions(client, args)
}

export function useGetLogs<
TAbiEvent extends AbiEvent,
TFromBlock extends BlockNumber | BlockTag,
TToBlock extends BlockNumber | BlockTag,
>(parameters: UseLogsParameters<TAbiEvent, TFromBlock, TToBlock>) {
const queryOptions = useGetLogsQueryOptions(parameters)
>(args: UseLogsParameters<TAbiEvent, TFromBlock, TToBlock>) {
const queryOptions = useGetLogsQueryOptions(args)
return useQuery(queryOptions)
}
49 changes: 0 additions & 49 deletions src/hooks/useImportTransferredTokens.ts

This file was deleted.

33 changes: 26 additions & 7 deletions src/hooks/useNetworkStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,33 @@ export function useNetworkStatus({
try {
const chainId = await client.getChainId()
const network = networks.find((x) => x.rpcUrl === client.key)
if (
network &&
chainId &&
network.rpcUrl === client.key &&
network.chainId !== chainId
) {
upsertNetwork({ rpcUrl, network: { chainId } })

if (network) {
let updatedNetwork = {}

// If chain becomes out of sync, update to the new chain.
if (
chainId &&
network.rpcUrl === client.key &&
network.chainId !== chainId
)
updatedNetwork = { ...updatedNetwork, chainId }

// If there is no fork block number, update to the current block number.
if (typeof network.forkBlockNumber !== 'bigint') {
updatedNetwork = {
...updatedNetwork,
forkBlockNumber: await client.getBlockNumber(),
}
}

if (Object.keys(updatedNetwork).length > 0)
upsertNetwork({
network: updatedNetwork,
rpcUrl: client.key,
})
}

return chainId
} catch {
return false
Expand Down
Loading

0 comments on commit 4a333c0

Please sign in to comment.