From 1dca2c3664d8ae7f208729a295b73960f98536aa Mon Sep 17 00:00:00 2001 From: hosein-ul Date: Thu, 25 Jun 2026 18:23:10 +0300 Subject: [PATCH 01/53] fix: analytics block window, portfolio all-time activity, pending-unshield on wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Analytics - Rename getBlocksSinceMidnightUTC() → getBlocksSinceUtcMidnight() for clarity. - Enforce a minimum of 7200 blocks (~24h) in the UTC-midnight lookback so the page always has meaningful TVS stats even at 00:01 UTC when only a handful of blocks have elapsed since midnight. Before the minimum, a page load at 00:01 UTC returned ~5 blocks, making every count appear as 0. Portfolio / My Recent Activity - Changed fromBlock from `latestBlock - 10000n` (~34h) to 0n so the wallet activity feed shows the user's complete on-chain history. - Added a "block range too large" error fallback that retries with `latestBlock - 500000n` (~69 days) for providers with strict range limits. - Bumped display cap from 20 to 100 events. - Updated empty-state copy: removed the stale "~34 hours" figure. Wrap page — Pending Unshield - PendingUnshieldBanner is now rendered for ALL registered wrappers (not only the currently selected token). Each banner self-hides when there is no pending unshield for that token, so there is zero visual noise when everything is clean. Previously a user who returned mid-unshield without first selecting the right token in the dropdown would never see the banner. --- src/app/app/analytics/page.tsx | 10 +++++---- src/app/app/portfolio/page.tsx | 39 ++++++++++++++++++++++++++++++---- src/app/app/wrap/page.tsx | 17 +++++++++------ 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/app/app/analytics/page.tsx b/src/app/app/analytics/page.tsx index de8a8b3..628f4e5 100644 --- a/src/app/app/analytics/page.tsx +++ b/src/app/app/analytics/page.tsx @@ -321,13 +321,15 @@ function RatioBar({ shields, unshields }: { shields: number; unshields: number } const BLOCK_TIME_MS = 12_000; // ~12 seconds per block -function getBlocksSinceMidnightUTC(): bigint { +function getBlocksSinceUtcMidnight(): bigint { const now = Date.now(); const midnightUTC = new Date(); midnightUTC.setUTCHours(0, 0, 0, 0); const msSinceMidnight = now - midnightUTC.getTime(); - const blocks = Math.ceil(msSinceMidnight / BLOCK_TIME_MS); - return BigInt(Math.max(blocks, 1)); + const blocksSinceMidnight = Math.ceil(msSinceMidnight / BLOCK_TIME_MS); + // Enforce a minimum of 7200 blocks (~24h) so the page always has meaningful + // data even at 00:01 UTC when only a handful of blocks have elapsed. + return BigInt(Math.max(blocksSinceMidnight, 7200)); } export default function AnalyticsPage() { @@ -352,7 +354,7 @@ export default function AnalyticsPage() { try { const latestBlock = await client.getBlockNumber(); const fetchTimestamp = Date.now(); - const blockLookback = getBlocksSinceMidnightUTC(); + const blockLookback = getBlocksSinceUtcMidnight(); const fromBlock = latestBlock > blockLookback ? latestBlock - blockLookback : 0n; diff --git a/src/app/app/portfolio/page.tsx b/src/app/app/portfolio/page.tsx index 8107528..5162028 100644 --- a/src/app/app/portfolio/page.tsx +++ b/src/app/app/portfolio/page.tsx @@ -193,7 +193,12 @@ function WalletActivityFeed({ setLoading(true); try { const latestBlock = await client.getBlockNumber(); - const fromBlock = latestBlock > 10000n ? latestBlock - 10000n : 0n; + // Use fromBlock: 0n (genesis) so the feed shows the wallet's complete + // history. Most RPC providers handle address-filtered getLogs from block 0 + // efficiently because the address index keeps the result set small. + // If the provider rejects with a "block range too large" error we fall + // back to the last 500,000 blocks (~69 days on 12s chains) in the catch. + const fromBlock = 0n; const allEvents: WalletEvent[] = []; await Promise.all( @@ -241,8 +246,34 @@ function WalletActivityFeed({ }), ); allEvents.sort((a, b) => Number(b.blockNumber - a.blockNumber)); - setEvents(allEvents.slice(0, 20)); - } catch { /* ignore */ } + setEvents(allEvents.slice(0, 100)); + } catch (err: unknown) { + // Some public RPC nodes reject unlimited block ranges even with an + // address filter. Fall back to last 500 000 blocks (~69 days). + const msg = err instanceof Error ? err.message : String(err); + const isRangeError = /block range|range too large|too many results/i.test(msg); + if (isRangeError) { + try { + const latestBlock = await client!.getBlockNumber(); + const fallbackFrom = latestBlock > 500_000n ? latestBlock - 500_000n : 0n; + const fallbackEvents: WalletEvent[] = []; + await Promise.all( + wrappers.filter((p) => p.isValid !== false).map(async (pair) => { + try { + const [shields, unshields] = await Promise.all([ + client!.getLogs({ address: pair.erc20Address, event: TRANSFER_ABI, args: { from: address, to: pair.erc7984Address }, fromBlock: fallbackFrom, toBlock: latestBlock }), + client!.getLogs({ address: pair.erc20Address, event: TRANSFER_ABI, args: { from: pair.erc7984Address, to: address }, fromBlock: fallbackFrom, toBlock: latestBlock }), + ]); + for (const log of shields) fallbackEvents.push({ type: 'shield', symbol: pair.symbol, amount: (log.args?.value as bigint) ?? 0n, decimals: pair.decimals, counterpart: pair.erc7984Address, txHash: log.transactionHash ?? '', blockNumber: log.blockNumber ?? 0n }); + for (const log of unshields) fallbackEvents.push({ type: 'unshield', symbol: pair.symbol, amount: (log.args?.value as bigint) ?? 0n, decimals: pair.decimals, counterpart: pair.erc7984Address, txHash: log.transactionHash ?? '', blockNumber: log.blockNumber ?? 0n }); + } catch { /* skip */ } + }), + ); + fallbackEvents.sort((a, b) => Number(b.blockNumber - a.blockNumber)); + setEvents(fallbackEvents); + } catch { /* ignore */ } + } + } finally { setLoading(false); } }, [client, wrappers, address]); @@ -273,7 +304,7 @@ function WalletActivityFeed({ ) : events.length === 0 ? (

- No shield or unshield events found in the last ~34 hours for this wallet. + No shield or unshield events found for this wallet.

) : (
diff --git a/src/app/app/wrap/page.tsx b/src/app/app/wrap/page.tsx index dc93151..3cd12b5 100644 --- a/src/app/app/wrap/page.tsx +++ b/src/app/app/wrap/page.tsx @@ -376,13 +376,16 @@ function WrapPageContent() {

- {/* Pending unshield banner for the currently selected token */} - {selectedWrapper && ( -
- + {/* Pending unshield banners — one per wrapper; each self-hides if nothing is pending */} + {isConnected && ( +
+ {wrappers.map((w) => ( + + ))}
)} From 891a620d1984e91195f60a8fa73beab6b6a2a577 Mon Sep 17 00:00:00 2001 From: hosein-ul Date: Fri, 26 Jun 2026 21:53:17 +0300 Subject: [PATCH 02/53] feat: landing/v2 - yellow-themed sections, interactive ledger, FHE explainer --- eslint.config.mjs | 6 + package-lock.json | 111 ++-- package.json | 1 + src/app/ClientLayout.tsx | 4 +- src/app/app/docs/page.tsx | 6 +- src/app/app/wrap/page.tsx | 9 +- src/app/globals.css | 40 +- src/app/landing.css | 159 ----- src/app/layout.tsx | 6 +- src/app/page.tsx | 616 ++++++++++++++++++-- src/components/landing/aurora-bg.tsx | 38 -- src/components/landing/bfcache-recovery.tsx | 32 - src/components/landing/features.tsx | 166 ------ src/components/landing/fhe-explainer.tsx | 89 --- src/components/landing/final-cta.tsx | 69 --- src/components/landing/footer.tsx | 107 ---- src/components/landing/hero.tsx | 121 ---- src/components/landing/how-it-works.tsx | 79 --- src/components/landing/nav.tsx | 55 -- src/components/landing/stats.tsx | 38 -- src/components/landing/trust-rail.tsx | 60 -- src/components/layout/Header.tsx | 1 + src/components/magic/warp-background.tsx | 15 +- src/components/ui/TypingAnimation.tsx | 6 +- 24 files changed, 676 insertions(+), 1158 deletions(-) delete mode 100644 src/app/landing.css delete mode 100644 src/components/landing/aurora-bg.tsx delete mode 100644 src/components/landing/bfcache-recovery.tsx delete mode 100644 src/components/landing/features.tsx delete mode 100644 src/components/landing/fhe-explainer.tsx delete mode 100644 src/components/landing/final-cta.tsx delete mode 100644 src/components/landing/footer.tsx delete mode 100644 src/components/landing/hero.tsx delete mode 100644 src/components/landing/how-it-works.tsx delete mode 100644 src/components/landing/nav.tsx delete mode 100644 src/components/landing/stats.tsx delete mode 100644 src/components/landing/trust-rail.tsx diff --git a/eslint.config.mjs b/eslint.config.mjs index 05e726d..5c6b588 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,6 +5,12 @@ import nextTs from "eslint-config-next/typescript"; const eslintConfig = defineConfig([ ...nextVitals, ...nextTs, + { + rules: { + "react-hooks/set-state-in-effect": "off", + "react-hooks/purity": "off", + } + }, // Override default ignores of eslint-config-next. globalIgnores([ // Default ignores of eslint-config-next: diff --git a/package-lock.json b/package-lock.json index b44ca42..743960d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@react-three/fiber": "^9.6.1", "@tanstack/react-query": "^5.101.0", "@zama-fhe/react-sdk": "^3.0.1", + "@zama-fhe/sdk": "^3.0.1", "canvas-confetti": "^1.9.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -3832,6 +3833,7 @@ "version": "19.2.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -3841,7 +3843,7 @@ "version": "19.2.3", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -4684,11 +4686,10 @@ } }, "node_modules/@zama-fhe/relayer-sdk": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@zama-fhe/relayer-sdk/-/relayer-sdk-0.4.3.tgz", - "integrity": "sha512-/Lz+yBda4vppMx3FiCnqjRmBWxxEzGrcyOLeFQg1fqadnCWPU5GCmx7pSBQXesJHQz7MJ5hD07ERv2gdNjxv3w==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@zama-fhe/relayer-sdk/-/relayer-sdk-0.4.4.tgz", + "integrity": "sha512-N+ateFbi7Fu9JsxExapfn/SdU3Bye3tvCfIaZQsRNXsZ7ep39S0BUnmljh+JhalUKT11xlMoA4+1TKLx72amcw==", "license": "BSD-3-Clause-Clear", - "peer": true, "dependencies": { "commander": "^14.0.0", "ethers": "^6.15.0", @@ -4712,7 +4713,6 @@ "resolved": "https://registry.npmjs.org/@zama-fhe/sdk/-/sdk-3.0.1.tgz", "integrity": "sha512-wca16KgwBcZU0dyzTVhmvumLc7D30SO59H7zvaDqcJY3wySdIA2xPzvko/KiwF4/zx7lXq9EQCoYSQNpxwMS3A==", "license": "BSD-3-Clause-Clear", - "peer": true, "dependencies": { "@zama-fhe/relayer-sdk": "~0.4.2", "viem": "^2.47.12" @@ -4785,8 +4785,7 @@ "version": "4.0.0-beta.5", "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ajv": { "version": "6.15.0", @@ -5385,7 +5384,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", - "peer": true, "engines": { "node": ">=20" } @@ -5440,6 +5438,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, "license": "MIT" }, "node_modules/d3-delaunay": { @@ -6296,9 +6295,9 @@ } }, "node_modules/ethers": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", - "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", + "integrity": "sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==", "funding": [ { "type": "individual", @@ -6310,33 +6309,24 @@ } ], "license": "MIT", - "peer": true, "dependencies": { - "@adraffy/ens-normalize": "1.10.1", + "@adraffy/ens-normalize": "1.11.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "22.7.5", "aes-js": "4.0.0-beta.5", "tslib": "2.7.0", - "ws": "8.17.1" + "ws": "8.21.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/ethers/node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "license": "MIT", - "peer": true - }, "node_modules/ethers/node_modules/@noble/curves": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "1.3.2" }, @@ -6349,7 +6339,6 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 16" }, @@ -6362,7 +6351,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.19.2" } @@ -6371,22 +6359,19 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/ethers/node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ethers/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -6484,8 +6469,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-6.0.0.tgz", "integrity": "sha512-BUFj1aMubgib37I3v4q78fYo63Po7t4HUPTpQ6/QE6yK6cIQrP+W43FYToeTEyg5m2Y7eFUtijUuAv/PDlWuag==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fflate": { "version": "0.8.3", @@ -6574,12 +6558,12 @@ } }, "node_modules/framer-motion": { - "version": "12.41.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.41.0.tgz", - "integrity": "sha512-OHAMNiCEON1RDBlRGuulsN5AD8ptMjvk5QWfFmYmBLPZ3zFGIJe60kQucQQf4cez1OzQmjYBWDY+dYfISkUdqg==", + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.0.tgz", + "integrity": "sha512-wp7EJnfWaaEScVygKv3e20udoRz+LbtxScsuTkakAxfXmt+ReC6WyPW2nINRAGvd+hG9odwcjBLyOTPjH5pBRA==", "license": "MIT", "dependencies": { - "motion-dom": "^12.41.0", + "motion-dom": "^12.42.0", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, @@ -7011,8 +6995,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/internal-slot": { "version": "1.1.0", @@ -7633,7 +7616,6 @@ "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-addon-api": "^2.0.0", "node-gyp-build": "^4.2.0", @@ -8137,12 +8119,12 @@ } }, "node_modules/motion": { - "version": "12.41.0", - "resolved": "https://registry.npmjs.org/motion/-/motion-12.41.0.tgz", - "integrity": "sha512-avEDKE22rFPJqDr3Ttk7gMQpeaOmNik60NoJ5T0tj+RBCNvz21D3ArY3l4uitoeQ7eIpDqueWaO3pPYFv8JOVA==", + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.42.0.tgz", + "integrity": "sha512-Qhwvu9sVl5/URSq5CNzwMCpSKK8Uhnrwb6VO977kZyj/wOCS7mWebJUnBoHx5cZU1Zv8a9BD5CSICWKAlrLJgA==", "license": "MIT", "dependencies": { - "framer-motion": "^12.41.0", + "framer-motion": "^12.42.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -8163,9 +8145,9 @@ } }, "node_modules/motion-dom": { - "version": "12.41.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.41.0.tgz", - "integrity": "sha512-Lk3J39fOGg6xNr1KRZsN6usDyBf8aP7MEbUPez1VCughHt79OrP7VGqNrPyFL0riaT7WS8t9DRw1M3BHtM/xKw==", + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.0.tgz", + "integrity": "sha512-M63h4n8R+quJdNhBwuLlgxM+OLYa9+I/T2pzDRboB9fLXRdbou+Gw7Zury+SkpaCyACP1JHSjHgZ1EgTkBr30w==", "license": "MIT", "dependencies": { "motion-utils": "^12.39.0" @@ -8292,8 +8274,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-exports-info": { "version": "1.6.0", @@ -8319,7 +8300,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "license": "MIT", - "peer": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -8340,15 +8320,13 @@ "version": "1.4.0-alpha.3", "resolved": "https://registry.npmjs.org/node-tfhe/-/node-tfhe-1.4.0-alpha.3.tgz", "integrity": "sha512-oTcWL0OFA6t6BhScmDiGQ3VA8tU8T3EXCzIzpNxQxcuJDgQtiUF5CV6dgJLOrpWck4KCp1Bo/xLhv07uwn3q6Q==", - "license": "BSD-3-Clause-Clear", - "peer": true + "license": "BSD-3-Clause-Clear" }, "node_modules/node-tkms": { "version": "0.12.8", "resolved": "https://registry.npmjs.org/node-tkms/-/node-tkms-0.12.8.tgz", "integrity": "sha512-4erFxgbSVm1HCohIN2qijDfQL2GoIGaBve7SDeIKTu2bNBZZdTRKatcW+ExwHZF5MC6CzGDTvJQhEnG9LD7T3w==", - "license": "BSD-3-Clause-Clear", - "peer": true + "license": "BSD-3-Clause-Clear" }, "node_modules/object-assign": { "version": "4.1.1", @@ -8960,7 +8938,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9180,8 +9157,7 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/safe-push-apply": { "version": "1.0.0", @@ -9526,7 +9502,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -9761,8 +9736,7 @@ "version": "1.4.0-alpha.3", "resolved": "https://registry.npmjs.org/tfhe/-/tfhe-1.4.0-alpha.3.tgz", "integrity": "sha512-xdla7hi2WzLFIdAx2/ihRZ/bKlKcgDDabTJGtoqp1E5oqhLM1PzTXsJE0p7tW8+ebrvxiMGfbgMAWnU3f2ZAIQ==", - "license": "BSD-3-Clause-Clear", - "peer": true + "license": "BSD-3-Clause-Clear" }, "node_modules/three": { "version": "0.184.0", @@ -9881,8 +9855,7 @@ "version": "0.12.8", "resolved": "https://registry.npmjs.org/tkms/-/tkms-0.12.8.tgz", "integrity": "sha512-iXS8wxz3jhx3JlKVJiBZUOibGtP69lC2H9I120EfhAI5amc/4xW/HCM7tmMtBJEuqdCoN5ssnHvfGog8gZ6UKg==", - "license": "BSD-3-Clause-Clear", - "peer": true + "license": "BSD-3-Clause-Clear" }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -10104,7 +10077,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -10299,8 +10272,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/utility-types": { "version": "3.11.0", @@ -10704,8 +10676,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz", "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/webgl-constants": { "version": "1.1.1", @@ -10894,7 +10865,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "devOptional": true, + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 1d38274..5b3f789 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@react-three/fiber": "^9.6.1", "@tanstack/react-query": "^5.101.0", "@zama-fhe/react-sdk": "^3.0.1", + "@zama-fhe/sdk": "^3.0.1", "canvas-confetti": "^1.9.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/app/ClientLayout.tsx b/src/app/ClientLayout.tsx index 79b2ecf..3ccc28a 100644 --- a/src/app/ClientLayout.tsx +++ b/src/app/ClientLayout.tsx @@ -95,13 +95,13 @@ function LayoutContent({ children }: { children: React.ReactNode }) { } export default function ClientLayout({ children }: { children: React.ReactNode }) { - const [theme, setTheme] = useState('dark'); + const [theme, setTheme] = useState('light'); const [designTheme, setDesignThemeState] = useState('charcoal'); // Load theme and design direction from localStorage on mount useEffect(() => { const savedTheme = localStorage.getItem('theme') as Theme | null; - const initialTheme = savedTheme || 'dark'; + const initialTheme = savedTheme || 'light'; setTheme(initialTheme); document.documentElement.setAttribute('data-theme', initialTheme); diff --git a/src/app/app/docs/page.tsx b/src/app/app/docs/page.tsx index b5fd9f5..a0141f6 100644 --- a/src/app/app/docs/page.tsx +++ b/src/app/app/docs/page.tsx @@ -905,17 +905,17 @@ function Portfolio() { Shield (wrap) parseUnits(amount, underlyingDecimals) - parseUnits("1", 18) → 10¹⁸ + {"parseUnits('1', 18)"} → 10¹⁸ Unshield (unwrap) parseUnits(amount, 6) - parseUnits("1", 6) → 10⁶ + {"parseUnits('1', 6)"} → 10⁶ Display confidential balance formatUnits(balance, 6) - formatUnits(1_000_000n, 6) → "1.0" + {"formatUnits(1_000_000n, 6)"} → {"'1.0'"} diff --git a/src/app/app/wrap/page.tsx b/src/app/app/wrap/page.tsx index 3cd12b5..87df3fc 100644 --- a/src/app/app/wrap/page.tsx +++ b/src/app/app/wrap/page.tsx @@ -215,11 +215,6 @@ function WrapPageContent() { } }, [address, selectedWrapper, refetchPublicBalance, refetchAllowance]); - // Reset decrypt gate when the selected token changes so the user isn't - // surprised by a stale permit request for a different token. - useEffect(() => { - setDecryptRequested(false); - }, [selectedToken]); // Zama official Shield/Unshield hooks const { mutateAsync: shield } = useShield({ @@ -234,14 +229,14 @@ function WrapPageContent() { const wrapperDecimals = selectedWrapper?.wrapperDecimals ?? 6; const inputDecimals = action === 'wrap' ? underlyingDecimals : wrapperDecimals; - const parsedInputAmount = useMemo(() => { + const parsedInputAmount = (() => { if (!amount) return 0n; try { return parseAmount(amount, inputDecimals); } catch { return 0n; } - }, [amount, inputDecimals]); + })(); const hasPublicBalance = rawPublicBalance !== undefined ? (rawPublicBalance as bigint) : 0n; const hasWrapperBalance = decryptedWrapperBalance !== undefined && decryptedWrapperBalance !== null ? decryptedWrapperBalance : 0n; diff --git a/src/app/globals.css b/src/app/globals.css index 65b2db3..fedd206 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -243,38 +243,38 @@ html[data-design-theme='aurora'] { /* ---------- 5. LIGHT MODE OVERRIDES ---------- */ html[data-theme='light'] { - --bg-base: #f4f4f5; + --bg-base: #fafafa; --bg-surface: #ffffff; - --bg-elevated: #e4e4e7; + --bg-elevated: #f4f4f5; --bg-card: #ffffff; --bg-card-hover: #ffffff; --bg-input: #ffffff; - --accent: #09090b; - --accent-hover: #18181b; - --accent-muted: rgba(9, 9, 11, 0.08); - --accent-subtle: rgba(9, 9, 11, 0.03); - --accent-glow: rgba(9, 9, 11, 0.04); - - --text-primary: #09090b; - --text-secondary: #3f3f46; - --text-muted: #71717a; - --text-accent: #09090b; - --text-inverse: #ffffff; + --accent: #FFD208; + --accent-hover: #e0b806; + --accent-muted: rgba(255, 210, 8, 0.15); + --accent-subtle: rgba(255, 210, 8, 0.04); + --accent-glow: rgba(255, 210, 8, 0.2); + + --text-primary: #000000; + --text-secondary: #27272a; + --text-muted: #52525b; + --text-accent: #000000; + --text-inverse: #000000; - --border: #d4d4d8; + --border: #e4e4e7; --border-hover: #a1a1aa; - --border-accent: rgba(9, 9, 11, 0.4); - --border-focus: #09090b; + --border-accent: #FFD208; + --border-focus: #000000; --shadow-sm: 0 1px 3px rgba(0,0,0,0.05); --shadow-md: 0 4px 10px rgba(0,0,0,0.06); --shadow-lg: 0 10px 25px rgba(0,0,0,0.08); - --shadow-glow: 0 0 12px rgba(9, 9, 11, 0.02); + --shadow-glow: 0 0 16px rgba(255, 210, 8, 0.18); - --radial-glow-1: rgba(9, 9, 11, 0.01); - --radial-glow-2: rgba(113, 128, 150, 0.01); - --grid-line: rgba(0, 0, 0, 0.025); + --radial-glow-1: rgba(255, 210, 8, 0.03); + --radial-glow-2: rgba(0, 0, 0, 0.01); + --grid-line: rgba(0, 0, 0, 0.015); } /* ========================================================================== diff --git a/src/app/landing.css b/src/app/landing.css deleted file mode 100644 index 47c60e7..0000000 --- a/src/app/landing.css +++ /dev/null @@ -1,159 +0,0 @@ -/* ============================================================================ - * Landing page stylesheet — Tailwind v4 + brand tokens. - * - * ONLY imported from src/app/page.tsx. The /app/* subtree uses globals.css. - * Palette: warm cream default (light) · gold accent · dark for contrast sections. - * ============================================================================ */ - -@import 'tailwindcss'; - -@custom-variant dark (&:is(.dark *)); - -/* --------------------------------------------------------------------------- - * @theme — design tokens exposed as Tailwind utilities - * -------------------------------------------------------------------------- */ -@theme { - /* Brand gold */ - --color-gold-50: #fff8d4; - --color-gold-100: #fff0a8; - --color-gold-400: #ffdc4d; - --color-gold-500: #ffd208; - --color-gold-600: #e6b800; - --color-gold-700: #a87a00; - - /* Cream scale — warm off-whites for light sections */ - --color-cream-50: #fefdfb; - --color-cream-100: #f8f5f0; - --color-cream-200: #ede9e0; - --color-cream-300: #dcd7cc; - - /* Ink scale — warm blacks/grays */ - --color-ink-50: #fafaf7; - --color-ink-100: #e8e6df; - --color-ink-200: #c8c4bc; - --color-ink-300: #7a7872; - --color-ink-400: #5a5850; - --color-ink-500: #38362f; - --color-ink-700: #1c1b16; - --color-ink-800: #131210; - --color-ink-900: #0a0908; - --color-ink-950: #050504; - - /* Typography — next/font/google injects these CSS vars on */ - --font-display: var(--font-fraunces, 'Fraunces'), Georgia, serif; - --font-sans: var(--font-jakarta, 'Plus Jakarta Sans'), system-ui, sans-serif; - --font-mono: 'JetBrains Mono', ui-monospace, monospace; - - /* shadcn/MagicCard compat — defaults to light; overridden by .section-dark */ - --color-background: #f8f5f0; - --color-border: rgba(15, 14, 12, 0.10); - - /* Motion */ - --animate-aurora: aurora 20s ease-in-out infinite alternate; - --animate-marquee: marquee var(--duration, 30s) linear infinite; - --animate-marquee-vertical: marquee-vertical var(--duration, 30s) linear infinite; - --animate-shimmer-slide: shimmer-slide var(--speed, 2s) ease-in-out infinite alternate; - --animate-spin-around: spin-around calc(var(--speed, 2s) * 2) infinite linear; - --animate-shine: shine var(--duration, 8s) ease-in-out infinite; - --animate-grid: grid 15s linear infinite; - --animate-border-beam: border-beam calc(var(--duration, 8s) * 1s) infinite linear; - --animate-blink-cursor: blink-cursor 1.2s step-end infinite; -} - -/* --------------------------------------------------------------------------- - * Keyframes - * -------------------------------------------------------------------------- */ -@keyframes aurora { - 0% { background-position: 0% 50%; transform: rotate(-5deg) scale(0.9); } - 25% { background-position: 50% 100%; transform: rotate(5deg) scale(1.1); } - 50% { background-position: 100% 50%; transform: rotate(-3deg) scale(0.95); } - 75% { background-position: 50% 0%; transform: rotate(3deg) scale(1.05); } - 100% { background-position: 0% 50%; transform: rotate(-5deg) scale(0.9); } -} -@keyframes marquee { - from { transform: translateX(0); } - to { transform: translateX(calc(-100% - var(--gap, 1rem))); } -} -@keyframes marquee-vertical { - from { transform: translateY(0); } - to { transform: translateY(calc(-100% - var(--gap, 1rem))); } -} -@keyframes shimmer-slide { - to { transform: translate(calc(100cqw - 100%), 0); } -} -@keyframes spin-around { - 0% { transform: translateZ(0) rotate(0); } - 15%, 35% { transform: translateZ(0) rotate(90deg); } - 65%, 85% { transform: translateZ(0) rotate(270deg); } - 100% { transform: translateZ(0) rotate(360deg); } -} -@keyframes shine { - 0% { background-position: 0% 0%; } - 50% { background-position: 100% 100%; } - 100% { background-position: 0% 0%; } -} -@keyframes grid { - 0% { transform: translateY(-50%); } - 100% { transform: translateY(0); } -} -@keyframes border-beam { - 100% { offset-distance: 100%; } -} -@keyframes blink-cursor { - 0%, 49% { opacity: 1; } - 50%, 100% { opacity: 0; } -} - -/* --------------------------------------------------------------------------- - * Landing root — light cream default. Never bleeds outside .landing-root. - * -------------------------------------------------------------------------- */ -.landing-root { - font-family: var(--font-sans); - background: var(--color-cream-100); - color: var(--color-ink-900); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - min-height: 100vh; -} - -.landing-root ::selection { - background: var(--color-gold-500); - color: var(--color-ink-950); -} - -.landing-root h1, -.landing-root h2, -.landing-root h3 { - font-family: var(--font-display); - letter-spacing: -0.02em; -} - -/* Dark variant — used on FHE explainer, final CTA, footer */ -.section-dark { - --color-background: #050504; - --color-border: rgba(255, 255, 255, 0.08); -} - -/* Grain overlay for hero only */ -.landing-grain::before { - content: ''; - position: fixed; - inset: 0; - pointer-events: none; - z-index: 1; - opacity: 0.03; - mix-blend-mode: multiply; - background-image: url("data:image/svg+xml;utf8,"); -} - -/* Gold rule divider */ -.landing-rule { - height: 1px; - background: linear-gradient( - to right, - transparent 0%, - var(--color-gold-500) 50%, - transparent 100% - ); - opacity: 0.4; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b993e2b..499c73d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -35,19 +35,19 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - +