Audit of every surface that could show somebody else's logo. Most of it was
already ours: the transaction success screen draws hash_bag.png and the
hashbag_sym_* glyphs, cake_logo_light/dark.svg and the Android icon set were
redrawn from the Hash Bags mark in May and only kept their old filenames, no
user-visible string contains "Cake", and every cupcake reference is a
HardwareWalletType icon sitting next to Ledger and Trezor, which is interop
rather than branding.
Two places were not ours.
The Flatpak manifest installed cakewallet_icon_180.png as the Linux desktop
icon, and that file is upstream Cake artwork from 2025 that the rebrand never
touched. So the Linux build has been shipping a Cake Wallet icon. It now uses
the Hash Bags mark. The macOS icon script had the same fault, latent only
because no workflow builds macOS; it gets a proper Hash Bags set at all seven
sizes rather than a landmine for whoever turns that build on.
Deleted the Cake artwork nothing needs: cake_logo.png, cakepay.png, the three
cakewallet_icon_* files and the macOS set. assets/images/ is bundled whole, so
unreferenced files were shipping inside the binary regardless of whether any
code could draw them.
Also fixes a bug the audit turned up rather than a branding one. The theme
picker chose its preview icon by matching theme.title, which is built from the
accent colour's display name, so renaming an accent silently changed the icon.
It had: the list still named Cake Primary, Tron Red and Frosting Purple, none
of which ship, while our own Such Pink and Such Blue were absent and fell
through to the plain dark icon. It asks the theme what it is now, not what it
is called.
Version to 1.0.3+13. pubspec_description.yaml is the single source for all five
platforms; the checked-in pubspec.yaml is a build artifact.
Still there, reported not removed: cake_pay_icon.png, reachable only through
the Cake Pay order provider, which is the only provider, has an empty API key
and cannot produce an order in this app. Removing it means removing the orders
feature, which is not a branding change.
An error report that cannot be tied to a binary tells us a bug exists and
nothing about whether we already fixed it. Of the ten reports received since
May, five carry the Wownero addresses crash that shipped fixed in 1.0.2, and we
could only tell by reading timestamps buried in the traces themselves.
Two gaps, both closed here. The body carried "App Version: 1.0.0" without the
build number, and 1.0.0 shipped as Play builds 9 and 10 which encrypted under
different keys, so the version alone cannot identify the binary that wrote a
wallet we are being asked to heal.
And the body is the part of this flow we do not control. It reaches us only if
the user pastes what we put on their clipboard. On 2026-09-17 somebody typed a
sentence into the trace box instead, and the report arrived with no version, no
platform and no stack at all. So the app now also puts its version and platform
in the query string of the link it opens, where the form reads it rather than
the user. Someone who reaches the page without the app simply reports nothing,
which is honest and stays empty rather than guessing.
- res/pictures/balance_card_icons/wownero.svg had an opaque background rect
(+#FFF5FD fill), so the ChainIcon's srcIn colorFilter flooded the whole
circle solid grey. Replaced with a clean alpha glyph (white W-in-circle on
transparent, like monero.svg) so the dark bg shows through the negative
space. Source in res/pictures → compile_graphics.sh regenerates the .vec.
- dark theme surface #0B1F14 → #10281B (a bit less dark, per feedback)
Bundles wownerod (aarch64-linux-android, built via monero depends) as
jniLibs libwownerod.so; EmbeddedNode.java execs it from nativeLibraryDir
(the exec-exempt path), binds RPC on 127.0.0.1:34568 for the wallet, pruned
mode by default, capped concurrency for phone thermals. Dart EmbeddedNode
service (start/stop/status/waitUntilReady) drives it over a method channel.
Verified: builds into the APK (binary bundled, arm64), and the daemon
executes on real hardware (moto g stylus) — inits core, binds RPC, connects
peers, and syncs blocks. UI toggle + foreground-service lifecycle are the
next layer; binary is provisioned like the wallet libs (gitignored).
- validate legacy-decoded wallet passwords are real generateKey() output
(696 chars, base64 of 512-byte key + 8-byte iv) so a wrong AES key that
unpads to printable bytes can't be re-saved as a bogus password
- test/legacy_decode_test.dart: proves 1.0.0->1.0.2 recovers PIN+password
and 16k wrong keys yield zero false-accepts
CI ran tool/generate_new_secrets.dart unpinned, so every release binary
shipped different AES keys/salts for the stored PIN and wallet passwords.
Updating the app then failed to decrypt what the previous build stored:
'Invalid or corrupted pad block' at PIN entry and the 'Corrupted seeds'
dialog, with wallet files fully intact.
- entities/encrypt.dart: legacy-key fallback decode for PIN and wallet
password blobs (candidate sets recovered from the shipped 1.0.1 binary;
output validated to reject PKCS7 false positives)
- key_service/auth_service: on successful legacy decode, re-encrypt under
the pinned key — installs self-heal at first unlock
- all build workflows: inject the eight pinned CRYPTO_* repo secrets after
secret generation and hard-fail if any is missing, so crypto salts can
never silently rotate again (values pinned via
~keys/set-gitea-crypto-secrets.sh)
- bump 1.0.2+12
User report 05ebf86e: monero?.getCurrentAccount on a Wownero wallet. The
null-aware operator guards plugin presence, not wallet type, so the
Monero bridge always ran and CWMonero's cast threw before the ?? chain
could reach the wownero branch. Dispatch by wallet.type instead. Swept
lib for the same anti-pattern: account_customizer already dispatches
(fixed 2026-08-07) and the settings_store call sites take no wallet
argument; this was the last live instance.
Server-side forex (ECB daily reference rates) shipped in
hash-wallet-prices; the wallet needed no code change. Comment updated so
the file stops claiming USD-only.
- Wownero default becomes node.wownero.org:443 (SSL, ours) instead of a
third-party plaintext host
- Arbitrum's default was arbitrum.nownodes.io, which requires an API key
we don't ship (nowNodesApiKey is empty) — every fresh install had a dead
default RPC; now arbitrum-one-rpc.publicnode.com
- remove the other NOWNodes entries from node lists and the EVM chain
registry for the same reason; historical migration maps keep their
entries so old users still get migrated off
Deposit side: natives of shipped chains (WOW, XMR, BTC, BCH, DOGE, XNO,
ETH, ETH-Base, ETH-Arb, BNB, POL) plus major stables (USDT/USDC variants,
DAI). Receive side: same minus BNB (inherited upstream restriction) plus
LTC as a receive-only target. ZEC, DASH, SOL, AVAX, Zano, Haven, ADA,
EOS, XLM, XRP, TRX, TON and the rest disappear from the swap UI; their
CryptoCurrency entries stay defined because the raw ids back Hive-stored
trade history.
- Cake Pay: 36 files (~5.3k LOC) plus DI registrations, routes, and UI
branches (feature was hard-disabled and unreachable)
- unreachable buy providers: robinhood, dfx, onramper, meld, kryptonim
(~1.7k LOC); MoonPay untouched
- exchange providers that only existed as commented-out wiring:
changenow, sideshift, chainflip, exolix, swaptrade, letsexchange,
stealthex, xoswap, swapsxyz, thorchain, simpleswap (~5.2k LOC);
Trocador untouched; ExchangeProviderDescription values and Hive
adapters kept so stored trades and orders still deserialize
- di.dart setup() split from one 1,452-line function into 10 sequential
chunk functions; registration execution order verified identical
before and after (251 register calls)
Address-field input no longer leaves the device except toward
infrastructure implied by the typed name itself:
- remove Twitter, Mastodon, Nostr, Yat, Unstoppable Domains, FIO,
ThorChain-name, zcash.me, and Zano alias lookups (Nostr and FIO ran
with no setting gate at all; Zano is not even a supported chain)
- keep OpenAlias, BIP-353, .well-known, LNURL, and ENS, each toggleable
in Settings -> Domain lookups
- BTC fee/block/restore-height queries move from mempool.cakewallet.com
to public mempool.space (also fixes two /api/v1 paths that 404 on
standard mempool deployments)
- PRIVACY.md updated to disclose the remaining flows (mempool.space,
name lookups, opt-in silent payments and payjoin); issue templates and
the translation prompt de-Caked
- resetToDefault omitted Wownero: the reset button null-crashed and left
WOW wallets with an empty node list
- accountLabel was missing a return and rendered blank for WOW wallets
- sec_random now throws instead of returning empty bytes when the native
entropy channel fails or under-delivers
- iOS builds no longer register the leftover cakewallet:// URL scheme
- WOW fee estimate now fetched from the connected daemon's
get_fee_estimate RPC and cached; the inherited XMR constant table
remains only as a pre-fetch fallback
- pin cake_backup, flutter_local_authentication, and bech32 git deps to
their locked SHAs for reproducible builds
Replace the static success illustration with HashBagSuccessAnimation: the money
sack sits at the bottom and #/$/₿ glyphs erupt from its mouth, rising and fading
on a loop. Glyphs are PNG assets (the app bundles no font with a ₿ glyph).
InfoPage gains an overridable buildIllustration() hook (default unchanged:
static HashImageWidget); only TransactionSuccessPage overrides it, so every
other InfoPage is untouched.
NOTE: written without a local Flutter build (Dart pub can't resolve here) —
verify on the next CI/device build. Self-contained and revertible; the static
hash_bag.png remains the fallback via imageLightPath/imageDarkPath.
Send-success art: replace the Cake birthday cake with a Hash Bags money sack
that has a # on it and erupts #/$/₿ (assets/images/hash_bag.png). Used by the
success page, send-confirm sheet, exchange-trade, and dEURO savings.
Asset renames (files + refs):
- birthday_cake.png -> hash_bag.png
- restore_cupcake(.png/_dark) -> restore_hashbag.png
- qr-cake.png -> qr-hashbag.png
- arrow_bottom_cake_green.png -> arrow_bottom_green.png (+ 2.0x/3.0x)
Identifier renames:
- CakeImageWidget -> HashImageWidget (widget + file + 93 refs)
- typography _cakeRegular/_cakeBold/_cakeSemiBold -> _hash*
Transaction filter: drop the Cake Pay "Orders" row and every non-Trocador
trade provider; the swap gate is already Trocador-only, so this just aligns the
filter UI with reality.
Android launcher: add breathing room to the adaptive-foreground # (all
densities, monochrome included); iOS icon unchanged.
About page: swap the Cake easter eggs for Hash Bags ones.
Deferred (needs a build to verify): new-ui .svg.vec filename renames
(cake_squircle_icon, cakewallet-wordmark, cake-setting) — already Hash Bags in
content, only the filenames are cake, and they route through the .vec precompile.
getWalletPassword force-unwrapped the secure-storage read, so a null iOS
Keychain result (item written by an older build under different Keychain
params, e.g. after a TestFlight update) hard-crashed the app and the wallet
showed "Corrupted seeds" — reported by a tester whose older Wownero and BTC
wallets broke on update.
Now it:
- falls back to the legacy readNoIOptions path (queries the OTHER iOS Keychain
accessibility), which can AUTO-RECOVER such wallets without a seed restore;
- falls back to the #__<name>_bak__# backup password the Monero migration
writes before re-encrypting;
- throws a catchable error instead of a null-check crash, so the loader can
offer seed/restore recovery rather than the app dying.
Only changes behavior on the previously-crashing null path — strictly safer.
Not the file cipher (iOS is always Salsa20) nor the Monero migration
(Wownero/BTC don't run it): the wallet files are intact, only the Keychain
password was unreadable. flutter_secure_storage stays pinned (ca897a08) and the
accessibility stays first_unlock; those must not change without a migration
(see docs/internal-notes.md).
Adds DEMO_WALLET_SEED/DEMO_WALLET_HEIGHT support so a demo build restores a
fixed (throwaway, funded) Wownero wallet instead of creating a fresh one, via
WalletRestoreViewModel.create. Balance lives on-chain against the seed, so it
survives any emulator wipe and is reproducible.
Three real bugs fixed on the way:
- build-apk.sh built the --dart-define args as a word-split string; the 16-word
seed's internal spaces split into separate argv tokens and flutter treated a
seed word as a build target ("Target file '<word>' not found"). Now a bash
array keeps each --dart-define one token.
- WalletRestoreViewModel.getCredentials reads name/passphrase from the options
MAP (not the vm field) and casts name as non-null String, so the restore
options must include 'name' and 'passphrase'.
- forward DEMO_WALLET_SEED/HEIGHT into the build container; source demo.env.
Verified end to end: demo build restores the wallet, its address matches the
funded one exactly (QR-decoded), it syncs at height 861800, and the dashboard
shows the real 13.37 WOW balance + tx history. Send shows Max 13.37.
The seed lives only in gitignored tools/demo/demo.env (never committed).
docs/internal-notes.md (gitignored) documents the FailedDecryption gotcha.
The iOS fastlane snapshot UITest already passes --dart-define=SCREENSHOT_MODE=
true; accept it as an alias for DEMO_MODE so the Mac screenshot path drives the
same demo-wallet boot without changing the UITest. Trivial const OR; validated
on next build.
Adds a debug-only capture mode so screenshots/video never depend on the
onboarding/PIN flow, whose synthetic taps are unreliable under the headless
emulator (both flutter_test and adb input drop taps on the PIN confirm screen).
lib/entities/demo_mode.dart: on launch, when kDebugMode AND
--dart-define=DEMO_MODE=true, create a fresh throwaway Wownero wallet through
the real WalletNewVM.create() (so walletInfo/derivation/paths/persistence and
changeCurrentWallet all happen exactly as in the UI), then set the PIN and
allow auth — landing on the dashboard. Reuses the wallet on later launches.
Both halves are compile-time const/kDebugMode, so this is tree-shaken out of
release: DEMO_MODE cannot be enabled in a store binary.
lib/main.dart: call maybeSetupDemoWallet() during bootstrap and force the
initial route to the dashboard in demo mode.
tools/demo/{build-apk,capture}.sh: DEMO=1 bakes the define into a local build;
flutter drive passes it so scenarios start at the dashboard.
Verified end to end: demo build boots to a live Wownero wallet and captured a
clean 1080x1920 store set (dashboard/receive/send/swap/settings) with no PIN.
This also implements the SCREENSHOT_MODE the iOS UITest scaffold already
references (store/SCREENSHOTS.md Path B).
Note: the API-35 emulator needs -gpu host (real GPU) for deep-page rendering;
-gpu software hard-crashes qemu on the Receive page. Stills use screencap
(screenrecord's encoder is unrelated).
getAvailableBuyProviderTypes() now returns [moonpay] only when moonPayApiKey is
non-empty, so MoonPay's Buy button appears only in builds where the CI secret is
present (and the exchange-helper signer is live). Both build workflows now inject
MOONPAY_API_KEY -> moonPayApiKey and EXCHANGE_HELPER_API_KEY -> exchangeHelperApiKey
alongside Trocador + WalletConnect. moonPaySecretKey is server-side and never injected.
The "Wallet Accounts" reorder modal threw on open for Wownero wallets:
account_customizer.dart unconditionally called monero!.getCurrentAccount,
which casts the wallet to MoneroWallet internally. WowneroWallet is a
sibling type, not a subtype, so the cast blew up before the active-card
swap logic ran.
Dispatch on wallet.type and use the wownero! proxy for Wownero, matching
the pattern already in card_customizer_bloc.dart, addresses_page.dart,
and dashboard_view_model.dart. Skip the swap entirely for any other
wallet type rather than guessing.
Bump 1.0.0+5 -> 1.0.0+6.
Two unrelated wallet-UX fixes in one commit:
1) lib/utils/exception_handler.dart — switch the "Report Error" flow
from "open prefilled GitHub issue URL" to "copy error trace to
clipboard + open https://hash.boats/report/". The hash.boats backend
(Node service + nginx proxy + Telegram relay) was already deployed
to the suchwow server; the in-app handler just never got wired to
use it. No GitHub account required, works on every platform.
2) lib/wownero/cw_wownero.dart — add 'primaryAddress' to the keys map
returned by getKeys(). The lib/monero/cw_monero.dart equivalent
already had this; without it, WalletKeysViewModel renders zero
primary-address entry for Wownero wallets and users can't easily
read off the main address for sharing (e.g. to set up a view-only
wallet on another device). The underlying WowneroWalletBase.keys
already populated primaryAddress — only the getKeys map projection
was missing it.
Replaced upstream Cake brand references in user-visible ARB *values*
(keys untouched, so generated S.current.<key> references still work):
- "Cake 2FA" → "Hash Bags 2FA"
- "Cake Pay" → "Hash Bags Pay" (still gated off via
FeatureFlag.isCakePayEnabled = false; rebranding the string so it
doesn't ship literal "Cake" copy if the flag ever flips)
- "Cake Wallet" → "Hash Bags"
- "Cake Labs" → "Such Software"
- "by Cake Pay" → "by Hash Bags Pay"
- "cakewallet.com" → "such.software"
English-only adjustments (other locales had their own translations):
- new_first_wallet_text "Keeping your crypto safe is a piece of
cake" → "Keeping your crypto safe shouldn't be hard" (drops the
Cake pun, which now reads odd post-rename)
- outdated_electrum_wallet_description + _receive_warning rewritten
to Hash-Bags-neutral phrasing: "Hash Bags now uses Electrum V2
wallets. Bitcoin wallets created in older builds need to be
replaced; receiving to old wallets may lose funds." Same Hash-Bags-
neutral rewrite propagated to all locales that had a translated
version of the original Cake-Electrum-V2 message.
Deliberately not touched:
- ARB *keys* (cake_2fa_preset, cake_pay_*, cakepay_*, disable_cake_2fa,
etc.) — keys must stay stable so generated S.current.x references
keep resolving.
- "Cupcake" / "cupcake" — a separate companion app referenced in
restore_*_from_cupcake strings, not part of the Cake brand we're
rebranding from.
- Internal Dart identifiers like CakeImageWidget class name.
Also fixed hardcoded titles in lib/src/screens/setup_2fa/setup_2fa.dart:
- Line 18: title 'Cake 2FA' → 'Hash Bags 2FA'
- Line 22: cake2FAGuideTitle 'Cake 2FA Guide' → 'Hash Bags 2FA Guide'
(Local variable name cake2FAGuideTitle kept as-is — it's a code
identifier, not user-visible.)
33 files touched: 31 ARBs (ar, bg, cs, de, en, es, fa, fr, gn, ha, hi,
hr, hy, id, it, ja, ko, my, nl, pl, pt, pt_BR, ru, th, tl, tr, uk, ur,
vi, yo, zh, zh_tw) + lib/src/screens/setup_2fa/setup_2fa.dart.
Cake Wallet → Hash Bags / Such Software LLC across the user-facing
platform configs:
- macos/Runner/InfoBase.plist: CFBundleDisplayName + CFBundleName
- windows/runner/main.cpp: top-level window title
- ios/Runner/InfoBase.plist: URL scheme cakewallet → hashbags,
CFBundleURLName y.at → com.suchsoftware.hashwallet
- android/app/src/main/AndroidManifestBase.xml: URL scheme
- scripts/windows/build_exe_installer.iss: full rebrand (name,
publisher, URL, exe name, AppId, DefaultDirName, output filename)
- assets/text/disclaimer_deuro.txt: legal disclaimer text
Version unification → 1.0.0 build 1 across all platforms:
- pubspec_description.yaml (was 0.0.0, description was "Cake Wallet.")
- scripts/android/app_env.sh (was 6.1.2 build 4410)
- scripts/ios/app_env.sh (was 6.1.2 build 418)
- scripts/macos/app_env.sh (was 6.1.0 build 147)
- scripts/windows/build_exe_installer.iss (was 6.1.0)
env.json (Windows) was already 1.0.0.
FAQ contact info → support@such.software / @such_software across all
13 locale faq_*.json files (was support@cakewallet.com /
@CakeWalletXMR / @cakewallet_bot).
Node lists:
- Delete assets/zano_node_list.yml — Zano not enabled in any
configure flag; file was dead code.
- Remove zcashDefaultNodeUri const from
lib/entities/default_settings_migration.dart — Zcash not in
product, const was unreferenced anywhere.
Note on BTC + LTC defaults: audit suggested these were Cake-by-default
but they were already non-Cake (blockstream and electrum-ltc.bysh.me).
Cake stays in the auto-switch pool — flagged for separate decision on
whether to disable auto-switching to Cake nodes for privacy.
Avoids any confusion / potential trademark friction with HashWallet
(Spanish hardware-wallet company). Hash Bags is a more distinctive
name, harder to collide with, and we can still rank for 'hash wallet'
search via App Store / Play Store subtitle ('Hash Bags - A Wallet
for your Coins').
What changed (all user-visible strings):
- Launcher labels: android/app.properties, scripts/android/app_env.sh,
scripts/ios/app_env.sh, linux window title (CMakeLists +
my_application.cc)
- In-app text: lib/generated/i18n.dart + ARB sources under res/values/
- Brand docs: README.md, CONTRIBUTING.md, PRIVACY.md,
assets/text/Terms_of_Use.txt, assets/text/Release_Notes.txt
- hash.boats website: index.html, og-image.svg + regen og-image.png,
site.webmanifest, styles.css comment, splash/confirm/pulse/mark/
lockup svg titles, report/index.html, server/server.js
- CI workflow display names ("Hash Bags Linux build", etc.)
What did NOT change (deliberate):
- Bundle ID / Package: com.suchsoftware.hashwallet (immutable app
identity on App Store + Play Store — changing == orphaning the app)
- Binary name: hash_wallet (Linux executable)
- Dart import paths: package:hash_wallet/...
- Git repo: hash-wallet (Such-Software/hash-wallet)
- URL scheme: hashwallet:// (internal deep links)
- support@such.software (no domain change yet)
- App Store / Play Store listing names (whatever was registered there
stays; we updated launcher label only)
- hash.boats domain (still the wallet site)
Also kept the '#ash Wallet' wordplay in the nav but updated to
'#ash Bags' so the # mark still serves as the H. Nav reads:
[# mark] #ash Bags
Website hero tagline now matches the App Store sub-title concept:
'A wallet for your coins. Open-source, non-custodial, multi-chain.
Privacy-leaning by default.'
108 files modified, ~674 string replacements.
Same root cause as the bottom navbar invisibility: iconColor was set to
theme.colorScheme.primary, which on the light theme is our dark forest
green (#1A5C38) and goes invisible on dark surfaces. onSurfaceVariant
is Material's de-emphasized-foreground token and has guaranteed contrast
against the surface across all our themes.
Two fixes:
1) lib/src/screens/seed/seed_verification/seed_verification_success_view.dart
After verifying a BTC wallet's seed, the original flow pushed the user to
the lightning_username_page which suggests an @cake.cash Lightning
address. We disabled Lightning entirely (no Greenlight infra) and the
page is meaningless without it. Collapse the conditional so the button
always pops back to the wallet list. Restore the conditional if/when
Hash Wallet ever runs its own Lightning backend.
2) lib/src/screens/dashboard/widgets/new_main_navbar_widget.dart
inactiveColor was set to theme.colorScheme.primary, which is our brand
dark forest green (#1A5C38) post-retheme. That renders nearly invisible
against the navbar's semi-transparent dark surface backdrop, so the
three non-active tab icons (Wallets / Contacts / Apps) disappear and
the user just sees three blob shapes. Material's onSurfaceVariant is
the standard token for de-emphasized icons and is visible across our
light/dark/black themes.
flutter_mailer has no Linux implementation (throws MissingPluginException)
and on other platforms required users to have a configured mail client.
Vanishingly few error reports ever reached anyone. The 'Send' button on
the error popup was effectively a no-op.
Replaced with a url_launcher call that opens a prefilled GitHub issue at
github.com/Such-Software/hash-wallet/issues/new with the error trace
inlined into the body (truncated to ~6.5KB to stay under GitHub's URL
length cap; full log path is shown in the body for users who want to
attach it manually). Adds a 'bug,from-app' label and a short prompt
asking the user to describe what they were doing.
Downsides: people without a GitHub account will get nothing useful when
they hit 'Send' — they'll see GitHub's sign-up page. Net still better
than the silent no-op we had. Adding a real reporting endpoint
(Cloudflare Worker) is the obvious follow-up if low report volume
turns out to matter.
Also removed flutter_mailer from pubspec.yaml — was only used here.
The .selected computed getter always called monero!.getCurrentAccount(_wallet),
which does an internal 'wallet as MoneroWallet' cast and threw
'WowneroWallet is not a subtype of MoneroWallet' whenever the dashboard
CardsView Observer rebuilt for a Wownero wallet. The .accounts getter
above already dispatched correctly by wallet.type; .selected didn't.
Now matches the same monero/wownero dispatch pattern.
Stragglers that weren't in any agent's batch but referenced the removed
identifiers:
- tool/configure.dart: stripped 'backupSeeds(Box<HavenSeedStore>)'
abstract method from generateWownero's emitted template + the
haven_seed_store.dart import. CI regenerates lib/wownero/wownero.dart
from this template each build, so the previous lib/wownero/wownero.dart
cleanup got reverted on rebuild. This is the actual fix.
- lib/core/trade_monitor.dart + lib/view_model/trade_details_view_model.dart:
removed JupiterExchangeProvider import + ExchangeProviderDescription.jupiter
switch cases (provider + URL builder).
- lib/src/screens/dashboard/dashboard_page.dart: deleted _showHavenPopup
helper + its call site + the haven_wallet_removal_popup import.
- lib/src/widgets/haven_wallet_removal_popup.dart: deleted (no callers).
- lib/src/screens/dashboard/pages/balance/crypto_balance_widget.dart:
removed the zcash 'missing funds' InfoCard and the decred 'syncing'
InfoCard widgets, plus their _dismissZcash and _rescanInternalChangeZcash
handlers.
- lib/src/screens/settings/connection_sync_page.dart: removed the TronGrid
history toggle row.
- lib/src/widgets/bottom_sheet/payment_confirmation_bottom_sheet.dart:
_isTokenSelectionFlow now only checks evmNetworkSelection (was also
branching on solana/tronTokenSelection enum values that no longer exist).
Generated .g.dart files for dashboard_view_model and connection_sync_view_model
still reference removed methods (rescanInternalChangeZcash, dismissZcash,
canUseTronGrid, setUseTronGrid). Those will be regenerated by build_runner
on next CI run and the methods will fall out — no manual fix needed.
94 files changed, -5926 net lines. No stubs, no generators, no dead enum
values, no orphan switch branches. Removed for principled reasons (we
do not ship these chains) and to make the codebase smaller and friendlier
to contribute to.
What's gone:
- lib/{solana,tron,zano,decred,zcash,haven}/ directories
- lib/exchange/provider/jupiter_exchange_provider.dart (Solana-only)
- lib/entities/haven_seed_store.dart
- WalletType.{solana,tron,zano,decred,zcash,haven} enum values
(HiveField IDs are pinned: Wownero stays at 12, all surviving types
keep their IDs, so existing user-saved wallets deserialize unchanged)
- All ~70 lib/ files that imported the removed chain stubs or branched
on the removed WalletType values
- backupSeeds(Box<HavenSeedStore>) abstract method + Wownero implementation
- Jupiter exchange branches in send/exchange view models
- TronGrid usage settings, Zano alias lookups, Zcash transparent address
handling, Decred default-spv-nodes branches, Haven seed migration
What stays (intentional):
- CryptoCurrency.{xhv,sol,trx,dcr,zano,zec} enum entries in cw_core —
they're still used as exchange/swap currency identifiers in
address_validator.dart and elsewhere. The wallet types are gone but
the *currencies* are still tradeable through Trocador.
- cw_core/spl_token.dart and cw_core/tron_token.dart Hive adapters in
main.dart — the tokens still register as Hive types for backwards-
compat with any old box data.
- lib/buy/{moonpay,robinhood,onramper,dfx,kryptonim,meld}/ provider
source files (just stripped of solana/tron/etc references; providers
themselves remain dormant per provider_types.dart).
Pinned-ID note: WalletType enum now has gaps in @HiveField IDs (4, 10,
11, 13, 14, 18 removed). This is deliberate — re-using a freed ID later
would mis-deserialize old hive boxes. Don't renumber.
Bundled config / CI hasn't changed; configure.dart was already free of
these chains in commit 4eb7db0b7.
Delete the WyreBuyProvider + WyreOrderProviderAdapter source files,
strip imports and call sites from buy/order view models and the
buy webview, force isBitcoinBuyEnabled = false in di.dart, and drop
the three wyreSecretKey/wyreApiKey/wyreAccountId entries from
tool/utils/secret_key.dart.
BuyProviderDescription.wyre (raw: 0) is kept as a no-op legacy entry
so any old Hive-persisted order with that raw value still deserializes
without throwing. Don't wire it back to UI/services.
- Stub dashboard bulletin (was polling service-api.cakewallet.com); returns
empty ServicesResponse until we stand up our own notice service.
- Repoint changelog 'View more info' link to hash.boats (modal trigger
remains disabled; this is just for when we re-enable it).
- Replace exchange-helper.cakewallet.com with exchange-helper.such.software
in moonpay/robinhood/onramper providers. Buy providers are still dormant
(empty getAvailable*ProviderTypes); URL change is a fail-loudly placeholder
to ensure we stand up our own proxy before re-enabling any of them.
- Delete Monerocom_Terms_of_Use.txt and Monerocom_Release_Notes.txt — these
were Cake's Monero.com brand variant, never used by Hash Wallet. Collapse
the isMoneroOnly branch in disclaimer_page.dart to always load
Terms_of_Use.txt.
- Add docs/links.md (gitignored) inventorying all public-facing URLs and
emails shipped in the binary.
Cake's email was hardcoded as the recipient for the 'Send error report'
flow in ExceptionHandler and as the contact in the TransactionCommitFailed
user-facing message. Anyone tapping Send would have mailed their wallet
metadata to Cake's support team. Repointed both to support@such.software.
Python regex strip from 6ec755ec2 removed the MoonPay + Robinhood
LinkListItem entries that lived inside an 'if (!isMoneroOnly) ...[ ]'
conditional list-spread, but left the opening '...[' dangling at
line 66 with no matching close bracket. mobx_codegen and hive_generator
both threw 'Expected to find ]' at line 67.
Remove the dead conditional. Build moves past secrets-generation +
mobx-codegen + hive-generator now.
Buy providers (Robinhood Connect, DFX, Onramper, MoonPay, Kryptonim, Meld):
- lib/entities/provider_types.dart: getAvailable{Buy,Sell}ProviderTypes()
both return [] now. Each provider requires a formal partner contract
with revenue-share — no free integrations exist. Re-add to the list
once Such Software has registered the partner relationship per provider.
Buy/Sell UI surfaces (cards_view.dart's onramp button -> Routes.buySellPage)
still render but the provider list is empty, so the screen shows nothing.
- lib/view_model/support_view_model.dart: removed the third-party support
LinkListItem entries for the dead buy providers. Kept the swap-provider
support links (ChangeNow, SideShift, SimpleSwap, Exolix, SwapTrade,
Trocador) — Trocador is still active and the others are useful for
legacy users who created swaps before the trim.
Default node flip (per user request — 'someone else top choice, Cake nodes
stay in the list of others'):
- xmr-node.cakewallet.com:18081 -> node.sethforprivacy.com:443
- electrum.cakewallet.com:50002 -> electrum.blockstream.info:50002
- ltc-electrum.cakewallet.com:50002 -> electrum-ltc.bysh.me:50002
- btc-electrum.cakewallet.com:50002 -> electrum.blockstream.info:50002
Cake's nodes remain in the augmented lists (see asset/*_node_list.yml).
Silent-payments Electrs (electrs.cakewallet.com) + zcash default URI
unchanged — no good free alternative for silent payments, and zcash is
removed anyway.
URL replacements throughout lib/:
- support_view_model.dart: removed Cake's own support channels (email,
website, forum, Telegram, Telegram bot). Only GitHub Issues + Releases
remain. Third-party provider support links (ChangeNow, SideShift,
SimpleSwap, Exolix, Trocador, Onramper, DFX, MoonPay, Robinhood,
Kryptonim) kept — genuinely useful when a swap goes sideways.
- transaction_details_view_model.dart + payjoin_details_view_model.dart:
mempool.cakewallet.com -> mempool.space (canonical free public mempool,
no affiliate).
- services_updates_widget.dart: status.cakewallet.com -> our GH issues.
- 8 widget/screen files: docs.cakewallet.com / blog / cakewallet.com help
URLs repointed to github.com/Such-Software/hash-wallet (placeholder
until we have our own docs; better than dead-linking to Cake's docs).
User-facing text changes:
- walletkit_service.dart: WalletKit metadata (name/description/url/icon/
redirect) all -> Hash Wallet / Such Software repo / hashwallet:// scheme.
- di.dart: TrezorConnect callback URL + appName -> Hash Wallet.
- vulnerable_seeds_popup.dart + haven_wallet_removal_popup.dart: copy
rewritten to say 'Hash Wallet' instead of 'Cake Wallet', and point to
GH issues instead of Cake's support email.
- swap_provider_initial_preference_modal.dart: trailing 'Cake Wallet.'
-> 'Hash Wallet.'
Deep-link URL scheme cakewallet:// -> hashwallet:// in:
- lib/main.dart, lib/src/screens/root/root.dart, lib/view_model/link_view_model.dart
Means any cakewallet:// link from a payment QR / Trezor callback /
shortcut now routes via hashwallet://. No existing user base so no
migration needed.
SVG asset swaps (content replaced, filenames kept so call-sites compile
without rewriting):
- assets/new-ui/cake_squircle_icon.svg -> hash_wallet/02_app_icon.svg
- assets/new-ui/cakewallet-wordmark-light.svg -> hash_wallet/03_lockup_horizontal.svg
(dark text for light backgrounds)
- assets/new-ui/cakewallet-wordmark.svg -> hash_wallet/03_lockup_horizontal_dark.svg
(light text for dark backgrounds)
- apps_widget.dart: the conditional cakelabs-icon render became a SizedBox()
no-op. The Apps tab is gutted anyway (placeholder content); this widget
is also used elsewhere where the Cake Labs attribution badge is unwanted.
The big one. Touches 760+ files. Locks in the user's decision to break
import-line compatibility with upstream cake-tech/cake_wallet in exchange
for a binary named hash_wallet on every platform.
Changes:
- pubspec_description.yaml: project name cake_wallet -> hash_wallet
- 762 Dart files: every 'package:cake_wallet/...' import rewritten to
'package:hash_wallet/...' (lib/, cw_*/lib/, tool/, test/, integration_test/)
- linux/CMakeLists.txt: BINARY_NAME cake_wallet -> hash_wallet
- windows/CMakeLists.txt: project + BINARY_NAME (CakeWallet -> HashWallet)
- windows/runner/Runner.rc: company / file / product strings to Hash Wallet
+ Such Software LLC copyright
- macos/Runner.xcodeproj/project_base.pbxproj: cake_wallet_new.app refs
-> hash_wallet.app (macOS output bundle name)
- com.suchsoftware.HashWallet.yml (Flatpak): all binary path refs
cake_wallet -> hash_wallet (e.g. /app/hash_wallet/hash_wallet)
- linux/com.suchsoftware.HashWallet.desktop: Exec=hash_wallet
- scripts/android/copy_monero_deps.sh: CW_DIR target path
- configure_hash_wallet.sh: error message typo (old filename)
INTENTIONALLY UNCHANGED:
- cw_* subpackage names (cw_core, cw_bitcoin, cw_wownero, etc.) — they
remain as the historical 'cake wallet' naming; renaming them would
cascade through every sub-package's internal structure
- Method channel name 'com.cake_wallet/native_utils' in iOS/macOS/Android
AppDelegates and MainActivity — it's a string identifier that has to
match the Dart side exactly. Renaming requires both-sides change; it's
internal-only and not user-visible.
- ghcr.io/cake-tech/cake_wallet:debian13-... docker image references in
build scripts — that's Cake Labs' published image we use as the build
environment, not ours.
User data directory now follows the new binary name:
~/.local/share/hash_wallet/ (was ~/.local/share/cake_wallet/)
~/.config/hash_wallet/ (was ~/.config/cake_wallet/)
Existing users on the old name will need migration if any exist.
Companion to 59a6b25ff. The accent enum got renamed (cakePrimary,
tronRed, frostingPurple removed; hashGreen, suchPink, suchBlue added)
but ThemeList still referenced the old names. Rename in lock-step:
cakePrimary -> hashGreen
tronRed -> suchPink
frostingPurple -> suchBlue
Plus the corresponding ThemeList static fields (blackThemeCakePrimary
etc.) and switch cases. The integer 'raw' deserialize codes (12-17,
112-117) stay the same — existing user theme prefs will resolve to the
new accent at the same raw value.
The companion to 78edfe0bb — that commit fixed the migration step 55 but
the resetToDefault() in lib/entities/node_list.dart was still trying to
loadDefaultNodes(WalletType.zcash) on every fresh wallet creation, which
is exactly where the user's reported popup fires.
The zcash chain was removed (cw_zcash deleted, assets/zcash_node_list.yml
deleted), but two places still tried to load it at runtime:
1. lib/entities/node_list.dart's resetToDefault() unconditionally called
loadDefaultNodes(WalletType.zcash) which tried to read the deleted YAML.
2. lib/entities/default_settings_migration.dart migration step 55 called
addWalletNodeList(type: WalletType.zcash) + _changeDefaultNode for zcash,
same failure.
Both surfaced as a 'Unable to load asset: assets/zcash_node_list.yml' error
popup on every fresh wallet creation. Removing both call sites; migration
step 55 becomes a no-op (existing wallets advance through it without effect).
Also includes the new SVG variants added to assets/images/hash_wallet/:
03/04/05_*_dark.svg, 09_mark_outline.svg, 10_wordmark_only.svg,
11_vertical_lockup.svg, 12_notification_mono.svg — fills out the brand
kit with dark-theme wordmarks plus tiny/outline/wordmark-only/vertical/
notification variants for cases the existing set didn't cover.
User reported the Apps page still surfaced Cake Labs and Cake-affiliate
third parties despite all the other rebrand work — they're hardcoded in
lib/src/screens/dashboard/pages/cake_features_page.dart's _buildOldUi
and _buildNewUi.
- Cake Pay: Cake Labs' own gift-card product, already disabled via
FeatureFlag.isCakePayEnabled but still rendered here
- Cupcake: Cake's hardware wallet companion app
- NanoGPT: third-party AI service with Cake affiliate revenue
- dEuro Savings: Frankencoin savings, also affiliate
Replaced both build methods with a simple 'No apps available yet'
placeholder. Page structure / nav tab kept intact so we don't have to
restructure the dashboard nav — can repopulate with Hash Wallet /
Such Software apps later (e.g. Smirk, Wowcheckout, etc.).
Per Trocador's commercial team, webhook-driven status updates are preferred
over polling. Adding 'webhook' param to /new_trade so Trocador POSTs status
changes to our Cloudflare Worker, which caches them in KV for the wallet to
read.
This commit only adds the producer side. The wallet still polls Trocador
directly (every 5 min via trade_monitor.dart); switching the polling source
to our worker is a follow-up.
Stop hitting fiat-api.cakewallet.com (and stop sending Cake's API key) for
spot price lookups. Point at our own Cloudflare Worker endpoint at
prices.suchsoftware.com which fetches Kraken (majors) + NonKYC (WOW) and
serves USD prices. Worker source lives in github.com/Such-Software/hash-wallet-prices.
Response shape unchanged so the rest of the wallet code (especially
balance display) needs no further edits.
Note: USD-only for now — non-USD fiats return 0 until forex conversion is
added server-side. Tor users fall back to clearnet until we deploy a .onion
mirror.