feat(frontend): switch from sepolia to mainnet#220
feat(frontend): switch from sepolia to mainnet#220jo-elimu wants to merge 6 commits intoelimu-ai:mainfrom
Conversation
✅ Deploy Preview for web3-sponsors ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 WalkthroughThis PR updates frontend imports across multiple files, switching smart-contract ABIs and Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
frontend/src/components/VerificationStatus.tsx (1)
98-98:⚠️ Potential issue | 🔴 CriticalEtherscan link still points to Sepolia.
The "Remove from queue" link on Line 98 uses
sepolia.etherscan.io. This should be updated toetherscan.iofor mainnet.- <Link className="text-orange-700" href={`https://sepolia.etherscan.io/address/${deploymentAddressQueueHandler}#writeContract#F2`} target="_blank"> + <Link className="text-orange-700" href={`https://etherscan.io/address/${deploymentAddressQueueHandler}#writeContract#F2`} target="_blank">🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/components/VerificationStatus.tsx` at line 98, In VerificationStatus.tsx update the Link that builds the Etherscan URL (the element using deploymentAddressQueueHandler) to use the mainnet domain by replacing "sepolia.etherscan.io" with "etherscan.io" while preserving the path/fragment (e.g., `#writeContract`#F2) and existing attributes (className, target); ensure the href now points to `https://etherscan.io/address/${deploymentAddressQueueHandler}#writeContract#F2`.frontend/src/pages/distributions/add.tsx (1)
198-199:⚠️ Potential issue | 🔴 CriticalEtherscan links still reference
sepolia.etherscan.io.Both the "Finalizing" and "Success" states link to Sepolia Etherscan. These should point to mainnet Etherscan.
🔧 Proposed fix
- <Link href={`https://sepolia.etherscan.io/tx/${writeHash}`} target='_blank' className="text-purple-400"> + <Link href={`https://etherscan.io/tx/${writeHash}`} target='_blank' className="text-purple-400">(Apply to both occurrences at Lines 198 and 208.)
Also applies to: 208-209
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/pages/distributions/add.tsx` around lines 198 - 199, Update the two Link components that build Etherscan URLs (they currently use `https://sepolia.etherscan.io/tx/${writeHash}`) to point to mainnet by replacing `sepolia.etherscan.io` with `etherscan.io`; locate the Link usage in the "Finalizing" and "Success" UI branches that reference `writeHash` and update both occurrences so the href becomes `https://etherscan.io/tx/${writeHash}` (preserve the `target` and `className` attributes).frontend/src/components/ProcessedQueuePairs.tsx (2)
67-67:⚠️ Potential issue | 🔴 CriticalEtherscan link still points to
sepolia.etherscan.io.This link should point to
etherscan.io(mainnet) now that the contracts are deployed on mainnet.- Block: <Link className="text-purple-600" href={`https://sepolia.etherscan.io/tx/${el.transactionHash}`} target="_blank">#{Number(el.blockNumber)}</Link> + Block: <Link className="text-purple-600" href={`https://etherscan.io/tx/${el.transactionHash}`} target="_blank">#{Number(el.blockNumber)}</Link>🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/components/ProcessedQueuePairs.tsx` at line 67, Update the Etherscan URL used in the ProcessedQueuePairs component: replace the hard-coded sepolia subdomain in the Link href that builds the transaction URL (currently using `https://sepolia.etherscan.io/tx/${el.transactionHash}`) with the mainnet `https://etherscan.io/tx/${el.transactionHash}` so the Link for `el.transactionHash` points to mainnet; change the href construction where `el.transactionHash` is referenced in the JSX inside ProcessedQueuePairs.tsx.
31-31:⚠️ Potential issue | 🔴 CriticalStart block and comment reference Sepolia — must be updated for mainnet.
The
startBlockvalue9_907_904and the accompanying Sepolia Etherscan link in the comment are specific to the Sepolia deployment. For mainnet, this needs to be the block number of the mainnet deployment transaction.🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/components/ProcessedQueuePairs.tsx` at line 31, The hardcoded Sepolia start block and comment must be updated for mainnet: replace the BigInt value assigned to startBlock in ProcessedQueuePairs (const startBlock = BigInt(9_907_904)) with the mainnet deployment block number and update the inline comment URL to point to the mainnet Etherscan transaction for the deployment; ensure the constant remains a BigInt and the comment contains the correct mainnet tx hash and Etherscan link for future reference.frontend/src/pages/distributions/[queueNumber].tsx (1)
43-43:⚠️ Potential issue | 🔴 CriticalEtherscan link still points to Sepolia.
The "Add verification" link uses
sepolia.etherscan.io— should beetherscan.iofor mainnet.- <Link className="text-purple-600" href={`https://sepolia.etherscan.io/address/${deploymentAddress}#writeContract#F3`} target="_blank"> + <Link className="text-purple-600" href={`https://etherscan.io/address/${deploymentAddress}#writeContract#F3`} target="_blank">🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/pages/distributions/`[queueNumber].tsx at line 43, The Link rendering the "Add verification" Etherscan URL currently hardcodes sepolia.etherscan.io; update the href in the Link component (the JSX using deploymentAddress and fragment "#writeContract#F3") to use etherscan.io instead of sepolia.etherscan.io (or make it network-aware if needed) so the link points to mainnet Etherscan.frontend/src/pages/sponsorships/add.tsx (1)
183-195:⚠️ Potential issue | 🔴 CriticalCritical: Etherscan links still point to Sepolia testnet.
Lines 183 and 193 use
https://sepolia.etherscan.io/tx/...but the contract artifacts and addresses are now mainnet. Users sending real ETH will see broken transaction links. This should behttps://etherscan.io/tx/...for mainnet.This is especially important given elimu.ai's mission to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — sponsors need to trust that their contributions are properly tracked!
🐛 Proposed fix
- <Link href={`https://sepolia.etherscan.io/tx/${writeHash}`} target='_blank' className="text-purple-400"> + <Link href={`https://etherscan.io/tx/${writeHash}`} target='_blank' className="text-purple-400"> View on Etherscan ↗ </Link>Apply the same fix on both Line 183 and Line 193.
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/pages/sponsorships/add.tsx` around lines 183 - 195, The Etherscan links in the JSX using writeHash currently point to the Sepolia testnet; update both Link href occurrences that build URLs with `https://sepolia.etherscan.io/tx/${writeHash}` to use the mainnet URL `https://etherscan.io/tx/${writeHash}` instead (preserve the Link component, target and className), i.e., change both places where `writeHash` is interpolated in the Link href to the mainnet domain so transaction links work for real ETH transfers.frontend/src/components/NextQueuePair.tsx (1)
183-195:⚠️ Potential issue | 🔴 CriticalCritical: Etherscan links still point to Sepolia testnet.
Lines 183 and 193 link to
sepolia.etherscan.iobut transactions will be on mainnet. Users will get dead links after processing queue pairs.🐛 Proposed fix
- <Link href={`https://sepolia.etherscan.io/tx/${writeHash}`} target='_blank' className="text-purple-400"> + <Link href={`https://etherscan.io/tx/${writeHash}`} target='_blank' className="text-purple-400">Apply to both Line 183 and Line 193.
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and decide whether a code change is actually needed. If the finding is not valid or no change is required, do not modify code for that item and briefly explain why it was skipped. In `@frontend/src/components/NextQueuePair.tsx` around lines 183 - 195, Links in NextQueuePair currently hardcode Sepolia; update the two Link hrefs that use writeHash to point to mainnet Etherscan instead of sepolia (change https://sepolia.etherscan.io/tx/${writeHash} to https://etherscan.io/tx/${writeHash}), or better yet compute the Etherscan base dynamically (e.g., getEtherscanBaseFromChain and use that) so the Link components referencing writeHash always use the correct network; modify both Link instances in the NextQueuePair component accordingly.
🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@frontend/src/components/NextQueuePair.tsx`:
- Around line 183-195: Links in NextQueuePair currently hardcode Sepolia; update
the two Link hrefs that use writeHash to point to mainnet Etherscan instead of
sepolia (change https://sepolia.etherscan.io/tx/${writeHash} to
https://etherscan.io/tx/${writeHash}), or better yet compute the Etherscan base
dynamically (e.g., getEtherscanBaseFromChain and use that) so the Link
components referencing writeHash always use the correct network; modify both
Link instances in the NextQueuePair component accordingly.
In `@frontend/src/components/PairedSponsorship.tsx`:
- Around line 2-5: The component imports mainnet artifacts (abi_queue_handler,
deployed_addresses) but incorrectly constructs a Sepolia runtime (sepolia /
createPublicClient) and uses a Sepolia startBlock; update the RPC chain and
start block to mainnet equivalents: replace sepolia with the appropriate mainnet
chain object when calling createPublicClient (the same chain that matches the
mainnet_v0-9-9 artifacts), ensure the RPC URL/provider targets mainnet, and set
startBlock to the mainnet deployment block number for the QueueHandlerModule
contract so event queries against deployed_addresses[...].address return
results.
In `@frontend/src/components/ProcessedQueuePairs.tsx`:
- Around line 2-4: The code imports mainnet contract artifacts
(abi_queue_handler, deployed_addresses) but still uses the sepolia chain and RPC
when creating the public client; change the chain import from sepolia to mainnet
(import { mainnet } from "viem/chains") and update the public client creation
(the variable/function that builds the PublicClient—e.g.,
createPublicClient/publicClient initialization) to use mainnet and a mainnet RPC
URL/provider so the ABI and deployed_addresses point to the same network.
- Line 67: Update the Etherscan URL used in the ProcessedQueuePairs component:
replace the hard-coded sepolia subdomain in the Link href that builds the
transaction URL (currently using
`https://sepolia.etherscan.io/tx/${el.transactionHash}`) with the mainnet
`https://etherscan.io/tx/${el.transactionHash}` so the Link for
`el.transactionHash` points to mainnet; change the href construction where
`el.transactionHash` is referenced in the JSX inside ProcessedQueuePairs.tsx.
- Line 31: The hardcoded Sepolia start block and comment must be updated for
mainnet: replace the BigInt value assigned to startBlock in ProcessedQueuePairs
(const startBlock = BigInt(9_907_904)) with the mainnet deployment block number
and update the inline comment URL to point to the mainnet Etherscan transaction
for the deployment; ensure the constant remains a BigInt and the comment
contains the correct mainnet tx hash and Etherscan link for future reference.
In `@frontend/src/components/Verifications.tsx`:
- Around line 4-5: Replace the Sepolia chain/RPC with Mainnet: change the
imported chain symbol from sepolia to mainnet, update the
createPublicClient(...) call (the public client configuration where sepolia and
the RPC endpoint are passed) to use the mainnet chain and a Mainnet RPC URL, and
set the startBlock variable (the startBlock used for querying mainnet artifacts)
to the mainnet deployment block number so queries use the correct chain and
block range; look for the import of sepolia, the createPublicClient(...)
invocation, and the startBlock constant in Verifications.tsx to update.
In `@frontend/src/components/VerificationStatus.tsx`:
- Line 98: In VerificationStatus.tsx update the Link that builds the Etherscan
URL (the element using deploymentAddressQueueHandler) to use the mainnet domain
by replacing "sepolia.etherscan.io" with "etherscan.io" while preserving the
path/fragment (e.g., `#writeContract`#F2) and existing attributes (className,
target); ensure the href now points to
`https://etherscan.io/address/${deploymentAddressQueueHandler}#writeContract#F2`.
In `@frontend/src/pages/distributions/`[queueNumber].tsx:
- Line 43: The Link rendering the "Add verification" Etherscan URL currently
hardcodes sepolia.etherscan.io; update the href in the Link component (the JSX
using deploymentAddress and fragment "#writeContract#F3") to use etherscan.io
instead of sepolia.etherscan.io (or make it network-aware if needed) so the link
points to mainnet Etherscan.
In `@frontend/src/pages/distributions/add.tsx`:
- Around line 6-7: The Etherscan links in the Distribution "add" page are
pointing to sepolia while the contract imports (abi and deployed_addresses)
target mainnet; update the hardcoded sepolia.etherscan.io URLs to etherscan.io
in the Distribution add page (the component that uses those links) and then
update the wagmi chain configuration in the app-level wagmi setup (the
configureChains/wagmi client setup in _app.tsx or the MyApp component) to import
and use the Ethereum mainnet chain instead of sepolia; after making these
changes, search for and replace other hardcoded sepolia references (e.g., in
sponsorships/add.tsx, distributors/[ethereumAddress].tsx,
sponsors/[ethereumAddress].tsx and any components that build Etherscan links) so
all Etherscan links and wagmi chain clients consistently target mainnet.
- Around line 198-199: Update the two Link components that build Etherscan URLs
(they currently use `https://sepolia.etherscan.io/tx/${writeHash}`) to point to
mainnet by replacing `sepolia.etherscan.io` with `etherscan.io`; locate the Link
usage in the "Finalizing" and "Success" UI branches that reference `writeHash`
and update both occurrences so the href becomes
`https://etherscan.io/tx/${writeHash}` (preserve the `target` and `className`
attributes).
In `@frontend/src/pages/distributors/`[ethereumAddress].tsx:
- Around line 5-8: The code imports mainnet artifacts (abi_distribution_queue,
deployed_addresses) but still uses Sepolia; change the chain import from sepolia
to mainnet from "viem/chains" and update createPublicClient usage to pass
mainnet plus a Mainnet RPC endpoint (use a config/env var like
NEXT_PUBLIC_MAINNET_RPC) instead of the Sepolia RPC; also replace the
Sepolia-specific startBlock with the mainnet start block (use the mainnet
deployment block from deployed_addresses for DistributionQueueModule or the
correct mainnet block number) and update the Etherscan URL generation to point
to https://etherscan.io (mainnet) instead of sepolia.etherscan.io so events and
addresses match mainnet artifacts (refer to abi_distribution_queue,
deployed_addresses, createPublicClient, startBlock, and the Etherscan URL
construction).
In `@frontend/src/pages/sponsorships/add.tsx`:
- Around line 183-195: The Etherscan links in the JSX using writeHash currently
point to the Sepolia testnet; update both Link href occurrences that build URLs
with `https://sepolia.etherscan.io/tx/${writeHash}` to use the mainnet URL
`https://etherscan.io/tx/${writeHash}` instead (preserve the Link component,
target and className), i.e., change both places where `writeHash` is
interpolated in the Link href to the mainnet domain so transaction links work
for real ETH transfers.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/src/components/ProcessedQueuePairs.tsx (1)
31-31:⚠️ Potential issue | 🔴 Critical
startBlockstill references a Sepolia block number and transaction.In support of elimu.ai's mission to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — we can't have the event scanner starting from the wrong block on the wrong chain!
9_907_904is the Sepolia deployment block. On Ethereum mainnet, block numbers are currently in the ~21M+ range, so this value would cause the client to unnecessarily scan millions of old, irrelevant blocks (hitting the 50k-chunk loop hundreds of times) before reaching the actual mainnet deployment block. The comment URL also still points tosepolia.etherscan.io.Update
startBlockto the mainnet deployment block and fix the comment link accordingly.🔧 Proposed fix (placeholder — replace with actual mainnet values)
- const startBlock = BigInt(9_907_904); // https://sepolia.etherscan.io/tx/0x4ccdae0794c5061a019b8674d2117b22b3e85b343ece4390b2fb22eb41d76bc3 + const startBlock = BigInt(<MAINNET_DEPLOYMENT_BLOCK>); // https://etherscan.io/tx/<MAINNET_DEPLOYMENT_TX_HASH>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/ProcessedQueuePairs.tsx` at line 31, The hardcoded startBlock constant in ProcessedQueuePairs.tsx is still set to the Sepolia block (startBlock = BigInt(9_907_904)) and the comment links to sepolia.etherscan; change startBlock to the Ethereum mainnet deployment block for this contract (replace the 9_907_904 value with the actual mainnet block number where the contract was deployed) and update the comment URL to the corresponding etherscan.io mainnet transaction URL; ensure the constant remains a BigInt and keep the descriptive comment but points to the mainnet tx/receipt.frontend/src/pages/sponsors/[ethereumAddress].tsx (1)
5-8:⚠️ Potential issue | 🔴 CriticalCritical: This file is only partially migrated — events are read from Sepolia but linked to mainnet Etherscan.
Lines 5–6 still import the ABI and
deployed_addressesfromsepolia_v0-9-8, line 8 still uses thesepoliachain, line 67 still points to the Sepolia RPC (ethereum-sepolia-rpc.publicnode.com), and line 75 references a Sepolia start block. However, line 125 now links transactions to mainnetetherscan.io. This means users will see Sepolia transaction hashes linked to mainnet Etherscan, which will either 404 or show the wrong transaction.All of these need to be updated together to target mainnet, consistent with the rest of the PR. In support of elimu.ai's mission to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — let's make sure sponsors see accurate on-chain data!
🐛 Proposed fix
-import { abi as abi_sponsorship_queue } from "../../../../backend/ignition/deployments/sepolia_v0-9-8/artifacts/SponsorshipQueueModule#SponsorshipQueue.json"; -import deployed_addresses from "../../../../backend/ignition/deployments/sepolia_v0-9-8/deployed_addresses.json"; +import { abi as abi_sponsorship_queue } from "../../../../backend/ignition/deployments/mainnet_v0-9-9/artifacts/SponsorshipQueueModule#SponsorshipQueue.json"; +import deployed_addresses from "../../../../backend/ignition/deployments/mainnet_v0-9-9/deployed_addresses.json";-import { sepolia } from "viem/chains"; +import { mainnet } from "viem/chains";const publicClient = createPublicClient({ - chain: sepolia, - transport: http("https://ethereum-sepolia-rpc.publicnode.com") // Max 50k blocks per request + chain: mainnet, + transport: http("https://ethereum-rpc.publicnode.com") })The
startBlockon line 75 and the comment's Etherscan link also need to be updated to the mainnet block number of the firstSponsorshipAddedevent on mainnet.Also applies to: 65-68, 75-75, 125-125
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/sponsors/`[ethereumAddress].tsx around lines 5 - 8, The file still references Sepolia artifacts and chain settings: replace the Sepolia ABI/deployed_addresses imports (abi_sponsorship_queue and deployed_addresses) with the mainnet equivalents, switch the chain constant from sepolia to the mainnet chain used by viem, update the public RPC URL passed to createPublicClient to a mainnet RPC, set the startBlock variable to the mainnet block number of the first SponsorshipAdded event, and change the Etherscan link construction to point to etherscan.io mainnet (not Sepolia); update every place that references the Sepolia-specific artifacts, sepolia constant, RPC URL, and startBlock so the contract addresses, ABI, RPC client, event startBlock, and transaction links are all consistent for mainnet.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@frontend/src/components/ProcessedQueuePairs.tsx`:
- Line 31: The hardcoded startBlock constant in ProcessedQueuePairs.tsx is still
set to the Sepolia block (startBlock = BigInt(9_907_904)) and the comment links
to sepolia.etherscan; change startBlock to the Ethereum mainnet deployment block
for this contract (replace the 9_907_904 value with the actual mainnet block
number where the contract was deployed) and update the comment URL to the
corresponding etherscan.io mainnet transaction URL; ensure the constant remains
a BigInt and keep the descriptive comment but points to the mainnet tx/receipt.
In `@frontend/src/pages/sponsors/`[ethereumAddress].tsx:
- Around line 5-8: The file still references Sepolia artifacts and chain
settings: replace the Sepolia ABI/deployed_addresses imports
(abi_sponsorship_queue and deployed_addresses) with the mainnet equivalents,
switch the chain constant from sepolia to the mainnet chain used by viem, update
the public RPC URL passed to createPublicClient to a mainnet RPC, set the
startBlock variable to the mainnet block number of the first SponsorshipAdded
event, and change the Etherscan link construction to point to etherscan.io
mainnet (not Sepolia); update every place that references the Sepolia-specific
artifacts, sepolia constant, RPC URL, and startBlock so the contract addresses,
ABI, RPC client, event startBlock, and transaction links are all consistent for
mainnet.
---
Duplicate comments:
In `@frontend/src/components/ProcessedQueuePairs.tsx`:
- Line 4: The import and client setup are still using sepolia: change the chain
import used in frontend/src/components/ProcessedQueuePairs.tsx from sepolia to
the mainnet chain (e.g., import { mainnet } from "viem/chains") and update the
publicClient construction (the publicClient variable and any RPC URL set in that
block) to use a mainnet RPC endpoint so the chain selection matches the mainnet
ABI/address artifacts referenced elsewhere; ensure any references to sepolia in
this file or in publicClient initialization are replaced with the mainnet symbol
and endpoint.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/components/PairedDistribution.tsx (1)
27-27:⚠️ Potential issue | 🔴 CriticalCritical: Update all Sepolia block numbers to mainnet deployment blocks
All six components and pages still reference Sepolia block numbers (9_907_880–9_907_904), which are ~March 2020 on mainnet. This causes unnecessary scanning of millions of empty blocks, wasting hundreds of RPC requests and creating long load times. Update
startBlockto the actual mainnet deployment blocks and fix allsepolia.etherscan.iolinks to mainnet Etherscan:
PairedDistribution.tsx:27PairedSponsorship.tsx:27ProcessedQueuePairs.tsx:31Verifications.tsx:27sponsors/[ethereumAddress].tsx:75distributors/[ethereumAddress].tsx:75This ensures elimu.ai's mission to build innovative learning software is supported by efficient infrastructure that serves out-of-school children without unnecessary RPC delays.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/PairedDistribution.tsx` at line 27, Replace the Sepolia block constants and Etherscan links with mainnet deployment values: locate the startBlock BigInt declarations (e.g., startBlock in PairedDistribution.tsx) and the equivalent startBlock variables in PairedSponsorship.tsx, ProcessedQueuePairs.tsx, Verifications.tsx, sponsors/[ethereumAddress].tsx and distributors/[ethereumAddress].tsx and set them to the correct mainnet deployment block numbers; also update any sepolia.etherscan.io URLs to https://etherscan.io links pointing to the corresponding mainnet txs/blocks so the components (startBlock usage and displayed Etherscan links) scan from the proper mainnet deployment instead of Sepolia.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@frontend/src/components/PairedDistribution.tsx`:
- Line 27: Replace the Sepolia block constants and Etherscan links with mainnet
deployment values: locate the startBlock BigInt declarations (e.g., startBlock
in PairedDistribution.tsx) and the equivalent startBlock variables in
PairedSponsorship.tsx, ProcessedQueuePairs.tsx, Verifications.tsx,
sponsors/[ethereumAddress].tsx and distributors/[ethereumAddress].tsx and set
them to the correct mainnet deployment block numbers; also update any
sepolia.etherscan.io URLs to https://etherscan.io links pointing to the
corresponding mainnet txs/blocks so the components (startBlock usage and
displayed Etherscan links) scan from the proper mainnet deployment instead of
Sepolia.
---
Duplicate comments:
In `@frontend/src/components/ProcessedQueuePairs.tsx`:
- Line 31: The hardcoded BigInt startBlock in ProcessedQueuePairs.tsx (const
startBlock = BigInt(9_907_904)) and its Sepolia URL comment are still pointing
to Sepolia; update the value to the mainnet deployment block number used
elsewhere (match the mainnet startBlock used in PairedDistribution.tsx or your
deployment record) and replace the Sepolia etherscan link/comment with the
corresponding mainnet transaction or block URL, ensuring the identifier
"startBlock" is updated consistently in ProcessedQueuePairs.tsx.
In `@frontend/src/components/Verifications.tsx`:
- Line 27: The startBlock constant currently uses a Sepolia block
number/comment; update the BigInt value assigned to startBlock in
Verifications.tsx to the mainnet block where DistributionVerifier was deployed
and replace the Sepolia tx URL/comment with the mainnet deployment tx or
explorer link. Locate the startBlock variable and the nearby references to
DistributionVerifier (and mirror the change you made in PairedDistribution.tsx)
so both files use the same mainnet deployment block and accurate comment.
In `@frontend/src/pages/distributors/`[ethereumAddress].tsx:
- Line 75: The startBlock constant is still set to the Sepolia block number and
comment; update the BigInt value assigned to startBlock and its inline comment
to the mainnet deployment block for the DistributionQueue contract so logs and
event scanning use the correct chain. Locate the startBlock constant (symbol:
startBlock) in this file and replace the 9_907_888 BigInt and the Sepolia tx
URL/comment with the mainnet block number and a mainnet Etherscan URL or
appropriate note referencing the DistributionQueue deployment.
In `@frontend/src/pages/sponsors/`[ethereumAddress].tsx:
- Line 75: The startBlock constant in sponsors/[ethereumAddress].tsx is still
set to Sepolia (BigInt(9_907_880)) and the comment references a Sepolia tx;
update the startBlock value to the Ethereum mainnet deployment block number for
the SponsorshipQueue contract and replace the comment with the mainnet tx or
etherscan URL for that deployment. Locate the startBlock declaration and adjust
the BigInt literal and inline comment to reflect the mainnet block/transaction
used in PairedDistribution.tsx (or the canonical SponsorshipQueue deployment) so
logs and indexing use the correct mainnet starting block.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
frontend/src/pages/distributors/[ethereumAddress].tsx (1)
106-108:⚠️ Potential issue | 🟡 MinorPerpetual loading spinner when a distributor has zero events.
If a distributor address has no
DistributionAddedevents, the fetch completes with an empty array and the component displays<LoadingIndicator />indefinitely. This is pre-existing, but now that the frontend is on mainnet — serving elimu.ai's mission to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — real users may encounter it. Consider distinguishing between "loading" and "no results" states.💡 Suggested approach
+ const [isLoading, setIsLoading] = useState(true) useEffect(() => { async function fetchContractEvents() { ... setEvents(allLogs); + setIsLoading(false); } fetchContractEvents() }, [ethereumAddress]) - if (events.length == 0) { + if (isLoading) { return <LoadingIndicator /> } + + if (events.length == 0) { + return <p>No distributions found.</p> + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/distributors/`[ethereumAddress].tsx around lines 106 - 108, The UI uses presence of events array to decide loading, so when fetch returns an empty array the component shows <LoadingIndicator /> forever; change the data flow to track loading versus loaded-empty by introducing or using an explicit loading flag (e.g., isLoading or events === null initial state) and update the render logic: show <LoadingIndicator /> only when isLoading is true, show an empty-state message or component (e.g., "No DistributionAdded events for this address") when events is an empty array, and keep existing rendering for non-empty events; adjust the fetch function (e.g., fetchEvents or the effect that loads DistributionAdded) to set isLoading false on both success and error so the empty-case is reachable.frontend/src/components/PairedDistribution.tsx (1)
22-57:⚠️ Potential issue | 🟠 Major
events.length == 0conflates "loading" with "no results" — infinite spinner when no events exist.If no
QueuePairProcessedevents have been emitted on mainnet yet (entirely possible on a fresh deployment),eventsstays as an empty array after fetching completes, and the component renders<LoadingIndicator />forever. This is a real UX bug now that you're on mainnet. elimu.ai's mission is to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — the interface should clearly communicate state, not leave users spinning.Additionally, there's no error handling around the RPC calls; a network failure will result in an unhandled rejection with no user feedback.
🐛 Proposed fix: separate loading state from empty results
const [events, setEvents] = useState(Array(0)) + const [isLoading, setIsLoading] = useState(true) useEffect(() => { async function fetchContractEvents() { - let allLogs: any[] = []; + try { + let allLogs: any[] = []; - const startBlock = BigInt(24_470_279); - const chunkSize = BigInt(50_000); - const currentBlock = await publicClient.getBlockNumber(); - for (let fromBlock = startBlock; fromBlock <= currentBlock; fromBlock += chunkSize) { - const toBlock = ((fromBlock + chunkSize) >= currentBlock) - ? currentBlock - : (fromBlock + chunkSize - BigInt(1)); - console.debug(`Fetching logs from block ${fromBlock} to ${toBlock}`); - const logs = await publicClient.getContractEvents({ - abi: abi_queue_handler, - address: deploymentAddress, - fromBlock, - toBlock, - eventName: "QueuePairProcessed" - }); - - allLogs = [...allLogs, ...logs]; - console.debug(`Found ${logs.length} events in this chunk. Total: ${allLogs.length}`); + const startBlock = BigInt(24_470_279); + const chunkSize = BigInt(50_000); + const currentBlock = await publicClient.getBlockNumber(); + for (let fromBlock = startBlock; fromBlock <= currentBlock; fromBlock += chunkSize) { + const toBlock = ((fromBlock + chunkSize) >= currentBlock) + ? currentBlock + : (fromBlock + chunkSize - BigInt(1)); + console.debug(`Fetching logs from block ${fromBlock} to ${toBlock}`); + const logs = await publicClient.getContractEvents({ + abi: abi_queue_handler, + address: deploymentAddress, + fromBlock, + toBlock, + eventName: "QueuePairProcessed" + }); + + allLogs = [...allLogs, ...logs]; + console.debug(`Found ${logs.length} events in this chunk. Total: ${allLogs.length}`); + } + + console.debug("All logs fetched:", allLogs); + setEvents(allLogs); + } catch (error) { + console.error("Failed to fetch contract events:", error); + } finally { + setIsLoading(false); } - - console.debug("All logs fetched:", allLogs); - setEvents(allLogs); } fetchContractEvents() }, [])Then update the guard:
- if (events.length == 0) { + if (isLoading) { return <LoadingIndicator /> }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/PairedDistribution.tsx` around lines 22 - 57, The component currently uses events (useState Array) to decide loading which conflates "loading" with "no results" and lacks RPC error handling; update the component to add a loading state (e.g., const [loading, setLoading] = useState(true)) and an error state (e.g., const [error, setError] = useState<Error | null>(null)), setLoading(true) before running fetchContractEvents and setLoading(false) in a finally block inside fetchContractEvents (or after awaiting it), catch errors in fetchContractEvents and setError(error) so you can render an error message, and change the render guard to show LoadingIndicator only when loading is true and render a "no events" placeholder when loading is false and events.length === 0; reference fetchContractEvents, setEvents, events, LoadingIndicator, useEffect for where to apply these changes.
🧹 Nitpick comments (4)
frontend/src/pages/distributors/[ethereumAddress].tsx (1)
65-68: Consider externalizing the RPC URL to an environment variable.Hardcoding a public RPC endpoint works for development, but for a mainnet production frontend serving elimu.ai's mission (to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months), a public endpoint with no SLA and rate limits may cause intermittent failures. An env var like
NEXT_PUBLIC_MAINNET_RPC_URLwould allow swapping providers without code changes.Also,
publicClientis recreated on every render. Consider hoisting it outside the component or wrapping it inuseMemo.♻️ Proposed refactor
+const publicClient = createPublicClient({ + chain: mainnet, + transport: http(process.env.NEXT_PUBLIC_MAINNET_RPC_URL || "https://ethereum-rpc.publicnode.com") +}) + export function LoadDistributionAddedEvents({ ethereumAddress }: {ethereumAddress: string}) { ... - const publicClient = createPublicClient({ - chain: mainnet, - transport: http("https://ethereum-rpc.publicnode.com") // Max 50k blocks per request - })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/pages/distributors/`[ethereumAddress].tsx around lines 65 - 68, Hardcoded RPC URL in the createPublicClient call should be moved to an env var and the client should not be recreated each render: replace the literal "https://ethereum-rpc.publicnode.com" with process.env.NEXT_PUBLIC_MAINNET_RPC_URL (or similar) when constructing publicClient in the createPublicClient call, and hoist the publicClient creation out of the component (or wrap it in useMemo) so createPublicClient / transport / http and the mainnet import are instantiated once rather than on every render.frontend/src/components/PairedDistribution.tsx (1)
17-20: Consider externalizing the RPC URL to an environment variable.Hardcoding a public RPC endpoint is fine for testing, but for mainnet production use — especially one serving elimu.ai's mission to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — you'll want reliability. Public nodes can rate-limit or become unavailable. Using
process.env.NEXT_PUBLIC_RPC_URL(or similar) would make it easy to swap to a dedicated provider (Alchemy, Infura, etc.) without code changes.♻️ Suggested change
const publicClient = createPublicClient({ chain: mainnet, - transport: http("https://ethereum-rpc.publicnode.com") // Max 50k blocks per request + transport: http(process.env.NEXT_PUBLIC_ETHEREUM_RPC_URL || "https://ethereum-rpc.publicnode.com") // Max 50k blocks per request })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/PairedDistribution.tsx` around lines 17 - 20, Replace the hardcoded RPC URL passed to createPublicClient with an environment variable (e.g., NEXT_PUBLIC_RPC_URL) so the app can switch providers without code changes; update the transport call in the publicClient creation (where createPublicClient, mainnet and http are used) to read process.env.NEXT_PUBLIC_RPC_URL with a sensible fallback to the current public node, and ensure the env var is documented/available in the runtime (client-safe NEXT_PUBLIC_ prefix).frontend/src/components/PairedSponsorship.tsx (2)
17-19: Public RPC endpoint for mainnet — consider rate-limit resilience.The switch to
https://ethereum-rpc.publicnode.comis correct for mainnet. Be aware that public RPCs can be rate-limited or throttled under load. Since this component fetches logs in 50k-block chunks, heavy concurrent usage could hit limits. For now this is fine, but if reliability becomes a concern for the children relying on elimu.ai's mission to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months, consider adding a fallback transport or usingfallback([http(...), http(...)])from viem.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/PairedSponsorship.tsx` around lines 17 - 19, The public RPC http("https://ethereum-rpc.publicnode.com") used when creating the publicClient in PairedSponsorship (createPublicClient, transport) is susceptible to rate-limits; update the client construction to use viem's fallback transport or a retry/backoff strategy so requests don't fail under throttle. Specifically, replace the single transport with fallback([http(primaryUrl), http(fallbackUrl1), http(fallbackUrl2)]) or wire in a small retry/backoff wrapper around the log-fetching calls so createPublicClient(publicClient) can automatically try alternate endpoints (configurable via env) before failing.
55-57: Edge case: perpetual loading spinner if no events exist on mainnet yet.If the QueueHandler has been freshly deployed and no
QueuePairProcessedevents have been emitted,events.lengthwill remain0after fetching completes, and the component will show<LoadingIndicator />indefinitely. This is pre-existing logic, but it becomes more relevant now on a fresh mainnet deployment. Consider distinguishing between "still loading" and "loaded but empty" states. elimu.ai's mission is to build innovative learning software that empowers out-of-school children to teach themselves basic reading📖, writing✍🏽 and math🔢 within 6 months — a stuck spinner could confuse sponsors trying to check their pairing status!♻️ Suggested approach: track loading state separately
const [events, setEvents] = useState(Array(0)) + const [isLoading, setIsLoading] = useState(true) useEffect(() => { async function fetchContractEvents() { // ... existing fetch logic ... setEvents(allLogs); + setIsLoading(false); } fetchContractEvents() }, [])Then use
isLoadingto decide whether to show the loading indicator:- if (events.length == 0) { + if (isLoading) { return <LoadingIndicator /> }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/PairedSponsorship.tsx` around lines 55 - 57, PairedSponsorship currently shows <LoadingIndicator /> whenever events.length === 0 which causes a perpetual spinner on fresh deployments; add a separate boolean state (e.g., isLoading) in the PairedSponsorship component, set isLoading = true before the fetch that populates events (the effect or fetch handler that currently sets events), and set isLoading = false in both success and error paths after the fetch completes; then change the render logic to show <LoadingIndicator /> only when isLoading is true, and render an explicit empty-state message/UI (instead of the spinner) when isLoading is false and events.length === 0 so sponsors understand there are no events yet.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@frontend/src/components/PairedDistribution.tsx`:
- Around line 22-57: The component currently uses events (useState Array) to
decide loading which conflates "loading" with "no results" and lacks RPC error
handling; update the component to add a loading state (e.g., const [loading,
setLoading] = useState(true)) and an error state (e.g., const [error, setError]
= useState<Error | null>(null)), setLoading(true) before running
fetchContractEvents and setLoading(false) in a finally block inside
fetchContractEvents (or after awaiting it), catch errors in fetchContractEvents
and setError(error) so you can render an error message, and change the render
guard to show LoadingIndicator only when loading is true and render a "no
events" placeholder when loading is false and events.length === 0; reference
fetchContractEvents, setEvents, events, LoadingIndicator, useEffect for where to
apply these changes.
In `@frontend/src/pages/distributors/`[ethereumAddress].tsx:
- Around line 106-108: The UI uses presence of events array to decide loading,
so when fetch returns an empty array the component shows <LoadingIndicator />
forever; change the data flow to track loading versus loaded-empty by
introducing or using an explicit loading flag (e.g., isLoading or events ===
null initial state) and update the render logic: show <LoadingIndicator /> only
when isLoading is true, show an empty-state message or component (e.g., "No
DistributionAdded events for this address") when events is an empty array, and
keep existing rendering for non-empty events; adjust the fetch function (e.g.,
fetchEvents or the effect that loads DistributionAdded) to set isLoading false
on both success and error so the empty-case is reachable.
---
Duplicate comments:
In `@frontend/src/pages/distributors/`[ethereumAddress].tsx:
- Around line 5-8: No code changes required: the imports abi_distribution_queue,
deployed_addresses and the viem chain import mainnet (and utilities Address,
createPublicClient, formatEther, http) are correctly aligned to mainnet, so
leave the imports in distributors/[ethereumAddress].tsx as-is and proceed with
the PR approval.
---
Nitpick comments:
In `@frontend/src/components/PairedDistribution.tsx`:
- Around line 17-20: Replace the hardcoded RPC URL passed to createPublicClient
with an environment variable (e.g., NEXT_PUBLIC_RPC_URL) so the app can switch
providers without code changes; update the transport call in the publicClient
creation (where createPublicClient, mainnet and http are used) to read
process.env.NEXT_PUBLIC_RPC_URL with a sensible fallback to the current public
node, and ensure the env var is documented/available in the runtime (client-safe
NEXT_PUBLIC_ prefix).
In `@frontend/src/components/PairedSponsorship.tsx`:
- Around line 17-19: The public RPC http("https://ethereum-rpc.publicnode.com")
used when creating the publicClient in PairedSponsorship (createPublicClient,
transport) is susceptible to rate-limits; update the client construction to use
viem's fallback transport or a retry/backoff strategy so requests don't fail
under throttle. Specifically, replace the single transport with
fallback([http(primaryUrl), http(fallbackUrl1), http(fallbackUrl2)]) or wire in
a small retry/backoff wrapper around the log-fetching calls so
createPublicClient(publicClient) can automatically try alternate endpoints
(configurable via env) before failing.
- Around line 55-57: PairedSponsorship currently shows <LoadingIndicator />
whenever events.length === 0 which causes a perpetual spinner on fresh
deployments; add a separate boolean state (e.g., isLoading) in the
PairedSponsorship component, set isLoading = true before the fetch that
populates events (the effect or fetch handler that currently sets events), and
set isLoading = false in both success and error paths after the fetch completes;
then change the render logic to show <LoadingIndicator /> only when isLoading is
true, and render an explicit empty-state message/UI (instead of the spinner)
when isLoading is false and events.length === 0 so sponsors understand there are
no events yet.
In `@frontend/src/pages/distributors/`[ethereumAddress].tsx:
- Around line 65-68: Hardcoded RPC URL in the createPublicClient call should be
moved to an env var and the client should not be recreated each render: replace
the literal "https://ethereum-rpc.publicnode.com" with
process.env.NEXT_PUBLIC_MAINNET_RPC_URL (or similar) when constructing
publicClient in the createPublicClient call, and hoist the publicClient creation
out of the component (or wrap it in useMemo) so createPublicClient / transport /
http and the mainnet import are instantiated once rather than on every render.
a216561
Resolves #9
Summary by CodeRabbit