Skip to content

feat(frontend): switch from sepolia to mainnet#220

Open
jo-elimu wants to merge 6 commits intoelimu-ai:mainfrom
jo-elimu:9-frontend-mainnet
Open

feat(frontend): switch from sepolia to mainnet#220
jo-elimu wants to merge 6 commits intoelimu-ai:mainfrom
jo-elimu:9-frontend-mainnet

Conversation

@jo-elimu
Copy link
Member

@jo-elimu jo-elimu commented Feb 16, 2026

Resolves #9

Summary by CodeRabbit

  • Chores
    • Frontend now uses Ethereum Mainnet deployment artifacts, RPC endpoints, and chain configuration across queues, sponsorships, verifications, and related pages; UI and behavior unchanged.
  • Bug Fixes
    • External transaction and verification links updated to the main Etherscan domain for correct explorer routing.

@jo-elimu jo-elimu requested a review from a team as a code owner February 16, 2026 20:10
@netlify
Copy link

netlify bot commented Feb 16, 2026

Deploy Preview for web3-sponsors ready!

Name Link
🔨 Latest commit a216561
🔍 Latest deploy log https://app.netlify.com/projects/web3-sponsors/deploys/6996f065d2c1de000842023f
😎 Deploy Preview https://deploy-preview-220--web3-sponsors.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉


Walkthrough

This PR updates frontend imports across multiple files, switching smart-contract ABIs and deployed_addresses.json from sepolia_v0-9-8 to mainnet_v0-9-9, and updates Etherscan links and chain/RPC config to 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.

Changes

Cohort / File(s) Summary
Component imports
frontend/src/components/DistributionSummary.tsx, frontend/src/components/Distributions.tsx, frontend/src/components/EstimatedCost.tsx, frontend/src/components/NextQueuePair.tsx, frontend/src/components/PairedDistribution.tsx, frontend/src/components/PairedSponsorship.tsx, frontend/src/components/ProcessedQueuePairs.tsx, frontend/src/components/SponsorshipSummary.tsx, frontend/src/components/Sponsorships.tsx, frontend/src/components/VerificationStatus.tsx, frontend/src/components/Verifications.tsx
Replaced ABI and deployed_addresses.json import paths from .../sepolia_v0-9-8/... to .../mainnet_v0-9-9/.... Updated some Etherscan links from sepolia.etherscan.io to etherscan.io. No public API or component-signature changes.
Page imports
frontend/src/pages/distributions/[queueNumber].tsx, frontend/src/pages/distributions/add.tsx, frontend/src/pages/distributors/[ethereumAddress].tsx, frontend/src/pages/process/index.tsx, frontend/src/pages/sponsorships/add.tsx, frontend/src/pages/sponsors/[ethereumAddress].tsx, frontend/src/pages/distributions/add.tsx
Switched contract ABI and deployed_addresses imports to mainnet artifacts; updated displayed Etherscan links and startBlock values where applicable. Page behavior, routing, and interfaces unchanged.
App config
frontend/src/pages/_app.tsx
Updated wagmi/RainbowKit configuration to use mainnet instead of sepolia (chains, transports, and initialChain).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • nya-elimu
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: switching the frontend from Sepolia testnet to Ethereum mainnet, which is the primary focus across all modified files.
Linked Issues check ✅ Passed The PR implements the frontend deployment requirements aligned with issue #9's objectives: all smart contracts (sponsorship queue, distribution queue, distribution verifier, queue handler) are now integrated with mainnet artifacts and configurations.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the mainnet migration objective: import paths, chain configurations, RPC endpoints, Etherscan links, and block references are systematically updated across all frontend components with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 | 🔴 Critical

Etherscan link still points to Sepolia.

The "Remove from queue" link on Line 98 uses sepolia.etherscan.io. This should be updated to etherscan.io for 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 | 🔴 Critical

Etherscan 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 | 🔴 Critical

Etherscan 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 | 🔴 Critical

Start block and comment reference Sepolia — must be updated for mainnet.

The startBlock value 9_907_904 and 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 | 🔴 Critical

Etherscan link still points to Sepolia.

The "Add verification" link uses sepolia.etherscan.io — should be etherscan.io for 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 | 🔴 Critical

Critical: 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 be https://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 | 🔴 Critical

Critical: Etherscan links still point to Sepolia testnet.

Lines 183 and 193 link to sepolia.etherscan.io but 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

startBlock still 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_904 is 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 to sepolia.etherscan.io.

Update startBlock to 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 | 🔴 Critical

Critical: 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_addresses from sepolia_v0-9-8, line 8 still uses the sepolia chain, 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 mainnet etherscan.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 startBlock on line 75 and the comment's Etherscan link also need to be updated to the mainnet block number of the first SponsorshipAdded event 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 | 🔴 Critical

Critical: 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 startBlock to the actual mainnet deployment blocks and fix all sepolia.etherscan.io links to mainnet Etherscan:

  • PairedDistribution.tsx:27
  • PairedSponsorship.tsx:27
  • ProcessedQueuePairs.tsx:31
  • Verifications.tsx:27
  • sponsors/[ethereumAddress].tsx:75
  • distributors/[ethereumAddress].tsx:75

This 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 | 🟡 Minor

Perpetual loading spinner when a distributor has zero events.

If a distributor address has no DistributionAdded events, 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 == 0 conflates "loading" with "no results" — infinite spinner when no events exist.

If no QueuePairProcessed events have been emitted on mainnet yet (entirely possible on a fresh deployment), events stays 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_URL would allow swapping providers without code changes.

Also, publicClient is recreated on every render. Consider hoisting it outside the component or wrapping it in useMemo.

♻️ 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.com is 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 using fallback([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 QueuePairProcessed events have been emitted, events.length will remain 0 after 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 isLoading to 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.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 17, 2026
nya-elimu
nya-elimu previously approved these changes Feb 18, 2026
@jo-elimu jo-elimu dismissed stale reviews from nya-elimu and coderabbitai[bot] via a216561 February 19, 2026 11:13
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.

backend: Deploy to Ethereum mainnet

2 participants