Skip to content

chore(release): v0.9.3#3164

Merged
ca333 merged 64 commits intomainfrom
dev
Oct 22, 2025
Merged

chore(release): v0.9.3#3164
ca333 merged 64 commits intomainfrom
dev

Conversation

@CharlVS
Copy link
Copy Markdown
Collaborator

@CharlVS CharlVS commented Oct 2, 2025

Komodo Wallet v0.9.3 Release Notes

This release sharpens sign-in convenience, analytics coverage, operational resilience, and ARRR support. Highlights include one-click remember-me login, a dual analytics pipeline with Matomo support, a hardened feedback workflow, and improved compliance guardrails across platforms.

🚀 New Features

🎨 UI & UX

🔒 Security & Compliance

⚡ Performance & Reliability

🐛 Bug Fixes

🛠️ Build & Developer Experience

📚 Documentation

⚠️ Breaking Changes

  • SDK Dart/Flutter Version Requirements [SDK] - Minimum Dart SDK version is now ^3.9.0 and Flutter version constraint is >=3.35.0 <3.36.0
  • ZHTLC Activation Parameters [SDK] - Breaking changes to activation params serialization and structure for ZHTLC and ERC20 coins
  • SDK Workspace Migration [SDK] - Legacy pubspec_overrides.yaml files removed in favor of Dart Pub workspace resolution

📦 SDK Changes

SDK Version: Updated from 68429b23dac43eddd53434dda1bd23296523f27d to 72c9de3b370f1b4169ebbb3150e8adedf4ed3b23

Full Changelog: 0.9.2...0.9.3

Dependency Changes

Details

Note that added hive_ce/hive_ce_flutter are community forks of the (no longer maintained) hive packages. They performed significant refactors for performance enhancements, but this may only represent a small portion of the entire package's codebase.

Changed Dependencies Summary:
Package Status Old version New version Dependency Old sha256 New sha256
bloc_lint Added - 0.2.1 direct dev - pub:116bfd31fd1fa050212a7cd48fbf148661107edebab2f93264fb8ae213c64ae3
checked_yaml Added - 2.0.4 transitive - pub:959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f
cupertino_icons Added - 1.0.8 direct main - pub:ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
dbus Added - 0.7.11 transitive - pub:79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c
device_info_plus Added - 11.5.0 transitive - pub:98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a
device_info_plus_platform_interface Added - 7.0.3 transitive - pub:e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
hive_ce Added - 2.11.3 transitive - pub:708bb39050998707c5d422752159f91944d3c81ab42d80e1bd0ee37d8e130658
hive_ce_flutter Added - 2.3.2 transitive - pub:f5bd57fda84402bca7557fedb8c629c96c8ea10fab4a542968d7b60864ca02cc
isolate_channel Added - 0.2.2+1 transitive - pub:f3d36f783b301e6b312c3450eeb2656b0e7d1db81331af2a151d9083a3f6b18d
matomo_tracker Added - 6.0.0 direct main - pub:e5f179b3660193d62b7494abd2179c8dfcab8e66ffa76eeefe3b6f88fb3d8291
pubspec_lock_parse Added - 2.2.0 transitive - pub:020cb470287124c936c30ebfc2f927b287f275b7bf7fc2ab11577e592c017764
win32_registry Added - 2.1.0 transitive - pub:6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae
file_system_access_api Removed 2.0.0 - transitive pub:c961c5020ab4e5f05200dbdd9809c5256c3dc4a1fe5746ca7d8cf8e8cc11c47d -
very_good_analysis Removed 8.0.0 - transitive pub:c529563be4cbba1137386f2720fb7ed69e942012a28b13398d8a5e3e6ef551a7 -
_fe_analyzer_shared Updated 80.0.0 85.0.0 transitive pub:dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 pub:da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
_flutterfire_internals Updated 1.3.54 1.3.59 transitive pub:de9ecbb3ddafd446095f7e833c853aff2fa1682b017921fe63a833f9d6f0e422 pub:ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11
analyzer Updated 7.3.0 7.7.1 transitive pub:192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e pub:974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d
asn1lib Updated 1.6.2 1.6.5 transitive pub:e02d018628c870ef2d7f03e33f9ad179d89ff6ec52ca6c56bcb80bcef979867f pub:9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024
coverage Updated 1.12.0 1.15.0 transitive pub:9086475ef2da7102a0c0a4e37e1e30707e7fb7b6d28c209f559a9c5f8ce42016 pub:5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d
dragon_charts_flutter Updated 0.1.1-dev.1 0.1.1-dev.3 direct main pub:663e73aeae425ec503942bde4ea40caa665c82250e760d20a1df2b89a16ffb3c git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
dragon_logs Updated 1.1.0 2.0.0 direct main pub:e697f25bd0f27b0b85af42aff7f55f003fe045c0e3eeda6164bf97aab1525804 git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
feedback Updated 3.1.0 3.2.0 direct main pub:26769f73de6215add72074d24e4a23542e4c02a8fd1a873e7c93da5dc9c1d362 pub:55edce4f8f0ec01a5ff023e29c5c57df86a7391c831d5647e3b3fdff05e4b01e
file_picker Updated 10.1.2 10.3.2 direct main pub:8986dec4581b4bcd4b6df5d75a2ea0bede3db802f500635d05fa8be298f9467f pub:e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22
firebase_analytics Updated 11.4.5 11.6.0 direct main pub:2416b9d864412ab7b571dafded801bbcc7e29b5824623c055002d4d0819bea2b pub:4f85b161772e1d54a66893ef131c0a44bd9e552efa78b33d5f4f60d2caa5c8a3
firebase_analytics_platform_interface Updated 4.3.5 4.4.3 transitive pub:3ccf5c876a8bea186016de4bcf53fc1bc6fa01236d740fb501d7ef9be356c58e pub:a44b6d1155ed5cae7641e3de7163111cfd9f6f6c954ca916dc6a3bdfa86bf845
firebase_analytics_web Updated 0.5.10+11 0.5.10+16 transitive pub:5e4e3f001b67c2034b76cb2a42a0eed330fb3a8fb41ad13eceb04e8d9a74f662 pub:c7d1ed1f86ae64215757518af5576ff88341c8ce5741988c05cc3b2e07b0b273
firebase_core Updated 3.13.0 3.15.2 direct main pub:017d17d9915670e6117497e640b2859e0b868026ea36bf3a57feb28c3b97debe pub:7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5
firebase_core_platform_interface Updated 5.4.0 6.0.0 transitive pub:d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf pub:5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb
firebase_core_web Updated 2.22.0 2.24.1 transitive pub:129a34d1e0fb62e2b488d988a1fc26cc15636357e50944ffee2862efe8929b23 pub:0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37
flutter_markdown Updated 0.7.7 0.7.7+1 direct main pub:634622a3a826d67cb05c0e3e576d1812c430fa98404e95b60b131775c73d76ec pub:08fb8315236099ff8e90cb87bb2b935e0a724a3af1623000a9cec930468e0f27
flutter_plugin_android_lifecycle Updated 2.0.28 2.0.30 transitive pub:f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e pub:b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31
flutter_window_close Updated 1.2.0 1.3.0 direct main pub:bbdd1ec57259cbffc3f978c1709a3314a0991f042490d9d0a02c5fd70ac8dff6 pub:7fecc628c6f6e751d279f2a988a22b5ffcc0d4c5da0bfe9b41a388803025819f
get_it Updated 8.1.0 8.2.0 direct main pub:e87cd1d108e472a0580348a543a0c49ed3d70c8a5c809c6d418583e595d0a389 pub:a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b
komodo_cex_market_data Updated 0.0.1 0.0.3+1 direct main git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_coin_updates Updated 1.0.0 1.1.1 transitive git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_coins Updated 0.3.0+0 0.3.1+2 transitive git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_defi_framework Updated 0.3.0+0 0.3.1+2 transitive git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_defi_local_auth Updated 0.3.0+0 0.3.1+2 transitive git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_defi_rpc_methods Updated 0.3.0+0 0.3.1+1 transitive git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_defi_sdk Updated 0.3.0+0 0.4.0+3 direct main git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_defi_types Updated 0.3.0+0 0.3.2+1 direct main git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_ui Updated 0.3.0+0 0.3.0+3 direct main git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
komodo_wallet_build_transformer Updated 0.3.0+0 0.4.0 transitive git:68429b23dac43eddd53434dda1bd23296523f27d git:679fd92a6ce6d87b631dadbcaca1c8343e6580c2
leak_tracker Updated 10.0.9 11.0.1 transitive pub:6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0 pub:8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0
leak_tracker_flutter_testing Updated 3.0.9 3.0.10 transitive pub:f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 pub:1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1
leak_tracker_testing Updated 3.0.1 3.0.2 transitive pub:6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3 pub:8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1
local_auth_android Updated 1.0.50 1.0.52 transitive pub:82b2bdeee2199a510d3b7716121e96a6609da86693bb0863edd8566355406b79 pub:48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3
local_auth_darwin Updated 1.5.0 1.6.0 transitive pub:25163ce60a5a6c468cf7a0e3dc8a165f824cabc2aa9e39a5e9fc5c2311b7686f pub:0e9706a8543a4a2eee60346294d6a633dd7c3ee60fae6b752570457c4ff32055
package_info_plus_platform_interface Updated 3.2.0 3.2.1 transitive pub:6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c pub:202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086
path_provider_android Updated 2.2.17 2.2.18 transitive pub:d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 pub:993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db
path_provider_foundation Updated 2.4.1 2.4.2 transitive pub:4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942 pub:16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd
petitparser Updated 6.1.0 7.0.1 transitive pub:07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646 pub:1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1
process Updated 5.0.3 5.0.5 transitive pub:107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d pub:c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744
provider Updated 6.1.5 6.1.5+1 transitive pub:4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84 pub:4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272
share_plus Updated 10.1.4 11.1.0 direct main pub:fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da pub:d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1
share_plus_platform_interface Updated 5.0.2 6.1.0 transitive pub:cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b pub:88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a
shared_preferences_android Updated 2.4.10 2.4.12 transitive pub:20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac pub:a2608114b1ffdcbc9c120eb71a0e207c71da56202852d4aab8a5e30a82269e74
test Updated 1.25.15 1.26.2 direct dev pub:301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e pub:65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb
test_api Updated 0.7.4 0.7.6 transitive pub:fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd pub:522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00
test_core Updated 0.6.8 0.6.11 transitive pub:84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa pub:80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a
url_launcher_android Updated 6.3.15 6.3.18 transitive pub:1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4 pub:69ee86740f2847b9a4ba6cffa74ed12ce500bbe2b07f3dc1e643439da60637b7
url_launcher_ios Updated 6.3.3 6.3.4 transitive pub:7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb pub:d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7
url_launcher_macos Updated 3.2.2 3.2.3 transitive pub:17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2 pub:c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f
url_launcher_web Updated 2.4.0 2.4.1 transitive pub:3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9 pub:4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2
vector_graphics Updated 1.1.18 1.1.19 transitive pub:44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de pub:a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6
vector_graphics_compiler Updated 1.1.16 1.1.19 transitive pub:1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad pub:d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc
vector_math Updated 2.1.4 2.2.0 transitive pub:80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803 pub:d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
video_player Updated 2.9.5 2.10.0 direct main pub:7d78f0cfaddc8c19d4cb2d3bebe1bfef11f2103b0a03e5398b303a1bf65eeb14 pub:0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a
video_player_android Updated 2.8.2 2.8.13 transitive pub:ae7d4f1b41e3ac6d24dd9b9d5d6831b52d74a61bdd90a7a6262a33d8bb97c29a pub:59e5a457ddcc1688f39e9aef0efb62aa845cf0cbbac47e44ac9730dc079a2385
video_player_avfoundation Updated 2.7.0 2.8.4 transitive pub:84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc pub:f9a780aac57802b2892f93787e5ea53b5f43cc57dc107bee9436458365be71cd
video_player_platform_interface Updated 6.3.0 6.4.0 transitive pub:df534476c341ab2c6a835078066fc681b8265048addd853a1e3c78740316a844 pub:cf2a1d29a284db648fd66cbd18aacc157f9862d77d2cc790f6f9678a46c1db5a
video_player_web Updated 2.3.4 2.4.0 transitive pub:3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476 pub:9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb
vm_service Updated 15.0.0 15.0.2 transitive pub:ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 pub:45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60
watcher Updated 1.1.1 1.1.3 transitive pub:69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104 pub:5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c
web_socket Updated 0.1.6 1.0.1 transitive pub:3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83 pub:34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c
web_socket_channel Updated 3.0.2 3.0.3 transitive pub:0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5 pub:d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
xml Updated 6.5.0 6.6.1 transitive pub:b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 pub:971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025

Note

Introduces one-click quick-login, robust IPFS-backed NFT media loading, ZHTLC (ARRR) activation/config UI with status bar, refined trading/geo filters, and cross-platform build/signing improvements, alongside analytics, UX, and dependency upgrades.

  • Auth & Onboarding:
    • Quick-login (remember me) with password-manager autofill handling; remembers last wallet and prompts on startup.
    • Wallet import/name validation and rename dialog; expanded password length and autofill hints.
  • DEX & Trading:
    • Geo-restrictions integrated in coin/order lists and trading enablement checks; table-utils optimized (caching, fewer lookups).
    • Maker/Taker confirmation gated per-asset; taker “Exact” amount button; debounce for coins search.
  • ZHTLC (ARRR):
    • Activation Status Bar; per-coin Configuration Dialog (params download, sync options); global handler wrapping DEX/Wallet.
    • ZHTLC config button on coin details; DEX page wrapped with configuration handler.
  • NFTs & IPFS:
    • NftImage/NftVideo reworked with Bloc + IpfsGatewayManager (gateway rotation, fallbacks, cooldowns); updated views to imageUrl.
  • Fiat & Withdrawals:
    • Debounced fiat amount input; tendermint/ZHTLC-only memo field; fee inputs/labels refined.
  • Analytics & Settings:
    • Dual analytics plumbing (updated event payloads); theme selection event; VersionInfo via bloc; seed/private key flows screenshot-hardened.
  • Wallet UI:
    • Balance placeholders until prices load; fiat per-address restored; consistent DEX address pill.
  • Build & Platform:
    • macOS: new bundle id/scheme, code-sign profile, window reopen; Linux: desktop file/icon; Windows: single-instance mutex.
    • Flutter 3.35.3 + Dart workspaces; SDK submodule/overrides; dependency updates.
  • Tests:
    • Added unit/integration tests for backoff strategy, IPFS manager, quick-login, conversions; removed flaky CEX tests.

Written by Cursor Bugbot for commit 28c9734. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Optional Matomo analytics and multi-provider analytics; geo-based trading restrictions; zHTLC/ARRR activation flow with UI configuration; NFT image loader with IPFS gateway fallbacks; quick-login and wallet rename; feedback contact opt-out.
  • Improvements

    • Expanded UI texts, validations (wallet names, mnemonics), feedback workflow, and zHTLC guidance; smarter pricing, charts and P&L with backoff; onboarding/activation refinements; raised mobile platform targets.
  • Build/CI

    • Flutter bumped to 3.35.3; recursive submodule handling; artifacts include short commit SHA.
  • Documentation

    • New/updated guides for Matomo, SDK submodule management, cloning, macOS Ruby/CocoaPods, analytics, and build/release procedures.

CharlVS and others added 30 commits August 1, 2025 19:14
…back_test_url-references

chore: remove FEEDBACK_TEST_URL references
Co-authored-by: charl <charl@vanstaden.info>
…logout-dropdown

fix(ui): close dropdown on window resize
…fine (#3037)

* refactor: simplify Docker env vars and build command logic

- Remove unnecessary environment variables from Docker container
- Keep only GITHUB_API_PUBLIC_READONLY_TOKEN as env var
- Replace hardcoded build logic with conditional credential handling
- Add proper validation for Trello and Cloudflare feedback services
- Use dart-define flags instead of environment variables for build configs
- Add warning messages for incomplete credential sets

* fix executable rights on build.sh

* remove the redundant FEEDBACK_TEST_URL, as it will no longer be used in the GUI

* swap BUILD_COMMAND and BUILD_CMD (important)

BUILD_CMD, which is built dynamically with --dart-define= arguments, should be called last (not during the assets-fetch stage) to ensure the app is actually built with the required defines and that all String.fromEnvironment(...) statements in the Dart code work as expected.
… NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* remove dgph binaries

* Ignore .dgph build artifacts in iOS
* refactor: drop balance override from CoinBalance

* chore: remove unused import

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(address-card): revert change to coinbalance and use extensions

* feat(coin-addresses): migrate to stream-based pubkey watch function

TODO: bump SDK version once merged

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* refactor duplicated translations

* apply consistent "dex address" pill style

* adds missing bracket
* fix missing price and change data on coin page, sync with main wallet page

* chore: remove unreferenced coin list and fiat widgets

* refactor(coin-details-info-fiat): move widget builder functions to widgets

https://stackoverflow.com/a/53234826

* adds Individual error handling for price and 24hr data sourcing

* cache 24hr data from CoinsBlock until SDK offers it

* fix layout issue (renderbox constraint violations)

* dispose of scrollbars thoughtfully

* Show skeleton for assets list addresses (#2990)

* feat(ui): show loading skeleton for coin addresses

* Reduce address placeholder items from 3 to 1

* fix: apply Cursor suggestions

---------

Co-authored-by: Francois <takenagain@users.noreply.github.com>
Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
* chore: roll SDK packages and fix non-exhaustive MnemonicFailedReason switch\n\n- Ran .github/scripts/roll_sdk_packages.sh\n- Updated git refs for SDK packages\n- Added handling for invalidWord and invalidChecksum in wallet_simple_import\n- Generated SDK_CHANGELOG.md

* feat: more specific mnemonic validation errors (invalid word, checksum, length)\n\n- Added locale keys and messages\n- Mapped MnemonicFailedReason to specific messages\n- Regenerated localization keys

* chore: normalize en.json EOF newline

* chore: re-roll SDK to latest refs (d5b5c3) and update SDK_CHANGELOG.md

* fix: patch breaking SDK changes

* chore: remove generated SDK changelog

* fix: apply cursor coin addresses bug fixes

TODO(@takenagain): Please revisit these change when you complete your PR for full integration of the latest SDK version with the pubkey changes.
* limit memo field to supporting protocols

* add TODO for unused component

* removes obsolete `MemoField`

* Add helper function to check memo support for specific protocols

Co-authored-by: charl <charl@vanstaden.info>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: charl <charl@vanstaden.info>
Co-authored-by: CharlVS <77973576+CharlVS@users.noreply.github.com>
* adds `isHiddenElse` to `HiddenWithoutWallet`

* only hide if `isHiddenElse` is `true`
Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
…indow; prevent zombie processes (#3063)

* Implement single instance enforcement for Komodo Wallet on Windows

Co-authored-by: charl <charl@vanstaden.info>

* Improve window handling and application reopening on Linux and macOS

Co-authored-by: charl <charl@vanstaden.info>

* Disconnect window signals and clear main window pointer in dispose method

Co-authored-by: charl <charl@vanstaden.info>

* fix(windows): single-instance mutex: handle ERROR_ACCESS_DENIED when detecting existing instance; focus existing window (#3063)

* fix(linux): replace deprecated application flag

Replace deprecated application flag for ensuring only a single instance can be open at any time.

* fix(windows): correct single-instance detection in mutex logic

Remove impossible ERROR_ACCESS_DENIED check when CreateMutexW returns a valid handle. GetLastError() returns ERROR_ACCESS_DENIED only if CreateMutexW fails and returns nullptr. Treat only ERROR_ALREADY_EXISTS as indication of existing instance.

* fix(linux): disconnect destroy handler by user_data to fix Linux build error

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…ck to `G_APPLICATION_FLAGS_NONE` (#3105)

* Use `GLIB_CHECK_VERSION(2,74,0)` to select `G_APPLICATION_DEFAULT_FLAGS` when available, otherwise use `G_APPLICATION_FLAGS_NONE`.
* Resolves build failures with older GLib headers while keeping the preferred constant on newer systems.
* No functional changes; improves cross-distro compatibility.
…3108)

* chore: update various deps references

* chore(deps): Upgrade SDK deps to pub.dev hosted

* chore: upgrade flutter version references

* chore(sdk): support Option 3 (hosted) SDK deps in roll script and docs

* chore(scripts): update roll_sdk_packages.sh

* chore(scripts): accept CLI flags (-a/--upgrade-all, -t/--target-branch, --help)

* feat(scripts): add --major-sdk-only to allow major upgrades for SDK hosted deps

* fix(scripts): preserve pubspec.yaml structure when using --major-sdk-only by backup/restore before inline updates

* fix(scripts): delete *.bak and *.bak_major even when no rolls detected

* chore: roll sdk

* chore: add Cursor ignore

* Fix shell array expansion in package upgrade script

Co-authored-by: charl <charl@vanstaden.info>

* Improve SDK package roll script with robust error handling and file processing

Co-authored-by: charl <charl@vanstaden.info>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
#3110)

* chore: update various deps references

* chore(deps): Upgrade SDK deps to pub.dev hosted

* chore: upgrade flutter version references

* chore(sdk): support Option 3 (hosted) SDK deps in roll script and docs

* chore(scripts): update roll_sdk_packages.sh

* chore(scripts): accept CLI flags (-a/--upgrade-all, -t/--target-branch, --help)

* feat(scripts): add --major-sdk-only to allow major upgrades for SDK hosted deps

* fix(scripts): preserve pubspec.yaml structure when using --major-sdk-only by backup/restore before inline updates

* fix(scripts): delete *.bak and *.bak_major even when no rolls detected

* chore: roll sdk

* chore: add Cursor ignore

* build(sdk): add sdk as git submodule and update deps to path overrides

* ci: add recursive submodules option to checkout steps

* docs: document submodule init step and related notes

* chore(submodules): pin SDK to recorded commit and update docs/docker

- Set sdk submodule to track dev with update=checkout and on-demand fetch
- Document explicit update flow and CI pinned behavior
- Ensure Docker builds initialize submodule to pinned commit

* docs(pubspec): clarify Option 1 uses sdk submodule (pinned; no symlink)

* docs(pubspec): reference SDK submodule docs for Option 1 (pinned setup)

* build(docker): bump pinned Flutter version to 3.35.1

* chore(build): bump Flutter to 3.35.2 in docs, workflows, & docker

---------

Co-authored-by: CharlVS <77973576+CharlVS@users.noreply.github.com>
* add GitHub Actions workflow to validate Linux build script

Introduce docker-linux-build.yml workflow that runs .docker/build.sh for
Linux builds inside Docker. This allows us to continuously verify that
the build script works as expected and that the Linux application can be
successfully built in a clean environment.

By having this check in CI, we ensure that end users will also be able
to build the application themselves using .docker/build.sh, which is the
only officially recommended build path.

* CI: touch .docker to trigger PR workflow

* remove temp .ci-touch file

---------

Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
* test: remove cex market data unit tests

API providers already moved to SDK, with market metrics soon to follow

* test: explicitly skip failing tests that require SDK internals mocking

* fix: conflicting cex and dex RPC imports

legacy and local import names conflicted with SDK exports when importing without the `show` option to limit imports.

* fix(sparkline): update to use AssetId and Di via RepositoryProvider

* fix(cex-price): migrate to local, deprecated model with Decimal

Double conversion used for widget display-only purposes, and Rational/Decimal defaulted to for internal calculations (e.g. repositories an blocs)

* fix(market-metrics): migrate to SDK MarketDataManager interface

* fix(price-chart): migrate to SDK MarketDataManager interface

* chore: migrate KW to mono-repo workspace

* fix: exhaustive dependency overrides for sdk packages

* build(deps): move SDK package overrides to pubspec_overrides.yaml

- Remove local path overrides from pubspec.yaml
- Add pubspec_overrides.yaml with ./sdk package paths

* fix(review): improve rational/decimal conversions and null check safety

* test(get-fiat-amount): re-enable fiat amount unit test

* fix(profit-loss-calculator): normalise timezones to UTC

* chore: sync native dependencies

* chore(ios): apply Flutter auto-migrations

* fix(macos): fix broken runner config paths

* feat(settings): add new SDK methods for coin config commit hashes

* fix(wallet-overview): prefer current balance over portfolio balance calc

* fix(app-version-info): switch to timer-based polling approach

- update wallet overview comments
- simplify total balance data source and calculations
- use valuegetter for copyWith function

* chore(app-version-info): bump polling interval back to 5min

---------

Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
#3115)

Previously, when logging apiCommitHash, the code printed the function reference (e.g. Closure: () => String) instead of the actual hash value.

Example:

```
2025-8-29: 18:38:32.869T+:0:00:00.036927 [LOG] {message: INFO: MM2 API version loaded successfully - Version: 2.5.1-beta_80766b0, Commit: Closure: () => String - null, path: VersionInfoBloc, app_version: 0.9.2, mm2_version: 2.5.1-beta_80766b0, os_language: en-US, screen_size: , timestamp: 1756492712864, date: 2025-08-29 20:38:32.864631}__metadata: {appVersion: null, mm2Version: 2.5.1-beta_80766b0, appLanguage: , platform: linux Linux 6.8.0-65-generic #68~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 15 18:06:34 UTC 2, osLanguage: en-US, screenSize: }
```
…iner (#3114)

* build(devcontainer): reuse .docker images and fix cross-platform paths

Use komodo/komodo-wallet image; prebuild base images in initializeCommand; remove USB mount; macOS/WSL compatible. Delete obsolete .devcontainer/Dockerfile.

* build(devcontainer): revert to Linux-only flow and validate on ubuntu CI

Build from .docker Dockerfile with USB mount; add GH workflow to build images on hosted runners.

* ci: remove devcontainer build workflow; use GitHub prebuilds instead

* build(devcontainer): init and pin submodules in postCreate

* build(devcontainer): ignore dirty state for sdk submodule; pin only commits

* build(devcontainer): move postCreate steps to script to avoid exec errors

* refactor(devcontainer): remove chown, don't ignore failures, disable privileged flag by default

---------

Co-authored-by: Francois <takenagain@users.noreply.github.com>
)

* feat: add remember me wallet login

* feat(auth): implement one-click remember me sign-in functionality

- Add automatic sign-in dialog for last logged-in wallet on app start
- Store and retrieve wallet information in local storage when remember me is enabled
- Implement remember me checkbox across all wallet flows (login, creation, import)
- Add session-based dialog prevention to avoid multiple prompts
- Support backward compatibility for existing stored wallet data

Technical changes:
- Introduce AppDialog as replacement for deprecated PopupDispatcher
- Add WalletId JSON storage with pubkey hash for precise wallet matching
- Update wallet manager widgets to support remember me state
- Add translations for new UI elements
- Implement proper storage cleanup when remember me is disabled

This enhancement streamlines the user experience by allowing quick access to
previously used wallets while maintaining security through password requirements.

* fix: reword quick login text

* Verify wallet identity using pubkey hash MD5 comparison

Co-authored-by: charl <charl@vanstaden.info>

* fix: prevent blank screen after login (#3043)

* fix(auth): avoid context usage after login dialog closes (#3044)

* bug(login): fix quick login dialog showing multiple times

* fix: various sign-in remember-me fixes

TODO(@takenagain): Refactor remember-me feature to bloc

* fix: use stable context in connect wallet dispatcher

* fix: navigator bug

* fix: add missing password reset autocomplete

* Fix: Use root navigator in remembered wallet dialog and reset flag on failure

* Improve password field auto-submit with paste detection logic

Co-authored-by: charl <charl@vanstaden.info>

* feat: integrate password manager to password reset

* docs: add wallet manager TODO

* fix(auth,autofill): finalize autofill context only after successful login to restore password manager saving\n\n- Remove premature TextInput.finishAutofillContext(shouldSave: true) on submit\n- Call finishAutofillContext(shouldSave: true) in onLogIn() after AuthBloc signals logged-in\n\nThis resolves the regression introduced with one-click login that prevented credential managers from saving/recalling credentials.

* fix(auth,dialog): guard dialog close and tolerate sign-out errors to prevent Android grey screen

- Make AppDialog close idempotent and use navigator.maybePop() to avoid 'Bad state: No element' during 1-click login transitions
- Wrap KDF signOut in try/catch so UI resets even if KDF stop times out
- Align deprecated PopupDispatcher.close() to use maybePop()

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…ement (#3111)

* fix(macos): show file picker by adding user-selected read-only entitlement

- Add com.apple.security.files.user-selected.read-only to DebugProfile and Release entitlements to enable file_picker dialog on macOS.\n- Bump iOS deployment target to 13.0 (project settings and AppFrameworkInfo.plist) to align with plugin requirements.\n- Update file_picker to ^10.3.2 and refresh lockfiles (iOS/macOS).\n\nRefs: https://github.com/miguelpruivo/flutter_file_picker/wiki/Setup

* chore: roll native ios/macos deps

* fix(macos): enable save dialog by switching to user-selected read-write entitlement

- Replace com.apple.security.files.user-selected.read-only with read-write in DebugProfile and Release entitlements to allow NSSavePanel.

Refs: https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_files_user-selected_read-write, #3111 (comment)
* Add exact amount button and improve large number parsing

Co-authored-by: charl <charl@vanstaden.info>

* Auto-fill sell amount when order is selected in taker form

Co-authored-by: charl <charl@vanstaden.info>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix impossible nested condition logic

* handle uninitialized logger exceptions gratefully

* caches `typeName` to avoid unneccesary `getCoinTypeName` calls

* adds caching for `isParent`

* set parents as native; use cached coin values

* special case to cover ARB

* chore: roll SDK (#3036)

Roll SDK for critical KMD API pricing fix

* chore: remove FEEDBACK_TEST_URL references

* fix(ui): close dropdown on window resize

* Fix null safety issues in UiDropdown widget

Co-authored-by: charl <charl@vanstaden.info>

* fix(build): correct env vars passing to Docker and Dart via --dart-define (#3037)

* refactor: simplify Docker env vars and build command logic

- Remove unnecessary environment variables from Docker container
- Keep only GITHUB_API_PUBLIC_READONLY_TOKEN as env var
- Replace hardcoded build logic with conditional credential handling
- Add proper validation for Trello and Cloudflare feedback services
- Use dart-define flags instead of environment variables for build configs
- Add warning messages for incomplete credential sets

* fix executable rights on build.sh

* remove the redundant FEEDBACK_TEST_URL, as it will no longer be used in the GUI

* swap BUILD_COMMAND and BUILD_CMD (important)

BUILD_CMD, which is built dynamically with --dart-define= arguments, should be called last (not during the assets-fetch stage) to ensure the app is actually built with the required defines and that all String.fromEnvironment(...) statements in the Dart code work as expected.

* fix(nft): add IPFS gateway resolution, retry, and fallback to improve NFT image loading (#3020)

* feat(nft): tolerate activation failures

* fix(nft): skip missing parents in firstWhere

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-main-repo): fix parent coin filter and use logging package

* fix(nft): don't return an error if there are no NFTs returned

* fix(nft): revert map-based error responses in favor of manual activation

* fix(skeleton-list-tile): add height constraint to fix renderflex assert

* fix(coin): temporarily skip calling deactivation RPC

circumvent "NoSuchCoin" error when re-enabling the coin in the same session.

* fix(activation): use more complete coin conversion function

* feat(nft): add nft image bloc for url resolution, fallbacks and retry

* fix(ipfs-gateway-manager): move gateway match above subdomain

gateway pattern matches subdomain due to loose alphanumeric requirement

* test: add unit tests for ipfs url normaliser and fix case sensitivity

* refactor(nft-image): remove dead code & move url testing out of bloc

* fix(nft): delegate IpfsGatewayManager disposal to root provider (#3047)

* fix: delegate IpfsGatewayManager disposal to root provider

* refactor: remove unnecessary line break

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(nft): reset NFT image on url change (#3046)

* fix: reset NFT image on url change

* refactor(nft-image): use ValueKey instead of Key

Using Key(imageUrl!) creates a new Key object on every build. Consider using ValueKey(imageUrl!) instead, which is more semantically appropriate for value-based keys and may have better performance characteristics.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* refactor(nft-image): use ValueKey instead of Key

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* style: apply updated dart formatting to modified files

* fix(coins): filter excluded and testnet coins out of price updates

* fix(nft-image): reduce the number of success events fired

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(build): add --no-web-resources-cdn to the web build in build.sh (#3055)

* Remove .dgph build artifacts from iOS project (#3058)

* remove dgph binaries

* Ignore .dgph build artifacts in iOS

* fix arb parent ticker

* include qtum parent

* chore(sdk): bump submodule to 170aab4 for parent display name suffix

Pulls in AssetId.displayName and CoinSubClass.tokenStandardSuffix

* feat(ui): disambiguate parent chain names via SDK displayName

- Use AssetId.displayName for top-level assets (SDK)\n- Update UI to show e.g. Ethereum (ARB20) for parents\n- Keep protocol pill consistent using coin.typeName (NATIVE for parents)\n- Search compares against displayName\n\nRefs: #2988 (comment)

---------

Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: charl <charl@vanstaden.info>
Co-authored-by: DeckerSU <deckersu@protonmail.com>
Co-authored-by: Francois <takenagain@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…lls on user input changes (#3125)

* chore(deps): bump sdk to 3f503d2 and fix breaking sparkline change

* perf(fiat-onramp): add debouncer to fiat amount input field

reduce API requests sent on user input. This was previously managed via `bloc_concurrency` debounce transformer, which was changed to `restartable` after incorrect state updates were reported in testing

* refactor(header): use SDK balance for header balance value

continuation of migration away from portfolio balance in previous PR

* refactor(review): explicit imports, clear flag, and use `.value` factory

---------

Co-authored-by: Charl (Nitride) <77973576+CharlVS@users.noreply.github.com>
* docs(setup): add ruby installation step for ios and macos builds

* docs(setup): replace specific versions with notes about using latest

specific versions are redundant, as there are no currently known version constraints, and the team is generally using the latest available versions of all tools

* build(android): bump ndk, platform, and build-tools to latest releases

* docs(setup): remove sudo from cocoapods install and fix misc issues
cursor[bot]

This comment was marked as outdated.

@CharlVS CharlVS added SEC review pending Awaiting SEC review QA Ready for QA Testing labels Oct 8, 2025
@DeckerSU
Copy link
Copy Markdown
Contributor

DeckerSU commented Oct 8, 2025

Just want to note that the current release uses komodo-defi-sdk-flutter from commit 679fd92a6ce6d87b631dadbcaca1c8343e6580c2, which has a build_config.json that does not account for macOS universal2 binaries, as described in #3154.

Before the release, build_config.json should be updated with a new matching_pattern for the macos platform, since the KDF release will include universal2 binaries and follow the new naming convention mentioned in the same issue.

https://github.com/KomodoPlatform/komodo-defi-sdk-flutter/blob/679fd92a6ce6d87b631dadbcaca1c8343e6580c2/packages/komodo_defi_framework/app_build/build_config.json#L26-L32

p.s. It should look like this:

"matching_pattern": "^(?:kdf-macos-universal2-[a-f0-9]{7,40}|kdf_[a-f0-9]{7,40}-mac-universal)\\.zip$"

The first part matches Jenkins releases (for example, kdf-macos-universal2-347d8fc.zip), and the second part matches CI/CD dev artifacts (for example, kdf_347d8fc-mac-universal.zip).

@DeckerSU
Copy link
Copy Markdown
Contributor

DeckerSU commented Oct 9, 2025

If we are not using package.json or any Node.js-related parts in komodo_defi_framework, maybe we can safely remove everything npm-related in komodo_wallet_build_transformer? I mean the npm call in _updateWebPackages and the entire node_path.dart, to make the build process more safe.

https://github.com/KomodoPlatform/komodo-defi-sdk-flutter/blob/679fd92a6ce6d87b631dadbcaca1c8343e6580c2/packages/komodo_wallet_build_transformer/lib/src/steps/fetch_defi_api_build_step.dart#L338-L364

@CharlVS
Copy link
Copy Markdown
Collaborator Author

CharlVS commented Oct 10, 2025

maybe we can safely remove everything npm-related in komodo_wallet_build_transformer?

@DeckerSU Good point, and it should be safe to remove. However, it is useful for cache busting with webpack. If @gcharang can confirm that, then I will refactor and update docs to make Node.js optional.

@gcharang
Copy link
Copy Markdown
Contributor

@CharlVS we don't have any webpack stuff right now and won't/don't need cache busting as we have a service worker. we can safely remove the highlighted nodejs stuff imo

@DeckerSU
Copy link
Copy Markdown
Contributor

All new and updated dependencies introduced in this release have been reviewed. No malicious or suspicious components were found. The integrity and authenticity of external packages have been verified where applicable (meaning the versions served from dart.pub and flutter.pub were compared with their corresponding GitHub sources).

This review covers only third-party dependencies and external code, not the application’s internal logic or functionality.

From an operational security standpoint, the dependency changes LGTM.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
.github/workflows/mobile-builds.yml (1)

34-35: Submodules: recursive — OK

Consistent with the repo-wide submodule adoption. No further action; prior discussion on shallow depth stands.

🧹 Nitpick comments (3)
.github/workflows/docker-android-build.yml (1)

47-58: Harden GITHUB_TOKEN permissions

You're exporting the default GITHUB_TOKEN (aliased here as GITHUB_API_PUBLIC_READONLY_TOKEN). For least privilege, explicitly set workflow/job permissions to read-only (contents: read) unless writes are required.

Example (top-level):

permissions:
  contents: read
.github/workflows/desktop-builds.yml (2)

73-76: Reduce GITHUB_TOKEN privileges

The env variable name suggests read-only, but the default GITHUB_TOKEN may have broader scopes. Explicitly lock down permissions:

At workflow top:

permissions:
  contents: read

Tighten further per platform if needed.


85-86: Analytics config OK; consider disabling for CI artifacts

MATOMO_URL and MATOMO_SITE_ID are safe to embed. If CI artifacts might run outside controlled environments, consider setting ANALYTICS_DISABLED=true in CI to avoid noisy telemetry.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 137dd4f and f042412.

📒 Files selected for processing (4)
  • .github/workflows/desktop-builds.yml (4 hunks)
  • .github/workflows/docker-android-build.yml (2 hunks)
  • .github/workflows/docker-linux-build.yml (1 hunks)
  • .github/workflows/mobile-builds.yml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/docker-linux-build.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: osv_scan
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: build-linux-docker
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: build_and_preview
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: unit_tests
  • GitHub Check: validate_code_guidelines
  • GitHub Check: Test web-app-linux-profile
  • GitHub Check: build-android-docker
  • GitHub Check: Test web-app-macos
  • GitHub Check: Build Desktop (macos)
  • GitHub Check: build_and_deploy
🔇 Additional comments (5)
.github/workflows/docker-android-build.yml (1)

62-66: Good: deterministic artifact suffix

Short SHA computation is correct and scoped to bash. No concerns.

.github/workflows/mobile-builds.yml (1)

86-90: Good: short SHA suffix for artifacts

Step is correct and consistent across workflows.

.github/workflows/desktop-builds.yml (3)

6-6: Branch filter expansion LGTM

Adding fix/* and add/* makes sense for coverage.


89-92: Good: short SHA computation

Matches other workflows; no issues.


98-99: Artifact naming

Using .zip in the artifact name is fine; upload-artifact will compress regardless. Just ensure consumers don’t double-zip on download.

Comment on lines +49 to +57
# Optional feedback provider secrets to embed dart-defines
TRELLO_API_KEY: ${{ secrets.TRELLO_API_KEY }}
TRELLO_TOKEN: ${{ secrets.TRELLO_TOKEN }}
TRELLO_BOARD_ID: ${{ secrets.TRELLO_BOARD_ID }}
TRELLO_LIST_ID: ${{ secrets.TRELLO_LIST_ID }}
FEEDBACK_API_KEY: ${{ secrets.FEEDBACK_API_KEY }}
FEEDBACK_PRODUCTION_URL: ${{ secrets.FEEDBACK_PRODUCTION_URL }}
MATOMO_URL: ${{ secrets.MATOMO_URL }}
MATOMO_SITE_ID: ${{ secrets.MATOMO_SITE_ID }}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Do not embed sensitive tokens into the APK

Passing TRELLO_TOKEN (and similar) as build envs risks compiling secrets into the app artifact and leaking them via public artifacts/logs. Matomo URL/site ID are fine as public config; Trello token is not.

Recommended:

  • Do not inject TRELLO_TOKEN (or any privileged token) into client builds. Move such calls server-side, or gate usage to CI-only actions that do not end up in the binary.
  • If you must keep them for internal QA, avoid uploading those artifacts publicly and gate injection behind a condition (e.g., internal branches) and strip before upload.

Please confirm these secrets are not compiled into the APK and that uploaded artifacts cannot expose them.


🏁 Script executed:

#!/bin/bash
set -e
echo "=== dart-define usage ==="
rg -n 'dart-define' -C3 .github/workflows/docker-android-build.yml || echo "No dart-define found"
echo "=== Flutter build commands ==="
rg -n 'flutter build' -C3 .github/workflows/docker-android-build.yml || echo "No flutter build found"
echo "=== DART_DEFINES usage ==="
rg -n 'DART_DEFINES' -C3 .github/workflows/docker-android-build.yml || echo "No DART_DEFINES found"

Length of output: 503


🏁 Script executed:

#!/bin/bash
set -e
echo "=== docker-android-build.yml lines 1-200 ==="
sed -n '1,200p' .github/workflows/docker-android-build.yml

Length of output: 2224


🏁 Script executed:

#!/bin/bash
set -e
echo "=== .docker/build.sh (first 200 lines) ==="
sed -n '1,200p' .docker/build.sh || echo "File not found or empty"
echo "=== dart-define usage in .docker directory ==="
rg -n 'dart-define' -C3 .docker

Length of output: 8481


Do not embed privileged tokens in client builds

  • TRELLO_TOKEN (and TRELLO_API_KEY) are passed via --dart-define in .github/workflows/docker-android-build.yml → .docker/build.sh, embedding them into the APK. Move these credentials to server-side or CI-only steps that never end up in the binary.
    Confirm removal of all privileged secrets from the build and ensure public artifacts cannot expose them.

Comment on lines +70 to 85
- name: Fetch packages, generate assets, and build for ${{ matrix.platform }}
env:
GITHUB_API_PUBLIC_READONLY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ${{ matrix.build_command }}
uses: ./.github/actions/generate-assets
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TRELLO_API_KEY: ${{ secrets.TRELLO_API_KEY }}
TRELLO_TOKEN: ${{ secrets.TRELLO_TOKEN }}
TRELLO_BOARD_ID: ${{ secrets.TRELLO_BOARD_ID }}
TRELLO_LIST_ID: ${{ secrets.TRELLO_LIST_ID }}
FEEDBACK_API_KEY: ${{ secrets.FEEDBACK_API_KEY }}
FEEDBACK_PRODUCTION_URL: ${{ secrets.FEEDBACK_PRODUCTION_URL }}
MATOMO_URL: ${{ secrets.MATOMO_URL }}
MATOMO_SITE_ID: ${{ secrets.MATOMO_SITE_ID }}
BUILD_COMMAND: ${{ matrix.build_command }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Avoid embedding privileged secrets in mobile apps; consider disabling analytics in CI

  • Risk: TRELLO_TOKEN (and related) may end up compiled into iOS/Android artifacts and then uploaded. This is sensitive and should not be client-embedded. Matomo config is safe to embed.
  • Actions:
    • Remove TRELLO_TOKEN (and any privileged API tokens) from client build inputs; handle server-side or CI-only.
    • Gate secret injection to internal builds only and skip artifact upload for such builds, or strip secrets before upload.
    • Optionally add ANALYTICS_DISABLED=true for CI/test builds to avoid sending analytics from CI artifacts if they ever run.

Please confirm these secrets are not embedded in the produced artifacts and that artifact visibility will not expose them.


🏁 Script executed:

#!/bin/bash
set -e

echo "Listing generate-assets action files:"
ls -R .github/actions/generate-assets

echo -e "\nInspecting action.yml:"
sed -n '1,200p' .github/actions/generate-assets/action.yml

echo -e "\nSearching for TRELLO_TOKEN in action code:"
rg -n 'TRELLO_TOKEN' -C3 .github/actions/generate-assets

Length of output: 10389


Remove privileged secrets from Flutter build inputs

  • The composite action injects TRELLO_API_KEY, TRELLO_TOKEN, TRELLO_BOARD_ID, and TRELLO_LIST_ID into the flutter build via --dart-define (action.yml lines 114–118), which embeds them in the app binary and can be extracted.
  • Move Trello feedback operations to a backend/CI-only process or strip these variables before the production build.
  • Apply the same gating to FEEDBACK_API_KEY (and any other sensitive tokens), or set ANALYTICS_DISABLED=true for CI/test builds to prevent unintended analytics from CI artifacts.

…ith occasional flickering (#3187)

* fix(maker-bot): sell coin leading widget takes up entire width

* fix(maker-bot): remove duplicate event and reduce emit frequency

race condition with sell coin selection event emission resulted in sell coin flickering between current and previous coin

* chore(sdk): update SDK to 448eecc to switch to KDF staging branch

* refactor(maker-bot): use intermediate state and clamp sell amount

* fix(maker-bot): add debounce to percentage slider

* revert: emit coin selection event early before preimage check

prevents input delays while waiting for preimage error checks
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
lib/bloc/market_maker_bot/market_maker_trade_form/market_maker_trade_form_bloc.dart (2)

134-172: Consider consolidating emissions to reduce state churn.

This method emits state up to 3 times in quick succession:

  1. Line 136: Initial coin selection update
  2. Line 156: Buy amount update
  3. Line 170: Preimage error update (if applicable)

While this provides incremental UI updates, rapid successive emissions can cause unnecessary widget rebuilds and potential flickering. Consider whether some of these can be consolidated, especially the buy amount calculation (lines 150-163) which could potentially be included in the initial emission if the calculation is fast enough.


474-479: Handle zero‐value sell amounts in _getMaxSellAmountFromPreImage
Clamping prevents negatives, but "0" still passes .isEmpty and yields a zero‐value trade. Add a numeric <= 0 validation (e.g. enforce a dust limit or emit an error) to reject or properly handle zero‐amount trades.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f042412 and 8cd8b52.

📒 Files selected for processing (2)
  • .gitignore (2 hunks)
  • lib/bloc/market_maker_bot/market_maker_trade_form/market_maker_trade_form_bloc.dart (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Format Dart code using dart format . before committing

Files:

  • lib/bloc/market_maker_bot/market_maker_trade_form/market_maker_trade_form_bloc.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Test web-app-linux-profile
  • GitHub Check: Test web-app-macos
  • GitHub Check: Cursor Bugbot
  • GitHub Check: validate_code_guidelines
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: Build Desktop (macos)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: unit_tests
  • GitHub Check: build_and_preview
  • GitHub Check: build-android-docker
  • GitHub Check: build-linux-docker
  • GitHub Check: build_and_deploy
🔇 Additional comments (4)
lib/bloc/market_maker_bot/market_maker_trade_form/market_maker_trade_form_bloc.dart (4)

86-94: LGTM: Improved UI responsiveness.

Calculating newBuyAmount upfront and including it in the initial emission provides faster feedback to the user.


114-121: Verify preimage error handling doesn't mask activation failures.

If _autoActivateCoin throws an error (line 112), the preimage check at line 116 will still execute. Consider whether activation failures should prevent preimage checks or be surfaced to the user.


184-224: LGTM: Clear separation of immediate update and async validation.

The immediate emission at line 196 provides responsive UI feedback, while the async preimage validation at lines 206-224 ensures correctness. The pattern is clear and maintainable.


109-112: Clarify or remove the TODO comment—it incorrectly describes the coin filtering logic.

The sell coin dropdown filters by USD balance only, not by active status. The code at lines 177–181 of lib/views/market_maker_bot/market_maker_bot_form_content.dart shows:

List<Coin> _coinsWithUsdBalance(List<Coin> coins) {
  return coins
      .where((coin) => (coin.lastKnownUsdBalance(context.sdk) ?? 0) > 0)
      .toList();
}

There is no isActive filter. The TODO's assumption that "only enabled coins with a balance are displayed" is inaccurate. Since coins without active status could theoretically have a USD balance, the _autoActivateCoin() call at line 112 is a necessary defensive activation. Either remove the comment entirely (if the activation is warranted), or update it to accurately reflect that coins are filtered by balance, not active status, and explain why pre-activation is still needed.

… reactivation (#3184)

* fix(zcoin): show zcoin on reactivation

zcoin activation function simply discarded coins that were already active without notifying listeners to display the coin in UI

* style(zhtlc): move block size and scan interval to advanced section

* feat(zhtlc): add config modification option to coin details page

* fix(zhtlc): simplify the config update and reactivation

* chore(sdk): update SDK to 448eecc to switch to KDF staging branch

* chore(zhtlc): reword dialog title and apply suggestions

* fix(zhtlc): coin incorrectly added to list on dialog cancel

* fix(zcoin): rethrow if user action is not

mismatch of assumptions: activateArrr returns an activation error result rather than throwing an exception, so it has to be rethrown in the error handler for it to bubble up.

there is also a mismatch between single and multiple activations, but that is fine for now since single activations are all that are present

---------

Co-authored-by: Nitride <77973576+CharlVS@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
lib/bloc/coins_bloc/coins_repo.dart (2)

95-114: Existing subscriptions not cancelled when assets become blocked.

The blocking check prevents NEW subscriptions for blocked assets (lines 99-102). However, if an asset becomes blocked AFTER activation, the existing subscription continues to run, wasting resources by watching untradable assets.

Consider adding a method to reactively cancel subscriptions when trading status changes:

+ /// Cancel balance subscription for an asset
+ void _cancelBalanceSubscription(AssetId assetId) {
+   _balanceWatchers[assetId]?.cancel();
+   _balanceWatchers.remove(assetId);
+ }
+
  /// Subscribe to balance updates for an asset using the SDK's balance manager
  void _subscribeToBalanceUpdates(Asset asset) {
    // Cancel any existing subscription for this asset
    _balanceWatchers[asset.id]?.cancel();

    if (_tradingStatusService.isAssetBlocked(asset.id)) {
      _log.info('Asset ${asset.id.id} is blocked. Skipping balance updates.');
      return;
    }

    // Start a new subscription
    _balanceWatchers[asset.id] = _kdfSdk.balances.watchBalance(asset.id).listen(
      (balanceInfo) {
        // Update the balance cache with the new values
        _balancesCache[asset.id.id] = (
          balance: balanceInfo.total.toDouble(),
          spendable: balanceInfo.spendable.toDouble(),
        );
      },
    );
  }

Then, listen to trading status changes and cancel subscriptions for newly-blocked assets:

// In constructor or initialization
_tradingStatusService.watchBlockedAssets().listen((blockedAssets) {
  for (final assetId in blockedAssets) {
    _cancelBalanceSubscription(assetId);
  }
});

625-633: Guard against empty asset list.

If assets is empty, boundedChunkSize becomes 0 and assets.slices(0) throws an ArgumentError, breaking fetchCurrentPrices whenever no assets are available.

Apply this diff to guard against empty assets:

  Future<void> _fetchAssetPricesInChunks(
    List<Asset> assets, {
    int chunkSize = 12,
  }) async {
+   if (assets.isEmpty) {
+     return;
+   }
    final boundedChunkSize = min(assets.length, chunkSize);
    final chunks = assets.slices(boundedChunkSize);

    for (final chunk in chunks) {
      await Future.wait(chunk.map(_fetchAssetPrice), eagerError: false);
    }
  }
🧹 Nitpick comments (5)
lib/services/arrr_activation/arrr_activation_service.dart (3)

120-127: Consider reducing the configuration timeout duration.

The 15-minute timeout for configuration requests is quite long. Most user interactions should complete within 1-5 minutes. A long timeout can leave resources held unnecessarily if users abandon the configuration flow.

Consider reducing the timeout to 3-5 minutes or making it configurable:

+      /// Default timeout for configuration requests
+      static const _configurationTimeout = Duration(minutes: 5);
+
       try {
         config = await completer.future.timeout(
-          const Duration(minutes: 15),
+          _configurationTimeout,
           onTimeout: () {

383-406: Consider improving UI listener detection.

The polling approach works but could be more efficient. Additionally, continuing execution when no listeners are detected (line 394-398) could result in lost configuration requests that are emitted but never received.

Consider:

  1. Using a Completer that gets completed when the first listener subscribes
  2. Throwing an error if no listeners are detected after the timeout, rather than continuing
  Future<void> _waitForUIListeners(AssetId assetId) async {
    const maxWaitTime = Duration(seconds: 10);
    const checkInterval = Duration(milliseconds: 100);
    final stopwatch = Stopwatch()..start();

    while (!_configRequestController.hasListener &&
        stopwatch.elapsed < maxWaitTime) {
      _log.info('Waiting for UI listeners to be ready for ${assetId.id}...');
      await Future.delayed(checkInterval);
    }

    if (!_configRequestController.hasListener) {
-      _log.warning(
+      final message = 
        'No UI listeners detected after ${maxWaitTime.inSeconds} seconds for ${assetId.id}. '
-        'Make sure ZhtlcConfigurationHandler is in the widget tree.',
+        'Make sure ZhtlcConfigurationHandler is in the widget tree.';
-      );
+      _log.severe(message);
+      throw StateError(message);
    } else {
      _log.info(
        'UI listeners ready for ${assetId.id} after ${stopwatch.elapsed.inMilliseconds}ms',
      );
    }

    stopwatch.stop();
  }

154-216: Consider distinguishing retryable from non-retryable errors.

The retry logic currently treats all activation failures as retryable by wrapping them in _RetryableZhtlcActivationException (line 192). Some errors may not benefit from retries, such as invalid configuration, permission errors, or service unavailability. Retrying these wastes time and resources.

Consider analyzing the error type or message to determine if retry is appropriate:

          if (lastActivationProgress?.isSuccess ?? false) {
            await _cacheActivationComplete(asset.id);
            return ArrrActivationResultSuccess(
              Stream.value(
                ActivationProgress(
                  status: 'Activation completed successfully',
                  progressPercentage: 100,
                  isComplete: true,
                  progressDetails: ActivationProgressDetails(
                    currentStep: ActivationStep.complete,
                    stepCount: 1,
                  ),
                ),
              ),
            );
          }

          final errorMessage =
              lastActivationProgress?.errorMessage ??
              'Unknown activation error';
+         
+         // Determine if the error is retryable based on the error message
+         final isRetryable = !errorMessage.contains('invalid') &&
+             !errorMessage.contains('permission') &&
+             !errorMessage.contains('unauthorized');
+         
+         if (!isRetryable) {
+           // Don't retry for permanent errors
+           throw Exception(errorMessage);
+         }
+         
          throw _RetryableZhtlcActivationException(errorMessage);
lib/bloc/coins_bloc/coins_repo.dart (2)

752-815: Consider extracting common post-activation logic.

The method handles already-activated and newly-activated assets separately, but both paths perform similar post-activation tasks (broadcasting state, subscribing to balances, registering icons). This duplication increases maintenance burden.

Extract common logic into a helper method:

+ /// Common post-activation tasks for ZHTLC assets
+ void _handleZhtlcPostActivation(
+   Asset asset,
+   Coin coin, {
+   bool notifyListeners = true,
+ }) {
+   // Broadcast active state
+   if (notifyListeners) {
+     _broadcastAsset(coin.copyWith(state: CoinState.active));
+     if (coin.id.parentId != null) {
+       final parentCoin = _assetToCoinWithoutAddress(
+         _kdfSdk.assets.available[coin.id.parentId]!,
+       );
+       _broadcastAsset(parentCoin.copyWith(state: CoinState.active));
+     }
+   }
+
+   // Subscribe to balance updates
+   _subscribeToBalanceUpdates(asset);
+   if (coin.id.parentId != null) {
+     final parentAsset = _kdfSdk.assets.available[coin.id.parentId];
+     if (parentAsset != null) {
+       _subscribeToBalanceUpdates(parentAsset);
+     }
+   }
+
+   // Register custom icon
+   if (coin.logoImageUrl?.isNotEmpty ?? false) {
+     AssetIcon.registerCustomIcon(coin.id, NetworkImage(coin.logoImageUrl!));
+   }
+ }

  Future<void> _activateZhtlcAssets(...) async {
    for (final asset in assets) {
      final coin = coins.firstWhere((coin) => coin.id == asset.id);
      final isAlreadyActivated = activatedAssets.any((a) => a.id == asset.id);

      if (isAlreadyActivated) {
        if (addToWalletMetadata) {
          await _addAssetsToWalletMetdata([asset.id]);
        }
-       // Broadcast, subscribe, register icon...
+       _handleZhtlcPostActivation(asset, coin, notifyListeners: notifyListeners);
      } else {
        await _activateZhtlcAsset(...);
      }
    }
  }

876-892: User cancellation detection is fragile.

The code detects user cancellation by checking if the error message contains "cancelled by user" (line 883). This string-matching approach is fragile and will break if the error message format changes in ArrrActivationService.

Consider using a dedicated exception type or error code for user cancellations:

In lib/services/arrr_activation/arrr_activation_service.dart:

class UserCancelledException implements Exception {
  const UserCancelledException(this.message);
  final String message;
}

Then in ArrrActivationService, throw this specific exception:

return ArrrActivationResultError(
  'Configuration cancelled by user or timed out',
  isUserCancellation: true, // Add this field
);

And in _activateZhtlcAsset, check the type:

        error: (message) {
          _log.severe(
            'ZHTLC asset activation failed: ${asset.id.id} - $message',
          );

-         final isUserCancellation = message.contains('cancelled by user');
+         final isUserCancellation = result.isUserCancellation ?? false;

          if (notifyListeners && !isUserCancellation) {
            _broadcastAsset(coin.copyWith(state: CoinState.suspended));
          }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cd8b52 and 8ee26a4.

⛔ Files ignored due to path filters (1)
  • lib/generated/codegen_loader.g.dart is excluded by !**/generated/**
📒 Files selected for processing (4)
  • assets/translations/en.json (11 hunks)
  • lib/bloc/coins_bloc/coins_repo.dart (20 hunks)
  • lib/main.dart (3 hunks)
  • lib/services/arrr_activation/arrr_activation_service.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Format Dart code using dart format . before committing

Files:

  • lib/main.dart
  • lib/bloc/coins_bloc/coins_repo.dart
  • lib/services/arrr_activation/arrr_activation_service.dart
🧠 Learnings (2)
📚 Learning: 2025-04-01T15:51:37.060Z
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2566
File: lib/bloc/coins_bloc/coins_bloc.dart:10-10
Timestamp: 2025-04-01T15:51:37.060Z
Learning: In the Komodo Wallet project, part files share imports with their parent files. The import for `app_config.dart` in `coins_bloc.dart` is necessary because the part file `coins_state.dart` uses `excludedAssetList` from that package.

Applied to files:

  • lib/main.dart
  • lib/bloc/coins_bloc/coins_repo.dart
📚 Learning: 2025-04-01T15:51:37.060Z
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2566
File: lib/bloc/coins_bloc/coins_bloc.dart:10-10
Timestamp: 2025-04-01T15:51:37.060Z
Learning: The `excludedAssetList` from `app_config.dart` is used in the `_filterExcludedAssets` method in `coins_state.dart`. Since `coins_state.dart` is a part file of `coins_bloc.dart`, the import needs to be in the parent file even though it's not directly used there. In Dart, part files share the namespace and imports of their parent files.

Applied to files:

  • lib/bloc/coins_bloc/coins_repo.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: Build Desktop (macos)
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: build-android-docker
  • GitHub Check: build_and_preview
  • GitHub Check: Test web-app-macos
  • GitHub Check: Test web-app-linux-profile
  • GitHub Check: validate_code_guidelines
  • GitHub Check: unit_tests
  • GitHub Check: build-linux-docker
  • GitHub Check: Cursor Bugbot
  • GitHub Check: build_and_deploy
🔇 Additional comments (7)
lib/services/arrr_activation/arrr_activation_service.dart (2)

16-19: LGTM!

The constructor properly initializes dependencies and immediately subscribes to authentication state changes, ensuring the service responds to auth lifecycle events.


516-536: LGTM!

The disposal logic is thorough and well-ordered. It prevents new operations, cancels subscriptions, completes pending operations with errors, and properly closes resources.

lib/main.dart (1)

63-84: LGTM!

The initialization sequence is well-ordered, ensuring dependencies are initialized before their consumers. The comment explaining Sparkline's Hive dependency is helpful for maintainability.

lib/bloc/coins_bloc/coins_repo.dart (4)

34-47: LGTM!

The constructor properly accepts and stores the new service dependencies while maintaining the existing initialization pattern.


257-279: LGTM!

The parameter rename from notify to notifyListeners improves clarity and is consistently applied throughout the method signature and documentation.


287-309: LGTM!

The separation of ZHTLC and regular assets is well-structured. Processing ZHTLC assets first ensures proper handling of their unique configuration requirements before proceeding with standard activations.


545-572: LGTM!

The expanded deprecation message provides clear guidance for migration and the implementation properly handles edge cases like multiple assets matching a single config ID.

}

if (!isUserCancellation) {
throw Exception("zcoin activaiton failed: $message");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in error message.

Line 890 contains a typo: "zcoin activaiton" should be "zcoin activation".

Apply this fix:

          if (!isUserCancellation) {
-           throw Exception("zcoin activaiton failed: $message");
+           throw Exception("zcoin activation failed: $message");
          }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
throw Exception("zcoin activaiton failed: $message");
if (!isUserCancellation) {
throw Exception("zcoin activation failed: $message");
}
🤖 Prompt for AI Agents
In lib/bloc/coins_bloc/coins_repo.dart around line 890, fix the typo in the
thrown exception message: change "zcoin activaiton failed: $message" to "zcoin
activation failed: $message" so the error text reads correctly; update only the
string literal in the Exception constructor.

Comment on lines +98 to +108
child: MultiRepositoryProvider(
providers: [
RepositoryProvider.value(value: komodoDefiSdk),
RepositoryProvider.value(value: mm2Api),
RepositoryProvider.value(value: arrrActivationService),
RepositoryProvider.value(value: coinsRepo),
RepositoryProvider.value(value: walletsRepository),
RepositoryProvider.value(value: sparklineRepository),
RepositoryProvider.value(value: tradingStatusRepository),
RepositoryProvider.value(value: tradingStatusService),
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify disposal handling for new services.

The provider configuration correctly exposes all newly initialized services. However, ensure that services requiring disposal (like ArrrActivationService which has a dispose() method) are properly disposed when the app terminates.

Verify disposal handling for the new services:


🏁 Script executed:

#!/bin/bash
# Check if ArrrActivationService has disposal handling
rg -n "dispose.*arrrActivationService|ArrrActivationService.*dispose" --type dart

# Check if there's a global disposal mechanism for services
ast-grep --pattern $'class $_App {
  $$$
  @override
  void dispose() {
    $$$
  }
  $$$
}'

Length of output: 256


Implement disposal for ArrrActivationService (and any other services with a dispose() method) in the root widget’s dispose().

Override your app’s dispose() (e.g., in MyApp) to call arrrActivationService.dispose() (and dispose additional services as needed).

🤖 Prompt for AI Agents
In lib/main.dart around lines 98 to 108, ArrrActivationService (and possibly
other services provided via RepositoryProvider) exposes a dispose() method but
the root widget does not override dispose() to call it; override your app's root
StatefulWidget (e.g., MyApp) dispose() and call arrrActivationService.dispose()
(and invoke dispose() on any other provided services that implement dispose),
ensuring you obtain the service instances (e.g., from fields or
RepositoryProvider) and clean them up before calling super.dispose().

Comment on lines 166 to 194
return MultiBlocProvider(
providers: [
BlocProvider<AuthBloc>(
create: (_) {
final bloc = AuthBloc(
komodoDefiSdk, walletsRepository, SettingsRepository());
komodoDefiSdk,
walletsRepository,
SettingsRepository(),
tradingStatusService,
);
bloc.add(const AuthLifecycleCheckRequested());
return bloc;
},
),
],
child: BetterFeedback(
feedbackBuilder: CustomFeedbackForm.feedbackBuilder,
themeMode: ThemeMode.light,
darkTheme: _feedbackThemeData(theme),
theme: _feedbackThemeData(theme),
child: AppFeedbackWrapper(
child: AnalyticsLifecycleHandler(
child: WindowCloseHandler(
child: app_bloc_root.AppBlocRoot(
storedPrefs: _storedSettings!,
komodoDefiSdk: komodoDefiSdk,
child: ScreenshotSensitivity(
controller: sensitivityController,
child: app_bloc_root.AppBlocRoot(
storedPrefs: _storedSettings!,
komodoDefiSdk: komodoDefiSdk,
),
),
),
),
),
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify ScreenshotSensitivityController disposal.

The widget tree structure is well-organized with proper dependency injection. The ScreenshotSensitivityController is created at line 165 but there's no visible disposal. Ensure the controller is properly disposed when MyApp is disposed to prevent resource leaks.

Check if ScreenshotSensitivityController requires disposal:


🏁 Script executed:

#!/bin/bash
# Check the controller's implementation
ast-grep --pattern $'class ScreenshotSensitivityController {
  $$$
  dispose() {
    $$$
  }
  $$$
}'

# Check if StatelessWidget needs conversion to StatefulWidget for disposal
rg -n "class MyApp extends.*Widget" lib/main.dart

Length of output: 41



---

🏁 Script executed:

```shell
#!/bin/bash
# Find ScreenshotSensitivityController definition and implementation
rg -n "class ScreenshotSensitivityController" --type dart

# Find ScreenshotSensitivity widget and its build method
rg -n "class ScreenshotSensitivity" --type dart -A 20

# Check if controller is passed to a provider or inherited widget
rg -n "ScreenshotSensitivityController" lib/main.dart -B 2 -A 2

Length of output: 3673



---

🏁 Script executed:

```shell
#!/bin/bash
# Check for dispose calls on sensitivityController
rg -n "sensitivityController" lib/main.dart

# Check if there's a dispose method in ChangeNotifier or StatefulWidget managing this
rg -n "dispose\(\)" lib/main.dart -B 2 -A 2

# Check complete MyApp class structure
rg -n "class MyApp" lib/main.dart -A 50

Length of output: 1611


Convert MyApp to StatefulWidget and dispose ScreenshotSensitivityController
Refactor MyApp (lib/main.dart) from StatelessWidget to StatefulWidget, move sensitivityController instantiation into initState, and override dispose() to call sensitivityController.dispose() to avoid ChangeNotifier leaks.

🤖 Prompt for AI Agents
In lib/main.dart around lines 166 to 194, MyApp is currently a StatelessWidget
and creates a ScreenshotSensitivity controller inline causing a ChangeNotifier
leak; convert MyApp to a StatefulWidget, promote sensitivityController to a late
final field on the State class, instantiate it in initState(), and override
dispose() to call sensitivityController.dispose(); update references in the
build method to use the State's controller instance so the controller lifecycle
is properly managed.

Comment on lines +425 to +452
Future<void> _cleanupOnSignOut() async {
_log.info('User signed out - cleaning up active ZHTLC activations');

// Cancel all pending configuration requests
final pendingAssets = _configCompleters.keys.toList();
for (final assetId in pendingAssets) {
final completer = _configCompleters[assetId];
if (completer != null && !completer.isCompleted) {
_log.info('Cancelling pending configuration request for ${assetId.id}');
completer.complete(null);
}
}
_configCompleters.clear();

// Clear activation cache as it's user-specific
var activeAssets = <AssetId>[];
await _activationCacheMutex.protectWrite(() async {
activeAssets = _activationCache.keys.toList();
for (final assetId in activeAssets) {
_log.info('Clearing activation status for ${assetId.id}');
}
_activationCache.clear();
});

_log.info(
'Cleanup completed - cancelled ${pendingAssets.length} pending configs and cleared ${activeAssets.length} activation statuses',
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify ongoing activations are properly handled on sign-out.

The cleanup logic properly cancels pending configuration requests and clears the activation cache. However, it doesn't explicitly handle the ongoing activation futures stored in _ongoingActivations (line 34). While these futures will eventually complete or error out, they might continue consuming resources after sign-out.

Verify whether ongoing activation futures need explicit cancellation or if they naturally terminate when the auth state changes. Run the following to check if activations reference auth-dependent resources:


🏁 Script executed:

#!/bin/bash
# Check if activation methods access auth-dependent resources
ast-grep --pattern $'_activateArrrInternal($$$) {
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Locate declaration and usage of _ongoingActivations
rg -n '_ongoingActivations' -C3 lib/services/arrr_activation/arrr_activation_service.dart
rg -n '_ongoingActivations' -C3 .

Length of output: 3349


Clear ongoing activations on sign-out
Add _ongoingActivations.clear() inside _cleanupOnSignOut() to drop in-flight activation futures and prevent reuse of stale futures across user sessions.

🤖 Prompt for AI Agents
In lib/services/arrr_activation/arrr_activation_service.dart around lines 425 to
452, the cleanup routine does not clear the _ongoingActivations map/collection
so in-flight activation futures can be reused across sessions; add a call to
_ongoingActivations.clear() inside _cleanupOnSignOut() (preferably after
clearing _activationCache within the protected write block or immediately after
it) to drop any in-flight activation futures and ensure no stale futures remain,
keeping the operation thread-safe by performing the clear while still in the
mutex-protected section or right after it before the final log statement.

Comment on lines +459 to +494
Future<void> updateZhtlcConfig(
Asset asset,
ZhtlcUserConfig newConfig,
) async {
if (_isDisposing || _configRequestController.isClosed) {
throw StateError('ArrrActivationService has been disposed');
}

_log.info('Updating ZHTLC configuration for ${asset.id.id}');

try {
// Cancel any pending configuration requests
final completer = _configCompleters[asset.id];
if (completer != null && !completer.isCompleted) {
_log.info(
'Cancelling pending configuration request for ${asset.id.id}',
);
completer.complete(null);
_configCompleters.remove(asset.id);
}

// 2. Disable the coin if it's currently active
await _disableCoin(asset.id.id);

// 3. Store the new configuration
_log.info('Saving new configuration for ${asset.id.id}');
await _configService.saveZhtlcConfig(asset.id, newConfig);
} catch (e, stackTrace) {
_log.severe(
'Failed to update ZHTLC configuration for ${asset.id.id}',
e,
stackTrace,
);
await _cacheActivationError(asset.id, e.toString());
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix error handling and ensure atomic configuration updates.

The method has two issues:

  1. Swallowed exceptions: Exceptions are logged and cached (line 492) but not rethrown, so callers don't know the update failed.
  2. Non-atomic updates: If saveZhtlcConfig fails after _disableCoin, the coin remains disabled without a valid configuration, leaving it in a broken state.

Apply this diff to fix error handling and add transaction-like semantics:

  Future<void> updateZhtlcConfig(
    Asset asset,
    ZhtlcUserConfig newConfig,
  ) async {
    if (_isDisposing || _configRequestController.isClosed) {
      throw StateError('ArrrActivationService has been disposed');
    }

    _log.info('Updating ZHTLC configuration for ${asset.id.id}');

    try {
      // Cancel any pending configuration requests
      final completer = _configCompleters[asset.id];
      if (completer != null && !completer.isCompleted) {
        _log.info(
          'Cancelling pending configuration request for ${asset.id.id}',
        );
        completer.complete(null);
        _configCompleters.remove(asset.id);
      }

+     // Save new configuration BEFORE disabling the coin
+     // This ensures we don't leave the coin in a broken state
+     _log.info('Saving new configuration for ${asset.id.id}');
+     await _configService.saveZhtlcConfig(asset.id, newConfig);
+
      // 2. Disable the coin if it's currently active
      await _disableCoin(asset.id.id);
-
-     // 3. Store the new configuration
-     _log.info('Saving new configuration for ${asset.id.id}');
-     await _configService.saveZhtlcConfig(asset.id, newConfig);
    } catch (e, stackTrace) {
      _log.severe(
        'Failed to update ZHTLC configuration for ${asset.id.id}',
        e,
        stackTrace,
      );
      await _cacheActivationError(asset.id, e.toString());
+     rethrow; // Let caller know the update failed
    }
  }
🤖 Prompt for AI Agents
In lib/services/arrr_activation/arrr_activation_service.dart around lines 459 to
494, change updateZhtlcConfig so failures are not swallowed and the update is
atomic: first persist the newConfig via _configService.saveZhtlcConfig, then
disable the coin via _disableCoin; if disabling fails, attempt to roll back by
re-enabling the coin (or delete/restore the saved config as appropriate) and
propagate the original error; always log and cache the error, then rethrow the
exception so callers see the failure; ensure any pending completer is still
cancelled/cleaned up in a finally block to avoid leaked state.

CharlVS and others added 2 commits October 16, 2025 18:23
Roll SDK to update KDF version to the latest v2.5.2-beta RC.

TODO! Update to the GH KDF release upon its release.
…racking (#3194)

* chore(analytics): remove scroll attempt event and update status

* Update lib/analytics/required_analytics_events.csv

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/analytics/analytics_factory.dart (1)

408-417: Broken reference confirmed: Remove unused factory method

The class ScrollAttemptOutsideContentEvent does not exist in the codebase. The factory method at lines 408-417 references a non-existent class and will cause a compile error. Since no callers of scrollAttemptOutsideContent() exist, remove the entire method.

Apply:

-  /// Scroll attempt outside content
-  static ScrollAttemptOutsideContentEvent scrollAttemptOutsideContent({
-    required String screenContext,
-    required double scrollDelta,
-  }) {
-    return ScrollAttemptOutsideContentEvent(
-      screenContext: screenContext,
-      scrollDelta: scrollDelta,
-    );
-  }
♻️ Duplicate comments (3)
lib/bloc/analytics/matomo_analytics_api.dart (2)

299-307: Initialization failure is swallowed after retry cap; rethrow to surface failure

After exhausting retries, initialize completes without error, leaving provider unusable but callers unaware. Rethrow after completing the error to fail fast.

Apply:

       } else {
         // Maximum retries exceeded
         if (!_initCompleter.isCompleted) {
           _initCompleter.completeError(e);
         }
+        rethrow;
       }

227-241: Prevent unbounded queue growth when Matomo is permanently disabled (no config)

With missing MATOMO_URL/SITE_ID, sendEvent() enqueues forever; there is no path to activation, risking OOM. Track config presence and drop events early when invalid.

Apply:

 class MatomoAnalyticsApi implements AnalyticsApi {
   late MatomoTracker _instance;
   final Completer<void> _initCompleter = Completer<void>();

   bool _isInitialized = false;
   bool _isEnabled = false;
+  bool _hasValidConfig = false;
   int _initRetryCount = 0;
@@
-      final bool hasConfig = matomoUrl.isNotEmpty && matomoSiteId.isNotEmpty;
+      final bool hasConfig = matomoUrl.isNotEmpty && matomoSiteId.isNotEmpty;
+      _hasValidConfig = hasConfig;
       if (!hasConfig) {
@@
   Future<void> sendEvent(AnalyticsEventData event) async {
+    // If Matomo is hard-disabled by missing config, drop the event.
+    if (!_hasValidConfig) {
+      if (kDebugMode) {
+        log(
+          'Matomo disabled (missing config); dropping ${event.name}',
+          path: 'analytics -> MatomoAnalyticsApi -> sendEvent',
+        );
+      }
+      return;
+    }
     // If not initialized or disabled, enqueue for later
     if (!_isInitialized || !_isEnabled) {
       _eventQueue.add(event);
       return;
     }

Optional: bound the queue even when temporarily disabled (e.g., keep last N=1000) to guard against long disable windows.

Also applies to: 320-325

lib/analytics/events/misc_events.dart (1)

115-117: Parameter key rename breaks consistency; revert to 'asset_symbol'

Factory emits 'asset_symbol', but this class sends 'asset'. This divergence can break analytics expecting the original key (e.g., Firebase, CSV contracts).

Apply:

   JsonMap get parameters => {
     'query_length': queryLength,
-    if (assetSymbol != null) 'asset': assetSymbol!,
+    if (assetSymbol != null) 'asset_symbol': assetSymbol!,
   };

Matomo normalization already maps asset_symbol → asset, so this preserves downstream expectations without losing Matomo data. Based on learnings.

🧹 Nitpick comments (1)
lib/analytics/analytics_factory.dart (1)

20-24: Unify parameter type to JsonMap for consistency

Other events use JsonMap; this one uses Map<String, Object>. Align for consistency and easier refactors.

Apply:

-  @override
-  Map<String, Object> get parameters => {
+  @override
+  JsonMap get parameters => {
     'timeframe': timeframe,
     'realized_pnl': realizedPnl,
     'unrealized_pnl': unrealizedPnl,
   };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ee26a4 and c838de8.

⛔ Files ignored due to path filters (1)
  • lib/analytics/required_analytics_events.csv is excluded by !**/*.csv
📒 Files selected for processing (4)
  • docs/ANALYTICS_EVENT_IMPLEMENTATION_PLAN.md (1 hunks)
  • lib/analytics/analytics_factory.dart (30 hunks)
  • lib/analytics/events/misc_events.dart (7 hunks)
  • lib/bloc/analytics/matomo_analytics_api.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Format Dart code using dart format . before committing

Files:

  • lib/bloc/analytics/matomo_analytics_api.dart
  • lib/analytics/analytics_factory.dart
  • lib/analytics/events/misc_events.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: build_and_preview
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: Build Desktop (macos)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: validate_code_guidelines
  • GitHub Check: Test web-app-linux-profile
  • GitHub Check: Test web-app-macos
  • GitHub Check: unit_tests
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: build-android-docker
  • GitHub Check: build-linux-docker
  • GitHub Check: build_and_deploy

Comment on lines +247 to +252
// Include backend API key header similarly to feedback feature
customHeaders: {
if (const String.fromEnvironment('FEEDBACK_API_KEY').isNotEmpty)
'X-KW-KEY': const String.fromEnvironment('FEEDBACK_API_KEY'),
},
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not send FEEDBACK_API_KEY as a header to analytics endpoint

Passing X-KW-KEY derived from FEEDBACK_API_KEY to Matomo risks leaking a backend secret to a third-party endpoint (or separate infra). The Matomo Tracking API does not require such a key for client-side tracking.

Apply:

       await MatomoTracker.instance.initialize(
         siteId: matomoSiteId,
         url: matomoUrl,
         dispatchSettings: const DispatchSettings.persistent(),
-        // Include backend API key header similarly to feedback feature
-        customHeaders: {
-          if (const String.fromEnvironment('FEEDBACK_API_KEY').isNotEmpty)
-            'X-KW-KEY': const String.fromEnvironment('FEEDBACK_API_KEY'),
-        },
       );

If authentication is required for a private Matomo, use a Matomo-specific public token intended for tracking, not a backend API key, and only when the endpoint is under your control. Based on learnings.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Include backend API key header similarly to feedback feature
customHeaders: {
if (const String.fromEnvironment('FEEDBACK_API_KEY').isNotEmpty)
'X-KW-KEY': const String.fromEnvironment('FEEDBACK_API_KEY'),
},
);
await MatomoTracker.instance.initialize(
siteId: matomoSiteId,
url: matomoUrl,
dispatchSettings: const DispatchSettings.persistent(),
);
🤖 Prompt for AI Agents
In lib/bloc/analytics/matomo_analytics_api.dart around lines 247–252, remove
sending the backend FEEDBACK_API_KEY as the X-KW-KEY header to the Matomo
endpoint (this leaks a backend secret). Instead, do not include that header; if
authentication is required for a private Matomo instance, read a dedicated
Matomo public/tracking token from a separate environment variable (e.g.
MATOMO_PUBLIC_TOKEN) and send that token (or the appropriate Matomo tracking
parameter) only when the endpoint is under your control; ensure the env var is
intended for client-side use and document it so backend secrets are never
exposed.

CharlVS and others added 2 commits October 20, 2025 14:56
* chore(sdk): roll to origin/bugfix/activation-asset-grouping for asset type tagging fix

* chore(sdk): roll to origin/fix/asset-chain-tagging

* fix(asset-tagging): set SMART_CHAIN ticker; improve parsing

- Sanitize ticker parsing for exact/partial matches\n- Restore partial ticker matching to preserve behavior\n- Prefer UTXO on exact "UTXO" to avoid mislabeling\n- Catch StateError specifically and deduplicate enum name extraction\n- Confirm UTXO formatted label is "Native"

* chore(submodule): roll SDK to ec40963 (fix SMART_CHAIN ticker, parsing)

* Delete run.sh
…n signing support for standalone distribution (#3185)

* change product bundle identifier (com.komodo.wallet)

* Set sdk submodule to chore/sdk-universal-macos-cdn-pods

#3175

* XCode: add production scheme and corresponding configurations

* make Release-production sign with Developer ID Application

* sdk: temp following submodules for patch-macos-release-profile

new https://github.com/KomodoPlatform/komodo-defi-sdk-flutter/tree/patch-macos-release-profile
branch for macos Developer ID Application release preparations.

* sdk: update submodules

* add OTHER_CODE_SIGN_FLAGS --options=runtime --timestamp

* fix developement team for Release-production

after this - kdf binary is signed (but still without timestamp)

* fix codesigning for Pods (now CP-User signing in Pods receive correct env)

'Release-production'=> :release, - CocoaPods will create this config in Pods project

* add --options=runtime --timestamp for codesigning pods

* sdk: pin version with code_sign_if_enabled in cp-user sh script

* sdk: bump to new location of KDF binary under MacOS

* macos: XCode project update / Pods_Runner.framework in Frameworks

* build(macos): set CODE_SIGN_INJECT_BASE_ENTITLEMENTS to NO for Release

need to remove below from Entitlements
"com.apple.security.get-task-allow" = 1;

To check:
codesign -d --entitlements :- "build/macos/Build/Products/Release-production/Komodo Wallet.app" | plutil -p -

Read more:
https://developer.apple.com/documentation/security/resolving-common-notarization-issues#3087731

* update .gitignore to exclude dist/ directory

* feat: add make-dmg.sh script for building DMG files on macOS

This script automates the process of creating a DMG file for the Komodo Wallet application, including setting up the Finder layout and handling background images. It requires macOS and utilizes hdiutil, osascript, and ditto for the operations.

* feat: add test-sign-timestamp.sh script for verifying code signing and timestamping on macOS

This script checks the code signing and timestamping of the Komodo Wallet application, providing feedback on the presence of timestamps and the authority of the timestamping service. It simplifies the verification process for macOS app builds.

* feat: enhance make-dmg.sh script with default app path and usage instructions

* chore: update Podfile.lock to include device_info_plus and update dependencies

* chore: update subproject commit reference in sdk

* feat: add README.md for contrib scripts and enhance test-sign-timestamp.sh

* chore(sdk): roll submodule to latest dev

- Update .gitmodules to track dev
- Sync sdk to origin/dev

---------

Co-authored-by: Nitride <77973576+CharlVS@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
contrib/make-dmg.sh (2)

16-30: Consider input validation for numeric parameters (optional refactor).

Parameters like WIN_W, WIN_H, APP_X, APP_Y are substituted directly into AppleScript (line 165) via shell variable expansion. While default values are numeric, custom values passed via environment variables are not validated. Non-numeric input would cause AppleScript syntax errors without clear diagnostics.

If caller responsibility is acceptable, this is fine. If robustness is preferred, consider a lightweight validation step:

# Optional validation function
validate_numeric() {
  local var="$1"
  if ! [[ "$var" =~ ^[0-9]+$ ]]; then
    echo >&2 "ERROR: $var must be numeric, got: $var"
    exit 1
  fi
}

# Call before using:
# validate_numeric "$WIN_W"
# validate_numeric "$WIN_H"
# validate_numeric "$APP_X"
# validate_numeric "$APP_Y"

140-206: AppleScript error handling could be more explicit (optional improvement).

The AppleScript block uses multiple try...end try blocks without reporting errors if they occur (lines 155–205). Silent failures can mask issues like missing .background folder, icon positioning problems, or window sizing failures. While the pragmatic approach assumes Finder will handle missing operations gracefully, explicit error logging would improve debuggability during DMG staging.

Current approach is functional, but consider adding error reporting if debugging time becomes an issue:

osascript <<OSAEOF 2>&1 | while read line; do
  [[ "$line" =~ error|Error ]] && echo "WARNING: AppleScript: $line"
done
# ... rest of osascript block
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92d5140 and 2ec7a2e.

⛔ Files ignored due to path filters (1)
  • macos/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • .gitignore (3 hunks)
  • contrib/README.md (1 hunks)
  • contrib/make-dmg.sh (1 hunks)
  • contrib/test-sign-timestamp.sh (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • contrib/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Test web-app-macos
  • GitHub Check: Test web-app-linux-profile
  • GitHub Check: build_and_preview
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Desktop (macos)
  • GitHub Check: Build Desktop (windows)
  • GitHub Check: unit_tests
  • GitHub Check: Build Desktop (linux)
  • GitHub Check: validate_code_guidelines
  • GitHub Check: build-android-docker
  • GitHub Check: build-linux-docker
  • GitHub Check: build_and_deploy
🔇 Additional comments (2)
contrib/test-sign-timestamp.sh (1)

1-63: Well-structured macOS code signing validation utility.

The script provides comprehensive signature and timestamping verification with solid error handling, portable POSIX regex patterns, and user-friendly color-coded output. Defensive programming throughout (early validation, suppressed optional errors, explicit checks on critical operations).

contrib/make-dmg.sh (1)

1-14: Well-structured DMG automation with solid error handling.

The script demonstrates professional Bash practices: early error handling with set -euo pipefail, cleanup trap, mount/unmount retries, and defensive directory checks. Parameter defaults with environment variable override pattern is idiomatic.

smk762 and others added 2 commits October 20, 2025 20:44
…egacy (#3189)

* fix(icons): update native platform app icons and desktop entry

- Replace Linux icon: remove SVG, add PNG, update .desktop

- Update macOS AppIcon assets (16-1024 px)

- Update Windows app icon (.ico)

- Adjust Linux runner code for app icon

* fix(icons): align iOS/Android app icons with legacy build

* fix(splash): mirror startup screen from legacy build (iOS LaunchScreen, Android launch_background)

* fix(ios): align AppLogo.imageset Contents.json with legacy images

* fix(desktop): mirror macOS AppIcon and Linux icon from legacy desktop

* chore(sdk): bump submodule to GLEECBTC/komodo-defi-sdk-flutter@717fe64

* feat(assets): refresh app logo assets across platforms\n\n- Replace PNG logo with WebP variants for app and web\n- Update iOS AppLogo images and Contents.json\n- Remove deprecated app_logo-1x/2x assets\n- Update web/index.html references to new logo\n- Format changed Dart file in ramp fiat provider\n\nRefs: fix/native-platform-app-icons

* fix(web): correct logo asset path in index.html for production hosting

Update prefetch and img src to /assets/assets/app_icon/logo_icon.webp to match Flutter web bundling and fix 404s on Firebase Hosting rewrites.

* fix(web,android): update app icon and favicon refs; ensure correct launcher XML for adaptive icons

* chore(sdk): update submodule to latest dev

* chore(macos/ios): role native dependencies lock files

* fix(icons): correct Linux app icon config and update web index references
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/bloc/market_maker_bot/market_maker_bot/market_maker_bot_bloc.dart (2)

209-224: Bug: stale polling snapshot in _waitForOrdersToBeCancelled causes spurious timeouts.

orders is fetched once and never refreshed inside the loop; the condition never sees updates. Refresh each iteration.

-    final orders = await _orderRepository.getTradePairs();
-    while (orders.any((order) => order.order != null)) {
+    while (true) {
+      final orders = await _orderRepository.getTradePairs();
+      final allCancelled = orders.every((o) => o.order == null);
+      if (allCancelled) break;
       if (DateTime.now().difference(start) > timeout) {
         if (fatalTimeout) {
-          // Log bot error
-          GetIt.I<AnalyticsRepo>().queueEvent(
-            MarketbotErrorEventData(
-              failureDetail: 'timeout_cancelling',
-              strategyType: 'simple',
-            ),
-          );
+          _safeLogMarketbotError('timeout_cancelling', strategyType: 'simple');
           throw TimeoutException('Failed to cancel orders in time');
         }
         return;
       }
       await Future<void>.delayed(const Duration(milliseconds: 100));
-    }
+    }

117-126: State consistency: revert settings if update flow fails after optimistic add.

addTradePairToStoredSettings happens before cancel/update; on failure, the pair remains in settings while the bot is stopped — inconsistent UX. Track the optimistic add and roll it back in catch.

@@
-      // Add the trade pair to stored settings immediately to provide feedback
-      // and updates to the user.
-      await _botRepository.addTradePairToStoredSettings(event.tradePair);
+      // Optimistic settings update; roll back on failure.
+      var addedToSettings = false;
+      await _botRepository.addTradePairToStoredSettings(event.tradePair);
+      addedToSettings = true;
@@
-      final stoppingState = const MarketMakerBotState.stopping().copyWith(
+      final stoppingState = const MarketMakerBotState.stopping().copyWith(
         error: e.toString(),
       );
       emit(stoppingState);
-      // Log bot error
-      GetIt.I<AnalyticsRepo>().queueEvent(
-        MarketbotErrorEventData(
-          failureDetail: 'update_failed',
-          strategyType: 'simple',
-        ),
-      );
+      if (addedToSettings) {
+        // Roll back optimistic settings change
+        await _botRepository.removeTradePairsFromStoredSettings(
+          [event.tradePair].toList(),
+        );
+      }
+      _safeLogMarketbotError('update_failed', strategyType: 'simple');
       await _botRepository.stop(botId: event.botId);
       emit(stoppingState.copyWith(status: MarketMakerBotStatus.stopped));

Also applies to: 137-150

♻️ Duplicate comments (2)
lib/bloc/market_maker_bot/market_maker_bot/market_maker_bot_bloc.dart (2)

74-76: Analytics accuracy: avoid hardcoding strategyType: 'simple'.

Derive the strategy type from the event/repo/settings to prevent mislabelled analytics. This was flagged earlier; please fix at source.

Would you confirm the available source for strategy type and payload fields?

#!/bin/bash
# Locate event payload and available fields
rg -nP 'class\s+MarketbotErrorEventData|strategyType|failureDetail' -C2
# Check market maker bot events for a strategy context
rg -nP '(class|sealed)\s+MarketMakerBot.*Event|strategy(Type|)\b' -C3

Also applies to: 98-100, 144-146, 191-193, 216-218


71-77: Guard analytics lookups; don’t let logging crash error paths.

Direct GetIt.I<AnalyticsRepo>() will throw when analytics is disabled/not registered; this breaks failure handling. Guard with isRegistered and swallow logging errors. Also centralize via a small helper to de-duplicate.

Apply these diffs to replace each call:

@@
-      // Log bot error
-      GetIt.I<AnalyticsRepo>().queueEvent(
-        MarketbotErrorEventData(
-          failureDetail: 'start_failed',
-          strategyType: 'simple',
-        ),
-      );
+      _safeLogMarketbotError('start_failed', strategyType: 'simple');
@@
-      // Log bot error
-      GetIt.I<AnalyticsRepo>().queueEvent(
-        MarketbotErrorEventData(
-          failureDetail: 'stop_failed',
-          strategyType: 'simple',
-        ),
-      );
+      _safeLogMarketbotError('stop_failed', strategyType: 'simple');
@@
-      // Log bot error
-      GetIt.I<AnalyticsRepo>().queueEvent(
-        MarketbotErrorEventData(
-          failureDetail: 'update_failed',
-          strategyType: 'simple',
-        ),
-      );
+      _safeLogMarketbotError('update_failed', strategyType: 'simple');
@@
-      // Log bot error
-      GetIt.I<AnalyticsRepo>().queueEvent(
-        MarketbotErrorEventData(
-          failureDetail: 'cancel_failed',
-          strategyType: 'simple',
-        ),
-      );
+      _safeLogMarketbotError('cancel_failed', strategyType: 'simple');
@@
-          // Log bot error
-          GetIt.I<AnalyticsRepo>().queueEvent(
-            MarketbotErrorEventData(
-              failureDetail: 'timeout_cancelling',
-              strategyType: 'simple',
-            ),
-          );
+          _safeLogMarketbotError('timeout_cancelling', strategyType: 'simple');

Add this helper (place near the bottom of the file):

void _safeLogMarketbotError(String failureDetail, {required String strategyType}) {
  try {
    final getIt = GetIt.I;
    if (getIt.isRegistered<AnalyticsRepo>()) {
      getIt<AnalyticsRepo>().queueEvent(
        MarketbotErrorEventData(
          failureDetail: failureDetail,
          strategyType: strategyType,
        ),
      );
    }
  } catch (_) {
    // Ignore analytics failures
  }
}

Based on learnings.

Also applies to: 95-101, 142-147, 189-194, 213-219

🧹 Nitpick comments (5)
lib/bloc/fiat/ramp/ramp_fiat_provider.dart (2)

65-74: Add validation for invalid sourceAmount.

If sourceAmount contains an invalid number string, Decimal.tryParse returns null, which will be sent to the API. Consider validating the input or throwing a descriptive error.

Apply this diff to add validation:

   ) => apiRequest(
     'POST',
     apiEndpoint,
     queryParams: {'endpoint': '/onramp/quote/all'},
     body: {
       'fiatCurrency': source,
       'cryptoAssetSymbol': getFullCoinCode(target),
-      'fiatValue': Decimal.tryParse(sourceAmount)?.toDouble(),
+      'fiatValue': (Decimal.tryParse(sourceAmount) ?? 
+          (throw ArgumentError.value(sourceAmount, 'sourceAmount', 'Invalid decimal value')))
+          .toDouble(),
     },
   );

186-217: Consider simplifying nested ternary operations for readability.

The nested ternary expressions on lines 206-215 for min/max purchase amounts reduce readability. Consider extracting them into local variables or helper methods.

Example refactor:

quoteResult.paymentMethods.forEach((
  String key,
  RampQuoteResultForPaymentMethod value,
) {
  _log.fine('Processing payment method key $key: $value');
  final feeAmount = value.baseRampFee / sourceAmountValue;
  
  final minAmount = asset.hasValidMinPurchaseAmount()
      ? asset.minPurchaseAmount
      : coins.minPurchaseAmount;
  final maxAmount = asset.hasValidMaxPurchaseAmount()
      ? asset.maxPurchaseAmount
      : coins.maxPurchaseAmount;

  final method = {
    'id': key,
    'name': _formatMethodName(key),
    'transaction_fees': [
      {
        'fees': [
          {'amount': feeAmount.toDouble()},
        ],
      },
    ],
    'transaction_limits': [
      {
        'fiat_code': source,
        'min': minAmount.toString(),
        'max': maxAmount.toString(),
      },
    ],
    'price_info': {
      'coin_amount': getFormattedCryptoAmount(
        value.cryptoAmount.toString(),
        asset.decimals,
      ),
      'fiat_amount': value.fiatValue.toString(),
    },
  };
  paymentMethodsList.add(FiatPaymentMethod.fromJson(method));
});
lib/bloc/nft_withdraw/nft_withdraw_bloc.dart (3)

21-23: Consider injecting AnalyticsRepo for consistency and testability.

The bloc constructor already injects NftWithdrawRepo, KomodoDefiSdk, and CoinsRepo as dependencies, but AnalyticsRepo is accessed via GetIt.I<AnalyticsRepo>() throughout the file (lines 103, 129, 140, 179, 199). This inconsistency makes unit testing harder, as you cannot easily mock the analytics repository.

Apply this diff to inject AnalyticsRepo:

 class NftWithdrawBloc extends Bloc<NftWithdrawEvent, NftWithdrawState> {
   NftWithdrawBloc({
     required NftWithdrawRepo repo,
     required NftToken nft,
     required KomodoDefiSdk kdfSdk,
     required CoinsRepo coinsRepository,
+    required AnalyticsRepo analyticsRepo,
   }) : _repo = repo,
        _coinsRepository = coinsRepository,
        _kdfSdk = kdfSdk,
+       _analyticsRepo = analyticsRepo,
        super(NftWithdrawFillState.initial(nft)) {

Then declare the field:

   final NftWithdrawRepo _repo;
   final KomodoDefiSdk _kdfSdk;
   final CoinsRepo _coinsRepository;
+  final AnalyticsRepo _analyticsRepo;

And replace all GetIt.I<AnalyticsRepo>() calls with _analyticsRepo.


99-109: Extract wallet type retrieval to reduce duplication.

The wallet type retrieval logic (await _kdfSdk.auth.currentUser)?.type ?? 'unknown' appears twice in this file (lines 99 and 175). Extracting this to a helper method would improve maintainability and ensure consistency.

Consider adding a helper method:

Future<String> _getWalletType() async {
  return (await _kdfSdk.auth.currentUser)?.type ?? 'unknown';
}

Then replace both occurrences:

-    final walletType = (await _kdfSdk.auth.currentUser)?.type ?? 'unknown';
+    final walletType = await _getWalletType();

128-147: Extract failure logging to reduce code duplication.

The failure logging code in the ApiError catch block (lines 129-135) and the TransportError catch block (lines 140-146) is nearly identical. A similar pattern also appears in _onConfirmSend (lines 179-185). Extracting this to a helper method would reduce duplication and make future updates easier.

Consider adding a helper method:

void _logNftTransferFailure({
  required String collectionName,
  required String failureDetail,
  required String hdType,
}) {
  _analyticsRepo.queueEvent(
    NftTransferFailureEventData(
      collectionName: collectionName,
      failureDetail: failureDetail,
      hdType: hdType,
    ),
  );
}

Then replace the duplicated blocks:

     } on ApiError catch (e) {
-      // Log failure
-      GetIt.I<AnalyticsRepo>().queueEvent(
-        NftTransferFailureEventData(
-          collectionName:
-              state.nft.collectionName ?? state.nft.symbol ?? 'unknown',
-          failureDetail: e.message,
-          hdType: walletType,
-        ),
-      );
+      _logNftTransferFailure(
+        collectionName: state.nft.collectionName ?? state.nft.symbol ?? 'unknown',
+        failureDetail: e.message,
+        hdType: walletType,
+      );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ec7a2e and 28c9734.

⛔ Files ignored due to path filters (29)
  • android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/launcher_icon_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/launcher_icon_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/launcher_icon_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/launcher_icon_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/launcher_icon_foreground.png is excluded by !**/*.png
  • assets/app_icon/logo_icon.png is excluded by !**/*.png
  • ios/Podfile.lock is excluded by !**/*.lock
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppLogo.imageset/AppLogo.png is excluded by !**/*.png
  • ios/Runner/Assets.xcassets/AppLogo.imageset/AppLogo@2x.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • android/app/src/main/res/drawable/launch_background.xml (1 hunks)
  • android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (1 hunks)
  • android/app/src/main/res/values/colors.xml (1 hunks)
  • ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (1 hunks)
  • ios/Runner/Assets.xcassets/AppLogo.imageset/Contents.json (1 hunks)
  • ios/Runner/Base.lproj/LaunchScreen.storyboard (1 hunks)
  • lib/bloc/fiat/ramp/ramp_fiat_provider.dart (7 hunks)
  • lib/bloc/market_maker_bot/market_maker_bot/market_maker_bot_bloc.dart (9 hunks)
  • lib/bloc/nft_withdraw/nft_withdraw_bloc.dart (9 hunks)
✅ Files skipped from review due to trivial changes (4)
  • android/app/src/main/res/values/colors.xml
  • android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  • ios/Runner/Assets.xcassets/AppLogo.imageset/Contents.json
  • ios/Runner/Base.lproj/LaunchScreen.storyboard
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Format Dart code using dart format . before committing

Files:

  • lib/bloc/fiat/ramp/ramp_fiat_provider.dart
  • lib/bloc/nft_withdraw/nft_withdraw_bloc.dart
  • lib/bloc/market_maker_bot/market_maker_bot/market_maker_bot_bloc.dart
🧠 Learnings (1)
📚 Learning: 2025-04-01T15:51:37.060Z
Learnt from: takenagain
PR: KomodoPlatform/komodo-wallet#2566
File: lib/bloc/coins_bloc/coins_bloc.dart:10-10
Timestamp: 2025-04-01T15:51:37.060Z
Learning: In the Komodo Wallet project, part files share imports with their parent files. The import for `app_config.dart` in `coins_bloc.dart` is necessary because the part file `coins_state.dart` uses `excludedAssetList` from that package.

Applied to files:

  • lib/bloc/nft_withdraw/nft_withdraw_bloc.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Mobile (iOS)
  • GitHub Check: Build Mobile (Android)
  • GitHub Check: build-android-docker
  • GitHub Check: build-linux-docker
  • GitHub Check: Build Desktop (windows)
🔇 Additional comments (5)
ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (1)

3-116: Asset catalog configuration looks correct.

The additions provide comprehensive icon coverage for iOS (iPhone and iPad) across all required sizes and scales:

  • iPhone: 20×20, 29×29, 40×40, 60×60 with appropriate scales (2×, 3×)
  • iPad: 20×20, 29×29, 40×40, 76×76, 83.5×83.5 with appropriate scales (1×, 2×)
  • App Store: 1024×1024 marked as ios-marketing (correct idiom for the App Store icon)

The idiom change for the 1024×1024 entry from universal to ios-marketing is appropriate and follows Xcode's Asset Catalog conventions. JSON structure and naming are consistent.

android/app/src/main/res/drawable/launch_background.xml (1)

6-8: Centered bitmap approach is appropriate for launch screen.

Using a <bitmap> element with android:gravity="center" is the standard Android pattern for maintaining aspect ratio and centering imagery on the launch screen. This implementation is sound.

lib/bloc/fiat/ramp/ramp_fiat_provider.dart (1)

15-15: WebP logo asset verified—URL is accessible.

The asset exists and is available at the new URL (HTTP 200). The logo format change from PNG to WebP is confirmed functional and will provide improved performance through better compression.

lib/bloc/nft_withdraw/nft_withdraw_bloc.dart (1)

196-207: Success event logging looks good.

The fee calculation safely handles nullable values and parse failures with appropriate fallbacks. Using double precision for analytics purposes is reasonable here, as this is for tracking rather than financial calculations.

lib/bloc/market_maker_bot/market_maker_bot/market_maker_bot_bloc.dart (1)

124-126: LGTM: clearer typing around status stream.

Explicit Stream<MarketMakerBotStatus> improves readability.

- Update `sdk` submodule pointer to latest `dev` commit
- No app code changes

Refs: none
Copy link
Copy Markdown
Contributor

@ca333 ca333 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sec reviewed by @DeckerSU

@ca333 ca333 merged commit da77aea into main Oct 22, 2025
11 of 17 checks passed
@smk762 smk762 mentioned this pull request Nov 23, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

QA Ready for QA Testing release candidate SEC review pending Awaiting SEC review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: ZHTLC (Pirate)

8 participants