The explorer shipped three sign-in systems. Two were Blockscout's and both
spoke to its /account/* backend, which this deployment does not run — measured,
every one of those endpoints 404s on api-explore.lux.network:
/account/get_csrf 404 /account/send_otp 404 /account/siwe_message 404
/account/user/info 404 /account/confirm_otp 404 /account/authenticate_via_* 404
So none of it could ever have worked. It is deleted, not re-pointed: the email
+ one-time-code modal, the SIWE wallet login, the CSRF handshake that fired on
every page render, the Dynamic.xyz provider, and the dev page that let you
paste a session cookie by hand. Rewriting any of it against our own backend
would have been building custom auth, which we do not do.
What is left is the standard OIDC client we already had, finished:
* PKCE (S256). This client is public — it runs in a browser and can hold no
secret — so the verifier is the only thing binding a redeemed code to the
page that asked for it. IAM advertises S256 in its discovery document and
we were not sending a challenge at all.
* userinfo went to <issuer>/api/userinfo, which is a 404 and an /api/ path we
do not serve. It is /v1/iam/oauth/userinfo, per IAM's own discovery.
* logout now ends the IdP session (end_session_endpoint) instead of only
dropping our cookie and leaving the user signed in upstream.
All three live in lib/oidc.ts, which already said never to rebuild these paths
at a call site.
The header's provider switch collapses to two states — signed in with IAM, or
account disabled and this is the wallet/settings menu. `rewards` is stated off:
its gate read authProvider === 'auth0', so it was already unreachable.
The ConfigMaps carried NEXT_PUBLIC_OIDC_CLIENT_ID=lux-explore-client-id, a
client that has never existed, so authorize answered 400 unknown client_id.
IAM names clients <org>-explore; all four brands now say so, and hanzo/zoo/pars
get the OIDC keys they never had.
Typecheck: no new error classes, production errors 26 -> 22.
Co-authored-by: Hanzo Dev <[email protected]>
Typing one character into the search box blanked every explorer in the estate.
The DOM collapsed to the error boundary — "Oops! Something went wrong" — with
TypeError: e.data?.forEach is not a function
thrown from the itemsGroups useMemo in
ui/snippets/searchBar/SearchBarSuggest/SearchBarSuggest.tsx:95.
/search/quick is served in two shapes. Upstream Blockscout answers with a bare
list; eth.blockscout.com/api/v2/search/quick?q=1 returns []. Our backend
(luxfi/explorer 1.5.3) answers with the same paginated envelope as /search:
api-explore.lux.network/search/quick?q=1
HTTP 200 {"items":[{"block_number":1,"type":"block"}],"next_page_params":null}
The hanzo, zoo and pars backends return that byte-for-byte too, which is why a
single bundle offset crashes every hostname. The frontend declared the payload
as Array<SearchResultItem> and iterated it, so the envelope object met .forEach.
This is not the rate limiter. The explorer does draw 429s from api.lux.network,
but useFetch rejects on any non-ok response, so an error body never reaches
query.data — it stays undefined and `data?.forEach` short-circuits. Only a 200
carrying a non-array JSON body can produce this crash.
Proven against the live v1.1.13 bundle by rewriting that one response in flight
and changing nothing else: envelope, DOM 132 chars, crash; the same page fed a
bare list, DOM 2081 chars, no console errors, suggest panel renders "Blocks 1".
So the wire type now admits both shapes and unwrapItems is the single place that
collapses them, applied as the select of the quick_search query — the one point
where the resource enters the app. Every consumer downstream (suggest groups,
the desktop "show all results" count, mobile) is handed an array by
construction rather than each guarding for itself. A body in neither shape
yields an empty list, which the component already renders as "No results found",
so a future contract change degrades instead of blanking the page.
zetaChainCCTXQuery.data?.items.length is guarded the same way: the optional
chain stopped at data and left .items.length to throw "Cannot read properties
of undefined (reading 'length')" — the second error in the report — for any
response missing items.
Co-authored-by: Hanzo Dev <[email protected]>
* basic login button implementation
* refactoring and add dynamic auth button to the other pages
* connect wallet without authenticating an user
* login and logout user in blockscout account
* refactoring and RPC overrides
* authenticate user with connected wallet
* add ENS to profile button
* override evm chains and fix contract write with waas wallet
* disconnect wallet and fix docker build
* add dynamic imports to components that use web3 wallet packages
* refactor user profile directory
* clean up
* tweaks
* update pw ci script
* fix "connect wallet" button behavior
* handle linking email to profile with dynamic provider
* fix test
* async loading web3 hooks and remove dynamic loading from components that use them
* fix pw tests
* add account navigation in horizontal layout when auth provider is dynamic
* fix address verification modal
* review fixes
* spelling fixes
* page layout
* add interval filter
* fix navigation
* value formatting and test
* fix: correct empty state message from 'pools' to 'hot contracts'
* update screenshots
* add disabled state to tag select and fix some bugs
* fix screenshot
* update select texts
* migrate to v2 API URLs for CSV exports
* don't ask user to solve recaptcha for first response; pass token in header as well
* hide "Try again" button if no bypass allowed
* fix tests
* epochs page
* epoch rewards distribution
* epoch election rewards
* address epoch rewards
* block epoch tag
* add some tests
* adjust epoch details for L1 epochs
* support non-finalized epochs
* fixes after design review
* add truncation to block numbers on mobile
* update epochs table layout
* update timestamp hint
* fix bug with subheading of first epoch
* fixes of mobile view
* update screenshots