Skip to content

Multichain ImageGen#295

Merged
fretchen merged 49 commits into
mainfrom
multichain_img
Jan 30, 2026
Merged

Multichain ImageGen#295
fretchen merged 49 commits into
mainfrom
multichain_img

Conversation

@fretchen
Copy link
Copy Markdown
Owner

Prepare for multichain deployment of the Image Generator (also on Base in the future)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Prepares the ImageGen frontend and shared tooling for multichain operation by centralizing chain/address/ABI selection in @fretchen/chain-utils and updating the website to use CAIP-2 network identifiers.

Changes:

  • Migrates website GenImNFT contract access from getChain.ts/hardcoded configs to @fretchen/chain-utils (CAIP-2 + getGenAiNFTAddress + GenImNFTv4ABI).
  • Introduces useAutoNetwork (deferred “switch at interaction”) and useNFTListedStatus hooks and updates components to use them.
  • Expands/updates tests and ABI export pipeline (adds GenImNFTv4 ABI artifacts; removes generated timestamps from ABI outputs).

Reviewed changes

Copilot reviewed 51 out of 55 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
website/utils/nodeNftLoader.ts SSR/build-time NFT metadata loader now uses CAIP-2 default network + chain-utils addresses/ABI.
website/utils/nodeChainUtils.ts Adds getDefaultNetwork() for SSR/build-time CAIP-2 selection; removes GenAI NFT legacy config exports.
website/utils/nftLoader.ts NFT loader now requires an explicit CAIP-2 network and uses chain-utils for address/ABI.
website/utils/getChain.ts Removes GenAI NFT legacy config; keeps legacy configs for other contracts and documents migration path.
website/hooks/useNFTListedStatus.ts New hook to read isTokenListed with error handling for legacy tokens.
website/hooks/useConfiguredPublicClient.ts Public client hook now takes a CAIP-2 network and derives chainId via fromCAIP2.
website/hooks/useAutoNetwork.ts New hook to resolve CAIP-2 network and provide deferred switchIfNeeded() behavior.
website/components/PublicNFTList.tsx Uses useAutoNetwork + chain-utils address/ABI for getAllPublicTokens().
website/components/NFTList.tsx Uses CAIP-2 network to query balance with GenImNFTv4 ABI.
website/components/NFTFloatImage.tsx Uses CAIP-2 network and chain-utils address/ABI for tokenURI() reads.
website/components/NFTCard.tsx Migrates reads/writes to chain-utils + adds listing-status hook + deferred chain switching on write actions.
website/components/MyNFTList.tsx Migrates reads to chain-utils + CAIP-2 chainId/address selection.
website/components/ImageGenerator.tsx Moves to CAIP-2 + deferred switching via switchIfNeeded(); adds hydration-safety handling.
website/components/EntryNftImage.tsx Migrates tokenURI reads to chain-utils + CAIP-2 public client.
website/components/AgentInfoPanel.tsx Uses useAutoNetwork and chain-utils for contract address display.
website/test/useNFTListedStatus.test.ts Adds unit tests for the new useNFTListedStatus hook behavior.
website/test/useConfiguredPublicClient.test.ts Updates tests for new CAIP-2 parameter requirement.
website/test/useAutoNetwork.test.ts Adds integration-style tests for useAutoNetwork using wagmi mock connector.
website/test/setup.ts Refactors wagmi mocks into exportable mock functions for per-test customization.
website/test/PublicNFTList.test.tsx Updates component tests to the new hooks/chain-utils integration.
website/test/MyNFTList.test.tsx Updates tests/mocks to the new chain-utils + useAutoNetwork pattern.
website/test/ImageGenerator.test.tsx Updates test suite; one network-switch test is now skipped.
website/test/ContractChainSelection.test.ts Updates to chain-utils address/ABI selection for contract read.
website/test/AgentInfoPanel.test.tsx Adds rendering/hook-order regression tests for AgentInfoPanel.
website/package.json Adds local workspace dependency on @fretchen/chain-utils.
website/package-lock.json Locks the new local chain-utils dependency.
website/MULTICHAIN_EXPANSION_PROPOSAL.md Updates migration plan/progress notes for multichain expansion phases.
shared/chain-utils/src/addresses.ts Adds LLM_V1_NETWORKS list and centralizes network lists for deployed contracts.
shared/chain-utils/src/abi/GenImNFTv4.ts Expands minimal GenImNFTv4 ABI to cover website needs (public tokens, listing, burn, etc.).
eth/test/SupportV2_Deployment.ts Formatting cleanup in deployment tests.
eth/scripts/export-abi.ts Adds GenImNFTv4 to ABI export list; removes generated timestamps from outputs.
eth/scripts/deploy-support-v2.config.json Trailing newline/formatting fix.
eth/deployments/support-v2-optsepolia.json Trailing newline/formatting fix.
eth/deployments/support-v2-optimisticEthereum.json Trailing newline/formatting fix.
eth/abi/contracts/SupportV2.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/SupportV2-summary.md Removes generated timestamp section.
eth/abi/contracts/Support.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/Support-summary.md Removes generated timestamp section.
eth/abi/contracts/LLMv1.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/LLMv1-summary.md Removes generated timestamp section.
eth/abi/contracts/GenImNFTv4.ts Adds exported GenImNFTv4 ABI TypeScript artifact.
eth/abi/contracts/GenImNFTv4.json Adds exported GenImNFTv4 ABI JSON artifact.
eth/abi/contracts/GenImNFTv4-summary.md Adds GenImNFTv4 ABI summary documentation.
eth/abi/contracts/GenImNFTv3.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/GenImNFTv3-summary.md Removes generated timestamp section.
eth/abi/contracts/EIP3009SplitterV1.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/EIP3009SplitterV1-summary.md Removes generated timestamp section.
eth/abi/contracts/CollectorNFTv1.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/CollectorNFTv1-summary.md Removes generated timestamp section.
eth/abi/contracts/CollectorNFT.ts Removes generated timestamp comment from ABI output.
eth/abi/contracts/CollectorNFT-summary.md Removes generated timestamp section.
eth/SUPPORT_V2_PROPOSAL.md Markdown formatting cleanup.
eth/DEPLOY_SUPPORT_V2_GUIDE.md Markdown formatting cleanup and minor formatting fixes.
Files not reviewed (1)
  • website/package-lock.json: Language not supported

Comment thread website/test/ImageGenerator.test.tsx Outdated
Comment on lines +169 to +174
// SKIPPED: This test has two issues:
// 1. vi.mocked(useChainId).mockReturnValue() doesn't work due to module caching
// (see useAutoNetwork.test.ts header for detailed explanation)
// 2. With "switch at interaction" pattern, switchChain is called via switchIfNeeded()
// inside the submit handler, not directly on button click
it.skip("should call switchChain when user attempts to create artwork on wrong network", async () => {
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

There’s a skipped test here (it.skip(...)), which reduces coverage and can let regressions through. Please either fix the test (e.g., by using the centralized mocks from test/setup.ts or by rewriting to align with the new switchIfNeeded() behavior) or remove it if it’s no longer relevant.

Copilot uses AI. Check for mistakes.
Comment on lines 61 to 67
const freshBalance = await readContract(config, {
...genAiNFTContractConfig,
address: contractAddress,
abi: GenImNFTv4ABI,
functionName: "balanceOf",
args: [address],
chainId: chain.id,
chainId,
});
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

loadUserTokenIds captures contractAddress and chainId (derived from network) but its useCallback dependency list currently doesn’t include them. If the active GenAI network changes (e.g., Optimism ↔ Optimism Sepolia), the callback can keep querying the previous chain/address. Update the dependency array to include contractAddress and chainId (or network) so reads always target the current network.

Copilot uses AI. Check for mistakes.
Comment on lines 226 to 229
const CreateArtworkButton = () => {
const isDisabled = buttonState === "needsPrompt";
const isLoadingState = buttonState === "loading" || buttonState === "switching";
const isLoadingState = buttonState === "loading";

Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

isLoadingState is computed but the button isn’t disabled while loading, so users can click repeatedly and trigger multiple concurrent handleX402Generate() runs (and potentially multiple payment/signature flows). Use isLoadingState to disable the button (or add an early-return guard) while generation/processing is in progress.

Copilot uses AI. Check for mistakes.
Comment on lines +281 to 290
// === Chain Switch at Interaction ===
// Ensure user is on the correct chain before making payment
if (currentChainId !== targetChain.id) {
console.log(`[x402] Chain mismatch: current=${currentChainId}, target=${targetChain.id} (${targetChain.name})`);
try {
await switchChainAsync({ chainId: targetChain.id });
console.log(`[x402] Successfully switched to ${targetChain.name}`);
} catch (switchError) {
console.error("[x402] Chain switch failed:", switchError);
const errorMsg = `${chainSwitchFailedText}: ${targetChain.name}`;
setError(errorMsg);
onError?.(errorMsg);
return;
}
const switched = await switchIfNeeded();
if (!switched) {
console.error("[x402] Chain switch rejected by user");
const errorMsg = `${chainSwitchFailedText}: ${targetChain.name}`;
setError(errorMsg);
onError?.(errorMsg);
return;
}
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

switchIfNeeded() is awaited before setIsLoading(true), so the UI doesn’t enter a loading/disabled state while the wallet chain-switch prompt is pending. This can lead to repeated clicks and multiple switch prompts/actions. Consider setting a dedicated “switching”/loading state before awaiting switchIfNeeded() and clearing it on failure/success.

Copilot uses AI. Check for mistakes.
Comment thread website/test/setup.ts
Comment on lines 88 to 91
// Mock useLocale hook
vi.mock("./hooks/useLocale", () => ({
useLocale: vi.fn(({ label }: { label: string }) => label),
}));
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

This mocks "./hooks/useLocale", but components import "../hooks/useLocale", so the mock won’t apply. Either change the specifier to match the real import path (e.g. "../hooks/useLocale") or remove this mock if it’s unnecessary.

Copilot uses AI. Check for mistakes.

// Get network and contract address from chain-utils
const { network, switchIfNeeded } = useAutoNetwork(GENAI_NFT_NETWORKS);
const contractAddress = getGenAiNFTAddress(network);
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

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

Unused variable chainId.

Copilot uses AI. Check for mistakes.
@fretchen fretchen merged commit f2673a4 into main Jan 30, 2026
9 checks passed
@fretchen fretchen deleted the multichain_img branch January 30, 2026 14:23
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