Skip to content

Commit 02a1e53

Browse files
authored
Merge pull request #67 from macalinao/igm/plural-accounts
Support fetching multiple PDAs and token accounts at once
2 parents ee0db91 + 5d2100a commit 02a1e53

22 files changed

+427
-128
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"**/.direnv": true
1313
},
1414
"typescript.tsdk": "node_modules/typescript/lib",
15+
"editor.defaultFormatter": "biomejs.biome",
1516
"[json]": {
1617
"editor.defaultFormatter": "biomejs.biome"
1718
},
@@ -22,7 +23,7 @@
2223
"editor.codeActionsOnSave": {
2324
"source.fixAll.eslint": "explicit",
2425
"source.fixAll.biome": "explicit",
25-
"source.action.organizeImports.biome": "explicit"
26+
"source.organizeImports.biome": "explicit"
2627
},
2728
"cSpell.words": ["dnum", "tmath", "TKNA", "TKNB"]
2829
}

biome.jsonc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"defaultBranch": "master"
88
},
99
"files": {
10-
"ignoreUnknown": false,
1110
"includes": [
1211
"**",
1312
"!**/bun.lock",
@@ -16,7 +15,6 @@
1615
},
1716
"formatter": {
1817
"enabled": true,
19-
"useEditorconfig": true,
2018
"formatWithErrors": false,
2119
"indentStyle": "space",
2220
"indentWidth": 2,
@@ -82,8 +80,7 @@
8280
}
8381
}
8482
}
85-
},
86-
"includes": ["**", "!**/bun.lock"]
83+
}
8784
},
8885
"assist": {
8986
"actions": {

bun.lock

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,12 @@
9090
"name": "@macalinao/gill-extra",
9191
"version": "0.0.4",
9292
"dependencies": {
93+
"@macalinao/clients-token-metadata": "^0.4.0",
9394
"@macalinao/dataloader-es": "workspace:*",
9495
"@macalinao/solana-batch-accounts-loader": "workspace:*",
9596
"@macalinao/token-utils": "workspace:*",
9697
"@macalinao/zod-solana": "workspace:*",
98+
"@solana-program/token": "^0.6.0",
9799
},
98100
"devDependencies": {
99101
"@macalinao/eslint-config": "catalog:",
@@ -114,7 +116,7 @@
114116
"version": "0.5.11",
115117
"dependencies": {
116118
"@gillsdk/react": "catalog:",
117-
"@macalinao/clients-token-metadata": "^0.3.0",
119+
"@macalinao/clients-token-metadata": "^0.4.0",
118120
"@macalinao/dataloader-es": "workspace:*",
119121
"@macalinao/gill-extra": "workspace:*",
120122
"@macalinao/solana-batch-accounts-loader": "workspace:*",
@@ -130,7 +132,7 @@
130132
"@tanstack/react-query": "catalog:",
131133
"@testing-library/react": "^16.3.0",
132134
"@types/bun": "catalog:",
133-
"@types/react": "^19.1.12",
135+
"@types/react": "catalog:",
134136
"gill": "catalog:",
135137
"react": "catalog:",
136138
"typescript": "catalog:",
@@ -147,7 +149,7 @@
147149
"name": "@macalinao/quarry",
148150
"version": "0.0.2",
149151
"dependencies": {
150-
"@macalinao/clients-quarry": "^0.3.0",
152+
"@macalinao/clients-quarry": "^0.4.0",
151153
"@macalinao/token-utils": "workspace:*",
152154
"@solana-program/token": "^0.6.0",
153155
"nonempty-array": "^0.1.4",
@@ -259,7 +261,7 @@
259261
"@types/bun": "catalog:",
260262
"eslint": "catalog:",
261263
"typescript": "catalog:",
262-
"zod": "^4.1.5",
264+
"zod": "^4.1.9",
263265
},
264266
"peerDependencies": {
265267
"@solana/kit": ">=1.0.0",
@@ -268,8 +270,9 @@
268270
},
269271
},
270272
"overrides": {
271-
"react": "^19.1.1",
272-
"react-dom": "^19.1.1",
273+
"@types/react": "catalog:",
274+
"react": "catalog:",
275+
"react-dom": "catalog:",
273276
},
274277
"catalog": {
275278
"@gillsdk/react": "^0.5.1",
@@ -610,9 +613,9 @@
610613

611614
"@lit/reactive-element": ["@lit/[email protected]", "", { "dependencies": { "@lit-labs/ssr-dom-shim": "^1.4.0" } }, "sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg=="],
612615

613-
"@macalinao/clients-quarry": ["@macalinao/clients-quarry@0.3.0", "", { "peerDependencies": { "@solana/kit": "*" } }, "sha512-PR5HCBKpNTgE7GYHjLcu74+Nak4bNQ4LBag7DgddSCd+I49KURKaR+rfoNZ1d4Gn8R9NMcXekKdhHEAjZuBmBQ=="],
616+
"@macalinao/clients-quarry": ["@macalinao/clients-quarry@0.4.0", "", { "peerDependencies": { "@solana/kit": "*" } }, "sha512-aO5NLR2U3xcT+8wVgudeEDLelYl27SYz5OfuPkXX5IU6oDVwjB6hvuIbsv+aUqopcv5nKdSKqbWLoMmLeCsQ4w=="],
614617

615-
"@macalinao/clients-token-metadata": ["@macalinao/clients-token-metadata@0.3.0", "", { "peerDependencies": { "@solana/kit": "*" } }, "sha512-LjPyTpgnO4Rp/kqLPCnlgdnYBF64PbEaxzzDvclWyRzMjQ9kERYD0JiqAbY69eVj3M7ys6TI1BdhjxennrG3FA=="],
618+
"@macalinao/clients-token-metadata": ["@macalinao/clients-token-metadata@0.4.0", "", { "peerDependencies": { "@solana/kit": "*" } }, "sha512-0AAZxq3gEdTligrrIRb3RODD04A4ji7MHFpSyqWcq4c1S8BF9zI/3lfADsMJU8t15lOhNgo03QVLGBTSNcaXAA=="],
616619

617620
"@macalinao/dataloader-es": ["@macalinao/dataloader-es@workspace:packages/dataloader-es"],
618621

@@ -1230,7 +1233,7 @@
12301233

12311234
"@types/node-fetch": ["@types/[email protected]", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
12321235

1233-
"@types/react": ["@types/[email protected].12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="],
1236+
"@types/react": ["@types/[email protected].13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
12341237

12351238
"@types/react-dom": ["@types/[email protected]", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ=="],
12361239

@@ -3004,7 +3007,7 @@
30043007

30053008
"yocto-queue": ["[email protected]", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
30063009

3007-
"zod": ["[email protected].5", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="],
3010+
"zod": ["[email protected].9", "", {}, "sha512-HI32jTq0AUAC125z30E8bQNz0RQ+9Uc+4J7V97gLYjZVKRjeydPgGt6dvQzFrav7MYOUGFqqOGiHpA/fdbd0cQ=="],
30083011

30093012
"@babel/core/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
30103013

@@ -4324,6 +4327,8 @@
43244327

43254328
"@trezor/connect/@solana/kit/@solana/transactions/@solana/nominal-types": ["@solana/[email protected]", "", { "peerDependencies": { "typescript": ">=5.3.3" } }, "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA=="],
43264329

4330+
"@walletconnect/utils/viem/abitype/zod": ["[email protected]", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="],
4331+
43274332
"@walletconnect/utils/viem/ox/@noble/curves": ["@noble/[email protected]", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
43284333

43294334
"@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/[email protected]", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
@@ -4748,6 +4753,8 @@
47484753

47494754
"qrcode/yargs/find-up/locate-path/p-locate": ["[email protected]", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
47504755

4756+
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/abitype/zod": ["[email protected]", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="],
4757+
47514758
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves": ["@noble/[email protected]", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
47524759

47534760
"@reown/appkit-controllers/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/[email protected]", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
@@ -4760,6 +4767,8 @@
47604767

47614768
"@reown/appkit-ui/qrcode/yargs/find-up/locate-path/p-locate": ["[email protected]", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
47624769

4770+
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/abitype/zod": ["[email protected]", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="],
4771+
47634772
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves": ["@noble/[email protected]", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
47644773

47654774
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/[email protected]", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
@@ -4770,6 +4779,8 @@
47704779

47714780
"@reown/appkit-utils/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/abitype": ["[email protected]", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A=="],
47724781

4782+
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/abitype/zod": ["[email protected]", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="],
4783+
47734784
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/curves": ["@noble/[email protected]", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="],
47744785

47754786
"@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/viem/ox/@noble/hashes": ["@noble/[email protected]", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@
6161
"*.{json,jsonc,html}": "biome format --write --no-errors-on-unmatched"
6262
},
6363
"overrides": {
64-
"react": "^19.1.1",
65-
"react-dom": "^19.1.1"
64+
"@types/react": "catalog:",
65+
"react": "catalog:",
66+
"react-dom": "catalog:"
6667
},
6768
"dependencies": {
6869
"dnum": "^2.15.0"

packages/gill-extra/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@
4444
"test": "bun test src/"
4545
},
4646
"dependencies": {
47+
"@macalinao/clients-token-metadata": "^0.4.0",
4748
"@macalinao/dataloader-es": "workspace:*",
4849
"@macalinao/solana-batch-accounts-loader": "workspace:*",
4950
"@macalinao/token-utils": "workspace:*",
50-
"@macalinao/zod-solana": "workspace:*"
51+
"@macalinao/zod-solana": "workspace:*",
52+
"@solana-program/token": "^0.6.0"
5153
},
5254
"devDependencies": {
5355
"@macalinao/eslint-config": "catalog:",
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import type { Metadata } from "@macalinao/clients-token-metadata";
2+
import type { TokenInfo } from "@macalinao/token-utils";
3+
import type { Mint } from "@solana-program/token";
4+
import type { AccountInfo } from "./types.js";
5+
import { createTokenInfo } from "@macalinao/token-utils";
6+
import { tokenMetadataSchema } from "@macalinao/zod-solana";
7+
8+
export interface FetchTokenInfoParams {
9+
mint: AccountInfo<Pick<Mint, "decimals">>;
10+
metadata: Metadata | null;
11+
}
12+
13+
/**
14+
* Fetches and constructs TokenInfo from Metadata and Mint accounts
15+
* @param params - Object containing mint address, mint account, and optional metadata
16+
* @returns TokenInfo or null if data is insufficient
17+
*/
18+
export async function fetchTokenInfo({
19+
mint,
20+
metadata,
21+
}: FetchTokenInfoParams): Promise<TokenInfo | null> {
22+
const uri = metadata?.data.uri;
23+
const decimals = mint.data.decimals;
24+
const onChainName = metadata?.data.name;
25+
const onChainSymbol = metadata?.data.symbol;
26+
27+
// Prepare metadata account data
28+
let metadataAccountData: { name: string; symbol: string } | null =
29+
onChainName && onChainSymbol
30+
? { name: onChainName, symbol: onChainSymbol }
31+
: null;
32+
33+
// Prepare metadata URI JSON data
34+
let metadataUriJson: { image: string } | null = null;
35+
36+
// Try to fetch metadata from URI if available
37+
if (uri && metadataAccountData) {
38+
try {
39+
const response = await fetch(uri);
40+
if (response.ok) {
41+
const result = tokenMetadataSchema.safeParse(await response.json());
42+
43+
if (result.success) {
44+
// Override with data from URI JSON
45+
metadataAccountData = {
46+
name: result.data.name,
47+
symbol: result.data.symbol,
48+
};
49+
if (result.data.image) {
50+
metadataUriJson = { image: result.data.image };
51+
}
52+
} else {
53+
console.error("Invalid token metadata:", result.error);
54+
}
55+
}
56+
} catch (error) {
57+
console.error("Error fetching token info:", error);
58+
}
59+
}
60+
61+
// Create token info with all collected data
62+
return createTokenInfo({
63+
mint: mint.address,
64+
mintAccount: { decimals },
65+
metadataAccount: metadataAccountData,
66+
metadataUriJson,
67+
});
68+
}

packages/gill-extra/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from "@macalinao/zod-solana";
55
export * from "./build-get-explorer-link-function.js";
66
export * from "./constants.js";
77
export * from "./fetch-and-decode-account.js";
8+
export * from "./fetch-token-info.js";
89
export * from "./get-confirmed-transaction.js";
910
export * from "./get-signature-from-bytes.js";
1011
export * from "./get-solscan-explorer-link.js";

packages/gill-extra/src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,10 @@ export type AccountInfo<TData extends Uint8Array | object> = Pick<
4444
Account<TData>,
4545
"data" | "address"
4646
>;
47+
48+
/**
49+
* A function that computes a PDA from some arguments.
50+
*/
51+
export type PdaFn<TArgs, TResult> = (
52+
args: TArgs,
53+
) => Promise<readonly [TResult, number]>;

packages/grill/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
},
4848
"dependencies": {
4949
"@gillsdk/react": "catalog:",
50-
"@macalinao/clients-token-metadata": "^0.3.0",
50+
"@macalinao/clients-token-metadata": "^0.4.0",
5151
"@macalinao/dataloader-es": "workspace:*",
5252
"@macalinao/gill-extra": "workspace:*",
5353
"@macalinao/solana-batch-accounts-loader": "workspace:*",
@@ -63,7 +63,7 @@
6363
"@tanstack/react-query": "catalog:",
6464
"@testing-library/react": "^16.3.0",
6565
"@types/bun": "catalog:",
66-
"@types/react": "^19.1.12",
66+
"@types/react": "catalog:",
6767
"gill": "catalog:",
6868
"react": "catalog:",
6969
"typescript": "catalog:"

packages/grill/src/hooks/create-decoded-account-hook.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ import type { Account, Address, Decoder } from "@solana/kit";
22
import type { UseQueryResult } from "@tanstack/react-query";
33
import { useAccount } from "./use-account.js";
44

5+
export type DecodedAccountResult<TData extends object> =
6+
UseQueryResult<Account<TData> | null> & {
7+
address: Address | null | undefined;
8+
};
9+
510
/**
611
* A hook for fetching and decoding accounts.
712
*/
813
export type UseDecodedAccountHook<TData extends object> = (args: {
914
address: Address | null | undefined;
10-
}) => UseQueryResult<Account<TData> | null> & {
11-
address: Address | null | undefined;
12-
};
15+
}) => DecodedAccountResult<TData>;
1316

1417
/**
1518
* Generic helper to create a hook for fetching and decoding accounts

0 commit comments

Comments
 (0)