Transactions
From proposal to block: lifecycle, proving time, fees and outcomes.
A proposal from your app becomes a transaction only after the user approves it. From then on the wallet gives you a handle and you follow it.

Lifecycle
awaiting_approval → building → proving → signing → submitted → included
↘ rejected · dropped · expired| Lifecycle | What's happening |
|---|---|
awaiting_approval | The approval sheet is open. It expires after 5 minutes, on lock, or on a network switch. |
building | The wallet reads fresh chain state and builds the exact message. |
proving | Private routes only: RISC Zero proves the transfer locally. proving.phase (preparing, proving, submitting, waiting_for_block) and proving.progress (0–100) update. |
signing | Nonces and program headers are re-checked, then the wallet signs. |
submitted | Sent to the sequencer; txHash is set. |
included | In a block (block.id). Final for watchers. |
rejected · dropped · expired | Didn't happen. error says why. |
On the official testnet a transaction can take a minute or more to be included. The wallet waits up to about 6 minutes before it reports a send as not included.
The protocol reserves finalized, but the wallet doesn't report it yet.
Outcomes: included is not "it worked"
LEZ 0.3 includes failed transactions (and charges their fee). So the wallet
proves each result from chain state and reports an outcome:
outcome | Evidence | Your app shows |
|---|---|---|
success | Your own account moved by exactly the amount, or the record your call writes exists | Done |
failure | Included, and the effect provably didn't happen | The error and a retry |
unknown | Included, but the wallet can't prove it either way | "Included, not confirmed yet", then re-read the state you expected to change |
outcomeSource says how it was decided (own-account-invariant, …).
Proving time
Private transactions need a zero-knowledge proof, made on the user's machine so keys never leave it.
| Machine | Time per proof | Peak memory |
|---|---|---|
| Apple M-series laptop | ~4.5 minutes (measured 267–337 s) | ~4.3 GB |
The wallet shows progress and lets the user close the sheet; the proof keeps running. Only one proof runs at a time.
Amounts: LGO and lepta
The native token is LOGOS, symbol LGO: 1 LGO = 10^9 lepta. LEZ is the name of the execution zone (the network), not of the token.
| Where | Unit |
|---|---|
The wire, JSON, the SDK (transfer, getWalletBalance, requestFunds results) | lepta, as strings |
| The wallet, the apps, the CLI's human output | LGO, up to 9 decimals |
The CLI's --json output | lepta |
The CLI's send --amount | lepta (42) or LGO (2.5, 2.5LGO, 3 LGO) |
LGO is shown with up to 9 decimals, nothing rounded and trailing zeros
trimmed: 1 lepta is 0.000000001 LGO. This follows the official Logos UI
convention (logos-blockchain-ui PR #69). In an app, show lepta with
kit.sdk.formatUnits(amount, 9) and parse what the user typed with
kit.sdk.parseUnits(text, 9).
Fees
Fees are paid in the native token: lepta on the wire, LGO on screen. Private transactions are fee-exempt in LEZ 0.3. A public one pays
min(cycles used, gas limit) × execution base fee + signed bytes × storage base fee + tipThe wallet shows three figures:
| Where | Figure | Source |
|---|---|---|
| Approval sheet, "Network fee" | The fee at today's base fees. A native transfer runs outside the zkVM at zero cycles, so its fee is exact: bytes × storage base fee + tip. A program call shows up to, pricing its cycles at the gas limit, because they're only known once it runs | getFeeState when the review is built |
| Approval sheet, technical details | The fee cap (maxFee) the payer signs, the gas limit and the base fee | The transaction itself |
| After inclusion (public native sends) | The fee paid | How much the sender's balance dropped beyond the amount |
The LEZ 0.3 RPC doesn't report gas used: getTransaction returns the
transaction and its block, and there is no simulate method. The paid fee is
therefore read from the sender's balance. If anything else moves that balance
in the meantime, such as an incoming payment or another send, the wallet shows
no fee paid rather than guess. The approval binds to the cap, so a base
fee rise between review and inclusion can never charge more than the user
signed for.
Re-checks at signing
Between approval and signing, time passes (sometimes minutes of proving). Just
before signing, the wallet re-checks what the approval depended on: the signer
nonces, the program's image, and, for testimonial posts, which stats page is
open. If something moved, it refuses with 6106 StaleApproval (propose again),
or, where the effect is provably identical, rebuilds the same post
(details).