# Changelog All notable changes to Vigil will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [0.7.14] - 2026-07-20 ### Added - **Vigil tells you when a new version is out.** Once per release, a single toast names the version and the exact command for how *you* installed Vigil (Homebrew or the install script) — it never updates itself, downloads anything, or nags twice for the same version. Turn it off with `VIGIL_NO_UPDATE_CHECK=true`. - **Order alerts reach you outside the terminal.** When a limit or trailing order triggers while Vigil is in a background window or another tmux pane, your terminal raises a desktop notification. It stays quiet while you are actually looking at Vigil, and Settings has a Notifications switch to turn it off entirely. - **A crash no longer leaves a wall of stack trace.** If something goes wrong, Vigil shows a readable crash screen with the error, a copy-the-report button, and the choice to restart or quit — it uses its own colours so it still renders even if the theme is what broke. - **Animations switch.** Settings can turn off spinners and effects (they degrade to static marks) for slow SSH sessions, screen readers, or recordings. - **Steadier loading.** Short waits no longer flash a spinner for a frame; when a spinner does appear it stays long enough to read. Orders that are executing right now show a spinner in the list. ### Fixed - **Closing the terminal no longer kills your background orders.** The daemon was started inside the terminal's own process group, so the hangup the terminal sends on close took it down with no graceful shutdown — limit, DCA and trailing monitoring simply stopped, and a stale lock file was left behind. It now runs in its own session, which is what "runs while you're away" was supposed to mean all along. - **A stale background daemon can no longer outlive an update.** The daemon reports its version, and a freshly updated Vigil replaces a daemon still running the old build instead of talking to it. A daemon that is alive but not answering is left alone rather than killed, and Vigil refuses to signal a process whose identity it cannot confirm. ## [0.7.13] - 2026-07-18 ### Added - **Trailing orders have a full home now.** A new Trailing list in the sidebar and a detail view — inspect entry/peak/trigger prices and cancel from either screen. Cancelling is refused while an order is mid-execution, so you can never yank an order the executor has already claimed. - **Order wizards ask how you want to execute.** Creating a limit or trailing order now includes an execution-mode step (automatic, notify-only — plus confirm-first for limit orders) and a slippage budget; limit orders also gain new expiry choices (6 hours or a custom date). - **Live order lists.** The Orders and DCA screens refresh in the background every 5 seconds without flicker or cursor jumps, and gained status filters, DCA-slice chips and on-hold markers. - **Send shows what will happen before you sign.** The review step estimates the network fee (with USD where pricing exists), and the confirm step warns when a dry-run predicts the transaction would revert. - **Swap protects you more.** Token approvals ask for explicit consent instead of approving silently; your slippage choice is enforced end-to-end; a notice asks you to re-review the amounts whenever the quote auto-refreshes; max-fill leaves gas headroom on native swaps. ### Fixed - **Creating orders from the wizards works.** The wizards built asset identifiers the daemon rejects (limit/DCA) or the price monitor cannot price (trailing — the order would sit forever without triggering). - **Trailing orders now execute after any unlock.** The trailing executor only started after creating a wallet or a Ledger unlock — a normal password unlock never started it. - Daemon errors render as their actual message instead of `[object Object]`. - Amount fields no longer accept `.`, `1.` or pasted non-numbers. - The daemon validates trailing-order creation — malformed orders are rejected with a clear error instead of being stored dead. - When several confirm-mode orders trigger together they now queue — the second one used to be silently lost. - Layout: the DCA cancel prompt showed no text, the limit-order confirm step overflowed 80×24, 24-word backup phrases overflowed small terminals, and the sidebar now scrolls instead of pushing Lock off-screen. ## [0.7.12] - 2026-07-05 ### Fixed - **Creating a wallet no longer crashes.** A reactive loop fired the moment a new wallet's chains connected, threw "Maximum call stack size exceeded", and left creation stuck — it now completes and lands on your dashboard. - **Screens no longer blank out.** On the current renderer a text element nested inside another crashed the screen into an empty state — this hit the Theme picker (blanked the instant you switched a theme), wallet **Unlock** (unlocking was broken), and the Orders / DCA / Portfolio-history empty screens. Fixed across all of them. - Creating a wallet or connecting chains can no longer hang: every background daemon request and per-chain address lookup is now bounded by a timeout, so an unreachable daemon degrades gracefully instead of freezing the flow. - The password minimum is now **8 characters**, matching what the screen always advertised — it was silently enforcing 12 and rejecting valid 8–11 char passwords. - Dropped a chain from the picker that could not actually be used. ### Changed - **Redesigned the create-wallet flow.** Show/hide password, a live requirements checklist with an estimated time-to-crack and a green "passwords match" indicator, a clearer recovery-phrase and verification step (it now starts on the first requested word), a chain picker with fuzzy search and select-all, an honest review screen (Verified vs Skipped for burner wallets), and an animated "creating → ready" moment. The step bar and content scale to your terminal width. - Password strength: the character classes (upper/lower/number/symbol) are now advisory — they raise the strength meter and the shown crack-time but no longer block — so a quick burner wallet can use any 8+ character password. Length and the breach-list check remain the hard requirements. ### Landing - Rewrote the feature overview at vigil.r5n.dev in plain language so it reads cleanly instead of scrolling sideways, and replaced the feedback mailto link with an in-page form. ## [0.7.11] - 2026-07-03 ### Changed - **Installed releases transact on mainnet out of the box.** The mainnet-execution gate now defaults ON in compiled release binaries — a shipped wallet should not need a hidden switch to do its job. The Settings → Mainnet Execution toggle is the opt-out (an explicit OFF is persisted and honored over the release default), and source/dev runs keep the testnet-only default so development never broadcasts real value by accident. `VIGIL_MAINNET_EXECUTION` is now a two-way operator override: `true`/`1` forces ON, `false`/`0` forces OFF (the escape hatch for headless/CI deployments). Every ambiguity still fails closed — a corrupt settings file or an unrecognized env value never enables broadcasting. - The gate has a single implementation in `@vigil/core`, evaluated by the daemon, the TUI gates and the TESTNET ribbon alike (previously two hand-mirrored copies that could drift). ## [0.7.10] - 2026-07-03 ### Added - **Mainnet execution can be enabled from Settings.** A persisted `mainnetExecutionEnabled` opt-in joins the `VIGIL_MAINNET_EXECUTION` env override (the env var still wins, so existing deployments are unaffected). Both sources fail closed — a missing or corrupt settings file reads as OFF — and the TUI and daemon derive the gate from the same sources, so the global TESTNET ribbon updates the moment the toggle changes, no restart needed. - **Portfolio prices survive restarts and rate limits.** Last-known-good token prices are persisted to a display-only on-disk cache and hydrated at boot; when CoinGecko's keyless tier rate-limits a fetch, the portfolio falls back to the cached price with its age surfaced instead of flashing $0. Cached prices never feed order execution, alerts, or any gated price path — those stay dual-source and fail-closed in the daemon. - **Scheme-allowlisted external-link opener.** Explorer and tx links open via the OS default handler behind an http(s)/mailto allowlist, so an attacker-influenced string (tx memo, pasted link) can never launch `file:`, `javascript:`, `data:` or app-protocol handlers. ### Changed - **Workspace layout**: vigil's own packages moved to `packages/vigil/*` and the vendored wick SDK to `packages/wick/*` (plus the new `@vigil/swap-exec` execution-bridge package). Release, CI, Docker and build tooling were realigned for the move — Touch ID helper build path, version-bump globs, Docker manifest copies, the CI wick-heal step and the SwapKit integration-test path. `bun type-check` is ~6× faster, with `bun type-check:tsc` as the classic fallback. Every tsconfig now declares `"types": ["bun", "node"]` explicitly (TypeScript 6 stopped auto-loading `@types/*`), per-package configs type-check standalone, and `apps/*/build.ts` + `drizzle.config.ts` joined the checked program. - The TUI mounts the dashboard/status chrome once above every screen instead of per-screen, fixing terminal-too-small height accounting. ### Fixed - The dependency tree audits clean (`bun audit`: 0 advisories): `ws`, `uuid`, `@babel/core` and `file-type` are held past their advisories, dead `axios`/`undici` overrides were dropped, and `solid-js` is deduplicated at a single 1.9.14 copy. ## [0.7.6] - 2026-07-02 ### Fixed - **Solana swaps quote again.** Jupiter sunset its old public API host — `quote-api.jup.ag` no longer resolves in DNS — which silently killed every Solana same-chain swap quote. The adapter now targets the current free-tier endpoint (`lite-api.jup.ag/swap/v1`, serving the v6-compatible schema), verified with a live SOL→USDC quote through the production router. ### Added - **Live-money smoke harness** (`scripts/live-tests`): one CLI driving the production wallet/swap/daemon entry points end-to-end against a funded throwaway wallet — read-only by default, `LIVE_FIRE=1` to arm anything that moves funds (developer tooling). - **Non-blocking SwapKit live-integration CI job** and project Zed settings pinning format-on-save to the exact `bun lint` output. ## [0.7.5] - 2026-07-02 ### Fixed - **The background daemon starts from installed binaries again.** Since v0.7.0 every brew/npm install failed daemon startup with "Can't find meta/\_journal.json": the Drizzle migrations folder was resolved via `import.meta.dir`, which points inside the compiled bundle where the folder does not exist — and the TUI's autospawn swallowed the error. Limit orders, price monitoring, and the SwapKit settlement tracker were effectively dead for binary installs. Migrations are now embedded into the executable and materialized into the data dir at startup; a guard test keeps the embedded set byte-identical to the source folder. ### Added - **Non-blocking SwapKit live-integration CI job** (develop pushes only, never PRs) exercising the SwapKit-API adapter against the real service. - **Project Zed settings**: format-on-save now routes through the exact `bun lint` biome command, so the editor and the pre-commit hook can no longer disagree. ## [0.7.4] - 2026-07-02 ### Fixed - **Ambiguous swap results no longer display as success.** An execution whose broadcast produced a known tx hash but whose confirmation failed or timed out now renders an UNCONFIRMED result — the hash plus a verify-on-chain-before-retrying warning — instead of "Swap executed". - **Send: a validated amount is immutable on the review step.** The send machine accepted amount edits while on review without re-running the exact-decimal balance bound; no shipped UI path dispatched them, but the machine contract now refuses the event (fail-closed). - **Limit orders: the confirm screen shows exactly what goes on the wire.** `expiresAt` is snapshotted when the expiration is selected; previously the wire value was recomputed at submit time and drifted from the displayed expiry by however long the user dwelled on confirm. ### Changed - Post-migration cleanup: dropped dead dependencies (`@xstate/solid`, `node-pty`, unused `@wick/*` entries in the daemon) and orphaned helpers; the e2e fixtures and stale comments were tidied up. ## [0.7.3] - 2026-07-02 ### Fixed - **Import Wallet works again.** v0.7.2 shipped the Import wizard stuck on its first step: the XState pilot used `@xstate/solid`'s `useMachine`, whose mount-deferred start left screens frozen on their initial state under the OpenTUI renderer. All screens now use a synchronous-start hook (`useScreenMachine`). - **Unlock hardening.** The TOTP requirement gates on truthy metadata again (a strict boolean compare could skip the second factor for legacy/hand- edited metadata files); Esc during an in-flight TOTP/recovery verification now always wins — previously the unlock could still fire after cancelling; the lockout countdown no longer restarts on every keystroke; Enter is no longer swallowed during the biometric availability probe. - **Ledger connect can be abandoned.** Esc during the (unbounded) on-device wait returns to the connect step; a late-resolving session is disposed instead of resurrecting the flow. - **Create Wallet backup-skip arming resets** when re-entering the verification step, so skipping always takes two deliberate presses. ### Changed - **The whole TUI now runs on XState v5 state machines** — router, onboarding wizards (Create/Import/Ledger), Unlock, Forgot/Change Password, Export/Delete Wallet, TOTP and biometric setup, Address Book, RPC settings, the Send/Swap/Receive panels, and the limit/DCA/trailing order forms — with ~250 new unit tests pinning flow, validation, and fail-closed behavior. - **About / FAQ / Changelog redesigned** as centered cards; the in-app changelog shows real per-release notes (0.1.0 → current) and scrolls. - **Releases are gated on documentation:** `prepare-release` refuses to bump to a version that is not documented in both `CHANGELOG.md` and the in-app changelog. - CI actions bumped off deprecated Node 20 (checkout v7, setup-bun v2.2.0). ## [0.7.2] - 2026-07-01 ### Fixed - **About / FAQ / Changelog open before unlock.** They were bounced back to the welcome screen because the lock-redirect allowlist omitted them. - **Send is usable again.** The recipient step advanced to the wrong step, so Enter never validated the address or moved on — Send was stuck at the recipient field. - **Portfolio balance list uses the full panel** instead of half of it. - **Quitting no longer stacks screen layers.** The welcome screen's vignette effect was re-added on every visit and never removed. - **Dashboard key handling.** `Esc` inside a panel no longer both rewinds a step and steals focus; the visible panel is focused on small screens; and `q`/`w` can no longer interrupt an in-progress send/swap. ### Changed - **Onboarding wizards are centered** (Name/Create/Import/Reset) as a constrained card rather than sprawling edge-to-edge. - **A too-small terminal shows a resize prompt** instead of a garbled frame. - **Send / Receive chain pickers scroll** when many chains are connected. - Website is shown as `vigil.r5n.dev` throughout; the (private) GitHub links were removed from the About and Feedback screens. ## [0.7.1] - 2026-07-01 ### Fixed - **Terminal is restored on exit.** Quitting the TUI (the Quit menu item, `Ctrl+C`, or `SIGTERM`) now tears the OpenTUI renderer down before the process exits, leaving the alternate screen and disabling mouse tracking. Previously every quit path called `process.exit()` directly — which does not fire OpenTUI's own cleanup, and whose `SIGINT`/`SIGTERM` handler pre-empted OpenTUI's — so the terminal was left with residual UI on screen and scroll events spewing escape codes into the shell. ## [0.7.0-beta.1] - 2026-06-25 > **Product-readiness release.** v0.7 replaces the remaining mocked > surfaces with real, audit-verified implementations: Swap, Send, > Receive, DCA and trailing-order creation now move real value (subject > to the mainnet fail-closed guard below). WalletConnect was removed > entirely. Mainnet swap/send execution remains **fail-closed to > testnet/stagenet by default** — set `VIGIL_MAINNET_EXECUTION=true` to > opt in. ### Added - **Real Send / Receive flows.** Native transfers with real broadcast; Receive shows a QR plus the per-chain address and auto-clears the copied address 30s after copy. Send resolves ENS / `.eth` / `.sol` names to addresses. - **Real cross-chain Swaps (`SwapPanel`).** Live quote + execute via the Wick SDK swap router, multi-protocol routing (Chainflip, Harbor/Maya, NEAR-intents, Wick, SwapKit-API), on-chain / non-custodial settlement, with slippage-tolerance display, quote-expiry guard, and a decimals-safety refusal. Replaces the previous deceptive mock panel. - **DCA and trailing-stop order creation.** Dollar-cost-average orders and trailing-stop orders join limit orders (price triggers above/below/equal) with real create flows wired through the daemon. - **Receipt verification of fills.** Executed orders verify the settlement against the expected destination address + amount per chain family before they are marked filled. - **Optional TOTP 2FA (RFC-6238).** At-rest encrypted, enforced at unlock; disabling it requires re-authentication. - **Optional biometric unlock** backed by the OS Keychain. - **Ledger hardware signer (EVM app only).** node-hid transport, no Electron. EVM chains only — not UTXO / Solana / Cosmos. - **EIP-712 typed-data signing** (`eth_signTypedData_v4`). - **Public keyless RPC defaults** so a fresh install works without per-chain RPC configuration. - **Portfolio snapshot + tax export (CSV).** - **`vigil daemon start|stop|status` CLI** — the compiled binary now dispatches daemon subcommands, so brew/npm users can manage the background daemon without a source checkout. - **Daemon auto-spawn on TUI boot** — the TUI starts the daemon automatically if it is not already running. Opt out with `VIGIL_NO_AUTOSPAWN=true`. - **`vigil --version`** prints the installed version and exits. - Root `env.example` documenting all supported environment variables. - `.github/` issue templates (bug, security) and a PR template. ### Changed - **Canonical asset-identifier producer.** A single producer now derives asset identifiers across chains, fixing previously broken Send and testnet-swap paths that mis-built identifiers. - Mainnet gate now accepts `VIGIL_MAINNET_EXECUTION=1` as well as `=true`. - Dependency bumps: Biome 2.5.1, undici 7.28 (security override), wrangler 4.104, `@ledgerhq` 1.7.1. - **OpenTUI `--single` cross-platform build fix** so single-file binaries build consistently across targets. - CI now fetches the `wick` submodule and runs audit + lint/knip green. - Docs overhaul for the closed beta: install channels (Homebrew tap, `@r5n/vigil`, direct R2 downloads), Configuration section, corrected keystore location in SECURITY.md, working feedback/vulnerability channel (feedback@r5n.dev), license metadata fixed to the valid SPDX id `FSL-1.1-ALv2`. ### Fixed - **`taxExport` negative-rounding bug.** Negative amounts no longer round the wrong direction in the CSV tax export. ### Security - **Mainnet execution is fail-closed by default.** Swap/send execution targets testnet/stagenet unless `VIGIL_MAINNET_EXECUTION=true` is set explicitly (`mainnetGate` + `testnetGate`); the daemon refuses to broadcast on mainnet otherwise. - **Destination-address settlement verification.** Fills are checked against the expected destination address + amount per chain family. - **SSRF / timeout guards on outbound HTTP.** Outbound `fetch` is bounded by per-host concurrency and request timeouts and rejects SSRF-prone targets. - **TOTP + biometric 2FA** as described above; disabling TOTP requires re-authentication. - **WalletConnect removed entirely.** All WalletConnect / WalletConnect v2 / reown / dApp-signing code was deleted; a Sidebar nav test guards against reappearance. ### Removed - **WalletConnect v2 dApp pairing.** Removed in full — there is no in-app dApp signing surface in v0.7. ## [0.6.1-beta.1] - 2026-05-22 > **Beta gate.** Mainnet-blocking issues from the v0.6 council audit are > closed; this is the first build we recommend for guarded mainnet use > after re-unlocking each wallet (see migration notes below). Three > known limitations are deferred to v0.7 — they are listed under > _Deferred to v0.7_. ### ⚠️ BREAKING - **Wallet HMAC token format changed.** The `X-Wallet-Token` header is no longer a fixed 64-hex string per `(authToken, walletId)`; it is now `${base64url(payload)}.${hmac_hex}` with `payload = { wid, iat, exp, jti }` and a 24h expiry. Existing TUI tokens stop working on the first request after upgrade — users must re-unlock the wallet to mint a new token. The TUI's `getDaemonWalletAuthHeaders` already calls the new minter, so no TUI code change is needed beyond a redeploy. (commit 775ffdb) - **`getWalletScopedToken` is now `mintWalletScopedToken`.** External consumers should rename the call. The function now returns a fresh random-`jti` token every time — do not cache the return value. - **`verifyWalletScopedToken` now returns `WalletTokenVerification`** (a tagged result with `{ ok; jti; exp }` or `{ ok: false; reason }`) instead of a plain boolean. Use `isWalletScopedTokenValid` if you only want the boolean wrapper. ### Added - **`p-limit(4)` recovery concurrency + per-host fetch limiter.** `packages/core/src/concurrency/{limit,perHostLimit}.ts` give the daemon bounded in-flight semantics. Executor's stale-order recovery fans out four at a time; outbound `fetchWithTimeout` calls are bucketed per `URL.origin` with a default 4-concurrent cap, so a recovery sweep can't burst 30+ simultaneous requests at one public RPC and trip a rate-limit. Opt-in: only the daemon entrypoint installs the global limiter. (commit dafb6cc) - **`jti`-bound replay protection on wallet tokens.** Daemon-local bounded FIFO set (10k entries) refuses a second verification of any token already seen this run. Daemon restart invalidates all live tokens anyway, so this lives entirely in process memory. - **`mintWalletScopedToken` / `verifyWalletScopedToken` rejection reasons.** `WalletTokenRejection` is a string-literal union (`format | payload_decode | wid_mismatch | expired | not_yet_valid | signature | replay`) surfaced through the Elysia `walletAuth` middleware so operator logs can distinguish replay vs expired vs signature attempts. - **Backfill migration for `tx_hash_chain`.** `0005_backfill_tx_hash_chain.sql` walks `orders` + `trailing_orders` once and populates the chain column for rows broadcast before v0.6.1 from `sell_asset`. Idempotent. (commit 4b81e0f) - **WalletConnect v2 MVP for EVM dApp connectivity.** Pair from a `wc:` URI, route `eth_sendTransaction` / `personal_sign` / `eth_sign` / `eth_signTypedData_v4` through the TUI confirm flow, sign or reject. Requires `VIGIL_WC_PROJECT_ID` from cloud.reown.com. - **Ledger hardware-wallet integration** through `@wick/signer-ledger`, end-to-end: USB transport open, EVM-address read, on-device confirmation, persisted as `{ derivationPath, address }` metadata. - **ENS + SNS resolution** in TUI address-input flow. - **Coinbase price source** as fallback alongside CoinGecko, with cross-source deviation check (3-confirmation baseline, 50% threshold). - **Default public RPC URLs** for all advertised EVM chains so a fresh install works without environment overrides. - **At-rest encryption** for `~/.vigil/transactions.log` and the per-wallet TOTP shared-secret file (AES-256-GCM, HKDF-derived per-domain keys). - **Hyperliquid integration via Wick SDK** restored after 0.3.0 removal — `hyperliquidChainSetup` wired into TUI + API, `createHyperliquidAdapter` plugged into `buildSwapRouter`. - TUI headless boot harness gated by `VIGIL_E2E=1` sentinel. - `/health/wick` endpoint exercising every chain setup per-request so operators can detect broken transports per chain. ### Changed - Bumped Wick submodule through several develop snapshots — Hyperliquid testnet integration, swap adapter, smoke scripts, network hardening, bittensor SS58, NFT + simulation v2. - WalletConnect handler L2 gas fallback now per-chain instead of a global constant. - CI builds via `bun run build:ci` (single-target) instead of full cross-compile during PR runs. ### Fixed - **OpenTUI text-bleed sweep across 9 TUI screens** (commits bed0776, 56b6258, d67dfc5). Three classes of bug: - Crash: nested `` inside `` raises `TextNodeRenderable only accepts strings...` — found in `About.tsx`, `ActivityDashboard.tsx`, `PortfolioHistory.tsx`. Fixed by flattening to sibling text nodes inside ``. - Render bleed: adjacent `` children of a column `` collapse into a single TextNode (line boundaries vanish, "Unlock with your PIN" → "UnlocktwithgyouriPINSB"). Fixed by wrapping each `` in ``. Applied to `CreateLedgerWallet`, `CreateWallet`, `BiometricSetup`, `TotpSetup`, `ChangePassword`, `DashboardPortfolio`. - Cell collapse: side-by-side `` without `flexDirection="row"` (`"01."` + `"mechanic"` → `"0mechanic"`) — fixed in the phrase grid on `CreateWallet`. - **Recovery-phrase backup defaults to 24 words** (was hardcoded 12). Press `[T]` on the Backup step to toggle 12 ⇄ 24. Verify step regains the "skip" affordance from v0.1: `[S]` arms a warning, `[S]` again skips ("burner wallets only — not recommended for funds"). - API daemon logger drain + test isolation: async buffered log writes flush on shutdown and do not leak between tests. - `apps/api/src/services/price.ts` primary/fallback branching now uses `ts-pattern .match()` instead of nested `if`s. - `@walletconnect/*` namespace-imported as CJS to avoid the dual-module reload bug. ### Security - **Mainnet policy enforced at the service layer**, not just at the TUI gate. Route-level explicit assert added for body-less endpoints. (commit 569d2da) - **Constant-time auth comparison** with length padding; key buffers zeroized after use. - **EIP-55 address enforcement** via Wick's `getEvmAddress` — lowercase legacy fixtures still parse, but typed input is checksum-validated. - **Bounded `fetchWithTimeout`** with jittered backoff (1s baseline, rate-limit-friendly) + retry budget + caller signal propagation; receipt verifiers can no longer hang indefinitely on a slow RPC. - **PBKDF2 phrase fingerprint v2** with salt + iteration count, automatic v1 → v2 migration on first unlock. - **HKDF-separated wallet HMAC key** so a stolen at-rest key from one domain cannot decrypt another. ### Deferred to v0.7 - **Schema `REAL` → `TEXT` migration for price columns** (`triggerPrice`, `fillPrice`, `lastPrice`, trailing prices). Closing the IEEE-754 risk for trigger comparisons spans 9 columns and ~50 callsites; deferred to reduce beta blast-radius. - **Reorg watchdog** for filled orders + `settlement_tx_hash` / `settlement_chain` columns for THORChain outbound observation. - **State-machine invariant `executing IFF executionNonce`** as a schema CHECK constraint — the production `acquireExecutionLock` path legitimately attaches a nonce to `'triggered'`, so the invariant needs an audit before it can be enforced at the DB layer. ### Migration If you are upgrading from `0.5.3`: 1. Stop the daemon and the TUI. `0.5.x` binaries have no daemon subcommand — stop the old daemon by killing the PID recorded in `~/.vigil/daemon/daemon.pid` (e.g. `kill "$(cat ~/.vigil/daemon/daemon.pid)"`). From this release onward, `vigil daemon stop` does this for you. 2. Upgrade via your install channel: - Homebrew: `brew upgrade r5n-labs/tap/vigil` - bunx/npx: `bunx @r5n/vigil@latest` - From source (private repo access): `git pull && git submodule update --init && bun install && bun run build` 3. Restart the daemon and re-unlock each wallet in the TUI. Outstanding `X-Wallet-Token` headers from the old format will return `403` with `reason: signature`. 4. Existing wallet metadata, encrypted seeds, TOTP secrets, and the transactions log are unchanged. No data migration is needed. 5. If you maintain custom scripts that call the daemon directly, rebuild any cached `X-Wallet-Token` via `mintWalletScopedToken({ walletId })` instead of the removed `getWalletScopedToken`. ## [0.5.3] - 2026-04-22 ### Added - **On-chain receipt verifiers** for UTXO (via Blockchair REST), Solana (`getSignatureStatuses`), and Cosmos (Cosmos REST) — each wired into the receipt router with chain-slug coverage and error-path tests. - `/v1/orders/:id/executed` flow now persists `txHashChain` for cross-chain receipt verification. - `__setAuthTokenLoaderForTests` / `__setPriceClientForTests` / executor tracker-client injection seams so test code no longer needs `mock.module(@vigil/core)` cascades. - Hot-rotation of `AUTH_TOKEN` via mtime-cached file re-read (no daemon restart required for rotation). - CoinGecko price client (replaces null-stub). - Legacy `@wick/wallet` keystore importer for migrating wallets from pre-Wick-rebrand vintages. - SwapKit-API tracker wired into order executor. - `@wick/tokens` registry wired into `createWick`; executor uses per-asset decimals instead of falling back to NATIVE. ### Changed - **Migrated to Wick 0.x post-rebrand**: dropped the SwapKit API surface; chain wiring goes through the per-package `{chain}ChainSetup` factories. - `/sync` barrel split out of `/testing` so production code no longer imports the test surface. - Single shared `Transport` instance between toolbox + swap router. - Bumped otpauth, biome, @types/bun, typescript to latest patches. ### Fixed - EIP-55 enforcement on Ethereum-family addresses. ## [0.5.0] - 2026-04-22 ### Added - **Trailing orders**: trailing stop and trailing take-profit order types, plus monitor service and REST routes. - **DCA orders**: recurring-order schema, types, DB functions, monitor wiring, and API routes. - Triggered-order query / endpoint for notify/confirm flows. - Confirm-mode approval flow from trigger to execution. - `mainnetGate` middleware enforcing `VIGIL_MAINNET_EXECUTION`. - Atomic CAS `claimExecutionIntent` / `releaseExecutionIntent` for exclusive execution. - HTTP-based execution lock — TUI stops writing directly to the daemon SQLite database. - Secondary on-chain receipt verification (tracker + RPC cross-check) for the executor. - Promoted `withTimeout` into `@vigil/core`; wraps executor tracker calls. - Persisted price-anomaly baselines across daemon restarts; baseline staleness rejected past 24h on load. - Send/Receive panels enabled in navigation; SendPanel dashboard wired to real transfer execution; fee-estimation display and max-balance warning. - Direct swap execution with quote preview. - Transaction-hash audit trail for sends and swaps. - Dashboard redesign (sidebar, content header, portfolio) to match design mocks. - ForgotPassword screen with phrase-based password reset. - ChangePassword and DeleteWalletConfirm screens. - ExportWallet screen for recovery-phrase re-export. - Auto-lock preference wired into `WalletProvider` timer. - TOTP setup wizard + verification screens; recovery codes. - Touch ID biometric service and setup screen (macOS Swift helper binary). - Responsive breakpoint system with design tokens; multiple screens migrated to responsive variants. ### Changed - **BREAKING**: Wallet-scoped HMAC keys derived via HKDF (RFC 5869) from the auth token using the stable info label `"wallet-hmac"` and salt `"vigil-v1-wallet-scope"`, instead of using the bearer auth token directly as the HMAC key. Existing wallet-scoped tokens are invalidated — re-unlock to mint new tokens. - **BREAKING**: Mainnet policy enforced at the service layer; share testnet registry across boundary checks. - Salted PBKDF2 phrase fingerprint with legacy v1 migration. - `_tag`-dispatched error classification; expanded `AppError` union. - Async execution handlers, atomic CAS, stricter mainnet gate. - Errors surfaced from tracker lookup, wallet-metadata reads, and `txLog` writes (no more silent swallowing). - Phrase removed from wallet state once derivation completes. - Multi-wallet picker on unlock; auto-lock timer and SIGINT cleanup; balance fetch parallelized with `Promise.allSettled`. ### Performance - Logger: async buffered writes; drain on shutdown. - Monitor: batched expired-order transitions into one DB transaction; batched price updates. - Orders: composite DB indexes for `(wallet, status)`, `(execution_status, status)`, `triggered_at`; SQL-level pagination replacing in-memory slicing; cached prepared statement for batch price updates; per-wallet SQL scoping hits composite index. - Rate limiter: eviction reduced from O(3n) to single-pass. - Price client: retry with backoff; bounded cache sizes; debounced baseline persistence with shutdown flush. - `intervalService.start`: start-offset jitter to desync tick boundaries; `stop()` awaits in-flight tick + warns on overrun. - TUI: order execution parallelized with bounded concurrency; EVM orders serialized per chain family to avoid nonce collisions. ### Fixed - TOCTOU race in `updateOrderStatus`. - Stale-execution detection uses `executionStartedAt` (was `executedAt`, always null). - Rate-limit middleware validates forwarded IPs and rejects unknown-IP callers in prod. - Daemon binds to `127.0.0.1` by default inside Docker. - Distinguish password errors from filesystem / corruption errors on unlock. - ENOENT vs real failures on TOTP erase. - Testnet detection uses chain-prefix allowlist (not substring). - Chain-specific address validators for Aptos, Sui, Tron, Cardano, NEAR, Substrate. - Chain-aware UTXO address validation. - Testnet gate on transfer bridge. - Wallet-creation phrase backup verification step. ### Security - Constant-time auth comparison; zeroize key buffers; exact decimal sums. - `eb1e0dd`: SHA-pinned CI actions; self-hosted runner gated to internal PRs. - `c204a69`: forwarded-IP validation in rate limiter. - `539a7a5`: HKDF-derived wallet HMAC keys (see Changed). - Phrase ownership verified before resetting keystore password. - Brute-force counter fix; sensitive signals cleared on unmount. ### Removed - Duplicate `POST /orders/:id/executed` route in favor of nonce-based flow. ## [0.4.0] - 2026-04-05 ### Added - **v0.4 foundation**: execution infrastructure, Eden Treaty client, swap bridge, new screens. - **v0.4 integration**: execution locks, route registration, tests. - Swap bridge wiring, env gate, on-chain receipts. - Wired `Settings` menu navigation and updated coming-soon text. - Order execution engine for triggered limit orders. - Wired portfolio to real wallet balances. - Dashboard sidebar + Send/Receive panels. ### Performance - Parallel order execution with bounded concurrency. - Async `getStoredWallets` with parallel file reads. ### Fixed - Replaced silent catch blocks with diagnostic logging across the codebase. - Restored CORS lockdown to the daemon port (not any localhost port). - `totalUsd` computed from real prices instead of raw token amounts. - Progressive lockout for failed unlock attempts. ## [0.3.0] - 2026-03-28 ### Added - Modern terminal UI with animated splash, redesigned welcome menu, and dashboard-style main menu - R2-based release pipeline (Cloudflare R2 at `releases.r5n.dev`) - Homebrew distribution via `brew tap r5n-labs/tap && brew install vigil` - npm/bun distribution via `bunx @r5n/vigil` ### Changed - Complete UI rewrite using SolidJS + OpenTUI with new visual design - Replaced SwapKit SDK with Wick SDK for swap aggregation - Distribution moved from GitHub Releases to Cloudflare R2 ### Removed - Hyperliquid integration (entire package, screens, API routes, trailing orders). Note: Hyperliquid was reintroduced in `[Unreleased]` via the Wick SDK (`hyperliquidChainSetup` + `createHyperliquidAdapter`). Trailing orders shipped independently in 0.5.0 as a Vigil-side feature. - SwapKit dependency and NPM token requirement - Scoop (Windows) distribution ## [0.1.0] - 2025-12-30 ### Added #### Wallet Management - Wallet creation with 12 or 24-word BIP-39 seed phrases - Wallet import from existing seed phrase - Multi-wallet support with wallet selector - Export wallet recovery phrase with password verification - Delete wallet with confirmation flow - Change password functionality #### Multi-Chain Support - Support for 40+ blockchain networks across 5 categories - Dynamic chain management - enable/disable chains per wallet #### Portfolio - Real-time portfolio value tracking with price feeds - Balance display with USD valuations - Hide/show values toggle for privacy #### Trading - Cross-chain swaps via SwapKit integration (THORChain, Maya, Chainflip, Jupiter aggregation) - Route comparison with provider info and estimated times - Slippage configuration #### Limit Orders - Price-triggered limit orders with daemon-based monitoring - Order management: view, filter by status, cancel - Persistent order storage with SQLite #### Send & Receive - Send transactions with address validation - Transaction confirmation flow with fee estimates - Receive funds with QR code generation #### User Interface - 16 built-in themes (11 dark, 5 light) - Vim-style keyboard navigation (j/k, h/l) - Responsive terminal UI #### Settings - Theme selection with live preview - Auto-lock timeout configuration ### Security - AES-256 encrypted keystore storage - Password verification for sensitive operations - Auto-lock on inactivity - All cryptographic operations performed locally ### Distribution - Pre-built binaries for macOS (arm64, x64), Linux (arm64, x64) - Homebrew formula for macOS/Linux --- Version-history note: version numbers 0.2.x and 0.6.0 were skipped (no releases exist for them — there are no missing entries), the 0.1.0 entry was originally misdated 2024-12-30 (the project's first commit is 2025-11-23), and git tags exist only from v0.6.1-beta.1 onward, so no compare links are provided for earlier versions. [Unreleased]: https://releases.r5n.dev/vigil/ [0.7.0-beta.1]: https://releases.r5n.dev/vigil/v0.7.0-beta.1/ [0.6.1-beta.1]: https://releases.r5n.dev/vigil/v0.6.1-beta.1/