github LedgerHQ/ledger-live @ledgerhq/live-desktop@4.24.0

latest release: live-mobile@4.24.0
5 hours ago

4.24.0

Minor Changes

  • #23017 eaff720 Thanks @mcayuelas-ledger! - Show a concise message when adding an account fails because the provider returns a server or network error

  • #22909 29ead28 Thanks @LucasWerey! - fix(add-account): allow creating other BTC address types when the existing account is empty

  • #22981 3faf47c Thanks @LucasWerey! - Rename the market banner "View all" tile to "More" so it no longer gets cropped in longer languages.

  • #22971 f8a4b3e Thanks @LucasWerey! - fix(top-bar): keep a minimum width for the search and truncate the update pills on narrow windows

  • #23139 320d2a1 Thanks @mcayuelas-ledger! - Resolve the market id of an asset from the ledger ids when needed, so favorites added from search show up in the Market banner

  • #22519 d60f240 Thanks @semeano! - feat(stacks): add desktop stake and unstake flows

    coin-stacks: spendableBalance now excludes locked (staked) STX for every Stacks account, matching getBalance, which lowers the Send max for accounts with a stake.

    coin-stacks: validateIntent rejects a stake during the pox-5 prepare phase (StacksStakeInPreparePhase), which the chain would abort while still charging the fee.

  • #22843 c954015 Thanks @semeano! - feat(stacks): add mobile stake and unstake flows

  • #23143 4101467 Thanks @LucasWerey! - refactor(contacts): clean up the Contacts debug tools

    The send-history contacts builder was copied in both apps. It now lives once in
    @domain/entity-contact/schema.mock as mockContactsFromSendHistory. @features/platform-contacts
    adds parseExcludedCurrencyIdsInput, which works like parseEligibleAddressFamiliesInput. The
    desktop tool no longer copies flag params into local state with effects. Its inputs show the flag
    value unless you are editing them, use cn, and have no hard-coded strings left. The mobile tool
    drops its StyleSheet, shows the families as tags, and builds the flag preview in its view model.

  • #23035 20bf9b0 Thanks @LucasWerey! - Route every copy/paste through the new @shared/clipboard package (expo-clipboard replaces @react-native-clipboard/clipboard on mobile) and enforce it with lint rules; copy feedback now only shows once the copy succeeded

  • #23043 4028b7e Thanks @ooke-ledger! - Hold back a per-currency fee buffer when depositing the max of a native coin into perps, configured by the new ptxTradeMaxConstant flag (feature_ptx_trade_max_constant). Only the MAX ratio is reduced; token accounts and other ratios are unchanged.

  • #22860 21fa5a5 Thanks @ooke-ledger! - Send the user back to the perps deposit form when they retry after a "not enough balance" error. Retrying re-ran the same deposit, which could only fail again; the form now reopens with the draft amount and funding account so the amount can be lowered. Other errors still retry in place

  • #22856 438c7b3 Thanks @ooke-ledger! - Hide accounts that cannot send, such as HyperCore, from the perps deposit funding picker. The receiving HyperCore account was still offered as a funding source even though a deposit cannot be sent from it. The picker now opens in the perpetuals:fund flow, which rejects send-disabled families, so modular dialog analytics from that picker report flow: "perpetuals:fund"

  • #23182 0d31c6b Thanks @ooke-ledger! - Open swap from Market only after the user has picked the network and account to swap from, whenever they hold an account on any of the asset's networks.

  • #22904 1696c5d Thanks @LucasWerey! - Wrap Analytics PnL cards and balance header on narrow windows instead of overflowing horizontally

  • #22890 ee95a8e Thanks @LucasWerey! - fix(cg-client): remove the unused CoinGecko supported coins list query

    Removes getSupportedCoinsList, useGetSupportedCoinsListQuery, useSupportedCurrencies, MarketCoinSchema, SupportedCoinsSchema and the MarketCoin / SupportedCoins types. useMarketDataProvider now only returns supportedCounterCurrencies.

  • #22920 c45454e Thanks @LucasWerey! - fix(errors): stop reporting DMK and empty errors as TranslatedError invalid usage

  • #22866 52747b3 Thanks @LucasWerey! - Name the default Me contact "Me" in the Pay tab contacts list instead of "My addresses (Me)"

  • #23053 2a09181 Thanks @mcayuelas-ledger! - Show each stablecoin as its own Pay balance filter option, including testnet holdings

  • #22988 7cfa427 Thanks @LucasWerey! - fix(crypto-addresses): keep the rename dialog open while accounts sync or countervalues refresh

  • #23172 37f6895 Thanks @mcayuelas-ledger! - fix(sidebar): reopen the sidebar after an automatic collapse

  • #22436 23455ab Thanks @ysitbon! - Add the countervalues domain api: rate fetching, and the orchestration that folds rates into the entity state.

    • @domain/api-market-countervalues owns the Countervalues Service endpoints and loadCountervalues, which moves out of @ledgerhq/live-countervalues.
    • The endpoints are injected into the shared countervalues api from @shared/api-services instead of standing up a second slice. The duplicate client in live-common is removed, so each app registers one countervalues reducer where it previously registered two against the same host. That slice is an RTK Query cache and is not persisted, so there is no stored state to migrate.
    • loadCountervalues takes its rates as an argument rather than reaching for a module-level client. The apps compose one in the countervalues bridge they already own; tests pass a mock directly, which removes the MOCK_COUNTERVALUES dispatcher hidden inside the fetch path.
    • Rate failures carry the HTTP status through unchanged, so an unsupported pair still clears its cache on 422, an HTTP failure still increments the per-pair backoff, and an offline period still does not.
    • Rate requests keep the previous request policy: a 60s timeout, so a hung connection can no longer stall countervalues polling, and the same retries as before. The two endpoints moved out of live-common keep not retrying.
    • @ledgerhq/live-countervalues drops loadCountervalues, its api entry point and the fetch contract types, and with them its dependencies on @ledgerhq/logs, @ledgerhq/live-network, @ledgerhq/live-promise and @ledgerhq/live-env. It no longer reaches the network.
    • web-tools now registers the shared countervalues api, which its portfolio countervalues loading dispatches through.
    • cvsApiExtra takes getCountervaluesServiceUrl, a getter read on every request, in place of the countervaluesServiceUrl string read once at store creation. Switching the developer staging toggle now applies to the next countervalues request again, as it did before the rates moved onto the shared api.
  • #23173 55e5d67 Thanks @mcayuelas-ledger! - Show the full Assets column label in a tooltip when it is truncated

  • #22759 bf29f88 Thanks @qperrot! - fix(coin-bitcoin): read the explorer and tuning values from the injected coin config

    The module no longer keeps configuration in module state. createBridges takes a Context
    (ADR-019) and every bridge method resolves config_currency_<id> from context.config() at call
    time. The endpoint explorer.url is required and defaults to today's production host in each
    served config_currency_<id> (http://localhost:9876 for bitcoin_regtest, whose btc_regtest
    explorer id also moves to its config). The optional fields fall back to named module defaults:
    explorer.batchSize (DEFAULT_EXPLORER_BATCH_SIZE, 1000), fees.stuckTransactionTimeoutMs
    (DEFAULT_STUCK_TRANSACTION_TIMEOUT_MS, 20 min), fees.rbfMinBumpRatio
    (DEFAULT_RBF_MIN_BUMP_RATIO, 0.1), fees.calculationCacheTtlMs and fees.feeRatesCacheTtlMs
    (5 min each) and sync.replacedOperationExpiryMs (DEFAULT_REPLACED_OPERATION_EXPIRY_MS, 2 h).
    The explorer is bound to a wallet-btc account from the config at use, so deserialization stays
    config-free and a remote change applies on the next call. wallet-btc still reads no configuration:
    the batch size is injected through WalletBtcCurrency.explorerBatchSize, and the RBF ratio and
    the unconfirmed-operation expiry are parameters.

    Breaking: createBridges(signerContext, context) takes a Context instead of a config getter;
    setCoinConfig, getCoinConfig, CoinConfig, BitcoinConfigInfo, makeAssignFromAccountRaw
    and getMinRelayFee are removed in favour of BitcoinCoinConfig / BitcoinContext and
    assignFromAccountRaw, and postSync becomes makePostSync(context). The module logs only
    through context.logger: buildTransaction, getTransactionStatus, prepareTransaction,
    calculateFees, signAccountTx, ChainAdapter.resolveFeePerByte, buildSignRawOperation and the
    hw-getAddress / hw-getFullViewingKey resolvers take a Logger. prepareTransaction, getTransactionStatus, buildTransaction,
    buildAccountTx, getOriginalTxFeeContext, getMinReplacementFeeSat,
    getMinReplacementFeeRateSatVb and getRbfContext take the coin config as first parameter. The
    getEditTransactionStatus and isStrategyDisabled bridge extensions require the mainAccount. The EXPLORER_REGTEST and BITCOIN_STUCK_TRANSACTION_TIMEOUT envs are
    removed, as are the config_currency_<id> defaults of the bitcoin-family currencies no loader
    serves (bitcoin_private, game_credits, gochain, lbry, nix, ravencoin, resistance,
    zclassic, zcoin).

  • #22938 7a2505b Thanks @qperrot! - Rename BNB Chain to BNB Smart Chain

  • #22639 0c507ff Thanks @live-github-bot! - Update @ledgerhq/coin-evm to 9.0.1 and pass a logger to its APIs

  • #22599 d819300 Thanks @OlivierFreyssinet! - Add failureType and subError properties to Device Intent Executor deviceflow_failed and deviceflow_aborted events

  • #22418 48874b3 Thanks @claudiiafg! - Add desktop E2E coverage for creating a contact, registering Ethereum addresses on the device and deleting both, and let device intents discover Speculos.

  • #23021 3dacfc2 Thanks @fAnselmi-Ledger! - Bump @ledgerhq/device-management-kit to 1.11.0 and @ledgerhq/dmk-ledger-wallet to 0.7.0.

  • #23246 71c5860 Thanks @aussedatlo! - Bump @ledgerhq/dmk-ledger-wallet to 0.7.1, @ledgerhq/device-transport-kit-speculos to 1.3.0 and @ledgerhq/speculos-device-controller to 0.4.0.

  • #23083 4c28d72 Thanks @gre-ledger! - Bump @ledgerhq/ledger-key-ring-protocol, @ledgerhq/hw-ledger-key-ring-protocol to 1.0.0 and @ledgerhq/evm-tools to 2.0.0 (ts-libs). No API change.

  • #23184 3dda070 Thanks @CremaFR! - Retry a swap up to twice, without showing the error, when the Exchange app rejects the provider signature (signVerificationFail at CHECK_TRANSACTION_SIGNATURE). executeSwap requests a new nonce and calls /swap again with the same parameters. Each rejected attempt is still reported to /swap/cancelled, with the attempt in the error message: Signature verification failed Code: R0 for the first attempt, then R1 and R2 for the retries. This replaces the [diagnostic=…] signature classification, which is removed

  • #22745 db3bde1 Thanks @lysyi3m! - Canton: hide Accept once an offer expires while the screen is open, and show a clear message instead of retry when accepting an expired offer

  • #23008 ac0379e Thanks @dilaouid! - fix(send): show a broadcast error on the new send flow confirmation and only offer to try again for temporary errors (network, server, locked device)

  • #22387 3dd4ee2 Thanks @lysyi3m! - feat(concordium): link the PLT support article from the token list and Receive alert

  • #22811 3132a4a Thanks @gre-ledger! - Consume @ledgerhq/ledger-key-ring-protocol and @ledgerhq/hw-ledger-key-ring-protocol from npm (they now live in ts-libs), and bump axios to 1.20.0. No API change.

  • #22657 932097d Thanks @claudiiafg! - Cover on-device contact rename in desktop E2E against the mock server, which keeps the OS available after the device leaves the Ethereum app.

  • #22930 5f07a43 Thanks @LucasWerey! - Keep the Ledger Wallet addresses entry at full height in the desktop contact detail on small windows, and let the empty detail scroll with the custom scrollbar (LIVE-38297).

  • #22604 ca82e70 Thanks @sarneijim! - Add an ab_tests attribute to desktop and mobile analytics events with the trackingConfiguration of each enabled English copy experiment, or {} when none applies

  • #22603 9c0feca Thanks @sarneijim! - Add feature_copy_* experiments to the feature flags debug screen so enabled and copy can be mocked locally

  • #22413 0f401bb Thanks @Moustafa-Koterba! - feat(cosmos): move the Cosmos memo onto the shared generic-adapter memo fields (LIVE-36108)

    Prep work for the Cosmos generic-coin-framework migration (depends on LIVE-35735, already fixed):
    the shared transactionToIntent only reads memoType/memoValue, fields the four Cosmos memo
    write sites (desktop send field, mobile memo-tag input, mobile edit-memo screen, wallet-api
    adapter) never set — they only wrote the legacy memo field. Left as is, flipping Cosmos into
    genericCoinFrameworkFamilies.json in a later ticket would silently drop every memo, with no
    error anywhere.

    Adds a cosmos entry to the shared memo-application registry, adds memoType/memoValue to
    CosmosLikeTransaction alongside the existing memo field (read unchanged by the live legacy
    bridge), and centralizes the three-field patch in a single cosmosMemoPatch helper all four
    write sites now call, so they can't drift out of sync. Also adds the memo length check
    (CosmosMemoTooLong) to the Alpaca validateIntent, which nothing previously enforced outside
    the UI's maxLength truncation.

  • #23001 21ab07f Thanks @ysitbon! - Move the countervalues Redux slice into @features/platform-market-countervalues: its reducer, action creators, initial state, state type and selectors. Both apps now mount countervaluesReducer at the same countervalues store key and keep their own useSelector hooks, persistence, polling and user-settings computation. The action types keep the desktop strings, so mobile's pending, error and wipe actions are now named COUNTERVALUES_STATE_SET_PENDING, COUNTERVALUES_STATE_SET_ERROR and COUNTERVALUES_WIPE. The reducer stays a plain function rather than createSlice, because immer would freeze the rate maps that loadCountervalues updates in place.

  • #23107 fa2c070 Thanks @ysitbon! - Countervalues user settings are no longer stored in Redux: each app computes them and hands them to the provider through the bridge's useUserSettings.

    • @features/platform-market-countervalues: the slice loses its userSettings field, setCountervaluesUserSettings (COUNTERVALUES_USER_SETTINGS_SET) and countervaluesUserSettingsSelector.
    • Desktop: useCalculateCountervaluesUserSettings returns the memoized settings instead of dispatching them, and the bridge calls it directly. The provider sees the real tracking pairs and refresh rate from the first render instead of one render late, so the saved rates are restored once and the boot loads once.
    • Mobile: no runtime change; its tests read a shared test settings constant instead of the removed slice field.
  • #21799 2c4e8cb Thanks @Moustafa-Koterba! - feat(lwd): fix modal height on send flow

  • #22722 03aa2c9 Thanks @LL782! - Import shared analytics directly in Desktop, coin-integration code

  • #22744 5879819 Thanks @ysitbon! - Import the countervalues logic, types and helpers from @domain/entity-market-countervalues instead of @ledgerhq/live-countervalues, and drop the legacy dependency. Specifier change only, no behaviour change.

  • #22950 d1eeaab Thanks @OlivierFreyssinet! - Stop setting the USER_ID env on desktop, now that the firmware checks read the user ID from the identities store

  • #22789 8569110 Thanks @LL782! - Remove stale analytics shim mocks and docs

  • #22726 e21564c Thanks @LL782! - Import shared analytics directly in engagement Desktop code

  • #22724 46fe382 Thanks @LL782! - Import shared analytics directly in live-devices Desktop code

  • #22804 948cc81 Thanks @ysitbon! - fix(desktop): build nightlies against the production Firebase project

    Desktop nightlies compiled the whole .env.staging, so they read feature flags from the Firebase
    staging project while mobile nightlies read production. Nightlies keep the staging services (Braze,
    Segment, Earn, Card, Datadog) but now take their FIREBASE_* values from .env.production.

  • #22859 c4cf243 Thanks @sarneijim! - Port device onboarding into desktop DevTools

  • #22727 5b11a5a Thanks @LL782! - Import shared analytics directly in platform Desktop code

  • #22935 8e427a6 Thanks @ysitbon! - Read the countervalues provider and hooks, useUsdToFiatRate and useGetCounterValueIdsPolling from @features/platform-market-countervalues instead of @ledgerhq/live-countervalues-react and live-common, and drop the @ledgerhq/live-countervalues-react dependency. The app and the test wrapper now mount the platform provider in place of the old one.

  • #22662 487620c Thanks @LL782! - Import shared analytics directly in ptx Desktop code

  • #22725 a4c1969 Thanks @LL782! - Import shared analytics directly in recover-software Desktop code

  • #23012 1289c30 Thanks @OlivierFreyssinet! - Remove the HTTP proxy device transport (DEVICE_PROXY_URL) from the desktop app, together with its IPC transport and the window.lld.transport bridge. Real devices and Speculos connect from the renderer through the Device Management Kit.

  • #22694 d9d44dc Thanks @LL782! - Import shared analytics directly in wallet-xp Desktop code

  • #23219 c50dc4d Thanks @dilaouid! - fix(send): resizeobserver amount fix

  • #22803 0e3e7b0 Thanks @ysitbon! - fix(feature-flags): show the Firebase project the build actually targets

    The debug feature flags screen read the project name from the firebaseEnvironmentReadOnly
    remote flag, a value set by hand in each Firebase project, so a staging build reported
    ledger-live-production. It now reads the project id from the Firebase config bundled in the
    build.

  • #22795 ff5e1b0 Thanks @ysitbon! - refactor(feature-flags): move the Firebase Remote Config mapping to @features/platform-feature-flags-firebase

    @features/platform-feature-flags now only exposes resolved flag state (hooks and FeatureToggle). formatToFirebaseFeatureId, formatDefaultFeatures, parseFirebaseFeatures and RemoteConfigValue are imported from @features/platform-feature-flags-firebase instead; the ./firebase subpath is removed. No behavior change.

  • #22352 c7e76f3 Thanks @ishaba! - fix(babylon): remove pre-selected validator, default to show all

  • #22950 dccba0c Thanks @OlivierFreyssinet! - Compute the firmware distribution salt of the non-DMK firmware update checks from the identities store instead of the USER_ID env, so they use the same salt as the DMK

  • #22591 828c892 Thanks @sarneijim! - Apply enabled feature_copy_* Remote Config values as English copy overrides, reusing the feature-flag fetch

  • #22913 6bb4b44 Thanks @mdomanski-ext-ledger! - feat(hedera): migrate desktop Hedera flows to the generic transaction shape and enable generic adapter

  • #22784 e72683b Thanks @mcayuelas-ledger! - Hide the Pay tab card and its history when the pay-tab flag's card param is false

  • #22985 4182256 Thanks @mdomanski-ext-ledger! - fix(hedera): generic adapter fixes for fee estimation, wallet API memo, token association wording, token receive and swap history saved by the legacy bridge

  • #22640 8783545 Thanks @francois-guerin-ledger! - chore(contacts): stop reading ethereumLikeInfo and promote chainId from coin config

  • #22779 9c8a8f3 Thanks @KVNLS! - The desktop app's own device animations are code-split per device model and loaded lazily instead of being read back through a runtime require(). The shared pin/continue animations are still bundled with the renderer.

  • #22395 39d91b6 Thanks @dilaouid! - feat(tracking): tracking error and warning in new send flow lwm

  • #22743 4d9cfbd Thanks @ysitbon! - Import the countervalues logic, types, helpers and mocks from @domain/entity-market-countervalues instead of @ledgerhq/live-countervalues, and depend on the entity package in place of the legacy one. Specifier change only, no behaviour change.

    Three app tests move with live-common because the calculate they mock is called inside live-common: desktop's useHistoryOperations and mobile's useOperationsListViewModel and useOperationsV1. Their mock has to name the same module live-common imports.

  • #23097 9bffec1 Thanks @gre-ledger! - Move the updater signature check to @features/platform-app-update, so desktop no longer depends on @noble/curves directly.

  • #22975 11cc5fc Thanks @ovoronkov-ledger! - Fix Market list and coin page showing the Settings currency symbol next to prices fetched in the currency picked from the Market dropdown

  • #22969 fb02fb0 Thanks @aussedatlo! - Show the mock server device as a floating window from @ledgerhq/device-mockserver-react, replacing the sidebar device screen.

  • #22808 bac3334 Thanks @live-github-bot! - Upgrade @ledgerhq/coin-evm to version 10.0.0 and remove obsolete gas tracker parameters

  • #22765 e3e6c22 Thanks @OlivierFreyssinet! - Extract the device discovery service and the connectivity types shared by device connection flows into a deviceConnectivity folder. The discovery, connection and unknown error UI states now use the shared ConnectivityUIStateTypes enum. ConnectDeviceUIStateTypes becomes a const object that includes these shared members, so type positions use typeof ConnectDeviceUIStateTypes.X or the new ConnectDeviceUIStateType type. The device type moves to the shared part as Device, and connectDevice keeps KnownDevice as an alias of it. connectDevice behaviour is unchanged.

  • #22915 957f451 Thanks @dgreen-ledger! - Require a genuine-checked device ID before the sync onboarding companion

  • #22695 570a8a0 Thanks @mcayuelas-ledger! - Add a Pay tab screen test id and cover the stablecoin balance, filter, and deposit options

  • #22878 d098cd3 Thanks @tonykhaov! - Show a "Go to CL Card" disclaimer below the Pay contacts when the card_disclaimer param of lwdPayTab is on. It opens the same CL Card webview as "I have a card" on the Card screen.

  • #22879 77e7162 Thanks @tonykhaov! - Show the Card login on the desktop Pay tab when the card_live_app param of lwdPayTab is on. "Create an account" opens the card program live app and "Log in" opens the CL Card live app.

  • #22876 d5de868 Thanks @tonykhaov! - Read the desktop Pay card face (native, live app, disclaimer) from one usePayCardFace hook.

  • #22910 177a5b4 Thanks @tonykhaov! - Pay card login: name Monavate instead of Baanx in "Log in to" and "Card provided by".

  • #22649 514d6f9 Thanks @koda-apps! - Show a newly linked Card asset when the user comes back to Pay from Baanx.

  • #22877 f49824c Thanks @tonykhaov! - Send the live app webview Back button to Pay when the webview was opened from Pay with fromPayTab state.

  • #22869 eb65ce4 Thanks @mcayuelas-ledger! - Add feature-flag scenarios for the native Pay card, Card live app login, and CL Card disclaimer

  • #22027 10e4a67 Thanks @ooke-ledger! - Default the Perps deposit funding account to the USDC account with the highest non-zero spendable balance

  • #22865 667d378 Thanks @ysitbon! - Add @features/platform-market-countervalues, the countervalues React glue: the provider, its context and the hooks reading it, plus useUsdToFiatRate and useGetCounterValueIdsPolling. It is a copy of @ledgerhq/live-countervalues-react and of the two live-common hooks, which keep their own until their consumers move over.

    • @ledgerhq/live-countervalues-react reads the platform package's CountervaluesContext instead of creating its own, so a provider from either package serves the hooks of both. It stops exporting CountervaluesContext, which nothing imported, and drops its unused @ledgerhq/types-live dependency.
    • The platform package depends on no logging library. Desktop and mobile hand it their logger with setCountervaluesLogger at app setup, next to the rate lookups.
  • #22654 78b38fb Thanks @dilaouid! - fix(send): sync account at the start of a send

  • #23150 4dec481 Thanks @tonykhaov! - Keep the device onboarding session in the machine context, follow a new session on reconnect, and let the host run the exit actions

  • #23297 2989e37 Thanks @francois-guerin-ledger! - fix(solana): refresh the blockhash after the device review to avoid "Blockhash not found"

  • #22766 b2792d8 Thanks @mcayuelas-ledger! - Show a setup state on the History card tab when the signed-in holder has not claimed a card yet.

  • #22978 8102f7d Thanks @LucasWerey! - Close the modular dialog, modals and drawer before handling any deeplink

  • #23114 bdf552d Thanks @ypolishchuk-ledger! - Bump Playwright from 1.60.0 to 1.63.0 and allure-playwright / allure-js-commons from 3.9.0 to 3.13.0

  • #22770 812d03f Thanks @ooke-ledger! - Resolve the Perps custom.perps.deposit request with the swap ID and quoted amount once the deposit is broadcast, and reject it when the user cancels. The deposit request now lives in wallet-api/Perps/depositRequest and is shared by desktop and mobile

  • #23024 c037aa8 Thanks @mcayuelas-ledger! - Migrate desktop Add Account off pre-ldls onto Lumen and remove the React pre-ldls entry

  • #22896 a663e23 Thanks @mcayuelas-ledger! - Remove unused react-ui components and switch the desktop token list checkbox to Lumen

  • #22830 8509abf Thanks @KVNLS! - Move the desktop renderer's application database and device transport (HTTP proxy) access onto the preload bridge (window.lld.db, window.lld.transport), with one named method per operation. Password attempts against the account database are now throttled in the main process after five consecutive failures.

  • #22831 fa15dfc Thanks @KVNLS! - Move the auto-updater and deep-link channels and the remaining renderer IPC onto the preload bridge, in preparation for enabling contextIsolation.

    Updater status and deep links are pushed to the renderer through on* subscriptions that return an unsubscribe closure. App lifecycle, native dialogs, file operations, the screen-awake blocker and the lld.json store writes go through named bridge methods instead of ipcRenderer. Channel names and main-side payloads are unchanged.

    With this, the only renderer ipcRenderer call left is the Pay card PNG save, which moves onto the bridge with the other save dialogs in the next change. The only other electron imports outside main and the preload scripts are the three chokepoints introduced earlier — clipboard, webFrame and shell.openExternal, none of which are IPC — plus one type-only import.

    Log export now checks whether the save dialog was cancelled. showSaveDialog always resolves to an object, so the previous if (path) guard was always true and the export ran on cancel, relying on the main process to ignore a cancelled target. The observable behaviour is unchanged; the check now says what it means.

  • #22832 20dccb1 Thanks @KVNLS! - Move the desktop renderer's last Electron chokepoints (clipboard, webFrame, shell.openExternal) onto the preload bridge, and run the save dialogs in the main process. Main now keeps the chosen path for the log export, the operations CSV export and the Pay card PNG save, so the renderer can no longer hand an arbitrary path back to be written. The write handlers return "saved" | "canceled" | "failed", so cancelling an export is no longer reported as an error. Main registers every IPC handler through the shared CHANNELS contract.

  • #22829 8c4ccbe Thanks @KVNLS! - Prepare the desktop renderer for running without Node integration: remove dead IPC channels and Node-only globals (global.localStorage, setImmediate in the post-onboarding redirect), replace winston in the renderer with a minimal logger of the same surface, route clipboard, webFrame, dialogs and os through single-purpose modules, import and export local Live App manifests with a file input and a download instead of the filesystem, and give the dev-only Firebase diagnostic its per-project configs from the build instead of reading .env files at runtime. No behaviour change.

  • #22780 8d10218 Thanks @KVNLS! - Add an explicit, allow-listed preload bridge (window.lld) for the desktop renderer, declared once in src/bridge/contract.ts and imported by both sides. Main captures a bootstrap snapshot (env, os, paths, distribution channel) that the renderer reads synchronously, electron-store moves into the main process, and the Datadog anonymizer reads its paths from the snapshot. The CARD_SESSION_BOOTSTRAP credential is kept out of the snapshot and handed over once per page load. The renderer still runs with nodeIntegration on; the bridge works in both modes, so this changes no behaviour on its own.

  • #22781 6c8bd31 Thanks @KVNLS! - Build the desktop renderer as a web target instead of electron-renderer: Node builtins resolve at build time rather than as runtime require() calls, and the bundle has no externals. process reads are supplied from a snapshot captured in main at startup, deliberately not a process/browser polyfill, which would report platform === "browser". A build-time guard fails the build on an unguarded process read or a bare setImmediate/clearImmediate, rather than letting it surface as a runtime crash.

    ZCash shielded sync receives its IPC channel through setZCashIpcRenderer instead of reaching for electron; the desktop app supplies it over the preload bridge.

    @ledgerhq/transaction-observability (the dApp intent's app_version) and @features/platform-device-action-content (the E2E animation switch) read process.env directly instead of globalThis.process, which the web-target renderer does not have.

  • #22902 240ce9c Thanks @gre-ledger! - chore: replace react-key-handler with an in-house hook for the Ctrl+E logs export shortcut, which behaves the same and drops about 21 MB of dependencies.

  • #23140 b99f923 Thanks @gre-ledger! - Play Lottie animations through the new @shared/lottie package: dotlottie on web (replacing the unmaintained react-lottie / lottie-web), lottie-react-native on mobile.

  • #22950 8737f89 Thanks @OlivierFreyssinet! - Keep the DMK firmware distribution salt in sync with the user ID of the identities store, so DMK flows follow the progressive OS rollout on desktop and mobile

  • #23183 271861f Thanks @mcayuelas-ledger! - fix(sidebar): always start fully open after a reload or app restart

  • #22846 42d4dc2 Thanks @benruseau! - Add the apply updates sub-step to the OS updates orchestrator, covering the OSU install, the MCU flash loop and the final firmware install

    Wait out the device reboots each install and flash leaves behind, reconnecting under the same session id

    Add the restore backup step, which runs as the last tenth of the bar when it follows an update and on its own when there is nothing left to update

    Sync BASE_SOCKET_URL to the DMK secure channel WebSocket URL

  • #21839 6d744e0 Thanks @YazhuEth! - estimateFees now returns the recipient token account, wallet address and input type of an SPL transfer alongside its fee, so the device screen names the destination; a recipient token account holding another token throws SolanaTokenAccountHoldsAnotherToken.

    makeEmptyTokenAccount now builds its id with encodeTokenAccountId, like the fourteen families that already do: the wallet-API placeholder previously used the contract address, so it matched no real sub-account id.

    Solana runs on the generic coin framework. The send and staking screens move onto the generic transaction shape, which names what it does — a mode, a memo, a stake account seed — instead of the nested command model the legacy bridge carried, and the apps now read it through one family module rather than reaching into the transaction themselves.

    The behaviours the legacy bridge produced are restored on the generic path: an incoming SPL transfer produces an operation, a stake withdrawal empties the account rather than signing a stale amount, opening a token account is charged its rent, sending the maximum to a new stake account leaves enough to unstake it later, the device confirmation screen lists every row the device itself shows, and a token account's frozen state and Token-2022 extensions are back on screen.

    A live app can again submit the four token and stake commands the wallet API defines, and a raw signature it gets back is hex, as the field it arrives in says. The device signer is selected through the family's own factory, so the ldmkSolanaSigner flag and the transaction-check option it carries keep deciding, as they did before. The mock bridge is rewritten on the coin module, so a mocked signature still yields a transaction the wallet API can deserialize.

  • #22304 e11e449 Thanks @dilaouid! - feat(tracking): tracking error and warning in new send flow lwd

  • #23112 7f0d867 Thanks @amaslakov! - Harden the Tronify rent payment: Retry stays locked until a payment that may still land has expired, a rent price rise is shown and must be accepted before ordering again, a signed payment about to expire is refused before broadcast, and the unreachable contract-data failure is removed.

  • #23032 bcd25fd Thanks @OlivierFreyssinet! - chore(live-dmk): remove the ldmkTransport feature flag

    DeviceManagementKitProvider on desktop no longer takes ldmkTransportEnabled and always provides
    the Device Management Kit. useDeviceManagementKit now returns a non-null DeviceManagementKit and
    throws outside the provider. The PayTab address verification always uses the Device Intent Executor,
    and the isLDMKTransportEnabled analytics property is removed.

  • #22710 da9651f Thanks @jcchevalier-ledger! - Keep explorer requests on the same Cloudflare load-balancer origin by replaying the __cflb affinity cookie

  • #22059 91ac227 Thanks @Moustafa-Koterba! - feat(cosmos): Migrate the desktop staking UI onto the generic path

  • #22760 4bab512 Thanks @ishaba! - Add the Tronify sponsored send to the desktop Send flow behind the gasSponsorship flag: a USDT transfer can pay its network fee with rented energy, signing the rent payment first, then the transfer once the energy is delivered on-chain.

  • #23031 3264580 Thanks @philipptpunkt! - Pass swapApiEnv (stg | prd) to the Swap live app so it follows Wallet's Swap backend

    • Derived from the SWAP_API_BASE url via new getSwapAPIEnv helper in live-common
    • Unknown hosts (e.g. localhost) send nothing; the live app keeps its own default
    • Stop passing the full swapApiBase url; the live app no longer reads it
  • #22891 cc764ec Thanks @ooke-ledger! - Open swap history from the swap/history deeplink, with the swap matching swapId opened

  • #23185 437d666 Thanks @LucasWerey! - Replace @react-native-community/netinfo with expo-network behind the new @shared/network-status package, and use it for the desktop network status

  • #22708 ad3303b Thanks @qperrot! - Let the Send flow dialog grow to fit its content so the Review button stays visible with long amount messages

  • #22959 b46294e Thanks @dilaouid! - feat(contact): display contact in tx details lwd

  • #22953 f482212 Thanks @OlivierFreyssinet! - chore(device): remove the legacy connectApp and the ldmkConnectApp feature flag

    connectApp and connectManager now always use the Device Management Kit device actions and fail
    with DmkTransportRequired on a non-DMK transport. apps/inlineAppInstall, hw/isUpdateAvailable
    and DeviceManagementKitTransport.listenLegacyConnectApp are removed.

  • #23223 0a5b68d Thanks @mdomanski-ext-ledger! - fix(hedera): skip association for erc-20 tokens in ReceiveWithAssociationModal and resolve the new association token in the legacy adapter

  • #22818 c56dcb3 Thanks @ysitbon! - useSendAmount takes the cryptoCurrency to convert instead of the account holding it. Callers resolve it with getAccountCurrency on the same account they passed before, so a token account still converts with its token. The hook no longer imports any account type or helper.

  • #22989 8312d68 Thanks @gre-ledger! - chore: take uuid from the pnpm catalog (11.1.0)

    uuid was spread over 8.3.2, 9.0.1 and 11.1.0. Every package now uses the catalog entry. @types/uuid is dropped: 11 ships its own types. The repo only imports v4, v5 and parse (parse in a coin-solana test fixture), which behave the same across these majors. 11 types v4 with overloads, so passing it directly as a callback (useState(uuid)) no longer typechecks and is now wrapped (useState(() => uuid())).

  • #22383 33094bc Thanks @ysitbon! - Let wallet-pnl declare the countervalues interface it needs

    The package computed profit and loss straight against the countervalues implementation, which
    tied a pure pricing calculation to a concrete state shape. It now declares the three operations
    it uses as a RateLookup interface, treats the state as an opaque snapshot, and drops
    @ledgerhq/live-countervalues from its dependencies. The apps fill the interface at startup,
    beside the crypto-assets store and the two lookups already registered there.

    The exported signatures keep their arity and the state argument is assignable as before, so no
    caller needs a change for the interface.

    The third operation is a cache key. getCostBasis memoises against a fingerprint of the rate
    history relevant to a pair, which it used to compute inline from three countervalues helpers.
    That computation moves to @domain/entity-market-countervalues as historyKey, beside the
    lenseRateMap it is built on, so the three apps share one copy instead of each carrying its own
    and risking drift. A drifted key serves a stale cost basis silently. The key string is unchanged,
    and the existing cache tests pin it without being modified.

    The synthetic state builder moves with it. buildCV, buildMultiCV and dailyHistory
    construct countervalues state rather than reading it, so they cannot work against an opaque
    snapshot; they now live behind @domain/entity-market-countervalues/mock, and
    @ledgerhq/wallet-pnl/scenarios no longer exports them. The web-tools pnl-calculator imports them
    from the entity directly.

    web-tools registers the interface too. It renders profit and loss through the same package but
    was never a consumer of the two lookups registered previously, so it needed wiring of its own.

Patch Changes

Don't miss a new ledger-live release

NewReleases is sending notifications on new releases.