Skip to content

EVM support, MetaMask wallet, supernodes, loyalty quests, and platform hardening - #92

Merged
akobrin1 merged 334 commits into
mainfrom
develop
Aug 28, 2026
Merged

akobrin1 merged 334 commits into
mainfrom
develop

Conversation

@akobrin1

@akobrin1 akobrin1 commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Brings the full develop line to main (332 commits): EVM network support with MetaMask, the supernode and loyalty/referral platforms, explorer features, and the hardening and dependency work on top.

EVM support & wallets

  • Selectable network profiles (devnet / testnet / mainnet) with per-profile chain, RPC, SDK, SNScope, and portal settings plus env overrides
  • EVM wallet support on EVM-enabled profiles: MetaMask connect/disconnect, network add/switch and verification against the profile RPC, EVM transfers, and both Bech32 + ETH hex address formats surfaced throughout
  • Portal-style wallet chooser with selectable MetaMask and Keplr, connected-wallet account menu, and MetaMask onboarding
  • Wallet-state correctness: stale-async guards on wallet flows, MetaMask ↔ Keplr switching with the teardown suppression scoped to the in-flight connect attempt (non-persisted), post-connect verification with fresh account reads and rollback, and wallet errors surfaced in place
  • Wallet-connect tracking hardened: atomic first-connect detection (no double referral bonuses across processes), lenient referral/acquisition validation so tracking is never lost, per-address session markers (no retry loops or double counts)

Explorer & dashboard

  • Global search and the account inspector (rich account page on a tested data layer, with independent degradation per data slice)
  • Blocks page with backfill during polling; transaction history direction classification and action icons
  • Governance: current votes, Bech32-keyed vote queries, active-proposal voting countdown
  • Staking: overview cache with deferred refresh, auto-refresh fixes, EVM-profile staking gating and warnings
  • Dashboard versions block; Portal link keyed by network profile

Supernodes & Cascade

  • Supernodes page and details page with favorites; hardware/metrics table
  • Cascade map geolocation via a server route with bounded parallel lookups, a checked-in cold-start seed, and browser fallback that supports hostname endpoints
  • Cascade upload/download flows with balance checks and upload tracking

Loyalty quests & referrals

  • /loyalty quest pages with server-side verification (SuperNode uptime, storage requests, Whale tier, first-100 uploads, invite quests, active-stake maintenance) behind Google reCAPTCHA
  • Referral pages, referral stats, and claim rewards from the referral list; admin user list / create-user pages with manual review

Infrastructure & quality

Test plan

  • 305 web unit tests pass (vitest), tsc --noEmit clean, next lint clean on touched files
  • Full production build succeeds on next 15.5.21 (compiles packages/ui)
  • Review threads on this PR addressed and resolved
  • Manual smoke test of MetaMask ↔ Keplr switching and Cascade upload on the testnet profile

🤖 Generated with Claude Code

ngvtuan added 30 commits January 5, 2026 16:37
Hide the Sense page
Add zoom limit for the 3D Earth map
fixed UI issues
Improve layout for the cascade page. - wallet connected
Remove drag & drop for the Supernodes chart on mobile
Fix the bug on the Cascade page where the UI disappears after loading finishes and then reappears.
Add a warning icon when APIs return  errors
Cascade - Update download button colour
Cascade - View Public files
Cascade - UI not adjusting properly
Cascade - Update download button colour
Cascade - View Public files
Cascade - UI not adjusting properly
Added more space to the left menu.
update tracking
add UI for Stats
add tracking for cascade download
update UI for tracking page
akobrin1 and others added 15 commits August 17, 2026 23:10
Leap was sunset by its vendor and Cosmostation shuts down 2026-09-01;
neither belongs in onboarding anymore. Add a MetaMask card gated on
IS_EVM_NETWORK, since mainnet has no EVM RPC endpoint or chain ID and
genuinely cannot support it yet.
fetchAccountInfo and fetchEvmAccountInfo wrapped their four sources in a
bare Promise.all, so one rejection emptied every slice: a rewards 500 also
zeroed the displayed balance, delegations and unbonding, where develop lost
only the rewards section. Both now settle each source independently through
a shared helper, keeping AccountInfoData's shape and the per-endpoint
console.error trace. A failed EVM balance query yields no balance rather
than a confident zero, and the evmBalanceToMicroLume conversion is
unchanged.

Six tests cover one-endpoint-fails per slice for both functions. Also
correct the ConnectedStaking.availableBalance comment (it is the total bank
balance, not the spendable amount) and split the onSlice test so the
progressive-render claim is actually asserted against the aggregate
promise instead of only checking that callbacks ran.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…zero

Round 1 made the four account slices degrade independently, which stopped
one failing endpoint from blanking all four — but it also removed the only
signal the Wallet screen had: nothing rejects, so account.error stayed null
and a failed balances query rendered as "Available: 0 LUME", the number that
bounds the Send and Delegate inputs.

fetchAccountInfo and fetchEvmAccountInfo now record the slices whose source
failed in an additive optional AccountInfoData.unavailable, and the wallet
page composes describeAccountInfoGaps() into the error string WalletScreen
already renders under the balance total, so no packages/ui change is needed
and partial data still renders. A list of slice names rather than a boolean
lets the notice name the missing figure.

The account page keeps its current behaviour: an endpoint failure has always
rendered as zero there, so this is not a regression, and no number on that
read-only page bounds a user action.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The SDK constructor throws when it cannot find an API key, and Next.js
imports every API route module during its "collect page data" build phase.
Constructing at module scope therefore failed `next build` on any machine
without Snag credentials, including CI and the hub-docker image build, whose
Dockerfile deliberately passes no build secrets.

Exporting SNAG_API_KEY in the shell did not help either: turbo.json's build
task declares a strict env allowlist (NEXT_PUBLIC_* plus NEXT_OUTPUT) with no
passThroughEnv, so turbo stripped it before Next ran. Only a file-based
apps/web/.env.local worked, which a container build has no way to supply.

Construction now happens on first use behind a Proxy, so the 31 route modules
keep importing the default export unchanged. Methods are bound to the genuine
instance because the SDK keeps private state in WeakMaps keyed on the object
the constructor saw (_APIClient_baseURLOverridden, read by buildURL through
__classPrivateFieldGet) and brands instances in a WeakSet — calling such a
method with a Proxy as `this` throws a private-member TypeError.

Only a successful construction is cached, so a misconfigured deployment keeps
raising the SDK's own missing-credential error per request rather than caching
a broken client or degrading into a silent no-op.

Verified: `make testnet-build` succeeds with SNAG_API_KEY absent from both the
environment and .env.local; 187/187 tests across 22 files; tsc --noEmit clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rrors in place

- resequence balance and transaction queries so a slower previous wallet
  cannot overwrite the active wallet's data after switching accounts
- validate the transaction hash MetaMask returns before reporting success
- show MetaMask errors inside the wallet modal and account menu instead of
  a header alert, and report global API failures as toasts
- require a complete profile (name, RPC, chain id) before advertising EVM
  support so a partial private override cannot enable MetaMask flows
- normalize SNSCOPE_URL (no trailing slash) and unify every call site to
  `${SNSCOPE_URL}/v1/...` so the path-proxied devnet deployment and
  slash-less overrides both resolve correctly
- memoize getClient/getOfflineSigner and cover connect, profile
  verification failure, disconnect revocation fallback and EIP-6963
  discovery with tests; add hook tests for send, transactions and wallet
  connect

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…upernode map

Wallet-connect tracking: normalize bad optional fields in hubUserSchema
instead of rejecting the whole request, decide isNewHub from the insert
itself so concurrent processes cannot double-award referral bonuses, track
every reported address per session (no retry loops on permanent 4xx, no
double counts on account switches).

Wallet state: connect/disconnect now supersede in-flight passive syncs in
the EVM provider, the header explains wallet errors that cleared the
address, and the global API error toast surfaces empty and overlapping
error messages instead of swallowing them.

Supernode map: geolocate unknown nodes through a bounded worker pool with
O(1) cache matching, restore the checked-in location seed as a cold-start
fallback, and let hostname-addressed nodes use the browser ipwho.is
fallback again.

Consolidation: shared useLatestRequest stale guard, openConnectView entry
point (fixes the dead Cascade upload connect prompt on EVM), shared ipwho
mapper and micro-LUME sum helper, PORTAL_URL keyed by network profile with
an env override.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wallet-switch guard was derived from persisted modal UI state
(isModalOpen + preferredWalletName), which failed in both directions: a
reload mid-switch rehydrated the flags and latched the suppression for
the whole session, while a connect started from the auto-preselected
option never armed it at all — so the synchronizer tore the fresh Keplr
session down mid-approval on one path and never cleaned stale state on
the other.

The guard now reads connectingWalletName from a new walletFlow slice
that is deliberately kept out of the redux-persist whitelist. The wallet
chooser sets it at the start of every connect attempt (however the
wallet was selected) and clears it in finally, after the selection
dispatches, so the window is bounded to the attempt and there is no
render where the guard is down but the old wallet is still selected.
The persisted-storage Keplr scrub pauses together with the in-memory
teardown.

Also: post-connect verification moved into a shared, tested
getKeplrConnectionIssue predicate and now requires a fresh getAccount
read from the extension (the store may hold a rehydrated account from a
previous session), rolls a failed connect back with disconnect(), and
maps the NotExist startup race to a recoverable message. setModalOpen
no longer clobbers a stored wallet target when re-opened without one,
the staking page routes Switch wallet through openConnectView (fixing
the dead non-EVM path), wallet-option clicks are local again instead of
dispatching app-wide, the synchronizer uses narrow selectors, and the
Switch-wallet menu item is present on the menu's first paint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…harts, @babel/core

Applies the version bumps from Dependabot PRs #83, #86, #87, #88, #89 and
#90 directly on this branch (their lockfiles were generated against main
and do not apply here). next is the important one: 15.5.21 fixes four
high- and five moderate-severity advisories (SSRF in rewrites and Server
Actions, middleware bypass, cache confusion, DoS). eslint-config-next
moves in lockstep with next. The caret ranges resolve slightly above
Dependabot's targets (axios 1.19.0, postcss 8.5.26, @babel/core 7.29.7).

Verified on the bumped tree: 305 web tests pass, tsc clean, next lint
clean, and a full production build succeeds (which also compiles
packages/ui with echarts 6.1.0). The echarts-for-react peer-range
warning predates this change (it never declared 6.x support).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/ui/src/screens/SupernodesScreen.tsx Fixed
The supernodes table guarded the hardware cell with the same CPUCores
check repeated three times (flagged by code review on PR #92), so a
report with cores but no memory/storage metrics would crash the render
on MemoryTotalGb.toFixed(). Each of the three rendered metrics now
guards itself, and the cell falls back to an em dash unless all three
are present.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@akobrin1 akobrin1 changed the title EVM wallet hardening, review fixes, and dependency security bumps EVM support, MetaMask wallet, supernodes, loyalty quests, and platform hardening Aug 21, 2026
@akobrin1
akobrin1 requested a review from a-ok123 August 21, 2026 17:56
@a-ok123
a-ok123 requested a balanced review from Copilot August 23, 2026 20:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR promotes the entire develop line (332 commits) into main, adding a large set of platform features to the Next.js web app: EVM network support with a MetaMask wallet flow, the supernode/Cascade explorer surfaces, a loyalty-quest and referral platform backed by TypeORM/SQLite entities and server routes, admin tooling, plus dependency-security bumps (next 15.5.21, axios, postcss, echarts 6.1, @babel/core) and hardening work with new unit tests.

Changes:

  • EVM + wallet support (MetaMask/Keplr selection, network profiles, EVM balance/transfer helpers, Bech32 + ETH address handling) and wallet-connect tracking hardening (session markers, lenient referral validation).
  • Explorer/dashboard/loyalty features: blocks/account/supernodes pages, governance vote countdown, Cascade geolocation server route, /loyalty quest pages with reCAPTCHA, referral pages, and admin user/tracking screens plus TypeORM entities/migrations.
  • Infrastructure/quality: turbo build env forwarding, PostCSS source-map stripping, redux slices (error/admin/walletFlow), many new utils with vitest coverage, and dependency/security upgrades.

Reviewed changes

Copilot reviewed 195 out of 428 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
apps/web/src/hooks/useSnagStake.ts Stake verification hook; early-return leaves loading flag stuck (flagged).
apps/web/src/app/api/supernode/validators.ts Supernode Zod schema; message typo + inaccurate "hex characters" wording (flagged).
apps/web/src/app/referral/page.tsx Referral page; malformed referral link when no address (flagged).
apps/web/src/hooks/admin/useRetentionRate.ts Retention hook; side-effect calls placed mid-import block (flagged).
apps/web/src/hooks/useSnag.ts Snag connect hook; accumulating click listener without cleanup (flagged).
apps/web/src/schemas/cascadeUploadSchema.ts Upload schema; awkward "taskId ID is required" message (flagged).
apps/web/src/middleware-bk.ts Dead backup middleware committed alongside active one (flagged).
turbo.json / package.json / tsconfig.json Build env allowlist, node engine range, decorator/ES2020 compiler options.
apps/web/src/redux/*.slice.ts, store/index.ts New error/admin/walletFlow slices and SSR-safe persistence storage.
apps/web/src/entities/, migrations/ TypeORM entities and admin-user seed migration for loyalty/tracking.
apps/web/src/utils/*.ts (+ tests) New EVM/search/governance/countdown/ipwho/env helpers with unit tests.
apps/web/src/app/loyalty referral
apps/web/src/app/api/** New Next route handlers for snag/loyalty/admin/supernode data.
packages/ui/** Screen additions, dependency swaps (drop numeral/jvectormap/svg, add echarts 6.1).
Others globals.css font, postcss plugin, .gitignore, README, dependency bumps.
Suppressed comments (1)

apps/web/src/app/api/supernode/validators.ts:29

  • Typo in this validation message: "IP addres" should be "IP address".

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/web/src/hooks/useSnagStake.ts
Comment thread apps/web/src/app/api/supernode/validators.ts Outdated
Comment thread apps/web/src/app/referral/page.tsx Outdated
Comment thread apps/web/src/hooks/admin/useRetentionRate.ts Outdated
Comment thread apps/web/src/hooks/useSnag.ts Outdated
Comment thread apps/web/src/middleware-bk.ts Outdated
Comment thread apps/web/src/schemas/cascadeUploadSchema.ts Outdated
a-ok123
a-ok123 previously approved these changes Aug 24, 2026
@akobrin1
akobrin1 merged commit 56fc2c9 into main Aug 28, 2026
4 checks passed
@akobrin1
akobrin1 deleted the develop branch August 28, 2026 18:19
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.

4 participants