Files
zeekay 2e1b7dcaf8 feat: @luxwallet/create — stamp a branded Lux Wallet from one brand.json
Generator that scaffolds a ready-to-run branded Lux Wallet web app for a new
chain/org from a single BrandConfig. One command per new chain.

- CLI `create-lux-wallet <brand-ref> [outDir] [--force]` + programmatic
  generate(brand, outDir): validates the brand via @luxwallet/brand's
  defineBrand, then stamps apps/web/ (Vite + React) that mounts @luxwallet/ui
  via WalletUIProvider, authenticates with @hanzo/iam (HIP-0111), reaches
  chains through @luxwallet/sdk, and ships the brand's /brand.json.
- DRY runtime-brand.json strategy: ONE brand-neutral app shell, byte-identical
  across brands (enforced by test). Only public/brand.json + public/logo.svg
  differ. No per-brand forks. *.tmpl files get {{brand.*}} interpolation.
- Example brands lux/hanzo/zoo/pars with canonical @luxwallet/chains ids
  (lux-c 96369, zoo 200200, hanzo 36963, pars 494949) + _template.json.
- New chains: add to @luxwallet/chains registry, reference id in brand.chains[].
- MIT, zero GPL — never imports @luxfi/wallet. @luxwallet/* + @hanzo/* are
  workspace deps with a documented switch to npm versions once published.

Verified headlessly: CLI tsc --noEmit clean; 7/7 node:test pass (tree,
brand.json validity via defineBrand, no token leak, DRY shell identity, force,
resolution); sample generation of all four brands validates.
2026-06-23 15:28:28 -07:00

87 lines
3.6 KiB
Cheetah

# {{brand.name}}
A branded [Lux Wallet](https://github.com/luxwallet) web app for **{{brand.name}}**
(`{{brand.id}}`), generated by [`@luxwallet/create`](https://github.com/luxwallet/create).
This is a thin Vite + React shell that mounts `@luxwallet/ui` screens, authenticates
with Hanzo IAM via `@hanzo/iam` (HIP-0111), and reaches chains through `@luxwallet/sdk`.
**The shell is brand-neutral** — everything brand-specific lives in
[`public/brand.json`](./public/brand.json), loaded at runtime by
`@luxwallet/brand`'s `loadBrandConfig()`. To re-brand, edit that one file (and
`public/logo.svg`); never fork the app.
## Prerequisites
> The `@luxwallet/*` and `@hanzo/*` packages are **not yet published to npm**.
> Until they are, install them as workspace/path deps:
>
> - In a pnpm monorepo: set each to `"workspace:*"` in `package.json`.
> - Standalone: use `"file:../path/to/sdk/packages/<pkg>"` etc.
>
> The versions pinned in `package.json` are the (future) npm versions to switch
> to once published. See the `//deps` note in `package.json`.
## Run
```bash
pnpm install # or npm install
pnpm dev # Vite dev server on http://localhost:5174
```
## Build (static export)
```bash
pnpm build # → dist/
pnpm preview # serve the production build locally
```
`dist/` is a static SPA. Deploy it to any static host (GitHub Pages, S3 +
`hanzoai/static`, etc.). The host must serve `index.html` for unknown routes so
the IAM callback path (`/auth/callback`) and client-side routing work.
## IAM registration (one-time, per brand)
Register an IAM application (HIP-0111) with:
- **client_id**: `{{brand.iam.clientId}}` (`<org>-<app>`)
- **redirect URI**: `https://<your-deploy-host>/auth/callback` (exact match)
- **scopes**: `openid profile email`
The superuser convention is `z@{{brand.domain}}` / `Ilove<App>2026!!`.
Secrets live in KMS — never in this repo.
## Brand config
[`public/brand.json`](./public/brand.json) is the validated brand. Its shape is
the `BrandConfig` from `@luxwallet/brand`:
| field | meaning |
|------------------|-------------------------------------------------------------|
| `id` | stable brand id (`{{brand.id}}`) |
| `name` | display name (`{{brand.name}}`) |
| `shortName` | compact label, e.g. "Continue with `{{brand.shortName}}`" |
| `domain` | primary domain (`{{brand.domain}}`) |
| `iam` | OIDC `serverUrl` + `clientId` + `scopes` |
| `gateway` | `rpcBaseUrl`; chains reached at `<rpcBaseUrl>/v1/rpc/<id>` |
| `theme` | token → color, applied as `--lw-<token>` CSS vars |
| `chains` | chain ids from `@luxwallet/chains` to enable |
| `logo` | optional logo URL (defaults to `/logo.svg`) |
## Adding a chain
Chains are defined ONCE in `@luxwallet/chains` (the registry), not here. To add a
new sovereign-L1 chain to this wallet:
1. Add the chain's entry to the `@luxwallet/chains` registry (id, evmChainId,
gateway `rpcRoute`, BIP-44, native asset).
2. Reference its **id** in `public/brand.json`'s `chains[]`.
Then `@luxwallet/sdk` resolves its RPC via the brand gateway automatically.
## Web3 wallet (SIWx) login — optional
The chain picker in `src/Login.tsx` drives the multi-chain SIWx flow handled by
`@luxwallet/connect` (EVM / Solana / Bitcoin / TON / XRP). That package is an
optional peer dep and is **not installed by default**. To enable it, add
`@luxwallet/connect` and follow the TODO in `src/Login.tsx`.