Analysis

How two wallet parsers handle Litecoin payment requests

Twenty identical requests reveal differences in repeated amounts, decimal precision and metadata at the parsing boundary of Electrum-LTC and Cake Wallet. Exact versions, code and results are published.

The same duplicate-amount URI returns a duplicate-key error in the tested Electrum function and amount text 2 in the tested Cake function. App validation and signing are separate.

Measured parsing boundary · pinned source functions, not complete wallet applications.

Saved articles
Sources, review record & reproducibility

Downloadable data.

Content review recorded: 2026-09-30. The review record does not identify a separate independent reviewer. An edited date above records an edit, not a new fact-check.

Sources saved with the review:

See the article body for source links and any downloadable materials. Editorial method · Corrections · Report an issue

On this page

A Litecoin payment request can look correct as text and still be interpreted differently at the next step. To find out where those differences begin, we passed the same 20 inputs through code from Electrum-LTC 4.2.2.1 and Cake Wallet v6.4.5.

The most useful finding is about repeated amounts. For amount=1&amount=2, Electrum’s URI function returned a duplicate-key error. Cake’s request-parsing function, running with Dart 3.13.5, returned the amount string 2. That is a reason to remove ambiguity from a request before sharing it.

This is a test of source-isolated parsing functions. We did not run either complete wallet, scan with a phone camera, construct a payment, sign or broadcast. A function returning an invalid amount or address does not establish that the complete application allows it. Its next screen can perform additional checks.

What we actually ran

The boundary of each test
ImplementationExecuted codeOutside the experiment
Electrum-LTC 4.2.2.1Unchanged upstream URI, Base58Check and SegWit validation function bodies, extracted through Python’s AST from the verified release archiveFull package startup, GUI, scanner, payment-request callback, signing and sending
Cake Wallet v6.4.5Unchanged constructor and PaymentRequest.fromUri factory from commit 9fe23970c7a6e7f88e2bab88abe4e6346c732316, compiled and executed with Dart 3.13.5Full app, fromString fallback, scanner, downstream send-screen amount/address checks, signing and sending

The Electrum archive was checked against SHA-256 ec5dbc72f7be1c3e490cae6281f9060ff36f4c27c0df783e0e6409e66c0f33d4. Cake’s source file and generated harness have separate hashes in the downloads. Its unrelated Lightning, ERC681 and Nano dependencies were replaced by guarded adapters. None of the corpus inputs entered those dependency branches; entering an unsupported branch would abort the experiment.

We used synthetic public address hashes with no known private keys. They test encoding and checksum behavior, not custody. Never fund an address in the corpus. No real customer request or wallet secret was used. The exact text and returned fields are available in the case explorer.

Nine cases that change how you should prepare a request

Results at the parsing boundary; “returned” is not “payable”
InputElectrum functionCake functionPractical consequence
URI with no amountNo amountNo amount textAsk the payer to enter and verify the agreed amount.
Nine decimals12345678 litoshis0.123456789Request only amounts representable with eight decimals.
Negative amount-100000000 litoshis-1A returned field does not establish a valid spend.
Duplicate amountError: Duplicate Key: 'amount'2Use one amount parameter; do not depend on precedence.
Unknown required fieldAmount plus req-invoice retainedAmount returned; req-invoice not exposedDo not depend on a required extension unless the actual wallet enforces it.
UTF-8 and encoded ampersandLabel: Café & invoice 17No note from labelCheck the destination through another trusted channel.
Wrong address checksumError: Invalid litecoin address: LLnCCHbSzfwWquEdaS5TF2Yt7uz5Qb1SZ20.125Address validation can happen after parsing; test the whole flow separately.
Wrong currency schemeError: Not a litecoin URI0.125A scheme returned as text is not currency validation.
Scientific notation1 litoshis1e-8Use ordinary decimal LTC amounts for portable requests.

The full 20-case table also covers plain addresses, one-litoshi amounts, an empty amount, a decimal comma, optional metadata, an unescaped ampersand, uppercase scheme, native SegWit, an amount above supply and expiry fields. These are deliberately selected cases, not a random sample of real-world requests. We do not turn their counts into a wallet reliability score.

Repeated amount fields are an avoidable disagreement

The request litecoin:address?amount=1&amount=2 contains two instructions under one key. In this Electrum version, parsing the query detects the repeated key and raises an error. Cake’s factory reads Dart’s single-value Uri.queryParameters map; in the tested runtime it obtains the last amount value.

Neither behavior is an excuse to send an ambiguous invoice. Generate one amount field, decode the generated request and compare it with the invoice. If you receive a request with duplicates, ask for a corrected one rather than guessing which value the sender intended.

Parsing is one stage of a paymentQR decoderreturns textURI parserextracts fieldsApp validationchecks paymentUser approvalthen signingMeasured boundaryThe experiment did not execute the other stages.
A readable QR symbol, a returned URI object and a valid payment are separate outcomes.

Precision can change before you see a send screen

With amount=0.123456789, Electrum returned 12345678 litoshis. Converting that integer back to LTC gives 0.12345678: the ninth decimal was truncated at this function boundary. Cake returned the original string 0.123456789. We did not test how its send screen rounds or rejects that string.

For an invoice, write an amount representable in eight decimal places. Avoid scientific notation, negative amounts and local decimal commas even when a parser happens to return them. Both tested functions returned a field for the negative-amount fixture; that observation is about parsing, not spend validation.

Required fields, labels and expiry need their own checks

Our unknown-required fixture added req-invoice=17. Electrum returned it in the parsed fields. Cake returned the address and amount without exposing that parameter in the request object. Neither result proves enforcement of a required extension by the complete application. A merchant should test the actual wallet flow before depending on an extension for acceptance.

An encoded label=Caf%C3%A9%20%26%20invoice%2017 became a readable label in Electrum. Cake’s tested factory uses message or tx_description for its note; the label fixture produced an empty note. A label can disappear without changing the destination, and a convincing label can accompany the wrong destination. Compare the full address through an authenticated channel.

The expiry fixture returned data at both boundaries. We did not establish whether either full application enforces its time and exp fields. Put quote expiry and late-payment policy in the invoice itself; do not assume an arbitrary URI field will enforce the commercial agreement.

A short preflight for merchants and payers

  1. Use one destination and one ordinary decimal amount in LTC. Avoid duplicated keys and unnecessary extensions.
  2. Decode the exact QR or URI you will share. Check every character of the destination and the eight-decimal amount against the invoice.
  3. Test the actual wallet version and device your payer uses, with a safe controlled procedure. Record the decoded text, populated fields and validation result separately.
  4. Before approving a real payment, read the destination and amount on the wallet’s trusted confirmation screen.
  5. After broadcast, match the actual output and apply your agreed confirmation policy. A QR scan does not prove settlement.

Our local QR inspector flags duplicates and unsupported required fields rather than choosing a payment interpretation. The payment checklist connects that preflight with request creation, transaction inspection and reconciliation.

Reproduce it and report a different result

Download the source subset, harnesses and results, verify the checksums, then follow the Python and Dart instructions. Results are also available as CSV and JSON. No package installation is needed for the source-isolated Python or generated Dart harness.

If your wallet behaves differently, record the exact version, operating system, URI text and stage where the difference occurs. Remove personal data and recovery secrets. A full-app observation can add evidence that this parser study does not provide. Submit a reproducible correction through our corrections page.

Primary references: Electrum-LTC release downloads, the pinned Cake payment-request source and BIP 21. BIP 21 is a Bitcoin specification; it supplies background for this widely used URI shape, not a guarantee about Litecoin wallet implementation.

Measured 30 September 2026. AI-assisted research, code and drafting; scripted verification, no independent human reviewer claimed. No complete-wallet safety ranking is implied.

Jarosław Wasiński
Editor-in-chief · Financial markets and Litecoin education

Editor-in-chief of Litecoin.watch and founder of MyBank.pl. His published work covers foreign exchange, financial education and Litecoin. On Litecoin.watch, his remit includes editorial direction, source transparency and the practical guides and research published by the site.

Background, selected work and editorial responsibility →

Founder of MyBank.plFinancial education and market analysisNamed editorial responsibility

Track Litecoin in real time

Rates for 30+ currencies. Check each tool for its latest source timestamp.

Open dashboard