diff --git a/skills/solana-dev/references/frontend.md b/skills/solana-dev/references/frontend.md index 7f9a5df..d891025 100644 --- a/skills/solana-dev/references/frontend.md +++ b/skills/solana-dev/references/frontend.md @@ -196,7 +196,7 @@ export function useBalance(accountAddress?: Address) { } ``` -**Multi-cluster apps:** include the cluster in the cache key, and derive it from the same source that built the client — the client is typically rebuilt one render *after* the selection flips, so a key read from selection state binds the new network's fetch to the previous network's `rpc`. The [Kit example app](https://github.com/anza-xyz/kit/blob/main/examples/react-app/src/components/Balance.tsx) stamps `chain` onto the client with `extendClient` and reads it back off `useClient()` to keep the two in lockstep. +**Multi-cluster apps:** include the cluster in the cache key, and derive it from the same source that built the client — the client is typically rebuilt one render *after* the selection flips, so a key read from selection state binds the new network's fetch to the previous network's `rpc`. The [Kit example app](https://github.com/anza-xyz/kit/blob/main/examples/react-app/src/components/Balance.tsx) stamps `chain` onto the client with `extendClient` and reads it back off `useClient()` to keep the two in lockstep. Render lamports with the Kit helpers rather than dividing by `1e9`: diff --git a/skills/solana-dev/references/kit/advanced.md b/skills/solana-dev/references/kit/advanced.md index a13d746..d355068 100644 --- a/skills/solana-dev/references/kit/advanced.md +++ b/skills/solana-dev/references/kit/advanced.md @@ -357,7 +357,9 @@ await airdrop({ **Accounts**: `getAccountInfo`, `getMultipleAccounts`, `getBalance`, `getTokenAccountBalance`, `getTokenAccountsByOwner`, `getProgramAccounts` -**Transactions**: `sendTransaction`, `simulateTransaction`, `getTransaction`, `getSignatureStatuses`, `getSignaturesForAddress` +**Transactions**: `sendTransaction`, `simulateTransaction`, `getTransaction`, `getSignatureStatuses`, `getSignaturesForAddress`, `getTransactionsForAddress` + +`getTransactionsForAddress` (`@solana/kit` 7.1+) combines address-history discovery and per-transaction fetching into a single query, with server-side filtering, bidirectional sorting, and cursor-based pagination — replacing a `getSignaturesForAddress` + N× `getTransaction` fan-out. It supports a `signatures`-only mode and a `full` mode (`json` / `jsonParsed` / `base58` / `base64`). It is part of the upcoming solana-rpc spec (`solana-rpc/superbank`) and is already available from major RPC providers, but is not yet universally supported — check the target endpoint before relying on it. Transaction metadata (from `getTransactionsForAddress` and `getTransaction`) also gained an optional `meta.costUnits` field. **Blocks**: `getBlock`, `getBlockHeight`, `getSlot`, `getLatestBlockhash`, `isBlockhashValid` diff --git a/skills/solana-dev/references/kit/react.md b/skills/solana-dev/references/kit/react.md index 8109515..95550cd 100644 --- a/skills/solana-dev/references/kit/react.md +++ b/skills/solana-dev/references/kit/react.md @@ -35,7 +35,7 @@ export function Providers({ children }: { children: React.ReactNode }) { } ``` -Always pass your client type to `useClient` — a bare `useClient()` gives you an untyped `Client` (and the type parameter is expected to become required): +Always pass your client type to `useClient` — as of `@solana/react` 7.1+, the `TClient` type parameter is required, so a bare `useClient()` fails to compile: ```tsx import { useClient } from '@solana/react'; @@ -60,6 +60,8 @@ function Balance({ address }: { address: Address }) { For caching, revalidation, and request dedup, prefer the framework adapters: `@solana/react/swr` (`useRequestSWR`, `useSubscriptionSWR`, `useTrackedDataSWR`) and `@solana/react/query` (`useRequestQuery`, `useSubscriptionQuery`, `useTrackedDataQuery`). Both are optional peer deps — install `swr` or `@tanstack/react-query` yourself. +As of `@solana/react` 7.1+, `useSubscriptionQuery` / `useTrackedDataQuery` (the TanStack Query adapters) surface a new error, `SOLANA_ERROR__SUBSCRIBABLE__STREAM_CLOSED_WITHOUT_ERROR`, when the underlying stream store closes in an error state with a nullish payload. The SWR adapters are unaffected. + ### useTrackedData / useTrackedDataSWR / useTrackedDataQuery Use these for any live account value (balances, token accounts, program state). The hook fires the initial RPC read and the subscription together and slot-dedupes them, so the first paint is fast and out-of-order arrivals never regress the surfaced value. Do **not** hand-roll a `getBalance` + `accountNotifications` pair. @@ -109,12 +111,61 @@ const { dispatch, dispatchAsync, data, error, isRunning, reset } = useAction( ``` - `dispatch` returns `void` and never throws — the variant for `onClick`. `dispatchAsync` resolves the value or rejects. -- Dispatching while a call is in flight aborts the first via its `AbortSignal`. Awaiters of the superseded `dispatchAsync` see an `AbortError`, filterable with `isAbortError` from `@solana/promises`, which `@solana/kit` 7 does not re-export — install that package explicitly if you need it. Sticking to `dispatch` where you can avoids the question entirely. +- Dispatching while a call is in flight aborts the first via its `AbortSignal`. Awaiters of the superseded `dispatchAsync` see an `AbortError`, filterable with `isAbortError`, importable directly from `@solana/kit` (7.1+ re-exports `@solana/promises`). Sticking to `dispatch` where you can avoids the question entirely. - `data` and `error` persist through subsequent `running` states for stale-while-revalidate UX; only `reset()` clears `data`. - `fn` is held in a ref pointing at the latest render's closure — no deps array. Most of the wallet plugin's action hooks (`useConnect`, `useDisconnect`, `useSignIn`, `useSignMessage`) are built on this and expose the same shape. +## Client Capability Hooks (requires `@solana/react` 7.1+) + +These read off whichever plugin capabilities the client advertises. Each takes the client as its only argument. + +### usePayer / useIdentity + +`usePayer(client)` reads `client.payer`; `useIdentity(client)` reads `client.identity`. Both return the current `TransactionSigner`, or `undefined` while none is available. + +```tsx +const payer = usePayer(client); +const identity = useIdentity(client); +return {payer ? `Paying with ${payer.address}` : 'No payer'}; +``` + +- When the client advertises `subscribeToPayer` / `subscribeToIdentity`, the hook subscribes so the returned signer always reflects the latest value. Otherwise it falls back to a one-time read. +- **Gotcha:** if reading the underlying value throws — as the wallet plugin does for `payer`/`identity` when it owns those roles and no wallet is connected — the hook surfaces `undefined` rather than throwing. + +### usePlanTransaction / usePlanTransactions / useSendTransaction / useSendTransactions + +Wrap a client's transaction planning/sending capabilities as `useAction`-style reactive actions — same `dispatch` / `dispatchAsync` / `data` / `error` / `isRunning` shape as `useAction`. + +| Hook | Wraps | `dispatch` args | Resolves with | +|------|-------|------------------|----------------| +| `usePlanTransaction(client)` | `client.planTransaction` | instruction input | the planned transaction message | +| `usePlanTransactions(client)` | `client.planTransactions` | instruction input | the full transaction plan (may span multiple transactions) | +| `useSendTransaction(client)` | `client.sendTransaction` | instructions, an instruction plan, a transaction message, or a transaction plan | the successful single-transaction-plan result | +| `useSendTransactions(client)` | `client.sendTransactions` | instructions, an instruction plan, or a transaction plan | the transaction plan result for all transactions | + +```tsx +const { dispatch, data, isRunning } = useSendTransaction(client); + +``` + +Use the singular hooks when you expect everything to fit in one transaction; reach for the plural hooks when instructions might need splitting across transactions. + +### useAirdrop + +Wraps a client's `airdrop` capability (`ClientWithAirdrop`) as a tracked `useAction`. `dispatch(address, amount)` requests an airdrop with an injected `AbortSignal` and resolves with the transaction `Signature`, or `undefined` when the airdrop was applied without a transaction (e.g. some local-validator implementations update balances directly, with no transaction to sign). + +```tsx +import { useAirdrop } from '@solana/react'; +import { lamports } from '@solana/kit'; + +const { dispatch, isRunning } = useAirdrop(client); + +``` + ## Wallet Hooks (`@solana/kit-plugin-wallet/react`) Requires `@solana/kit-plugin-wallet` 0.14+ and the `walletSigner` (or `walletWithoutSigner`) plugin on the client. Every hook takes the wallet-enabled `client` as its first argument, keeping the app fully typed end-to-end. diff --git a/skills/solana-dev/references/rpc-quick-lookups.md b/skills/solana-dev/references/rpc-quick-lookups.md index ff96f46..fa3792f 100644 --- a/skills/solana-dev/references/rpc-quick-lookups.md +++ b/skills/solana-dev/references/rpc-quick-lookups.md @@ -94,6 +94,8 @@ curl -s https://api.mainnet-beta.solana.com -X POST \ -d '{"jsonrpc":"2.0","id":1,"method":"getSignaturesForAddress","params":["",{"limit":10}]}' ``` +If the endpoint supports it, `getTransactionsForAddress` replaces this call plus the follow-up `getTransaction` fan-out with one query — it does address-history discovery and per-transaction fetching together, with server-side filtering, bidirectional sorting, cursor pagination, and both `signatures`-only and `full` (`json`/`jsonParsed`/`base58`/`base64`) response modes. It's part of the upcoming solana-rpc spec and already live at major RPC providers, but not yet universally available — check the target endpoint before assuming it's there. + ### Cluster liveness — `getSlot` / `getHealth` Quick sanity check that the endpoint is reachable.