Skip to content

Commit 2eed665

Browse files
committed
refactor: enhance useTokenAccountsByOwner hook with existing account type
- Introduced a new utility type `ExistingAccount` to better represent on-chain accounts. - Updated the `account` property in `TokenAccountWithAddress` to use the new type. - Simplified the query function by removing unnecessary error handling and improving account processing logic.
1 parent 0dc8f9c commit 2eed665

1 file changed

Lines changed: 42 additions & 44 deletions

File tree

packages/react/src/hooks/token-accounts-by-owner.ts

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
"use client";
22

3+
import { useQuery } from "@tanstack/react-query";
34
import type { Account, Address, FetchAccountConfig, Simplify } from "gill";
45
import type { Token } from "gill/programs/token";
56
import { decodeToken, TOKEN_PROGRAM_ADDRESS } from "gill/programs/token";
6-
import { useQuery } from "@tanstack/react-query";
77
import { GILL_HOOK_CLIENT_KEY } from "../const";
88
import { useSolanaClient } from "./client";
99
import type { GillUseRpcHook } from "./types";
1010

1111
type RpcConfig = Simplify<Omit<FetchAccountConfig, "abortSignal">>;
1212

13+
/**
14+
* Utility type for accounts that exist on-chain
15+
*/
16+
type ExistingAccount<TData extends object | Uint8Array, TAddress extends Address = Address> = Account<
17+
TData,
18+
TAddress
19+
> & { exists: true };
20+
1321
/**
1422
* Token account with its associated token account address
1523
*/
1624
type TokenAccountWithAddress<TAddress extends Address = Address> = {
1725
/**
1826
* The token account data
1927
*/
20-
account: Account<Token, TAddress> & { exists: true };
28+
account: ExistingAccount<Token, TAddress>;
2129
/**
2230
* The address of the token account
2331
*/
@@ -92,61 +100,51 @@ export function useTokenAccountsByOwner<TConfig extends RpcConfig = RpcConfig, T
92100
const { data, ...rest } = useQuery({
93101
...options,
94102
enabled: !!owner,
95-
queryFn: async (): Promise<TokenAccountsQueryResult<TAddress>> => {
96-
const allAccounts: TokenAccountWithAddress<TAddress>[] = [];
97-
98-
try {
99-
let filter;
100-
if (tokenMint) {
101-
filter = { mint: tokenMint };
102-
} else {
103-
filter = { programId: TOKEN_PROGRAM_ADDRESS };
104-
}
103+
queryFn: async (): Promise<TokenAccountsQueryResult<Address>> => {
104+
const allAccounts: TokenAccountWithAddress<Address>[] = [];
105105

106-
const response = await rpc.getTokenAccountsByOwner(owner, filter, { encoding: "base64", ...config }).send();
107-
108-
for (const accountInfo of response.value) {
109-
try {
110-
const rawAccount: Account<Uint8Array, TAddress> & { exists: true } = {
111-
address: accountInfo.pubkey as TAddress,
112-
data: new Uint8Array(Buffer.from(accountInfo.account.data[0], "base64")),
113-
executable: accountInfo.account.executable,
114-
exists: true,
115-
lamports: accountInfo.account.lamports,
116-
programAddress: accountInfo.account.owner,
117-
space: accountInfo.account.space,
118-
};
119-
120-
const decodedAccount = decodeToken(rawAccount);
121-
122-
if (!includeZeroBalance && decodedAccount.data.amount === 0n) {
123-
continue;
124-
}
125-
126-
allAccounts.push({
127-
account: decodedAccount as Account<Token, TAddress> & { exists: true },
128-
address: accountInfo.pubkey as TAddress,
129-
});
130-
} catch (decodeError) {
131-
console.warn(`Failed to decode token account ${accountInfo.pubkey}:`, decodeError);
132-
}
106+
const filter = tokenMint ? { mint: tokenMint } : { programId: TOKEN_PROGRAM_ADDRESS };
107+
108+
const response = await rpc.getTokenAccountsByOwner(owner, filter, { encoding: "base64", ...config }).send();
109+
110+
for (const accountInfo of response.value) {
111+
const rawAccount: ExistingAccount<Uint8Array, Address> = {
112+
address: accountInfo.pubkey,
113+
data: new Uint8Array(Buffer.from(accountInfo.account.data[0], "base64")),
114+
executable: accountInfo.account.executable,
115+
exists: true,
116+
lamports: accountInfo.account.lamports,
117+
programAddress: accountInfo.account.owner,
118+
space: accountInfo.account.space,
119+
};
120+
121+
const decodedAccount = decodeToken(rawAccount);
122+
123+
if (!includeZeroBalance && decodedAccount.data.amount === 0n) {
124+
continue;
133125
}
134-
} catch (queryError) {
135-
console.warn(`Failed to query token accounts:`, queryError);
136-
throw queryError;
126+
127+
const tokenAccount: ExistingAccount<Token, Address> = {
128+
...decodedAccount,
129+
exists: true,
130+
};
131+
132+
allAccounts.push({
133+
account: tokenAccount,
134+
address: accountInfo.pubkey,
135+
});
137136
}
138137

139138
return {
140139
accounts: allAccounts,
141140
total: allAccounts.length,
142-
} satisfies TokenAccountsQueryResult<TAddress>;
141+
};
143142
},
144143
queryKey: [GILL_HOOK_CLIENT_KEY, "getTokenAccountsByOwner", owner, tokenMint, includeZeroBalance],
145144
});
146145

147146
return {
148147
...rest,
149148
accounts: (data as TokenAccountsQueryResult<TAddress> | undefined)?.accounts || [],
150-
total: (data as TokenAccountsQueryResult<TAddress> | undefined)?.total || 0,
151149
};
152150
}

0 commit comments

Comments
 (0)