feat(allow-block-list-token): migrate frontend to @solana/kit - #689
Conversation
Moves the webapp off @solana/web3.js + @solana/wallet-adapter-react onto @solana/kit + @solana/connector, matching the sibling kit examples (nft-meta-data-pointer, world-cup). Wallet connection goes through @solana/connector/react, RPC calls use kit's typed createSolanaRpc, and program interaction goes through a Codama-generated Kit-native client built from the Anchor IDL (scripts/generate-client.ts) instead of the @anchor-lang/core Program wrapper. Rebased the migration onto origin/main's already-merged abl-token fix (solana-foundation#672) rather than the stale program this branch forked from, since that fix changes tx_hook's client-facing account layout: transfers now need both the sender's and receiver's ab_wallet PDA (source first, then destination), not just the receiver's. useSendTokens resolves and appends both, in the order the program's get_extra_account_metas() expects. Verified: pnpm typecheck/build/lint/format:check all pass, anchor test passes (9 unit + 5 litesvm + 1 mocha, including the source-blocked regression test), no web3.js/wallet-adapter imports remain in src/, and anchor/ has zero diff from origin/main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Greptile SummaryThe PR migrates the allow/block-list Token-2022 frontend from the legacy Web3.js and wallet-adapter stack to Solana Kit, Connector, and a Codama-generated client.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Reviews (4): Last reviewed commit: "fix(allow-block-list-token): correct pro..." | Re-trigger Greptile |
The root `pnpm run check` script runs prettier from the repo root, which only reads the root .prettierignore, not the app-level one - so the app-level ignore added for idl/abl_token.json (a raw copy of the anchor build output, regenerated on every `pnpm run generate-client`) had no effect on CI's root-level check. Mirrors the existing games/gacha/pinocchio/idl/ entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
amilz
left a comment
There was a problem hiding this comment.
@Harsh-H-Shah thank you! This is looking great. Drop some comments throughout. LMK if you have any questions!
- Any interest in adding some basic tests using the new TS Client?
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/tests/basic.test.ts anchor/…/instructions/remove_wallet.rs- can you addwalletseeds?seeds = [AB_WALLET_SEED, wallet.key().as_ref()], bumpand regenerate idl/clients so thatgetRemoveWalletInstructionAsync({ authority, wallet })resolves both.
- remove_wallet.rs: declare ab_wallet's PDA seeds (seeds = [AB_WALLET_SEED,
wallet.key()]) instead of requiring the caller to pre-derive and pass the
PDA directly, so getRemoveWalletInstructionAsync({ authority, wallet })
resolves it the same way getInitWalletInstructionAsync already does.
Also aligns config's seeds with the CONFIG_SEED constant, matching
init_wallet.rs. Regenerated the IDL/client and simplified the two
frontend callers (removeWallet, processBatchWallets) accordingly.
- Bump @solana/kit and @solana/program-client-core to ^7.1.0 (both the
app's own deps and the generated client's peerDependencies, via a new
dependencyVersions option on the codama renderVisitor call) and
@solana-program/token-2022 to ^0.15.0.
- cluster-data-access.tsx: drop useClusterRpc/deriveWebsocketUrl in favor
of @solana/connector's useSolanaClient across every consumer, and fix
addCluster's endpoint validation, which silently accepted any string -
createSolanaRpc doesn't parse its endpoint eagerly despite a comment
claiming otherwise. new URL(endpoint) is the actual check.
- use-send-instruction.ts: adopt @solana/connector's useTransactionPreparer
for blockhash + simulation-derived compute unit limit, sourcing
rpc/rpcSubscriptions for the send-and-confirm step from useSolanaClient
instead of the removed custom hook. (client.sendAndConfirmTransaction,
suggested in review, doesn't actually exist in the installed - and
latest published - @solana/connector@0.2.6, despite one JSDoc example;
kept sendAndConfirmTransactionFactory from kit for that step.)
- account-data-access.tsx: useSendTokens now resolves the transfer-hook's
extra accounts via @solana-program/token-2022's
getTransferCheckedWithTransferHookInstructionAsync (reads the mint's
on-chain extra-account-metas list) instead of hardcoding this program's
ab_wallet PDA convention client-side. useRequestAirdrop now uses kit's
airdropFactory, which confirms the airdrop instead of returning
immediately after requesting it. useTransferSol now checks
signer.address against the viewed account instead of silently signing
with a possibly-different connected wallet than the page's address.
(useGetBalance/useGetTokenAccounts/useGetSignatures stay on a
cluster-scoped RPC call, not connector's useBalance/useTokens/
useTransactions - those hooks are scoped to the connected wallet only
and don't take an address, so they can't back the generic
/account/[address] page, which needs to read arbitrary addresses.)
- abl-token-data-access.tsx: fixed transferHookAuthority being set to
mintAuthority instead of the form's own transferHookAuthority field (a
legacy bug predating this migration). mintTo now uses
getMintToATAInstructionPlanAsync + flattenInstructionPlan instead of
manually assembling the create-ATA and mint-to instructions.
- Added anchor/tests/basic.test.ts: LiteSVM-backed tests exercising the
generated Kit client directly (init_config, init_wallet, the new
seeds-based remove_wallet, and an authority-mismatch rejection case).
This project's `anchor test` has no local-validator step to test
against - its Anchor.toml [scripts] test command fully replaces
Anchor's normal build+validator+deploy flow - so a real RPC connection
isn't available; LiteSVM gives the TS client something real to run
against without one. The old placeholder test never actually exercised
anything.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks so much for the thorough review — really appreciate you taking the time to go through this in detail. I've pushed a commit addressing everything. |
…ccount resolution The Codama-generated instruction builders resolve their default PDAs through findConfigPda()/findAbWalletPda() with no program-address argument, so those helpers fall back to the IDL's declare_id even when the instruction itself is built for a different program. programIdForCluster pointed devnet and testnet at 6z68wfurCMYkZG51s1Et9BJEd9nJGUusjHXNt4dGbNNF, which made every write path send a PDA derived from the local program id to a different program, while getConfig (the one call site that passed the override to the PDA helper) read the correct account. That address is a system-owned wallet copied from the legacy-next-tailwind-basic template, not a deployment of this program, so the override is dropped and the generated ABL_TOKEN_PROGRAM_ADDRESS is used throughout. - useSendTokens: getTransferCheckedWithTransferHookInstructionAsync resolves the hook's extra accounts from an AccountData seed over the destination token account, which it reads over RPC. A first-ever transfer to a recipient with no associated token account therefore threw during instruction construction, because the idempotent create-ATA instruction sat in the same unsent transaction. Create the ATA in its own transaction when it is missing, and restore the preconditions the migration dropped: an explicit error when the mint has no transfer hook, and one when its extra-account-metas account does not exist (both cases otherwise degrade to a bare transferChecked that fails on chain). - Replace the `enabled` + isLoading pairs with isPending. A disabled TanStack query reports isLoading false with no data, so ClusterChecker, AccountBalanceCheck and AblTokenProgram rendered their error states on first paint, before the connector client existed. - Serialize the program account with a bigint replacer. kit types lamports and space as bigint, and the BigInt.prototype.toJSON patch lives in layout.tsx, a server component, so the browser bundle never receives it. - Classify program errors by the codes in src/generated/errors instead of matching Anchor variant names in log strings. - useTransferSol: stop swallowing send failures, and report through the transaction toasts. ModalSend renders only on the connected wallet's own account page, matching the signer check. - Give initWallet and removeWallet distinct mutation keys (both used 'change-mode'), and invalidate get-ab-wallets after each write to the list. - Derive the connector's localnet cluster from the endpoint host rather than the cluster being named 'local', and key AppProvider on the endpoint, so a custom cluster is no longer advertised to the wallet as devnet. - generate-client: prefer anchor/target/idl/abl_token.json when present and fall back to the committed idl/. The client hardcodes the program id from the IDL, so a keys-synced local build otherwise left the webapp pointing at an address the deploy never created. - Delete anchor/src/abl-token-exports.ts and anchor/src/index.ts, unreachable since the @project/anchor alias was removed, and with them the last @anchor-lang/core and @solana/web3.js imports; drop both dependencies. - Drop the unused useHasTransferHookEnabled, take LAMPORTS_PER_SOL and lamportsToSol from @solana/connector instead of redefining them, and correct the .prettierignore note about how idl/ is produced.
|
@Harsh-H-Shah thank you! |
dev-jodee
left a comment
There was a problem hiding this comment.
Kit migration solid — tested & CI clean.
Summary
@solana/web3.js+@solana/wallet-adapter-reactonto@solana/kit+@solana/connector, matching the sibling kit examples (nft-meta-data-pointer, world-cup).@solana/connector/react; program interaction via a Codama-generated Kit-native client built from the Anchor IDL (scripts/generate-client.ts) instead of the@anchor-lang/coreProgramwrapper.main's already-merged#672fix rather than the stale program my branch originally forked from — that fix changestx_hook's client-facing account layout (both sender's and receiver'sab_walletPDA now required, not just the receiver's).useSendTokensnow resolves and appends both, in the order the program expects.Test plan
pnpm run typecheck— cleanpnpm run build— cleanpnpm run lint— clean (one pre-existing warning, unrelated to this PR)pnpm run format:check— clean (addedidl/andsrc/generated/to.prettierignore)pnpm run anchor-test— 9 unit + 5 litesvm + 1 mocha tests passing, including thesource_blocked_is_always_rejectedregression test@solana/web3.js/wallet-adapterimports remain insrc/anchor/has zero diff frommain— program untouched