build_bindings.sh in bitbox_flutter unconditionally runs
'gomobile bind -target=android -androidapi 24' which produces an
api.aar — needed only for Android. The Mac runner has no Android SDK,
so gomobile fails with 'could not locate Android SDK'.
iOS doesn't need the .aar. BitBox's iOS support is a separate native
plugin under bitbox_flutter/ios/Classes/ + bitbox_flutter.podspec,
linked via flutter pub get + pod install. We just need the directory
present so the path-dep resolves.
Replace the wrapper invocation in iOS workflows with the clone steps
only; skip build_bindings.sh entirely. Android workflow keeps using
the wrapper as-is.
Auto-triggers on push were noisy — every merged PR kicked off the
linux + android + ios-sim builds. Switching to workflow_dispatch only.
Trigger via Gitea Actions UI when you want a build. workflow_dispatch
runs as the authenticated user, so secrets are always present.
Adds the push trigger back when we want pre-merge gating or CI on every
commit (e.g., release-tag automation).
The Android workflow's 'ANDROID_KEYSTORE_BASE64 not set' failure is
secrets-not-reaching-runner, not a missing secret. The secret IS set
in Builds/hash-wallet's repo secrets. The issue: workflows are being
triggered by 'pull_request' events when github-such-software/hash-wallet
is mirrored into Builds/hash-wallet via PR. Gitea (and GitHub) Actions
deliberately strip secrets from workflows triggered by PRs from forks
to prevent rogue PRs from exfiltrating secrets.
Fix: drop the pull_request trigger from all auto-build workflows. Each
workflow now runs exactly once, on push to dev/main (post-merge), in
the destination repo's context, with secrets intact.
Also added a debug step in the Android keystore decode that prints
secret LENGTHS (never values) so future failures of this shape are
diagnosable immediately.
scripts/build_bitbox_flutter.sh invokes build_bindings.sh which calls
gomobile to generate iOS bindings for the Go BitBox client. Without
Go + gomobile on the Mac runner, that step fails with 'gomobile:
command not found'.
Adds an idempotent step: install Go via brew if missing, then 'go
install golang.org/x/mobile/cmd/{gomobile,gobind}@latest' if missing.
Self-hosted runner persists $GOPATH/bin between runs, so steady-state
is zero-cost after the first install.
Same conditional-install pattern as Flutter + CocoaPods.
Android:
- monero_c prebuilt bundle doesn't ship i686-linux-android (32-bit x86
Android — essentially extinct, sim/emulators use x86_64). Was failing
loud on the missing target. Now: missing target = skip + log; only
the truly-modern ABIs (arm64-v8a, x86_64) are REQUIRED. armeabi-v7a
(32-bit ARM) is shipped if available but not required. The resulting
APK is universal across whichever ABIs got staged.
iOS:
- 'sudo gem install cocoapods' was hitting a password prompt because
the Gitea runner user has no passwordless sudo configured (rightly).
Switched to brew-first install (Homebrew lives in its own prefix,
no sudo needed on Mac). Falls back to 'gem install --user-install'
(no sudo) if brew is somehow unavailable. The whole step is still
no-op if 'pod' is already on PATH.
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.
iOS workflows were broken on the Mac mini runner because Flutter
wasn't installed. Three fixes:
1) Conditional Flutter setup. Check 'flutter --version' first; only
pull subosito/flutter-action@v2 if missing or wrong version. Self-
hosted Mac runner persists SDKs between runs, so steady-state is
zero-cost. First run on the runner triggers a full SDK download
via subosito (with cache: true so subsequent fresh installs are
still fast).
2) wget → curl across all iOS workflow steps. macOS doesn't ship
wget by default; curl is always present and respects -fsSL +
redirect properly.
3) Concurrency groups on all four workflows. A burst of commits no
longer queues N copies of the same build — newer pushes cancel
in-flight runs on the same branch. Groups:
linux-<ref>, android-<ref>, ios-sim-<ref>, ios-testflight-<ref>
This addresses the '6 runs from one merge' issue: each commit in
the merge triggered all 3 push-listening workflows. Concurrency
cancels the earlier 3 the moment the newer commit's runs start.
4) CocoaPods install is also conditional (was already 'if ! command -v
pod' under the hood; just tightened the step name).
Phase 2 of iOS CI. Full signed pipeline that:
1) Decodes secrets:
- APPLE_DIST_CERT_P12_BASE64 + password → temp keychain
- APPLE_PROVISIONING_PROFILE_BASE64 → ~/Library/MobileDevice/...
- APPLE_API_KEY_P8_BASE64 → ~/.appstoreconnect/private_keys/
2) Parses the .mobileprovision for its UUID + Name (used in ExportOptions).
3) Generates ios/ExportOptions.plist dynamically with the right Team ID +
profile name + 'app-store' method.
4) Runs flutter build ipa --release --export-options-plist=...
5) Uploads the .ipa to TestFlight via xcrun altool with the API key.
6) Always cleans up keychain + temp credentials, even on failure.
Trigger: workflow_dispatch ONLY (manual). TestFlight uploads consume a
build number with every push — we don't want auto-trigger spamming
TestFlight. Bump the build number in scripts/ios/app_env.sh before
each TestFlight push (or wire a workflow_dispatch input later).
All Apple secrets (and the Trocador ones reused from Linux/Android) are
already configured in Gitea Actions.
If signing fails on first run: most likely the profile name extracted
from the .mobileprovision doesn't match what Xcode expects, OR the
distribution cert in the .p12 doesn't match what the profile pins. The
keychain identity sanity-check + ExportOptions.plist echo in the logs
will tell us which.
Phase 1 of iOS CI. Validates the Mac runner end-to-end with the
simplest possible target: an unsigned simulator .app.
Runs on the mac-mini-m2 self-hosted runner (label: macos-latest).
Mirrors the Linux/Android workflows for the shared prep steps
(torch_dart, reown_flutter, bitbox_flutter, monero_c prebuilt bundle,
configure, codegen, Trocador secrets), then does flutter build ios
--simulator --no-codesign and zips Runner.app.
Artifact: hash-wallet-ios-sim-<sha>. Unzip on any Apple Silicon Mac,
drag Runner.app into Simulator to run.
Phase 2 (TestFlight, separate file) follows after Phase 1 is green —
adds keychain setup, .p12 + provisioning profile install, ipa build,
xcrun altool upload using the App Store Connect API key. All Apple
secrets are already configured in Gitea.
The 'Inspect iOS targets in monero_c bundle' debug step will reveal
which Apple targets the prebuilt bundle ships — we'll need
aarch64-apple-ios-sim (or similar) for arm64 simulator builds on
M-series Macs. If missing, follow-up will either fetch from a different
source or build the iOS .a archives from source via Cake's scripts/ios/
build_*.sh chain (slow but reliable).
Mirrors the Linux workflow's approach — uses the Cake-Labs prebuilt
Docker image (Flutter 3.32.0 + NDK r28 + Go + Android SDK + JDK17 +
all native build deps) and the prebuilt monero_c .so bundle, so we
skip the multi-hour native cross-compile.
Stages monero + wownero .so files into android/app/src/main/jniLibs/
for all 4 Android ABIs (arm64-v8a, armeabi-v7a, x86, x86_64). Zano
libs in the bundle are ignored.
Decodes the upload keystore from secret ANDROID_KEYSTORE_BASE64,
writes android/key.properties (which build.gradle's signingConfigs
already reads), builds a universal release APK for sideload + an
AAB for Play Console. Both signed with the upload key; Play App
Signing re-signs the AAB server-side with the production key on
upload.
Required Gitea Actions secrets:
ANDROID_KEYSTORE_BASE64
ANDROID_KEYSTORE_PASSWORD
ANDROID_KEY_ALIAS
ANDROID_KEY_PASSWORD
TROCADOR_API_KEY (already set, reused from Linux)
TROCADOR_MONERO_API_KEY (same)
TROCADOR_EXCHANGE_MARKUP (same)
mwebd (Litecoin MWEB privacy) is NOT built. LTC works without it,
just no MWEB feature. Add the build step + go build pipeline if we
want MWEB on Android — separate effort.
Artifacts:
- hash-wallet-android-apk-<sha> (single universal APK, 14-day retention)
- hash-wallet-android-aab-<sha> (Play Console upload, 30-day retention)
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.
The source-of-truth pubspec template — gitignored pubspec.yaml is
regenerated from this on each configure.dart run, so the dep would have
reappeared on next build. Follow-up to a8e071a05/4c09950e0.
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.
CONTRIBUTING.md explains the fork relationship, branch model, generated-
code workflow, and what changes we will and won't accept (no re-enabling
Solana/Tron/Zano/Decred/Zcash, no Cake-domain endpoints, no Lightning
yet, no telemetry).
README.md: removed the stale ./scripts/prepare_zcash.sh reference (file
doesn't exist) and added a link to CONTRIBUTING.
.gitignore: untrack docs/UPSTREAM_SYNC.md (internal merge-strategy
playbook, kept locally alongside docs/links.md).
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.
These chains were already disabled in availableWalletTypes (none of them
were getting created), but the source dirs and the codegen scaffolding
for them still lived in tree (~20K lines of dead Dart).
Surgery:
- Delete cw_decred/ cw_solana/ cw_tron/ cw_zano/ source trees
- Strip 5 generate*() function bodies from tool/configure.dart
(generateSolana, generateTron, generateZano, generateDecred,
generateZcash) plus their top-level imports, args, calls,
signatures, and conditional pubspec/walletTypes injection blocks.
configure.dart shrinks from 2134 to 1561 lines and dart analyze
is clean.
- Strip solana/tron secrets config + output paths from
tool/import_secrets_config.dart
- Delete scripts/{android,ios,macos}/build_decred.sh,
scripts/ios/build_zano{,_all}.sh
- Patch scripts/{android,ios,macos}/build_all.sh,
scripts/android/copy_monero_deps.sh, scripts/ios/setup.sh,
scripts/ios/gen_framework.sh to drop decred/zano steps
- Patch scripts/android/docker/build.sh + Dockerfile.final to drop the
decred Docker stage; delete scripts/android/docker/Dockerfile.decred
- Update .github/workflows/build-linux.yml comments to reflect the
remaining cw_* module list (evm, nano, bitcoin)
Note: WalletType.{solana,tron,zano,decred,zcash} enum values still live
in cw_core/lib/wallet_type.dart and there are dead switch cases in
lib/di.dart and lib/new-ui/pages/*.dart that reference them. Those
paths are unreachable (the enum values never get assigned to any wallet)
but cleaning them up is a separate hygiene pass.
Cake's nodes are kept in the available list (their public infra is fine,
and users may want to opt in) but no longer the freshest-install default
for XMR, BTC, or LTC.
XMR: node.sethforprivacy.com:443 (matches newCakeWalletMoneroUri migration
target, so existing users and fresh installs converge on the same node).
BTC: electrum.blockstream.info:50002 (matches newCakeWalletBitcoinUri).
LTC: electrum-ltc.bysh.me:50002 (matches cakeWalletLitecoinElectrumUri).
- 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.
Three semi-independent fixes flagged from a user-facing testing pass:
1. cw_core/lib/root_dir.dart had a hardcoded 'cake_wallet' for the
Linux app data dir, bypassing the binary name entirely. That's why
~/.config/cake_wallet/ kept being created even after the project
rename. Changed appName const to hash_wallet. Also:
- CAKE_WALLET_DIR env-var override -> HASH_WALLET_DIR (with the
old name kept as a fallback so users migrating from a Cake
install via env-var don't lose their path).
- linuxSymlinkSharedPreferences kept the legacy
['com.example.cake_wallet','cake_wallet'] paths in the migration
array so existing Cake users get auto-migrated into hash_wallet's
new home on first launch of the fork.
2. lib/new-ui/new_dashboard.dart: commented out the
Future.delayed(300ms).then(_showChangelog) trigger. The changelog
content lives under assets/new-ui/changelog/text and describes
Cake's v6.1.0 release notes — not ours. The 'View more info' button
inside the modal launched blog.cakewallet.com. Re-enable once we
write our own changelog content.
3. tool/configure.dart: WalletType.wownero hoisted to the top of the
generated availableWalletTypes list. It's the reason this fork
exists, so it should be the first choice in create / restore
pickers. Monero stays as #2.
Replaces both placeholders with the legal-reviewed Hash Wallet documents
authored by the user.
Per user direction: stripped the Tor/I2P recommendation from the Privacy
Policy section 2 (network-level privacy guidance). New text recommends
running your own node and pointing the Software at it via custom node
settings — same intent, framed around the recommendation the user
actually wants to make for Hash Wallet rather than naming specific
overlay networks we don't currently integrate or document well.
- res/values/strings_en.arb: made_easy value 'made easy' -> 'made fun'.
This is what AnimatedTypingText actually feeds (line 183 of
create_pin_welcome_page.dart), not payment_made_easy which is unused
in this rendering path.
- assets/images/cake_logo_{light,dark}.svg replaced with mark-only
(hash_wallet/01_mark.svg — just the # in green box, no embedded
wordmark). Welcome screen layout already renders 'Hash Wallet' text
next to this image; the previous wordmark-embedded SVG caused the
duplicate 'Hash Wallet [...] Hash Wallet' you screenshot'd. Mark
alone is theme-agnostic (green box with white # works on both light
and dark backgrounds), so light + dark use the same file.
- assets/images/welcome_{dark,light}_theme.svg: gradient bottom stop
faded to transparent. Eliminates the hard cutoff edge where the
sky-rect ended and flat surface color began — the SVG now blends
smoothly into the page background.
- assets/text/Terms_of_Use.txt: replaced 188-line Cake Labs LLC legal
document with a Hash Wallet placeholder (same pattern as PRIVACY.md).
Real ToS pending legal review.
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.
GTK app identifier missed in last commit (Edit failed because Read wasn't
run first; the rest of the welcome-screen batch landed cleanly). Now the
Linux GDBus name + dock entry uses our own reverse-DNS, not the default
'com.example.*' GTK template value.
- assets/images/cake_logo_{light,dark}.svg replaced with the Hash Wallet
horizontal lockup variants (03_lockup_horizontal.svg + ..._dark.svg).
Welcome screen now shows our wordmark instead of the Cake mark.
- assets/images/welcome_dark_theme.svg rewritten as a cyberpunk starry
night: deep green gradient sky, mint/pink/blue nebula glows, sharp
4-point stars, and a subtle '#'-shaped constellation made of dots
connected by mint lines — keeps the night-sky feel but in our palette
and ties back to the brand mark.
- assets/images/welcome_light_theme.svg rewritten as a sunny morning:
minty sky gradient, warm yellow sun, soft pink lower-left halo, white
clouds, plus subtle brand-green sparkles for continuity with the dark
variant.
- linux/CMakeLists.txt: APPLICATION_ID changed from the default
com.example.cake_wallet to com.suchsoftware.hashwallet. (BINARY_NAME
stays cake_wallet — renaming it requires touching every
package:cake_wallet/... import in the codebase; explicitly deferred.)
- res/values/strings_en.arb: 'payment_made_easy' string changed from
'Payments made easy' to 'Payments · Privacy · Security · made fun'.
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.).
GTK title bar (and non-header-bar fallback) were both hardcoded in
linux/my_application.cc. User reported 'Cake Wallet' showing in the
window decoration despite all the Dart-side display name changes — that
string only exists in the C++ native shell.
Gitea Actions does not implement the v2+ artifact HTTP API that GitHub
introduced. upload-artifact@v4 fails with GHESNotSupportedError. v3 uses
the older wire format that Gitea's act_runner handles correctly.
The Linux build itself succeeded — this just lets the downloadable
artifact get attached to the run page.
Previous CI step pre-wrote tool/.secrets-config.json with a curated key
subset. The generator at tool/generate_secrets_config.dart has an early
return when the base config exists (line 61), which ALSO skips creating
the per-module configs (evm/solana/nano/tron/bitcoin). Result: dozens
of secrets.xxx references in cw_bitcoin/cw_evm/cw_nano/lib/main.dart
failed at compile time with 'Undefined name'.
New approach (matches Cake's CI pattern):
1. Run generate_new_secrets.dart with no pre-existing config → it creates
all the JSON files from the full SecretKey list with empty defaults,
then writes the per-module .secrets.g.dart files
2. sed-inject Trocador values into lib/.secrets.g.dart
Side effect: changenow_exchange_provider.dart's 'Map<String,dynamic> not
assignable to Map<String,String>' error also resolves — that error was
caused by Dart inferring 'dynamic' for the apiKey ternary because both
arms referenced undefined secrets. Once secrets exist as empty strings,
inference settles on String.
The 'async' flag in model_generator.sh launches per-module flutter pub get
in parallel via 'bash -c ... &'. Flutter has a single-process startup lock
for SDK initialization — when N parallel calls race for it, most lose,
leaving the SDK cache half-initialized. Subsequent pub gets then fail
with the misleading 'doesn't support null safety' error because Flutter
can't resolve its own bundled sky_engine.
Two fixes:
1. Drop 'async' — model_generator.sh now runs the 8 modules sequentially.
Adds maybe 3 minutes per CI run vs parallel, but reliable beats fast.
2. Add explicit 'flutter precache --linux' step before model_generator. The
'|| true' absorbs the known flutter_gpu.zip 404 on Flutter 3.32.0 —
that asset isn't actually published at the URL Flutter constructs and
isn't needed for desktop Linux.
These came along with the original cake_wallet clone but reference Cake
Labs' private self-hosted runners (e.g. 'runs-on: [Linux, amd64, forlinux]'),
private docker registry tokens, and Cake-internal paths. They never run
successfully on our infrastructure and just clutter the Actions UI with
red warning triangles.
Removed:
- pr_test_build_{linux,android}.yml — Cake's own CI builds
- reusable-build.yml — shared build workflow they call into
- automated_integration_test.yml — heavy integration suite
- are_translations_sane.yml — translation lint
- no_{http_imports,print_in_dart,restricted_imports}.yaml — code lints
Keeping our build-linux.yml. Lint workflows can be re-added later if we
want them, adapted for our setup.
Single workflow at .github/workflows/build-linux.yml that builds Linux
release in Cake's prebuilt Docker image. Skips the simplybs source-toolchain
bootstrap (which ate 9GB on jw-laptop before bailing) — uses the prebuilt
monero_c .so bundle instead, just like Cake's own CI does.
Targets runs-on: ubuntu-latest, which matches both your linux-beast
self-hosted runner (per its labels in the Gitea runners panel) AND
GitHub-hosted ubuntu-latest, so the same workflow file works whether CI
fires from Gitea Actions or GitHub Actions.
Triggers on push to dev/main, on PRs, and manual workflow_dispatch.
Outputs hash_wallet_linux_<sha>.zip as a downloadable artifact (14d retention).
Secrets needed on the runner / repo:
- TROCADOR_API_KEY
- TROCADOR_MONERO_API_KEY (set to same value as TROCADOR_API_KEY for now)
- TROCADOR_EXCHANGE_MARKUP (e.g. "1")
Add via: GitHub repo Settings > Secrets and variables > Actions, or
Gitea repo Settings > Secrets.
monero_c (MrCyjaneK's multi-coin C wrapper) bundles monero, wownero, and
zano as sibling git submodules. Upstream prepare_moneroc.sh did a naive
'git submodule update --init --recursive' which pulled all three plus
their deep transitive submodules — zano alone drags down a ~100MB Qt UI
subtree we never compile.
Now: deinit + rm -rf zano (so it stays gone across runs), init only
monero and wownero, --depth 1 for shallow, --jobs 8 for parallel. Same
patches loop trimmed to drop zano.
Zano was already removed at the configure layer, but the per-platform
build_monero_all.sh scripts still compiled libzano_wallet2_api_c on
Android and iOS — wasted build minutes for a chain we don't ship.
Linux + macOS already had the trimmed loop.
Leftover from zcash removal — Cake's Linux runner installed the warp_api_ffi
shared library produced by scripts/zcash_lib's Rust build. We deleted the
zcash_lib source so this install rule fails CMake. Drop it.
Upstream Cake declares bitcoinConfigPath + bitcoinOutputPath at the top of
tool/import_secrets_config.dart but never references them in the function
body. Result: every fresh clone runs 'dart run tool/generate_new_secrets.dart'
and ends up with cw_evm/cw_solana/cw_tron/cw_nano/.secrets.g.dart populated
but cw_bitcoin/lib/.secrets.g.dart still missing — and the Linux build
fails on the cw_bitcoin import that needs breezApiKey.
Plumb bitcoin into the pipeline the same way the others are. The bitcoin
JSON config (tool/.bitcoin-secrets-config.json) only has breezApiKey today,
which we populate as an empty string since Lightning is disabled.
Cake's mwebd Go daemon is only built for iOS and Android — no Linux/macOS/
Windows toolchain in their build scripts. ffigen consequently never runs
on those platforms, leaving cw_mweb/lib/mweb_ffi.dart dangling on a
non-existent generated_bindings.g.dart import.
This stub provides type-compatible signatures so the Dart build compiles
on every platform. At runtime, DynamicLibrary.open will fail on desktop
(no libmweb.so/.dll/.dylib shipped) and MWeb features will no-op — standard
non-MWEB Litecoin sends/receives still work fine through cw_bitcoin.
For Android the real bindings are still produced via ffigen against the
libmweb.h Go-generated header, overwriting this stub at build time.
Force-added past the *.g.dart gitignore — this one's a hand-maintained
desktop fallback, not a build artifact.