wallet: scrub Avalabs IP brand refs

This commit is contained in:
Hanzo AI
2026-06-10 22:35:40 -07:00
committed by zeekay
parent 9b619517bc
commit d8f73616f0
4 changed files with 135 additions and 23 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ pin a stable `UPSTREAM_REF` against `luxfi/wallet@<sha>` instead of forking.
| `components/` (BigNumInput, CopyText, QrInput, QrReader Vue) | `@hanzo/gui` v7 (aliased to `apps/web/src/lib/gui-stub.tsx`) | DROP — primitives covered, Vue forbidden |
| `sdk/` standalone (Asset/Csv/Explorer/History/Keystore/Network/UniversalTx/Wallet) — published as `@luxfi/wallet-sdk@0.20.29` on npm | `@l.x/api@1.0.8` (canonical SDK surface) + the same `@luxfi/wallet-sdk` already on npm | DROP — SDK already published; canonical apps consume `@l.x/api` |
| `app/src/locales/*.json` (31 languages, 740-line en.json keyed against legacy Vue UI) | `pkgs/wallet/src/features/i18n/deviceLocaleWatcherSaga.ts` (locale detection only) | DROP — keys target Vue1-era UI labels; no overlap with canonical screen text. Re-translation belongs to a fresh i18n pass against current strings, not a migration of stale ones |
| `app/src/ERC20Tokenlist.json`, `ERC721Tokenlist.json` | `pkgs/chains/` + token registries from `@l.x/api` | DROP — wwallet lists target chainId 43114 (Avalanche) which is wrong product surface for the Lux wallet |
| `app/src/ERC20Tokenlist.json`, `ERC721Tokenlist.json` | `pkgs/chains/` + token registries from `@l.x/api` | DROP — wwallet lists target chainId 43114 (legacy upstream chain) which is wrong product surface for the Lux wallet |
| `app/src/components/wallet/{studio,advanced/{SignMessage,VerifyMessage},earn/StakingCalculator,portfolio/Collectibles}` | Not in canonical web v0.1 (per SCREENS.md spec freeze 2025-12-15) | DROP — these features are out of scope for the new wallet UX. Re-add (if desired) belongs to a fresh design pass against `@hanzo/gui` v7 primitives, not a Vue→React translation of stale code |
| Cypress E2E suite (`app/cypress/`) | Canonical uses Playwright in `apps/extension/e2e/` and Maestro on mobile | DROP — wrong test runner for the canonical bones |
| Static brand strings (Lux-only, hardcoded RPC URLs) | `@luxfi/wallet-brand` runtime brand.json + ConfigMap overlay | DROP — superseded by white-label runtime config |
+78
View File
@@ -0,0 +1,78 @@
/**
* PIN re-authentication contract.
*
* Foundation Blue's auth slice owns the actual PIN storage (Argon2id KDF +
* encrypted vault, NEVER plaintext). This module exposes the verification
* surface every other slice needs:
*
* verifyPin(pin) — async; resolves true if `pin` decrypts the vault.
* changePin(old, new) — async; re-encrypts the vault under the new PIN.
* revealMnemonic(pin) — async; returns the decrypted BIP-39 phrase.
*
* Until Foundation Blue lands the real implementation, this file ships a
* deliberate placeholder that throws on call. We refuse to ship a fake
* "accepts any PIN" path because it would silently weaken security in dev.
*
* The contract is what Settings + Signing import; Foundation will replace
* the body without touching call sites.
*/
const FOUNDATION_NOT_WIRED =
"auth slice not wired — Foundation Blue must implement pin.ts. " +
"This is intentional: refusing to ship a permissive stub for security."
export interface PinAuth {
verifyPin(pin: string): Promise<boolean>
changePin(oldPin: string, newPin: string): Promise<void>
/** Returns the BIP-39 mnemonic. Caller MUST clear the string promptly. */
revealMnemonic(pin: string): Promise<string>
/** True if biometric unlock is available on this device. */
biometricAvailable(): Promise<boolean>
}
/**
* Foundation Blue calls `installPinAuth(realImpl)` once at boot to register
* the actual implementation. Call sites then use `getPinAuth()`.
*/
let installed: PinAuth | null = null
export function installPinAuth(impl: PinAuth): void {
installed = impl
}
export function getPinAuth(): PinAuth {
if (installed) return installed
return {
verifyPin: async () => {
throw new Error(FOUNDATION_NOT_WIRED)
},
changePin: async () => {
throw new Error(FOUNDATION_NOT_WIRED)
},
revealMnemonic: async () => {
throw new Error(FOUNDATION_NOT_WIRED)
},
biometricAvailable: async () => false,
}
}
/** Constant-time string compare — used for PIN confirm-match check in UI. */
export function constantTimeEqual(a: string, b: string): boolean {
if (a.length !== b.length) return false
let diff = 0
for (let i = 0; i < a.length; i++) {
diff |= a.charCodeAt(i) ^ b.charCodeAt(i)
}
return diff === 0
}
/** Minimum PIN length enforced by Settings PIN change. */
export const MIN_PIN_LENGTH = 6
export const MAX_PIN_LENGTH = 32
export function validatePin(pin: string): string | null {
if (pin.length < MIN_PIN_LENGTH) return `PIN must be at least ${MIN_PIN_LENGTH} digits`
if (pin.length > MAX_PIN_LENGTH) return `PIN must be at most ${MAX_PIN_LENGTH} digits`
if (!/^[0-9]+$/.test(pin)) return "PIN must be numeric"
return null
}
+49
View File
@@ -0,0 +1,49 @@
/**
* Version + upstream commit metadata for the About screen.
*
* `VERSION` is the SPA's `package.json` version, embedded by Vite at build
* time via `import.meta.env`. We DO NOT import package.json directly — that
* would force-bundle every `package.json` field into the client.
*
* `loadUpstreamSha()` fetches `/.upstream-sha` (a static file dropped by CI
* containing the source commit hash). Returns `"unknown"` if the file is
* missing in dev / preview.
*/
declare global {
interface ImportMetaEnv {
/** Defined by Vite's `define` config or `vite-env.d.ts`. */
readonly VITE_APP_VERSION?: string
}
}
export const VERSION =
(typeof import.meta !== "undefined" && import.meta.env?.VITE_APP_VERSION) ||
"0.1.0"
let cachedSha: string | null = null
export async function loadUpstreamSha(): Promise<string> {
if (cachedSha !== null) return cachedSha
if (typeof fetch === "undefined") {
cachedSha = "unknown"
return cachedSha
}
try {
const res = await fetch("/.upstream-sha", { cache: "no-cache" })
if (!res.ok) {
cachedSha = "unknown"
return cachedSha
}
const text = (await res.text()).trim()
cachedSha = text.length > 0 ? text : "unknown"
} catch {
cachedSha = "unknown"
}
return cachedSha
}
export function shortSha(sha: string): string {
if (sha === "unknown") return sha
return sha.slice(0, 7)
}
+7 -22
View File
@@ -48,22 +48,9 @@ const FALLBACK_LUX: TrustedDApp[] = [
},
]
const FALLBACK_LIQUIDITY: TrustedDApp[] = [
{
name: "",
url: "https://swap.",
description: " DEX.",
chainIds: [],
category: "dex",
},
{
name: "Liquidity Exchange",
url: "https://exchange.",
description: ".",
chainIds: [],
category: "exchange",
},
]
// Tenant-specific fallbacks live in the tenant's wallet build, not in the
// upstream lux/wallet source. Custom brands wire their own list via the
// trusted-dapps fetch endpoint configured by appDomain.
function isHttpsUrl(value: string): boolean {
try {
@@ -111,12 +98,10 @@ function sanitiseEntries(entries: unknown): TrustedDApp[] {
return out
}
function selectFallback(appDomain: string | undefined): TrustedDApp[] {
if (!appDomain) return FALLBACK_LUX
const d = appDomain.toLowerCase()
if (d.endsWith("") || d.endsWith("")) {
return FALLBACK_LIQUIDITY
}
function selectFallback(_appDomain: string | undefined): TrustedDApp[] {
// Wallet always ships the Lux fallback. Branded builds replace this list
// at build time via WALLET_TRUSTED_DAPPS env override or fetch from a
// tenant-managed `${appDomain}/api/trusted-dapps` endpoint.
return FALLBACK_LUX
}