GUNZscope
v0.8.1 // EARLY ACCESS
[ Home ][ Portfolio ][ Onchain Explorer ]

Version History

Early Access · Public Development Log

GUNZscope is under active development. This page tracks every meaningful release since the first commit. Features ship fast — if something’s missing, request it.

v0.8.1

Current

Mar 14, 2026

  • Cross‑wallet favorite labels — PinnedFavoritesRow now shows source wallet label (from portfolioAddresses) with title attr for full address; falls back to truncateAddress(), then "other wallet" for unresolved stubs
  • Favorite metadata now stores walletAddress — FavoritePinActions passes walletAddress into FavoriteButton metadata; usePinnedFavorites stub path reads fav.metadata.walletAddress instead of hardcoding "unknown"
  • walletLabels prop — PortfolioClient builds Map<string, string> from portfolioAddresses; threaded through PinnedFavoritesRow for label‑over‑address display
  • NFTGalleryGridCardProps.walletAddress — new optional prop threaded from NFTGallery → NFTGalleryGridCard → FavoritePinActions for metadata capture
  • Matrix decode entrance animation — CSS keyframes: matrix‑scanline (lime sweep), matrix‑card‑decode (clip‑path + scaleY + blur + brightness), matrix‑rain‑col (vertical lines), matrix‑label‑decode (letter‑spacing + blur flicker), matrix‑container‑enter (inward glow), matrix‑divider‑decode (scaleX sweep)
  • DecodeText component — character‑by‑character scramble effect using requestAnimationFrame interval; resolves left‑to‑right with randomized probability; 18‑frame cycle (~300ms)
  • MatrixRain component — generates N random vertical gradient lines with staggered delays/durations; positioned absolutely within matrix‑container
  • Animation gating — hasAnimated ref in PinnedFavoritesRow prevents replay on re‑renders; prefers‑reduced‑motion media query disables all matrix animations
  • Admin panel: Fees & Revenue tab — new AdminTab "fees" with FeesRevenueTab component; 3 sections: Revenue Streams (lime gradient, dynamic stats from /api/admin/revenue), User‑Facing Costs (purple gradient, static table), Operator Costs (warning gradient, static table with cache notes)
  • /api/admin/revenue route — GET endpoint, Bearer $ADMIN_SECRET auth; returns attestationCount, handleChangeCount, avaxCollected (placeholder values, TODO: wire to on‑chain events)
  • WalletAddressInput default border — border‑transparent → border‑white/[0.12]; focus: border‑[var(‑‑gs‑lime)]/40
  • useUserProfile event handler fix — gs:profile‑updated handler wrapped in queueMicrotask() to prevent "setState during render" warning when FavoriteButton dispatch triggers setProfile in WalletDropdown’s useUserProfile instance
  • UsersTools.tsx placeholder fix — \u2026 in JSX string attr rendered literally; wrapped in {""} expression for proper unicode interpretation
  • NFTGalleryPagination debug info — gated behind ?debug=1 URL param instead of NODE_ENV === "development"
  • usePinnedFavorites resolvedCacheRef — caches previously resolved NFT+wallet pairs so walletMap re‑fetches don’t downgrade full cards to stubs

v0.7.5

Mar 10, 2026

  • NFTDetailPositionCard text readability pass — row labels 9px/40% → 10px/50%, section headers 10px → 11px, GUN values 14px → 15px, USD conversions 50% → 60% opacity, arrows 30% → 40%, italic subtexts switched to text-white/50 + tracking-wide
  • Purple accent visibility — VIA SALES label, waterfall dropdown buttons, Reference Estimate header, warning icon all bumped to full opacity (were /60–/80)
  • Low-confidence waterfall dropdown: labels 20% → 30%, values 12px/40% → 13px/50%; full-confidence: labels 25% → 35%, values same bump
  • NFT description subtitle in modal: added tracking-wide letter spacing
  • Image lightbox — click NFT image in modal to open fixed z-[200] overlay; scroll-to-zoom (0.5×–5×, 0.15 step), click-to-toggle (1×/2×); bg-black/95 solid (no backdrop-blur to avoid GPU load); zoom % indicator at bottom; plain <img> tag to avoid Next.js Image fill constraints
  • Modal image size bump — 180×180/220×220 → 220×220/280×280 (mobile/desktop); container changed from aspect-square+max-w to explicit dimensions; parent switched to flex justify-center for proper centering
  • High-res image pipeline — imageHires field added to NFT type, CachedMetadataData, and avalanche.ts cache read path; /api/opensea/orders extracts image_url from maker_asset_bundle; threaded through getNFTListings → enrichment orchestrator → metadata cache (7d TTL); lightbox uses imageHires || image
  • Acquisition timeline tooltip — glass effect: background rgba(22,22,22,0.6), backdrop-blur 6px, border 12% white opacity

v0.7.4

Mar 10, 2026

  • /build-games landing page overhaul — reordered sections: "The Market" (13M players, 450K DAU, zero existing trackers) now leads as section 01 before Architecture; judges see the "why" before the "how"
  • GitHub repo link added to hero CTAs and bottom CTA section — links to Gunzilla-NYC/gunzscope for judge access to source code
  • Attestation explorer link — "View on Snowtrace" button in On-Chain Proof section links directly to the attestation contract on AVAX C-Chain
  • Market section copy refined — "OTG and GUNZscope Phase I is a sequenced strategic entry point, not the ceiling" replaces generic framing
  • Footer — CRYPTOHAKI text now links to /cryptohaki profile page

v0.7.3

Mar 8, 2026

  • CSS design token system — 12-step neutral scale (--gs-n-0 through --gs-n-11), 14 semantic aliases (--gs-bg, --gs-surface, --gs-card, --gs-text-*, --gs-border, --gs-status-*), 3 transition tokens (--gs-ease, --gs-dur-fast, --gs-dur-norm); enables single-point theme switching
  • Variable-driven corner-cut utilities — .cut-sm (4px), .cut-md (8px), .cut-lg (12px) classes backed by --gs-cut-* custom properties; replaces hardcoded clip-path polygons
  • Accessibility: scroll-behavior forced to auto in prefers-reduced-motion media query — smooth scrolling was still active for users with reduced motion enabled (WCAG 2.1 SC 2.3.3)
  • Compositing layer merge — grid-bg + scanlines collapsed into single .page-bg element across 8 page files; eliminates one full-viewport GPU texture per page (~2-4 MB VRAM savings)
  • IntersectionObserver auto-disconnect — observers in home page social proof, brand page, and build-games page now call unobserve() after element reveal; ~29 persistent observer callbacks eliminated post-animation
  • rAF-gated scroll handlers — Navbar, PublicNav, and ScrollToTopButton scroll listeners wrapped in requestAnimationFrame ticking gate with passive: true; caps setState calls at 1/frame (8× reduction on 120Hz displays)
  • content-visibility: auto on 3 below-fold home page sections (Features, Social Proof, Dashboard Preview) — browser skips layout+paint for offscreen content; ~200-400 DOM nodes deferred on initial load

v0.7.2

Mar 7, 2026

  • Wallet modal UX overhaul — "Connect Whitelisted Wallet" → "Get Started"; two lanes now labeled "View Only" (paste address) and "Full Access" (Dynamic connect) with badge indicators; description copy rewritten for clarity
  • Middleware view‑only bypass — /portfolio with ?address= query param now skips gs_session cookie validation; applies to both missing‑cookie and expired‑cookie paths in middleware.ts
  • connectionMode fix — PortfolioClient.tsx compares activeWalletData.address against primaryWallet.address (case‑insensitive); returns "view‑only" when viewing a different address than the connected wallet; fixes View Only badge, attestation button gating, and ShareDropdown signing controls
  • useIsViewOnly() hook — new selector in PortfolioContext.tsx; reads connectionMode from context; consumed by WalletIdentity.tsx (badge) and ShareDropdown.tsx (attestation gating)
  • Portfolio initializing hard timeout — 15s setTimeout in isPortfolioInitializing effect; fires regardless of gunPrice state; prevents permanent "Calculating…" when CoinGecko times out; existing 10s enrichment timeout preserved as inner guard
  • Error boundaries — app/global‑error.tsx (root‑level, wraps <html>/<body>) and app/portfolio/error.tsx (route‑level with brand styling); both show error digest + retry button
  • Body scroll lock — useEffect in app/page.tsx sets document.body.style.overflow="hidden" when showWalletModal is true; cleanup restores on unmount
  • NFTGalleryPagination "All N NFTs loaded" message gated behind process.env.NODE_ENV === "development"
  • E2E test suite — 57 Playwright specs across 5 files (wallet‑modal, view‑only‑flow, hard‑refresh, network‑edge‑cases, data‑integrity‑responsive); desktop‑chrome + mobile‑chrome (Pixel 7) projects; runs against BASE_URL || gunzscope.xyz
  • Tweet thread automation — compose‑tweet.mjs gains ‑‑version flag for targeting specific update entries; post‑tweet.mjs auto‑loads .env.local credentials; tweet.mjs interactive CLI with preview/edit/post flow

v0.7.1

Mar 5, 2026

  • Server‑side whitelist enforcement — middleware.ts verifies Bearer JWT (API routes) and gs_session cookie (page routes) against whitelist_entries via checkWhitelistEdge() on every request; 7 page routes + 26 API routes in matcher
  • Session cookie (gs_session) — lib/auth/sessionCookie.ts creates HS256‑signed JWT via jose SignJWT; set by /api/access/validate on 3 success paths (permanent, trial, promoted); cleared by /api/auth/logout POST; 7‑day maxAge, httpOnly + Secure + SameSite=Strict
  • Soft delete for whitelist — WhitelistEntry.isActive column; removeFromWhitelist() sets isActive=false instead of DELETE; banService.ts fixed to use update() not delete(); addToWhitelist() upserts with isActive=true for re‑activation
  • whitelistService.edge.ts — Edge‑compatible whitelist check via @neondatabase/serverless HTTP queries; predicate: isActive=true AND (expiresAt IS NULL OR expiresAt > NOW())
  • useAutoLogin whitelist pre‑check — calls /api/access/validate before /api/me; non‑whitelisted wallets get handleLogOut() immediately, preventing ghost profile creation
  • promoteFromWaitlist() fix — upsert update clause now sets isActive: true (survives prior admin soft‑delete)
  • KonamiOverlay trial‑expired UX — parses trialExpired from /api/access/konami 403 response; shows "Trial already used" instead of generic error
  • Navbar + WalletButton disconnect — fire‑and‑forget fetch("/api/auth/logout") before handleLogOut()
  • Ghost profile cleanup — 4 zero‑engagement UserProfile rows deleted; Digital Panoply whitelisted via direct DB upsert

v0.7.0

Mar 5, 2026

  • Portfolio Pins — FavoriteButton wired onto NFTGalleryGridCard image overlay (bottom‑right, opacity‑0 group‑hover:opacity‑100); PinButton component reads useUserProfile().favorites, PATCH /api/favorites/[id] toggles pinned; useNFTGalleryFilters partitions by pinnedRefIds Set, floats pinned to top preserving sort order within each group
  • isOwnPortfolio prop threaded NFTGalleryProps → NFTGalleryInner → NFTGalleryGridCard; computed in PortfolioClient via connectedWallets.includes(activeWalletData.address.toLowerCase())
  • Wishlist model — FavoriteItem extended with externalContract, externalTokenId, externalChain (String?), lastKnownValue (Float?), lastValueAt (DateTime?); type union includes "wishlist"
  • GET /api/favorites — listFavorites() splits by type !== "wishlist" vs type === "wishlist", returns { favorites, wishlist }
  • GET /api/favorites/refresh‑wishlist — updates lastValueAt for all wishlist items
  • AccountPanel Wishlist tab — TabId union extended; wishlistItems/favoriteItems computed from profile.favorites.filter(); star icon, lastKnownValue GUN display, lastValueAt date
  • Admin Users tab — listUsers() in userService with Prisma OR search (displayName, email, wallet address); GET /api/admin/users with verifyAdmin + isWhitelisted cross‑reference; UsersTools component with debounced search, 7‑column grid, whitelist dot indicator
  • Feature Requests GlitchLink in desktop navbar — gated behind hasWallet, positioned after ExperimentsDropdown
  • useUserProfile — togglePin() action with optimistic update; FavoriteItem interface gains pinned: boolean + wishlist fields; AddFavoriteInput gains optional externalContract/externalTokenId/externalChain
  • addFavorite() return type includes pinned: boolean; upsert create/update now persists wishlist fields
  • Display name fallback — UsersTools, ShareLeaderboard, admin shares page now show truncateAddress(primaryWallet) instead of raw email or "Anonymous"
  • shareService getShareLeaderboard() includes primaryWallet via wallets relation (orderBy isPrimary desc, take 1)
  • Duplicate cryptohaki UserProfile cleaned via raw SQL script (scripts/cleanup‑duplicate‑user.ts) with correct FK column mapping per table

v0.5.4

Mar 4, 2026

  • PortfolioSparkline component — new chart in ValueHeader showing % change from cost basis over time; dual‑clip split‑gradient fill (profit above zero, loss below), zero baseline dashed line, pulsing endpoint dot, edge‑aware hover tooltip as absolute div sibling
  • PortfolioSparkline colors — profit fill #A6F700 (brand lime), loss fill #B44AFF (soft orchid / ‑‑gs‑rarity‑epic); endpoint glyph + drop‑shadow glow match; tooltip % text uses same palette
  • ValueHeader 7d badge loss state — switched from var(‑‑gs‑loss) red to #B44AFF orchid (bg/border/text)
  • PnLScatterPlot refinements — floor cluster annotation (horizontal dashed line for dots < 5 GUN), simplified legend (4 items), zone label opacity 0.18 + fontSize 11, break‑even label rotation via atan2, break‑even dot treatment (white stroke within 5%)
  • PnLScatterPlot + AcquisitionTimeline margins normalized to { top: 16, right: 24, bottom: 32, left: 40 } in embedded mode
  • AcquisitionTimeline — removed vertical grid lines; lollipop stems converted to gradient opacity (5 linearGradient defs per venue, stemGradient() helper)
  • AcquisitionTimeline stem gradient fix — gradientUnits="userSpaceOnUse" with explicit pixel y1/y2 coordinates; default objectBoundingBox caused zero‑width line degenerate bounding box
  • AcquisitionTimeline horizontal crosshair — dashed line from hovered dot to Y‑axis on proximity lock
  • AcquisitionTimeline tooltip — added acquisition date (MMM DD, YYYY) and current USD value fields
  • AcquisitionTimeline stem bottom stopOpacity reduced from 0.25 to 0.10

v0.5.3

Mar 4, 2026

  • 40‑item performance audit across 5 phases — parallelization, caching, architecture, DRY, decomposition
  • Parallelized 6 critical paths: fetchGunPricesForDates (5‑concurrent batches), /api/leaderboard (Promise.all DB+price), floor‑drop/portfolio‑digest/whale‑tracker crons, avalanche.ts RPC calls
  • Cache‑Control headers on 6 API routes: /api/price/gun, /api/portfolio/[wallet]/pnl, /api/nft/pnl/[tokenId], /api/marketplace/purchases/*
  • Deferred Vercel Analytics + SpeedInsights after hydration via AnalyticsDeferred component
  • motion/react added to optimizePackageImports — tree‑shakes Framer Motion bundle
  • useGunPrice migrated to SWR — built‑in dedup, stale‑while‑revalidate, background refresh
  • Shared server‑side GUN price cache (lib/server/gunPrice.ts) — single in‑memory cache across all API routes
  • /api/scarcity — in‑memory cache + parallel mint‑count lookups
  • React.cache() on share/referral server pages for same‑request dedup
  • PortfolioContext — 14 prop‑drilled values lifted into context provider, eliminates drilling cascade
  • GalleryFilterContext — filter state moved from prop threading to dedicated context
  • WalletIdentity — removed redundant boolean guards
  • Deduplicated timeAgo, validateSlugLocally, slug constants into lib/utils/
  • OpenSea cache‑control helpers consolidated to app/api/opensea/cacheHelpers.ts
  • memo() on NFTGalleryControls + chart sub‑components (AcquisitionTimeline, PnLScatterPlot)
  • animate‑spin SVGs wrapped in <span> for GPU compositing
  • .map().filter() → single‑pass .reduce() in hot paths
  • Leaderboard DB‑level DISTINCT instead of JS dedup
  • Cron logAlert via after() for non‑blocking response
  • AdminPanel.tsx decomposed: 1,342 → 155 lines + 8 sub‑components in components/account/admin/
  • useNFTAcquisitionPipeline: types + candidates extracted to lib/hooks/acquisition/ (1,747 → 1,360 lines)
  • brand/page.tsx: 5 static sections extracted to app/brand/sections/ (1,682 → 195 lines)
  • PortfolioClient: PortfolioSummaryBar + Footer converted to dynamic() imports (5 total lazy‑loaded components)
  • Passive scroll listeners + startTransition for scroll‑driven state
  • 10s timeout on all CoinGecko fetches
  • /api/price/history restored to 24h revalidate cache

v0.5.2

Mar 2, 2026

  • /build‑games landing page — hero, stats bar (live from /api/stats/site), BuildVelocityChart, multi‑chain architecture diagram, 9‑card feature grid, on‑chain proof section (live attestation count), valuation waterfall, dashboard preview, roadmap CTA; layout matches homepage patterns (max‑w‑7xl, section‑number, section‑line)
  • /build‑games/roadmap — public fork of /strategy with admin gate removed; DocBadge, BuildVelocityChart, 6 phases, ScopeBar, vision banner; minimal nav with Logo + back link
  • PublicNav component — reusable nav for public pages (no Dynamic Labs dependency); Logo, VersionBadge, GlitchLink items, Login CTA, mobile hamburger, scroll backdrop blur; matches Navbar layout exactly
  • /explore now uses PublicNav instead of Navbar — anonymous visitors see Home + Onchain ID links instead of empty bar
  • /explore/attestation/[cid] viewer page — renders attestation metadata as branded UI instead of raw JSON; summary cards (wallet, value, items, block), merkle root with copy, holdings table (first 100 + expand), Autonomys DSN badge; getMetadataLink() extracts CID and links to viewer
  • Strategy page — added BuildVelocityChart section above vision banner
  • Homepage — Onchain ID link now uses GlitchLink (bracket + scramble effect on hover)
  • KonamiOverlay bug fixes — input bg‑black/60 → bg‑black/85 (bottom transparency fix); border‑1 → border‑2 with higher opacity (0.15 empty, 0.50 valid); input text‑white/90 → text‑[var(‑‑gs‑white)] + tracking‑wider + caret‑lime; focus‑within state on empty input
  • globals.css — input::selection override: rgba(166,247,0,0.3) instead of solid lime; fixes green flash on paste
  • DynamicProvider — .modal‑card bg rgba(22,22,22,0.5) → rgba(22,22,22,0.88); auth modal readability fix

v0.5.1

Mar 2, 2026

  • Nav restructure — Leaderboard, Scarcity, Market grouped under “Experiments” dropdown; new ExperimentsDropdown component with GlitchLink‑style trigger (useGlitchScramble, brackets, chevron), close‑on‑outside/Escape/route‑change
  • “Explore” renamed to “Onchain ID” across navbar (desktop GlitchLink + mobile menu) and home page
  • Explore page — Autonomys DSN changed from external link to static label; Avalanche link color → AVAX red (#E84142); Autonomys label color → brand blue (#4A7AFF); per‑row metadata links blue
  • Autonomys attestation count fix — isAutonomysURI() helper matches both direct gateway URLs (gateway.autonomys.xyz) and proxy URLs (/api/attestation/metadata/{cid}); tooltip now shows correct count
  • Admin notification badge on WalletDropdown — fetches /api/feature‑requests, counts status=open; red pill badge on trigger + inline badge next to Feature Requests nav item; admin‑only, refreshes on route change

v0.5.0

Mar 2, 2026

  • /api/market/listings — parallelized getActiveListingsDetailed + getCollectionSaleEvents via Promise.all; previously sequential
  • Module‑level collection sales cache in OpenSeaService.getCollectionSaleEvents — keyed by slug::afterDateMs, 30‑min TTL; findUsableSalesCache() cross‑key reuse (unfiltered 200‑entry cache serves 50‑entry unfiltered requests)
  • Module‑level GunzScan name cache in resolveTokenMetadata — keyed by contract:tokenId, 24h TTL, 500‑entry max; batch fetch only uncached tokens; logs hit/miss ratio
  • New lib/api/marketCache.ts — MarketReferencePrice / MarketReferencePriceCache interfaces; module‑level singleton with 5‑min TTL; populated by /api/market/listings, consumed by /api/market/reference‑prices
  • New /api/market/reference‑prices route — lightweight GET returning per‑item‑name floor prices from shared cache; no OpenSea calls; s‑maxage=300, stale‑while‑revalidate=60; returns empty if market data not cached
  • MarketReferencePriceData type added to lib/types.ts
  • applyValuationTables() — new optional 5th param marketReference?: MarketReferencePriceData; fills currentLowestListing from market bulk data only when per‑NFT enrichment hasn’t provided one (nft.currentLowestListing === undefined)
  • PortfolioClient.tsx — 4th parallel fetch for /api/market/reference‑prices alongside rarity/comparable/floor; passed to applyValuationTables()
  • NFTDetailPositionCard — expandable waterfall tier list in both Reference Estimate and Market Reality sections; builds waterfallTiers from currentLowestListing/comparableSalesMedian/rarityFloor/floorPrice; best tier marked, others behind toggle

v0.4.9

Mar 2, 2026

  • /api/attestation/status — now returns contractAvaxBalance (contract’s AVAX balance from collected fees) and attestFee (current fee in AVAX); batched via Promise.all with existing totalAttestations query
  • ATTESTATION_ABI extended with owner() view and withdraw() — new exports: withdrawFees(signer) calls contract.withdraw() and waits for receipt; getContractOwner(provider) reads on‑chain owner address
  • OnChainTools admin component — AVAX Earned + Current Fee rows in Live Status; Withdraw button with 5‑state flow (idle/switching/signing/confirming/success); chain switch via ensureAvalancheChain, signer from Dynamic’s primaryWallet.connector.getWalletClient(); tx hash links to Snowtrace on success
  • Admin panel auth fix — production showed empty whitelist/waitlist because NEXT_PUBLIC_ADMIN_SECRET was not set in Vercel; fetch callbacks use data.entries ?? [] which treats 401 as empty data silently

v0.4.8

Mar 1, 2026

  • PortfolioAttestation.sol v3 — attest() now takes explicit `address wallet` as first parameter instead of using msg.sender; enables delegation (wallet A pays, wallet B gets the attestation); require(wallet != address(0)) guard
  • UUPS proxy upgraded on C‑Chain: implementation 0x80A6C9661Fb0fEd1cCEBf568bCb709D548B98358; proxy address unchanged (0xEBE8FD7d40724Eb84d9C888ce88840577Cc79c16)
  • Frontend ABI + submitAttestation() updated to pass wallet param; usePortfolioAttestation hook passes tracked walletAddress (in‑game wallet) as attestation target
  • Attestation flow reordered: chain switch → get signer → fetch blockNumber from signer’s provider (fixes RPC mismatch causing estimateGas failures)
  • Contract ownership transferred to Ledger wallet (0x8ABF…488C); hardhat‑ledger plugin + upgrade script configured for future UUPS upgrades
  • Implementation contract verified on Snowtrace via Routescan API
  • Test suite expanded to 29 tests: delegation (alice pays for bob), multi‑payer, zero‑address rejection

v0.4.7

Mar 1, 2026

  • PortfolioAttestation.sol v2 — configurable attestFee (0.01 AVAX default), owner/withdraw/transferOwnership/setFee; attest() now payable with require(msg.value >= attestFee); totalFeesCollected counter; FeeUpdated + OwnerTransferred events
  • Contract redeployed to Avalanche C‑Chain: 0xf8f5aa3D940009987F02AD92e44A5434Bab748bf
  • Frontend contract layer — ABI updated with payable attest + attestFee() view; submitAttestation() reads fee from contract and sends as tx value; exported getAttestFee() for UI display
  • Metadata URI now routes through gunzscope.xyz/api/attestation/metadata/{cid} instead of gateway.autonomys.xyz — /api/attestation/metadata/[cid] proxy route with 24h immutable cache
  • Test suite expanded to 26 tests: fee enforcement, overpayment, owner withdraw with gas accounting, ownership transfer, fee update, zero‑address guard

v0.4.6

Mar 1, 2026

  • GUN Δ hollow dots on Cost vs Value scatter chart — NFTs without market valuation (no listing, comparable sale, rarity floor, or collection floor) now appear as hollow circles positioned via synthetic floor derived from GUN token appreciation: syntheticFloor = cost × (gunPrice / historicalGunUsd)
  • Hollow dots use profit/loss green/red coloring (not amber) with dashed stems to distinguish from filled market‑valued dots; fixed 4px radius, no quantity scaling
  • Grouped GUN Δ NFTs (×2, ×3) expanded into individual hollow dots with deterministic ±2% cost jitter to prevent visual stacking
  • Legend restructured with MARKET / GUN Δ sections separated by pipe dividers; each section shows filled vs hollow profit/loss indicators
  • portfolioInsights.ts — generateInsights now includes GUN Δ items in total unrealized P&L; added getGunDeltaPnlUsd() helper for Track A currency appreciation; new gun_delta insight type with isNeutral amber styling
  • Insight quantity counting uses nft.quantity ?? 1 instead of array length — grouped ×2 NFTs count as 2 individual items in "below cost basis" and totalTracked denominators
  • InsightsPanel.tsx — gun_delta icon (swap arrows SVG) with amber accent when isNeutral
  • portfolioInsights test suite expanded to 12 tests; added quantity>1 coverage

v0.4.5

Mar 1, 2026

  • Autonomys Auto Drive integration — attestation metadata uploaded to Autonomys DSN via @autonomys/auto‑drive SDK; /api/attestation/upload route accepts JSON payload, returns CID + gateway URL; usePortfolioAttestation uploads before on‑chain tx, falls back to inline data: URI if upload fails
  • On‑Chain Explorer — public /explore page queries PortfolioAttested events from C‑Chain contract; /api/attestation/events route with chunked queryFilter (49k block range per call, public RPC 50k limit) + 5‑min server‑side cache + stale fallback on error; useExplorer hook
  • Explorer UI — stats banner (attestations/wallets/GUN attested), desktop table + mobile cards, Snowtrace tx/address links, Autonomys gateway metadata links, loading skeletons, empty state with portfolio CTA
  • Navbar + sitemap + home page Explorer links — public page, no auth gate; added to isInApp check, desktop GlitchLink, mobile menu, sitemap at hourly/0.7
  • Exported ATTESTATION_ABI and getContractAddress() from lib/attestation/contract.ts for event query reuse

v0.4.4

Mar 1, 2026

  • Seaport v1.6 ABI fix — extractCostFromOrderFulfilled now tries v1.5 ABI first, falls back to v1.6 (which adds address recipient to OrderFulfilled non‑indexed data); previous v1.5‑only decode silently failed on GunzChain’s Seaport, causing tx.value fallback to assign total batch cost to every item
  • NFT detail cache schema v24→v25 — invalidates all stale entries with incorrect batch‑purchase prices
  • On‑chain portfolio attestation — usePortfolioAttestation hook builds Merkle tree of NFT holdings, submits root+totalValue to PortfolioAttestation contract on Avalanche C‑Chain; ensureAvalancheChain() handles wallet_switchEthereumChain / wallet_addEthereumChain
  • ShareDropdown attestation UI — "Attest On‑Chain" button with 7‑state flow (idle/building/switching‑chain/signing/confirming/success/error); existing attestation indicator; Snowtrace tx link on success
  • WalletIdentity passes Dynamic primaryWallet connector + isOwnWallet to ShareDropdown for attestation signing
  • Attestation status API — GET /api/attestation/status reads deployer GUN balance (GunzChain) + AVAX balance (C‑Chain) + totalAttestations from contract
  • AdminPanel OnChainTools — added C‑Chain AVAX balance display
  • Hardhat config — added avalanche mainnet network (chainId 43114) + Routescan etherscan verification; deploy:avalanche npm script

v0.4.3

Feb 28, 2026

  • Konami trial access — Konami code now grants 72‑hour trial whitelist instead of permanent access; WhitelistEntry gains expiresAt DateTime? field (null = permanent, non‑null = trial)
  • getWhitelistStatus() discriminated union — returns { status: permanent | trial | expired | none, expiresAt? }; replaces boolean isWhitelisted() in validate and waitlist/status endpoints
  • Konami API rewrite — checks existing whitelist status before granting; permanent → no‑op, active trial → return existing info, expired → 403 "trial already used", none → creates 72h trial entry + waitlist entry with threshold 1
  • joinWaitlistForTrial() — creates or updates waitlist entry with promotionThreshold: 1 (vs default 3); idempotent downgrade if already on waitlist
  • Tiered referral thresholds — DEFAULT_PROMOTION_THRESHOLD=3, TRIAL_PROMOTION_THRESHOLD=1, EXPIRED_TRIAL_PROMOTION_THRESHOLD=2
  • bumpExpiredTrialThreshold() — lazy idempotent upgrade 1→2 on expired trial detection; called from validate and waitlist/status endpoints
  • promoteFromWaitlist() upsert pattern — converts expired trial to permanent whitelist (sets expiresAt: null) when referral threshold met
  • Validate API trial‑aware responses — { trial: true, expiresAt } for active trials; { trialExpired: true, waitlisted: true } with threshold bump for expired
  • Home page trialExpired redirect — expired trial users redirect to /waitlist?address=xxx&trialExpired=true; active trial stores expiresAt in localStorage
  • KonamiOverlay messaging — "TRIAL ACCESS GRANTED" with "72 hours of full access activated" and "Refer 1 friend to keep it forever"
  • WaitlistClient trialExpired state — reads ?trialExpired=true URL param; shows "Trial Ended" header with dynamic referral count based on per‑entry promotionThreshold

v0.4.2

Feb 28, 2026

  • Ban/reset system — BanEntry model in Prisma; banService with isBanned/banAddress/unbanAddress/resetAddress/listBans; ban guards on /api/access/validate, /api/access/konami, /api/access/reconcile, /api/waitlist/status, and joinWaitlist(); banned users get 403 with { banned: true }
  • Admin PATCH /api/admin/whitelist — { address, action: "ban"|"unban"|"reset", reason? }; ban removes from whitelist + waitlist + blocks re‑enrollment; reset clears whitelist + waitlist without ban (user can rejoin); GET ?view=banned returns paginated ban list
  • AdminPanel ban/reset UI — Ban/Reset buttons on whitelist entries, Ban button on waitlist entries, dedicated Banned Users section with unban capability
  • WaitlistClient banned state — useWaitlist hook returns isBanned; banned users see "ACCESS REVOKED" page with support contact instead of join form
  • ReferralRedirect banned handling — email‑only validate returning { banned: true } shows revoked message instead of redirect
  • KonamiOverlay wallet flow fix — submitting state was never reset after successful wallet submission, permanently disabling the Confirm button in the handle phase; added setSubmitting(false) + initial handle availability check via /api/referral/check‑slug
  • Home page validation refactor — separated wallet and email validation into independent useEffect blocks; wasConnectedOnMount now tracks wallet only (email users always validate); emailValidatingRef prevents duplicate email validation calls
  • Attestation status API — GET /api/attestation/status route stub
  • Hardhat config — updated GunzChain testnet RPC URL; added Fuji (Avalanche C‑Chain testnet) network

v0.4.1

Feb 28, 2026

  • Hero redesign — split title into super‑label ("YOUR OTG" at text‑2xl‑3xl with 0.15em tracking) + dominant scramble headline (text‑6xl‑[104px]); removed "Arsenal" line; purple glow text‑shadow on OTG (40px blur, 0.3 opacity)
  • Scramble words updated — Intelligence, Lore, Legacy, Edge (was Intelligence, Dominance, Advantage, Edge)
  • Hero subtitle rewrite — "The tactical intelligence layer for Off The Grid / Start your legacy, analyze the market, dominate the meta."
  • CTA section hierarchy — "Early access — whitelist only" label above Connect Wallet button; Konami hint below at white/25 opacity; removed redundant "Connect here" link
  • KonamiOverlay v2 — "Ready Player Zero" title with rotating subtitles (3 variants, module‑level counter); custom input accepting EVM/Solana/email with type badge; onSubmit returns Promise<boolean>; confirmed state with "CLEARANCE CONFIRMED" card; auto‑proceeds to Dynamic auth after 2.5s via onProceed callback

v0.4.0

Feb 27, 2026

  • Konami code easter egg — useKonamiCode hook listens for ↑↑↓↓←→←→BA on home page; 2s inactivity timeout resets progress; triggers KonamiOverlay
  • KonamiOverlay tactical scan — full‑screen overlay with hex matrix rain (120ms refresh), horizontal scan line (2.5s linear sweep), corner bracket framing, 5‑line sequential reveal with motion/react stagger
  • Konami whitelist input — after scan animation completes, WalletAddressInput slides in with clip‑path ENTER button; validates via detectChain; ESC or backdrop click to dismiss
  • POST /api/access/konami — accepts { address, email }; attempts promoteFromWaitlist first, falls back to addToWhitelist with "Konami code" label; reconciles email+wallet if both provided

v0.3.9

Feb 27, 2026

  • Email waitlist gate — /api/access/validate accepts { email } alongside { address }; emails stored as email:user@example.com identifier in waitlist/referrer tables; deriveAutoSlug handles email: prefix (username before @)
  • Email‑to‑wallet reconciliation — new POST /api/access/reconcile endpoint; promoted email user connects wallet → whitelists wallet address with reconciled:{email} note; WaitlistClient detects wallet connection and auto‑reconciles
  • WaitlistClient email mode — identifier resolution from wallet OR ?email= search param; "Signed in as" email notice; promotion celebration shows Connect Wallet CTA instead of auto‑redirect for email users
  • useWaitlist type parameter — hook accepts type: "wallet" | "email"; fetches /api/waitlist/status with ?address= or ?email= accordingly
  • Email gate in app/page.tsx — email‑only Dynamic users (no wallet) now go through /api/access/validate instead of bypassing straight to /portfolio; non‑whitelisted emails redirect to /waitlist?email=
  • GlitchText container stability — glitch hover effect no longer resizes the login button; fixed by preserving container dimensions during letter scramble animation
  • SEO: robots.txt — blocks /api/, /admin/, /brand, /roadmap, /strategy; references sitemap.xml
  • SEO: dynamic sitemap — app/sitemap.ts with 13 public pages, priority‑weighted (1.0 home → 0.1 legal)
  • SEO: root layout metadata — Viewport export (themeColor #0A0A0A), metadataBase, title.template "%s | GUNZscope", default OG/Twitter cards, JSON‑LD WebApplication schema
  • SEO: page metadata — added Metadata exports to changelog, updates, credits, privacy, terms, cookies; created layout.tsx wrappers for client‑component pages (market, insanity); noindex on brand/roadmap/strategy
  • SEO: canonical URL on /portfolio layout to prevent ?address= duplicates
  • SEO: alt text on 4 NFT images in scarcity and market pages (was empty string)
  • Admin‑gated /strategy page — 6‑phase strategic roadmap; vertical timeline with phase nodes, pill‑tag items, market scope expansion bar
  • Admin panel Links tab — card grid linking to all admin/internal pages with colored dot indicators
  • Brand page Working Links section — Build Games landing preview link; Waitlist Flow section 06 with gate/state/promotion test panels

v0.3.8

Feb 26, 2026

  • Waitlist redirect fix — paste‑address flow (non‑Dynamic‑SDK users) now passes address as query param to /waitlist; WaitlistClient reads from primaryWallet?.address || searchParams.get(‘address’); previously redirected back to / because no Dynamic wallet was connected
  • Waitlist page Suspense boundary — wrapped WaitlistClient in <Suspense> in app/waitlist/page.tsx; required by Next.js for useSearchParams() during static prerender
  • Waitlist status API auth removed — GET /api/waitlist/status no longer requires Dynamic JWT; position and referral count are non‑sensitive; paste‑address users have no auth token
  • useWaitlist hook auth optional — getAuthToken() now called inside try block; token sent as Authorization header only when available; missing token no longer causes early return that left isLoading stuck at true
  • Reusable WalletAddressInput component — components/ui/WalletAddressInput.tsx; unified chain detection (GunzChain/Solana badge, validation border, hint text) across 5 input locations: home page, admin panel, account page, insanity mode, portfolio search
  • WalletAddressInput validateChain prop — when false, disables red border for non‑matching input; used by Handle Tools where slugs are valid input alongside wallet addresses
  • Admin panel column layout standardization — WhitelistTools, WaitlistTools, ShareLeaderboard all use same toolbar‑at‑top pattern with shrink‑0 pb‑3 mb‑3 border‑b divider; address + action button on same row
  • Stale .next cache diagnosis — dev server was serving compiled chunks with old error text "This address isn’t on the early access list yet." from cached .next/dev/ files while source had been updated

v0.3.7

Feb 23, 2026

  • Referral register GET handler — added try/catch around getReferrerByWallet() DB call; was the only API route handler without error wrapping, causing unhandled throws to return HTML 500 instead of JSON
  • useReferral client hook — added regRes.ok guard before .json() parse; non‑2xx responses now log status + body via console.warn("[Referral]") and show status code in error message instead of generic "Failed to load referral data"
  • Admin‑gated /roadmap page — app/roadmap/page.tsx; converted gunzscope‑blockchain‑architecture.html to React/Tailwind with brand CSS vars, clip‑path corners, proper typography; isAdminWallet() gate with redirect

v0.3.6

Feb 22, 2026

  • Updates page accordion refactor — extracted UPDATES data + UpdateEntry interface to lib/data/updates.ts; page.tsx slimmed from 449 → 48 lines, imports data and delegates to new UpdateTimeline client component
  • UpdateTimeline component — components/updates/UpdateTimeline.tsx; ‘use client’ accordion with useState‑based open set, CSS height transition (200ms ease‑in‑out), chevron rotation; tag:’current’ entry auto‑expanded, others collapsed, multiple can be open simultaneously
  • Push‑to‑main workflow updated — CLAUDE.md and docs/notes/push‑to‑main‑workflow.md now reference lib/data/updates.ts instead of app/updates/page.tsx for user‑facing update entries

v0.3.5

Feb 22, 2026

  • Card/modal market data unification — NFTDetailPositionCard Track B now uses same waterfall as deriveCardData(): marketExitGun → comparableSalesMedian → rarityFloor → currentLowestListing; previously modal only checked marketExitGun + computeMarketInputs (which excluded rarityFloor)
  • Tier‑confidence gating — new trackBIsSalesBased boolean on NFTCardData; gallery cards and list rows only show Track B MARKET line for sales‑based tiers (1‑4: EXACT, VIA SALES, VIA SKIN, VIA WEAPON); statistical proxies (tiers 5‑6: RARITY, FLOOR, LISTED, SIMILAR) suppressed from card display
  • Modal low‑confidence treatment — tiers 5‑6 render "Reference Estimate" card instead of "Market Reality": dimmer styling (opacity‑80), no VS COST row, no MARKET P&L percentage, warning text explaining it’s a proxy not sales data
  • exitTierLabel fallback chain — modal’s Track B exitTierLabel now falls back through VIA SALES → RARITY → LISTED when marketExitTierLabel is null, matching card behavior

v0.3.4

Feb 22, 2026

  • Dual‑track P&L card redesign — NFTDetailPositionCard restructured into two distinct cards: Track A ("Your Deal", lime border) shows GUN token appreciation since purchase; Track B ("Market Reality", purple border) shows market‑based P&L from comparable sales waterfall
  • Cost Basis merged into Track A — standalone COST BASIS section removed; cost basis row now lives inside the Track A card as the first data row, followed by TODAY’S VALUE row, providing a natural reading flow from "what you paid" → "what it’s worth" → "your P&L"
  • P&L hero treatment — both track cards use a border‑top divider to separate data rows from the P&L value, displayed in font‑display 20px bold with profit/loss coloring; italic subtext below explains the number in plain English
  • Label‑left / value‑right row pattern — all data rows use flex justify‑between with shrink‑0 labels (mono 9px uppercase gray) and right‑aligned values (display 14px semibold white tabular‑nums); arrow separator (→) between GUN and USD amounts
  • Track B confidence line — shows data quality indicator (green dot + tier label like "VIA SALES" + sample count), plus ABOVE/BELOW FLOOR pill when market exit differs from collection floor
  • Card styling standardized — bg‑[var(‑‑gs‑dark‑3)] with subtle border, 3px colored left border (lime for Track A, purple for Track B), p‑5 padding, rounded‑lg corners
  • Removed Observed Market Range section — NFTDetailObservedMarketRange component no longer rendered in modal; getPositionOnRange helper removed
  • Admin gate on /brand page — /brand now restricted to admin wallets using existing isAdminWallet() utility; non‑admin users redirected to /

v0.3.3

Feb 22, 2026

  • Tiered valuation waterfall (Track B) — 6‑tier Market Exit estimate per NFT: EXACT (same tokenId), VIA SALES (same baseName), VIA SKIN (same skinDesign), VIA WEAPON (same weapon), SIMILAR (deferred), FLOOR (collection floor)
  • Time‑weighted median — comparable sales weighted by recency (7d = 1.0, 7‑30d = 0.75, 30‑90d = 0.50, 90+ = 0.25); weighted‑median walk instead of simple median
  • Item name parser — new parseItemName() extracts skinDesign and weapon from "X for the Y" naming pattern, enabling Tier 3 and Tier 4 waterfall groupings
  • Pure valuation service — lib/portfolio/valuationService.ts walks waterfall with minimum‑sale‑count gates (1 for EXACT, 2 for all others), returns estimatedGun + tier + tierLabel
  • Waterfall data in comparable‑sales API — /api/opensea/comparable‑sales now returns waterfall (byTokenId, byName, bySkin, byWeapon) alongside existing items; backward‑compatible optional field
  • applyValuationTables enhanced — calls getMarketExitValuation() per NFT, writes marketExitGun, marketExitTier, marketExitTierLabel to NFT objects
  • Track B on gallery cards — grid cards (medium+) and list rows show "~592 GUN · VIA SALES" below existing P&L and ValuationLabel
  • Track B in modal QuickStats — 4th column "Market Exit" shows estimated GUN, USD conversion, tier label, and P&L vs cost basis; grid adapts 3→ 4 columns when data available
  • Scarcity tracking prep — useNFTEnrichmentOrchestrator now tracks max observed mint number per baseName in scarcityMapRef for future Tier 5 matching
  • NFT type extended — 3 new fields: marketExitGun, marketExitTier (1‑6), marketExitTierLabel

v0.3.2

Feb 21, 2026

  • Full‑pagination enrichment — enrichment now defers until all NFT pages are loaded (was firing per‑50‑item page, causing concurrent enrichment races and backward progress jumps on wallets with 50+ NFTs)
  • Generation‑guarded enrichment — startEnrichment increments a generation counter; all state updates (setProgress, setEnrichedNFTs, updateCallback, setIsEnriching) check gen === generationRef.current before writing, preventing stale enrichments from wallet switches
  • Enrichment diagnostic summary — console.info after completion logs total/cached/fresh/failed counts, date/costGUN/costUSD/listing resolution percentages, free transfer count, and venue breakdown
  • Incremental refresh — handleRefresh uses new invalidateListingPrices() instead of clearWalletCache(); only clears listingFetchedAt/currentLowestListing/currentHighestListing on each cached entry, preserving all acquisition data
  • Removed groupNFTsByMetadata import from PortfolioClient — handleLoadMoreNFTs now passes mergedNFTs (already grouped) directly to startEnrichment instead of re‑grouping per page
  • cumulativeBaseRef reset — new startEnrichment calls reset cumulativeBaseRef to 0 alongside generation bump, preventing stale cumulative offsets

v0.3.1

Feb 21, 2026

  • Server‑side GUN price history cache — new GunPriceHistory Prisma model stores confirmed historical GUN/USD rates in Neon PostgreSQL; shared across all users so the first person to resolve a date’s price populates it for everyone
  • Waterfall tier 2: server cache — resolveHistoricalGunPrice now checks the shared server table between localStorage and CoinGecko (3s timeout), with write‑through to localStorage on hit and fire‑and‑forget write‑back on CoinGecko/DefiLlama success
  • GET /api/gun‑price/history — public endpoint with CDN caching (1h fresh, 24h stale‑while‑revalidate); 404s cached for 5 min to avoid hammering DB for missing dates
  • POST /api/gun‑price/history — validated write endpoint with ATH guard, confidence‑based upgrade logic (won’t overwrite daily with estimated), rejects estimated prices from shared table
  • "Synced X ago" indicator — ValueHeader shows when the portfolio was last loaded from server cache, with staleness coloring (>24h = brighter gray)
  • Manual refresh button — spinning refresh icon next to the synced timestamp clears localStorage cache and re‑triggers full wallet fetch + enrichment
  • Refresh disabled during enrichment — button grays out and spins while NFT enrichment is active to prevent redundant requests

v0.3.0

Feb 21, 2026

  • Modal P&L reorganization — separated market valuation from GUN appreciation into two distinct P&L stories: market-based (via listings/sales/floor) when available, xGUN fallback otherwise
  • Unified P&L computation — QuickStats UNREALIZED and YOUR POSITION P&L now always agree (both use market-first, xGUN fallback)
  • Valuation method labels — QuickStats and YOUR POSITION show specific source: VIA LISTING, VIA SALES, VIA FLOOR, or GUN Δ
  • GUN Based Performance sub-section — when market data drives headline P&L, a separate section shows pure GUN token appreciation with explanatory narrative
  • CoinGecko fetch guard — modal acquisition pipeline skips redundant historical price fetches when enrichment data already provides confirmed USD values
  • Valuation method badges on gallery cards — 6-tier taxonomy (LISTED, SALES, RARITY, FLOOR, COST, UNLISTED) shown on NFT cards
  • Hidden redundant GUN @ line — cost basis section no longer shows "GUN @ $X.XXXX at time of purchase" when GUN Based Performance section is visible

v0.2.9

Feb 21, 2026

  • xGUN P&L formula — PnL now purely reflects GUN/USD price appreciation: Y = historicalGunPrice, Z = currentGunPrice, P&L = costGun × (Z‑Y). Removed market‑data waterfall (listing/comparable‑sales/rarity‑floor) from cards, modal, sort, and portfolio summary
  • Removed pnlSource labels — "vs listing" / "vs sales" / "vs floor" badges no longer appear on NFT cards since PnL is now single‑source
  • OpenSea event_timestamp fix — 4 parse sites were treating Unix seconds as milliseconds, producing dates in January 1970 and triggering $0.0776 fallback prices
  • Stale closure overwrite fix — async modal loadItemDetails captured resolvedAcquisitions at effect start time; cache‑rendered data was overwritten ~1s later. Fixed via resolvedAcquisitionsRef pattern in both NFTDetailModal and useNFTAcquisitionPipeline
  • Transfer chain tracing fix — buildCandidateFromHoldingRaw now uses senderAcquiredAtIso, senderVenue, and senderTxHash when using sender cost data, instead of the transfer date/venue
  • Transaction fee extraction — txFeeGun and senderTxFeeGun computed from receipt.gasUsed × receipt.gasPrice in avalanche.ts; propagated through ResolvedAcquisition, selectBestAcquisition, and all candidate builders
  • Gas fees display — YOUR POSITION section in NFTDetailModal shows purchase and transfer gas fees when available
  • Server cache hydration sanitization — PortfolioClient strips legacy purchasePriceUsd values from server‑cached NFTs when purchasePriceUsdEstimated !== false
  • CoinGecko ATH sanity check — /api/price/history rejects prices above $0.12 (GUN ATH ~$0.115) and logs a warning
  • Stale Next.js server cache bypass — /api/price/history temporarily switched to cache: 'no‑store' to purge incorrect CoinGecko historical data (revert to revalidate: 86400 after confirmation)
  • Enrichment trust guard — modal no longer overwrites confirmed purchasePriceUsd (purchasePriceUsdEstimated === false) with its own recomputation
  • Cache schema v24 — full client‑side re‑enrichment forced after CoinGecko data correction and server cache purge
  • MetaMask fallback — main page wallet connect falls back to MetaMask deep link when Dynamic SDK fails to trigger wallet
  • wGUN acquisition support — enrichment orchestrator handles wGUN‑based purchases for cost extraction
  • useNftPnL hook rewrite — portfolio summary P&L now uses xGUN formula instead of floor‑based calculation
  • PnL sort rewrite — useNFTGalleryFilters pnl‑desc sort uses xGUN unrealized USD gain with currentGunPrice threading

v0.2.8

Feb 19, 2026

  • Historical price CORS fix — new /api/price/history server‑side proxy routes CoinGecko historical price requests through the server, fixing silent CORS failure that left purchasePriceUsd undefined on all client‑side lookups
  • 14‑day sparkline — /api/price/gun now fetches 14d market_chart alongside 7d sparkline; PriceData type extended with sparkline14d; bootstrap and performance hooks prefer 14d data
  • Portfolio history backwards extension — bootstrapPortfolioHistory can now prepend synthetic points from the sparkline when the sparkline reaches further back than stored history, with 30‑min buffer gap and ~24‑point sampling
  • On‑chain cost extraction for transfers — acquisition pipeline now captures costGunFromChain for cross‑wallet transfers with wGUN payment, calculates USD from historical GUN price
  • Universal GUN→USD fallback — any item with finalPurchasePriceGun > 0 and no USD value gets historical price lookup as a last‑resort conversion
  • Transfer cost basis propagation — NFTDetailModal costBasisGun now falls through to traced original purchase price for TRANSFER acquisitions instead of always returning null
  • Enrichment cache invalidation — marketplace purchases (opensea, in_game_marketplace) with missing price are treated as incomplete and retried on next enrichment cycle
  • USD‑first acquisition card — NFTDetailAcquisitionCard shows $USD as primary line with GUN as secondary when USD is available, for both decode cost and purchase price sections
  • Chart tooltip dynamic positioning — BackdropChart tooltip now renders above the point when point is in lower half of chart, below when in upper half, with hoverY null‑check guard
  • ValueHeader pointer‑events — elements with [title] attribute now receive pointer‑events for native tooltip hover
  • Item origins expansion — new categories early_access, reward, content_pack; Pioneer Set, Player Zero Set, Prankster Set, Anarchist Set reclassified; Going Ape Shit, Hump for Dominance added to Aperil Fools
  • Empty wallet state — portfolios with 0 GUN and 0 NFTs show centered "Nothing Detected" message with inline search bar + Leaderboard/Market CTAs instead of empty $0.00 dashboard
  • CLAUDE.md — documented Production Whitelist API endpoints and admin workflow

v0.2.7

Feb 18, 2026

  • Item origin registry scaled to 35+ releases — added Enforcer BP, Pink Fury BP, Mr Fuckles BP, Hopper Pilot BP, Mad Biker BP, Neotokyo event, Trick Treat or Die event expansion, plus dozens of individual items
  • AIRDROP label — any NFT with a known origin and sub‑1‑GUN acquisition cost now displays "AIRDROP" instead of "0 GUN"; unknown‑origin items keep their raw price
  • Contains match rules — Don DeLulu CP and Mrs Crackhead Santa CP items now use fuzzy‑contains matching to catch blockchain name variations that exact‑match missed
  • ItemRelease description field — releases can now carry rich event descriptions (lore, mechanics, reward details); Trick, Treat or Die is the first with full event metadata
  • Trick, Treat or Die event badge — Halloween items now show the actual event name instead of generic "Halloween"
  • Loading messages refreshed — three new OTG‑themed quips in the portfolio loading rotation
  • Welcome popup streamlined — merged feedback paragraphs, removed redundant bug‑report CTA; single "Got it, let me explore" button

v0.2.6

Feb 18, 2026

  • Search bar validation — invalid addresses (e.g. trailing special characters) now show inline chain detection badge and hint text instead of silently failing; "Go" button properly gates on address validity
  • Wallet actions relocated — Watch and Portfolio buttons moved from search dropdown to the wallet identity bar, where users have context after viewing a wallet’s data
  • Item origin database — curated lookup table mapping NFT items to their release origin (Battle Pass, Content Pack, Event) with 26 releases catalogued
  • Navbar dropdown contrast — darker background and stronger shadow on wallet dropdown so it no longer blends into the page behind it

v0.2.5

Feb 18, 2026

  • Hook extraction — five custom hooks pulled from PortfolioClient (loading messages, chart milestone gating, portfolio snapshots, wallet search actions, multi‑wallet gallery), reducing component from 1,203 to 1,012 lines
  • Lazy‑load below‑fold — ChartInsightsRow and NFTGallery dynamically imported with skeleton placeholders for faster initial paint
  • Accessibility — skip‑to‑content link, aria‑live on metrics grid, ARIA tablist with roving tabIndex and arrow‑key navigation on chart tabs
  • Wallet switch race fix — request ID ref pattern on handleWalletSubmit discards stale responses when rapidly switching wallets
  • Gallery card stagger — first 24 NFT cards fade‑in with translateY stagger animation (30ms grid, 20ms list); cards beyond 24 render instantly

v0.2.4

Feb 17, 2026

  • Cost basis sparkline — dashed white line on the portfolio value chart shows historical cost basis alongside market value, visually revealing unrealized P&L gap
  • Star‑appear animation — chart dots fade in like stars appearing in a night sky as NFTs enrich, growing from tiny pinpoints to full size over ~10 seconds
  • Random dot stagger — new dots appear in randomized order across the chart (Fisher‑Yates shuffle) instead of chronologically, for a more organic night‑sky feel
  • "Under Active Dev" label — moved from chart tab headers into the Insights section for a cleaner chart UI

v0.2.3

Feb 17, 2026

  • Share image redesign — tactical HUD aesthetic OG image with dot‑grid background, corner brackets, gradient accent line, metric cards for GUN balance / NFTs / cost basis
  • Download portfolio image — new button in share dropdown fetches the OG image and saves it as PNG
  • Cost basis in share links — GUN spent on NFTs is now stored in share snapshots and displayed on the OG card
  • Chart zoom fix — zooming no longer pushes dots off‑screen; scales use base width so data positions stay stable
  • Zoom to cursor — Shift+scroll zooms toward the mouse pointer; zoom buttons auto‑scroll to the densest data cluster
  • Gallery performance — React.memo on card components + memoized card data prevents unnecessary re‑renders
  • Search debounce — 200ms debounce on gallery search input eliminates lag from keystroke‑driven re‑filtering
  • content‑visibility: auto on NFT cards — browser skips painting offscreen cards, reducing compositor work on large galleries
  • Enrichment speed — batch delay reduced from 800ms to 200ms, priority window expanded from 12 to 18 above‑fold NFTs

v0.2.2

Feb 17, 2026

  • Chart crossfade — Timeline and Cost‑vs‑Value charts stay mounted simultaneously, opacity crossfade via motion/react eliminates DOM rebuild flicker
  • Aligned chart dimensions — embedded Timeline now matches Scatter plot margins and height so content doesn’t shift during crossfade
  • Multi‑wallet NFT total fix — portfolio wallets that load after the primary wallet now correctly update the NFT count
  • NFT count includes duplicates — gallery item count sums quantities instead of unique token count
  • Holdings card cleanup — removed per‑category GUN amounts, combined Bought+Minted on one row, consistent vertical spacing
  • Navbar wallet dropdown — converted from slide‑out panel to positioned dropdown with spring animation, click‑outside and ESC‑key close
  • Navbar layout fix — three‑group flex prevents wallet address width changes from shifting navigation links
  • Transition demo — interactive comparison of four chart transition styles added to brand page

v0.2.1

Feb 17, 2026 · 6:30 AM EST

  • Spring‑physics animations site‑wide — all panels, modals, drawers, and accordions now use motion/react with consistent spring config
  • Custom green arrow cursor — replaces default pointer everywhere, zero‑lag tracking via direct mousemove transform
  • Drop‑panel close fix — resolved race condition where trigger button click re‑opened panel immediately after click‑outside closed it
  • Active‑state indicators — wallet‑switcher and share trigger icons stay green while their panels are open
  • Navbar layout stability — three‑group flex prevents wallet address from shifting navigation links
  • BreakdownDrawer accordion — smooth height expand/collapse replaces instant show/hide
  • UnlockBanner trust section — spring‑animated height reveal instead of instant toggle
  • WeaponLabDrawer exit animation — drawer now slides out instead of vanishing on close
  • ConnectPromptModal entrance — scale + fade spring animation replaces no‑animation mount

v0.2.0

Feb 16, 2026 · 5:48 AM EST

  • wGUN cost extraction fix — OpenSea offer fills now resolve acquisition cost from ERC‑20 receipt logs
  • Offer fill detection — NFTs acquired via pre‑signed OpenSea offers show "OpenSea (Offer)" as source
  • Hardcoded wGUN contract address as constant — no longer depends on env var for cost extraction

v0.1.9

Feb 16, 2026 · 3:21 AM EST

  • Bundle diet — removed 15 unused dependencies (210 packages), including Nivo, GSAP, tsparticles, force‑graph, reaviz
  • Replaced axios with native fetch across all API services (−30 KB)
  • Replaced framer‑motion with a single CSS keyframe for page transitions (−45 KB)
  • Code‑split 13 heavy components via next/dynamic — charts, modals, debug panels load on demand
  • Deferred PostHog initialization to after hydration for faster first paint
  • Added optimizePackageImports for visx, ethers, posthog‑js — tree‑shakes unused exports
  • AVIF image format enabled site‑wide (20‑50% smaller than WebP on supported browsers)
  • Converted barrel‑file imports to direct imports in key components for better tree‑shaking

v0.1.8

Feb 16, 2026 · 1:10 AM EST

  • Market page — search all active OpenSea listings, drill into individual items with buy links
  • Scarcity upgrades — quality badges, Best Deal sort, price range filter, cross‑links to Market
  • OpenSea listing coverage tripled — fetches up to 3,000 listings (was 1,000)
  • PnL scatter plot redesign — gradient stems, lighter grid, boosted zone labels, legend row, bordered data strip
  • Sqrt‑aware Y‑axis ticks — labels evenly spaced in visual space instead of bunching at the bottom
  • Chart height increase — both charts get more vertical breathing room
  • Fixed zoom height jump — switching between charts no longer causes jarring layout shift
  • Quality metadata pipeline — GunzScan rarity trait extracted and propagated end‑to‑end

v0.1.7

Feb 15, 2026 · 8:23 PM EST

  • Acquisition Timeline — log‑scale Y‑axis with curated tick marks for better dot distribution
  • Data‑driven dot entrance animation — new dots materialize as enrichment discovers them
  • Portfolio sparkline stability — snapshots only record after enrichment completes, eliminating jagged reloads
  • Backdrop sparkline clipping fix — increased top margin and enforced minimum container height
  • Hydration fix — loading text no longer mismatches between server and client renders
  • CSS shorthand/longhand conflict resolved in chart metadata card and insights border
  • Chart zoom no longer inflates container height — fixed‑height chart area with hidden scrollbar
  • ShareDropdown cleanup — removed dead code, simplified conditional logic
  • SimpleMetrics and usePortfolioSummaryData reduced by ~700 lines of dead code
  • PnLScatterPlot simplified — removed unused tooltip state and redundant computations

v0.1.6

Feb 14, 2026 · 8:57 PM EST

  • Social sharing — Share on X, Discord, or copy link with rich OG preview cards showing portfolio value, P&L, and NFT count
  • Valuation waterfall upgrade — per‑item listing > comparable sales median > rarity‑tier floor > cost basis
  • Insights panel expansion — unrealized P&L, most valuable, biggest loss (5 insight types total)
  • Acquisition Timeline chart — interactive visx timeline of NFT purchases by venue and date
  • P&L Scatter Plot promoted to main portfolio view (was insanity‑only)
  • All charts now use full valuation waterfall (listing > comparable > rarity > floor)
  • Chart visual overhaul — sqrt scales, glow effects, gradient zones, smarter axis formatting

v0.1.5

Feb 14, 2026 · 4:05 PM EST

  • NFT valuation waterfall: per‑item listings, rarity‑tier floors, comparable sales medians
  • Dual‑value display — cost basis vs market value side by side
  • Per‑item P&L with visx interactive charts
  • Feature request system with community voting, bug reports, and screenshot attachments
  • Collapsible request cards with lightbox image viewer
  • UXR welcome popup for new testers with onboarding guidance
  • Crosshair cursor performance: removed backdrop‑blur from overlays, cached DOM walks, targeted cursor rules
  • Display name support for wallet profiles
  • Portfolio history bootstrap with sparkline seeding
  • Hybrid portfolio: aggregated summary + per‑wallet gallery with SWITCH
  • Read‑only portfolio access via ?address= param — browse any wallet without logging in
  • Migrate from SQLite to Neon PostgreSQL — full read/write in production

v0.1.4

Feb 13, 2026 · 4:56 AM EST

  • Scramble‑decode loading text matching home hero animation
  • 10pm Easter egg — because someone had to
  • NFT Holdings sparkline toggle on first wallet search
  • Server‑side RPC proxy for reliable production wallet loading
  • View transitions with framer‑motion page animations
  • Wallet address help panel for new users
  • Auto‑populate credits from completed feature requests

v0.1.3

Feb 12, 2026 · 4:35 PM EST

  • NFT sparkline toggle with historical hover counts
  • Dynamic Labs SDK upgrade (4.59.1 → 4.61.2)
  • Crosshair cursor performance fix
  • UX polish: onboarding flow, nav, login gate, multi‑admin
  • Grouped NFT visual overhaul: dynamic rarity accents, mergeIntoGroups
  • Decode cost extraction fix for relayer‑submitted transactions

v0.1.2

Feb 11, 2026 · 10:37 PM EST

  • GunzScan API migration with infinite scroll
  • Ambient backdrop sparkline with smooth curves and overlay toggles
  • Auto‑load portfolio on wallet connect
  • Component decomposition: Navbar, PortfolioSummaryBar, scarcity, feature‑requests
  • Wallet dropdown enhancements + identity bar refactor
  • SEO metadata for all pages
  • Standardized API response types

v0.1.1

Feb 10, 2026 · 11:47 PM EST

  • Confidence indicator overhaul with enrichment reliability fixes
  • Insanity Mode toggle + clip‑corner card design
  • Sticky accent lines and container transparency polish
  • Email auth flow + adaptive onboarding
  • Scarcity page UX improvements
  • Disconnect UX and network switch visibility fixes

v0.1.0

Feb 9, 2026 · 7:20 PM EST

  • Public feature request and management system
  • Dynamic wallet onboarding with styled connect flow
  • Redesigned footer with social links
  • Leaderboard page with access gate and active wallet display
  • Nav glitch effect + gallery refactor

v0.0.3

Feb 5–8, 2026

  • NFTDetailModal decomposition (3,163 → 1,069 lines via 4 extracted hooks)
  • Portfolio context + hooks architecture refactor
  • useWalletDataFetcher, useNFTEnrichmentOrchestrator, useWalletAggregation hooks
  • WaffleChart composition visualization with stagger animation
  • Marketplace price enrichment pipeline
  • Portfolio three‑section layout with Simple/Detailed toggle

v0.0.2

Jan 31 – Feb 1, 2026

  • NFT P&L pipeline with historical prices, rarity floors, and comparable sales
  • Interactive rarity filter pills in NFT gallery
  • YOUR POSITION section in NFT detail modal
  • Floor price enrichment + metadata caching
  • Security vulnerability fixes (31 → 9)
  • Functional tier support from raw metadata
  • Native GUN balance fetch fix

v0.0.1

Genesis

Jan 19–22, 2026

  • Initial release — GUNZscope is born
  • Multi‑chain portfolio tracker for Off The Grid
  • NFT Armory/Lab feature with weapon compatibility
  • Acquisition truth layer using RPC‑only fingerprints
  • Progressive accounts implementation
  • OpenSea + in‑game marketplace data integration

Built for the Off The Grid community · Not affiliated with GUNZILLA Games

© 2026 GUNZscope
·Terms·Privacy·Credits··

Built with ♥ by CRYPTOHAKI for the Gunzilla community.