Skip to content

chore: upgrade nft-meta-data-pointer app to Next.js 16 and React 18.3 - #657

Open
Harsh-H-Shah wants to merge 1 commit into
solana-foundation:mainfrom
Harsh-H-Shah:chore/upgrade-nft-meta-data-pointer-app-nextjs
Open

chore: upgrade nft-meta-data-pointer app to Next.js 16 and React 18.3#657
Harsh-H-Shah wants to merge 1 commit into
solana-foundation:mainfrom
Harsh-H-Shah:chore/upgrade-nft-meta-data-pointer-app-nextjs

Conversation

@Harsh-H-Shah

Copy link
Copy Markdown

Summary

This Token-2022 example's frontend was on Next.js 13.4.4 / React 18.2.0 (mid-2023) — the only browser app in this repo, and the one place where dependency staleness is a security question (wallet-connected) rather than pure hygiene. This PR brings it to Next.js 16.2.12 / React 18.3.1.

Stays on React 18.x rather than 19: @magicblock-labs/gum-react-sdk (used for the session-key feature) hard-pins react: ^18.2.0 in every published release up to latest (3.0.10), with no React 19 support. Next.js itself doesn't force the issue — both Next 15 and 16 still accept react: ^18.2.0.

What's in scope vs. what surfaced

The version jump itself is small. Getting next build to pass under it was not — Next 16's stricter type-checking and Turbopack bundling caught several pre-existing bugs that had never been exercised before. I've tried to keep those fixes minimal and mechanical rather than rewriting anything.

Direct upgrade

  • next 13.4.4 → 16.2.12, react/react-dom 18.2.0 → 18.3.1
  • eslint 8.41.0 → 9.39.5, eslint-config-next → 16.2.12
  • .eslintrc.jsoneslint.config.mjs (flat config) — next lint was removed entirely in Next 16
  • typescript 5.0.4 → 5.9.3 (needed — several @solana/* transitive deps require typescript >= 5.4.0)

Pre-existing bugs this surfaced

  • idl/extension_nft.ts hand-writes this program's Anchor IDL and was in an old schema (isOptional instead of optional, account structs embedded directly instead of pointing into a types array, "publicKey" instead of "pubkey" as a type literal, and missing the now-required address/metadata/discriminator fields) — incompatible with the already-installed @anchor-lang/core client, which silently collapsed every account's decoded type to never. Restructured to the current schema. Instruction/account discriminators are computed via sha256("global:"|"account:" + name).slice(0, 8), matching Anchor's own algorithm exactly — not guessed — worth double-checking against the real deployed program's IDL if you have it handy.
  • utils/anchor.ts: the Program constructor no longer takes programId as a positional argument now that idl.address is required and used instead.
  • @coral-xyz/anchor and axios were imported in a couple of files but never declared as dependencies — they only resolved before by accident, via node_modules hoisting under Next 13's looser module resolution. Now declared properly (axios) or replaced with the already-used @anchor-lang/core/@solana/web3.js equivalents.
  • @solana/wallet-adapter-wallets (the mega-package bundling every hardware/mobile wallet adapter) pulls in a Ledger dependency with a broken ESM export under Turbopack, crashing the build. This app only ever uses Phantom + Solflare, so swapped to the standalone @solana/wallet-adapter-phantom / @solana/wallet-adapter-solflare packages instead of fighting the bundler over unused code.
  • gum-react-sdk's createSession() signature drifted between the pinned ^3.0.4 range and the resolved 3.0.10: the 2nd parameter changed from a boolean to topUpLamports: number.
  • ChopTreeButton.tsx: one chopTree instruction call was missing the required systemProgram/tokenProgram accounts (would have failed on-chain), and an NFT-authority field (typed as string | { address: string }) was read unsafely in two places without checking which shape it was.

Requesting extra scrutiny on

  • The discriminator values and restructured idl/extension_nft.ts — I computed these correctly against Anchor's known algorithm, but I don't have a way to test them against the actual deployed program (H31ofLpWqeAzF2Pg54HSPQGYifJad843tTJg8vCYVoh3) in this environment.
  • The ChopTreeButton.tsx account/null-safety fixes — logically sound based on the sibling code path in the same file, but not exercised against a live wallet.

Test plan

  • next build passes: full TypeScript check + static generation of all routes
  • next dev serves the homepage (GET / 200), and the SSR output contains real Chakra UI + wallet-adapter markup — the full provider tree mounts and renders without throwing
  • eslint . passes with 0 errors (3 pre-existing exhaustive-deps warnings left as-is, unrelated to this change)
  • Live browser click-through / wallet connect — not possible in the environment this was built in (no Chromium available). Needs a manual smoke test before merging.

Bumps this Token-2022 example's frontend from Next.js 13.4.4/React
18.2.0 (mid-2023) to Next.js 16.2.12/React 18.3.1, closing a
multi-year gap in a wallet-connected browser app. Stays on React 18.x
rather than 19 because @magicblock-labs/gum-react-sdk hard-pins
react: ^18.2.0 in every published release; Next 16 itself accepts
either.

Migrates .eslintrc.json to eslint.config.mjs (flat config), since
`next lint` was removed in Next 16.

The version jump surfaced several pre-existing bugs that strict
type-checking had never caught before:

- idl/extension_nft.ts hand-writes this program's Anchor IDL and used
  an old schema (isOptional, embedded account structs, the
  "publicKey" type literal, no address/metadata/discriminator fields)
  incompatible with the already-installed @anchor-lang/core client.
  Restructured to the current schema; instruction/account
  discriminators are computed via sha256("global:"/"account:" + name),
  matching Anchor's own algorithm, not guessed.
- utils/anchor.ts: the Program constructor no longer takes programId
  positionally now that idl.address is required and used instead.
- @coral-xyz/anchor and axios were imported but never declared as
  dependencies; resolved only by accident via node_modules hoisting
  under Next 13's looser module resolution.
- @solana/wallet-adapter-wallets (which bundles every hardware/mobile
  wallet adapter) pulls in a Ledger dependency with a broken ESM
  export under Turbopack. Replaced with the standalone
  @solana/wallet-adapter-phantom and -solflare packages, since those
  are the only two this app actually uses.
- gum-react-sdk's createSession() second parameter changed from a
  boolean to topUpLamports (a lamport amount) between the pinned
  ^3.0.4 range and the resolved 3.0.10.
- ChopTreeButton.tsx: one instruction call was missing required
  systemProgram/tokenProgram accounts, and an NFT-authority union type
  was read unsafely in two places.

Verified: `next build` passes (full typecheck + static generation),
`next dev` serves the homepage with real Chakra UI / wallet-adapter
markup in the SSR output, `eslint .` passes with 0 errors (3
pre-existing exhaustive-deps warnings left as-is). Live browser
click-through wasn't possible in this environment - worth a manual
smoke test before merging.
@Harsh-H-Shah
Harsh-H-Shah requested a review from dev-jodee as a code owner July 29, 2026 18:05
const onChopClick = useCallback(async () => {
setIsLoadingSession(true);
if (!playerDataPDA || !sessionWallet?.publicKey) return;
if (!playerDataPDA || !sessionWallet?.publicKey || !sessionWallet.sessionToken) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Session loading state stays active

When the session token expires or is cleared before this handler runs, the new guard returns after setIsLoadingSession(true) without restoring the state, leaving the session chop button indefinitely loading and preventing another attempt without remounting the component.

Suggested change
if (!playerDataPDA || !sessionWallet?.publicKey || !sessionWallet.sessionToken) return;
if (!playerDataPDA || !sessionWallet?.publicKey || !sessionWallet.sessionToken) {
setIsLoadingSession(false);
return;
}

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Greptile Summary

Upgrades the NFT metadata-pointer frontend toolchain and repairs compatibility with the newer Anchor client.

  • Upgrades Next.js, React, TypeScript, ESLint, wallet adapters, and the application lockfile.
  • Migrates ESLint to flat configuration and updates wallet/session SDK integrations.
  • Restructures the hand-authored Anchor IDL and updates Program construction.
  • Adds required chop-tree accounts and safer NFT authority handling.

Confidence Score: 4/5

The session-token early-return path should be fixed before merging because it can permanently leave the chop control in a loading state.

The dependency and IDL migrations are internally consistent, but the changed session guard exits after enabling loading without restoring it when the token disappears.

Files Needing Attention: tokens/token-2022/nft-meta-data-pointer/anchor-example/app/components/ChopTreeButton.tsx

Important Files Changed

Filename Overview
tokens/token-2022/nft-meta-data-pointer/anchor-example/app/components/ChopTreeButton.tsx Adds account and null-safety handling, but the new missing-session-token exit leaves the session button stuck loading.
tokens/token-2022/nft-meta-data-pointer/anchor-example/app/idl/extension_nft.ts Migrates the hand-authored program interface to the current Anchor IDL shape with explicit instruction and account discriminators.
tokens/token-2022/nft-meta-data-pointer/anchor-example/app/package.json Upgrades the frontend framework and tooling dependencies and replaces the wallet mega-package with standalone adapters.
tokens/token-2022/nft-meta-data-pointer/anchor-example/app/pnpm-lock.yaml Introduces a lockfile resolving the upgraded frontend dependency graph.
tokens/token-2022/nft-meta-data-pointer/anchor-example/app/utils/anchor.ts Updates Program construction so the program address is sourced from the migrated IDL.

Reviews (1): Last reviewed commit: "chore: upgrade nft-meta-data-pointer app..." | Re-trigger Greptile

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.

1 participant