Summary
Multiple client-side components import publicClient from lib/rpc.ts, which uses the server-side fallback transport (no CORS headers). In the browser, these calls fall back to the default chain RPC (mainnet.base.org), bypassing the CORS-safe fallback rotation and causing 429 rate limits.
Screenshot shows TradingWidget.tsx:61 and RatingWidget.tsx:61 hitting mainnet.base.org directly with 429 errors.
Root Cause
lib/rpc.ts exports one publicClient built with buildServerTransport(). This works on the server (API routes) but not in the browser — the browser needs CORS headers. The CORS-safe transport exists (createFallbackTransport()) but is only used for wagmi config, not for direct publicClient.readContract() calls in components.
Affected Components (browser-side, use publicClient.readContract())
| File |
Line |
Call |
src/components/TradingWidget.tsx |
61 |
getReserveForToken / getRefundForTokens (price estimate) |
src/components/RatingWidget.tsx |
61 |
balanceOf (token balance check) |
src/components/DonateWidget.tsx |
38, 60, 75, 90 |
allowance, balanceOf, waitForTransactionReceipt |
src/components/ClaimRoyalties.tsx |
40, 95 |
getRoyaltyInfo, waitForTransactionReceipt |
src/components/ReaderPortfolio.tsx |
48, 64 |
multicall, readContract |
src/components/WriterTradingStats.tsx |
23 |
readContract |
src/app/create/page.tsx |
93 |
creationFee read |
src/app/dashboard/reader/page.tsx |
64 |
readContract |
Fix
Option A: Export a browser-safe public client (recommended)
Add to lib/rpc.ts:
/**
* Browser-safe public client with CORS fallback.
* Use this in client components ("use client") instead of publicClient.
*/
export const browserClient = createPublicClient({
chain,
transport: IS_MAINNET ? createFallbackTransport() : (CUSTOM_RPC_URL ? fallback([http(CUSTOM_RPC_URL), http()]) : http()),
});
Then update all affected components to import browserClient instead of publicClient.
Option B: Use wagmi's useReadContract hook
Replace direct publicClient.readContract() calls with wagmi's useReadContract hook, which already uses the CORS-safe transport from wagmi config.
Recommendation
Option A is simpler — one new export, find-and-replace in 8 files. Option B would be a larger refactor touching the data fetching patterns.
Server-side files (NO change needed)
These correctly use the server-side publicClient:
src/app/api/index/* (all API routes)
src/app/api/cron/* (cron routes)
src/app/api/ratings/route.ts
lib/price.ts
lib/contracts/erc8004.ts
scripts/backfill-trade-prices.ts
Acceptance Criteria
Branch
task/{issue-number}-browser-rpc-fallback
Summary
Multiple client-side components import
publicClientfromlib/rpc.ts, which uses the server-side fallback transport (no CORS headers). In the browser, these calls fall back to the default chain RPC (mainnet.base.org), bypassing the CORS-safe fallback rotation and causing 429 rate limits.Screenshot shows
TradingWidget.tsx:61andRatingWidget.tsx:61hittingmainnet.base.orgdirectly with 429 errors.Root Cause
lib/rpc.tsexports onepublicClientbuilt withbuildServerTransport(). This works on the server (API routes) but not in the browser — the browser needs CORS headers. The CORS-safe transport exists (createFallbackTransport()) but is only used for wagmi config, not for directpublicClient.readContract()calls in components.Affected Components (browser-side, use
publicClient.readContract())src/components/TradingWidget.tsxgetReserveForToken/getRefundForTokens(price estimate)src/components/RatingWidget.tsxbalanceOf(token balance check)src/components/DonateWidget.tsxallowance,balanceOf,waitForTransactionReceiptsrc/components/ClaimRoyalties.tsxgetRoyaltyInfo,waitForTransactionReceiptsrc/components/ReaderPortfolio.tsxmulticall,readContractsrc/components/WriterTradingStats.tsxreadContractsrc/app/create/page.tsxcreationFeereadsrc/app/dashboard/reader/page.tsxreadContractFix
Option A: Export a browser-safe public client (recommended)
Add to
lib/rpc.ts:Then update all affected components to import
browserClientinstead ofpublicClient.Option B: Use wagmi's
useReadContracthookReplace direct
publicClient.readContract()calls with wagmi'suseReadContracthook, which already uses the CORS-safe transport from wagmi config.Recommendation
Option A is simpler — one new export, find-and-replace in 8 files. Option B would be a larger refactor touching the data fetching patterns.
Server-side files (NO change needed)
These correctly use the server-side
publicClient:src/app/api/index/*(all API routes)src/app/api/cron/*(cron routes)src/app/api/ratings/route.tslib/price.tslib/contracts/erc8004.tsscripts/backfill-trade-prices.tsAcceptance Criteria
mainnet.base.org429 errors in browser consolepublicClient(no change)npm run typecheckpassesnpm run lintpassesBranch
task/{issue-number}-browser-rpc-fallback