Back to Freedom.Tech Back
All Ledger Live Desktop releasesAll versions
Release Fri, Oct 2, 2026 7 min read

Ledger Live Desktop 4.23.0

Original release notes

4.23.0

Minor Changes

  • #22217 63960b1 Thanks @vpenskyi-ledger! - Fix the Swap receive field staying empty when reaching Swap from the Earn no-funds screen. Desktop now always identifies a token by toTokenId (plus its toToken alias), which toCurrencyId alone could not do; mobile passed no parameters at all and now forwards the asset. On both, an account the Earn live app synthesised for a token the user does not hold is no longer sent as an unresolvable id
  • Add getCardCashback endpoint, resolving the asset's currency/network pair (both nullable) to its ledgerId
  • Remove getRewardWallet (GET /v1/wallet/reward), its schema, types, mock and handlers
  • useCardCashback replaces useCardRewardWallet in the reward banner
  • Banner subtitle now shows the rate and ticker: "Total cashback 1% in BTC"
  • cardRewardsAvailable / cardRewardCurrency analytics now read the cashback (amount > 0)

Removes the llmThai / lldThai feature flags. Flags resolve on their enabled: false default until the first remote fetch settles, so on every cold start the locale guard saw Thai as unsupported and persisted English over the user's choice.

  • #22840 e4c24f3 Thanks @LucasWerey! - Name the default Me contact "Me" in the Pay tab contacts list instead of "My addresses (Me)"
  • #22381 c5964f8 Thanks @ysitbon! - Rename @domain/api-market-sentiment to @domain/api-market-index-fear-and-greed, and its exported api from marketSentimentApi to fearAndGreedApi, so the name states which CoinMarketCap index the package serves
  • #22653 e8d5e1b Thanks @OlivierFreyssinet! - Bump DMK dependencies: device-management-kit 1.10.0, device-signer-kit-solana 1.13.3, device-signer-kit-ethereum 1.18.1, context-module 2.6.0, dmk-ledger-wallet 0.6.0, device-contacts-kit 0.5.0, signer-utils 1.3.0, device-transport-kit-mockserver 1.1.2
  • #22567 3ee4143 Thanks @tonykhaov! - List the Me contact in the desktop Send recipient contacts, like mobile, with only its addresses on the selected network.
  • #22615 7bc8d65 Thanks @mcayuelas-ledger! - Open the Pay request flow from the Add stablecoin "Crypto address" option instead of the standard Receive flow
  • Both platforms read on by scrolling: native through the list's onEndReached, web through an observer on a sentinel at the end of the table.
  • A spinner marks the page in flight; no new copy, so nothing to translate.
  • Both take loadMore/isLoadingMore from the shared view model, so the three-row previews on the Pay surfaces are unaffected.
  • #22474 1a26e59 Thanks @live-github-bot! - Update coin module dependencies (coin-evm, coin-module-framework, coin-stellar, coin-tezos) and rebuild the lockfile
  • #22572 6e76dda Thanks @tonykhaov! - ContactAvatar takes isMe and is the only avatar that formats the Me label, so a Me avatar is announced once as "<name> (Me)". MeAvatar takes a display-ready label and is no longer exported; ME_AVATAR_URL stays exported. PaySuccessRecipient.isMe is now required.
  • #22656 486a1a4 Thanks @LucasWerey! - Only mention ENS in the contact address input placeholder for networks that support domain resolution (LIVE-38284).
  • #22348 f7cd861 Thanks @ysitbon! - Let asset-aggregation and wallet-analytics declare the countervalues interface they need

Both packages only ever needed one countervalues operation, calculate, over a state they receive as a parameter and never inspect. They now declare that operation themselves as a RateLookup interface, treat the state as an opaque RateSnapshot, and drop @ledgerhq/live-countervalues from their dependencies entirely. The apps fill the interface at startup, beside the crypto-assets store and the currencies resolver.

No caller changes: the exported signatures keep their arity and the state argument is assignable as before, so the 41 files consuming these two packages are untouched.

Tests get simpler as a side effect. Mocking countervalues was a module mock reaching across a package boundary; it is now an injected fake passed to setRateLookup.

A feature-flags re-resolution that throws at boot is now reported through logger.critical, whatever the state of the remote-flag cache.

Adds a generic AddressBookProvider<T> in live-dmk-shared (the EVM provider is refactored onto it), a tronAddressBookProvider instance, a pure toTronAddressBook mapper (Contact[] -> TronAddressBook, Tron-family only, no chain id, ledgerAccounts always empty), and registers the source at each app's composition root. An absent or empty book leaves signing behavior unchanged.

transaction lifecycle events for native staking and allow-listed dApps on Desktop and Mobile.

  • #22614 b4599a5 Thanks @mcayuelas-ledger! - Update the verify address next steps copy, add a third step, and size the mobile shield spot to match desktop

The device storage figures and the install success banner render their values as bare text nodes, so a test can see the containers but cannot assert what they show. This adds them to the used, capacity, apps count and free space figures in the storage card, and to the install success banner's title and its manage accounts button.

No behaviour changes: every addition is a data-testid attribute.

The manager screen already exposes test IDs for its containers, inputs and success states, but not for several triggers and submit buttons, so those flows could not be driven from a test. This adds them to the app catalog's Show and Sort dropdowns, the device rename entry point and its submit button, the custom lock screen removal link and its success state, and the OS version and genuine badge values.

No behaviour changes: every addition is a data-testid attribute.

  • #22571 e3c51c5 Thanks @tonykhaov! - Show a matched Me contact as "<name> (Me)" in Send: the recipient card, the "Address matched" row, the amount step "To" header, the Pay success title and the History counterparty. MatchedContact and RecipientHeaderContact now carry isMe, and RecipientHeaderPresentation.label is renamed recipientDisplayValue and never holds a contact name.
  • #22438 f9b43be Thanks @pawell24! - fix(near): size staking gas from measured usage and price it the way the chain does

Staking fees priced the attached gas at the current gas price. nearcore buys the gas attached to a receipt at max(current_gas_price, min_gas_purchase_price), and that floor is an order of magnitude above the current price on mainnet, so every stake, unstake and withdraw quoted about a tenth of what the account had to hold. A withdraw quoted at 0.02 NEAR was rejected on broadcast with NotEnoughBalance naming a cost of 0.1759 NEAR.

The fee now uses the same floor the runtime does, and the attached gas drops from 125 TGas (175 for withdraw_all) to 50 TGas for every staking call. The heaviest poolv1 path, the first call in a new epoch which also restakes and runs the pool's 20 TGas on_stake_action callback, was measured across five mainnet pools: at most 13.64 TGas charged, and 30 TGas attached succeeds on it. The old budget, bought at the floor, locked 0.2 NEAR for a call that burns about 0.001; the new one locks 0.055.

Unstake and withdraw are validated against the balance left above storage staking, which is what the chain checks, instead of the spendable balance that also subtracts the minimum-balance