Skip to content

feat(allow-block-list-token): migrate frontend to @solana/kit - #689

Open
Harsh-H-Shah wants to merge 3 commits into
solana-foundation:mainfrom
Harsh-H-Shah:feat/allow-block-list-token-kit-migration
Open

feat(allow-block-list-token): migrate frontend to @solana/kit#689
Harsh-H-Shah wants to merge 3 commits into
solana-foundation:mainfrom
Harsh-H-Shah:feat/allow-block-list-token-kit-migration

Conversation

@Harsh-H-Shah

Copy link
Copy Markdown
Contributor

Summary

  • Migrates the allow-block-list-token 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 via @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/core Program wrapper.
  • Rebased onto main's already-merged #672 fix rather than the stale program my branch originally forked from — that fix changes tx_hook's client-facing account layout (both sender's and receiver's ab_wallet PDA now required, not just the receiver's). useSendTokens now resolves and appends both, in the order the program expects.

Test plan

  • pnpm run typecheck — clean
  • pnpm run build — clean
  • pnpm run lint — clean (one pre-existing warning, unrelated to this PR)
  • pnpm run format:check — clean (added idl/ and src/generated/ to .prettierignore)
  • pnpm run anchor-test — 9 unit + 5 litesvm + 1 mocha tests passing, including the source_blocked_is_always_rejected regression test
  • No @solana/web3.js/wallet-adapter imports remain in src/
  • anchor/ has zero diff from main — program untouched

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-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR migrates the allow/block-list Token-2022 frontend from legacy Web3.js and wallet-adapter transaction APIs to Solana Kit, Connector, and a Codama-generated client.

  • Adds generated Kit-native account, instruction, PDA, error, type, and program clients.
  • Reworks wallet connection, RPC access, transaction submission, token management, and account views around Kit APIs.
  • Updates the transfer path to resolve source and destination allow/block-list accounts in program order.
  • Adds LiteSVM coverage for generated client instructions and strengthens remove_wallet PDA validation.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the eligible follow-up review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/account/account-data-access.tsx Migrates SOL and Token-2022 transfers to Kit and the transfer-hook-aware instruction builder, including source and destination wallet metadata resolution.
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/abl-token/abl-token-data-access.tsx Replaces Anchor Program calls with generated Kit instructions for configuration, mint, wallet-list, mode, and token-management operations.
tokens/token-2022/transfer-hook/allow-block-list-token/src/hooks/use-send-instruction.ts Centralizes Kit transaction preparation, signing, submission, and confirmed-commitment handling.
tokens/token-2022/transfer-hook/allow-block-list-token/src/components/solana/solana-provider.tsx Replaces wallet-adapter providers with Connector-backed wallet and Kit RPC infrastructure.
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/programs/abl-token/src/instructions/remove_wallet.rs Binds the removable allow/block wallet account to the supplied wallet through canonical PDA seeds.
tokens/token-2022/transfer-hook/allow-block-list-token/anchor/tests/basic.test.ts Adds LiteSVM tests covering generated configuration, wallet initialization, canonical removal, and authority enforcement.
tokens/token-2022/transfer-hook/allow-block-list-token/scripts/generate-client.ts Introduces deterministic Codama client generation from the checked-in Anchor IDL.
tokens/token-2022/transfer-hook/allow-block-list-token/package.json Adds the Kit, Connector, Token-2022, Codama, and LiteSVM dependencies and wires client generation into development, build, and type-check workflows.

Reviews (3): Last reviewed commit: "fix(allow-block-list-token): address rev..." | 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
amilz self-requested a review August 18, 2026 19:19
@amilz amilz self-assigned this Aug 18, 2026

@amilz amilz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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 add wallet seeds? seeds = [AB_WALLET_SEED, wallet.key().as_ref()], bump and regenerate idl/clients so that getRemoveWalletInstructionAsync({ authority, wallet }) resolves both.

Comment on lines +16 to +20
"peerDependencies": {
"@solana/kit": "^6.10.0"
},
"dependencies": {
"@solana/program-client-core": "^6.10.0"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use 7.1? I think there are some new hooks in the latest version.

Comment on lines +110 to +124
/**
* Derives kit's RPC + RPC-subscriptions clients from the active cluster's endpoint. Every
* part of the app that talks to a cluster should read from this hook so that switching
* clusters (via `setCluster`) moves them all together.
*/
export function useClusterRpc() {
const { cluster } = useCluster();
return useMemo(
() => ({
rpc: createSolanaRpc(cluster.endpoint),
rpcSubscriptions: createSolanaRpcSubscriptions(deriveWebsocketUrl(cluster.endpoint)),
}),
[cluster.endpoint],
);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this duplicates useSolanaClient from connector

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though this looks fine, i think you already have some helpers to clean this up. Something like

const { prepare } = useTransactionPreparer();
const { client } = useSolanaClient();
const prepared = await prepare(txMessage);
const signed = await signTransactionMessageWithSigners(prepared);
await client.sendAndConfirmTransaction(signed);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Connector has a lot of these hooks out of the box. Double check please (useGetBalance / useGetTokenAccounts / useGetSignatures vs connector's useBalance / useTokens / useTransactions), which share one cache (1 RPC round trip vs your 3).
I think can swap them and use invalidateSharedQuery(getBalanceQueryKey(…)) instead of the hardcoded key strings.

Also, check out https://github.com/anza-xyz/kit/tree/main/packages/react/src/query

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

legacy bug, but should this be transferHookAuthority?

Suggested change
transferHookAuthority: args.transferHookAuthority,

mutationKey: ['transfer-sol', { endpoint: connection.rpcEndpoint, address }],
mutationFn: async (input: { destination: PublicKey; amount: number }) => {
let signature: TransactionSignature = '';
mutationKey: ['transfer-sol', { endpoint: cluster.endpoint, address }],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key is address but changed destination from address to signer. i think need to key off of signer.address or do some check that address === signer.address

.requestAirdrop(address, lamports(BigInt(Math.round(amount * LAMPORTS_PER_SOL))), {
commitment: 'confirmed',
})
.send();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need confirmation logic?

@@ -77,7 +77,9 @@ export function ClusterProvider({ children }: { children: ReactNode }) {
clusters: clusters.sort((a, b) => (a.name > b.name ? 1 : -1)),
addCluster: (cluster: SolanaCluster) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably worth doing url validation somewhere (e.g., new URL(endpoint))


// The local validator serves its websocket subscriptions on port 8900, not the HTTP
// RPC port (8899); every other cluster serves subscriptions on the same host as HTTP.
function deriveWebsocketUrl(endpoint: string): string {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you'll get this from connector via useSolanaClient

mintInfo.decimals,
undefined,
TOKEN_2022_PROGRAM_ID,
const createAtaIx = await getCreateAssociatedTokenIdempotentInstructionAsync({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

token client has getMintToATAInstructionPlanAsync and getTransferToATAInstructionPlanAsync helpers so you don't need to manaully assemble each ix

- 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>
@Harsh-H-Shah

Copy link
Copy Markdown
Contributor Author

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.

@amilz
amilz self-requested a review August 19, 2026 03:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants