From 20f3d06bb6128daf75d82234e163271d0327dd47 Mon Sep 17 00:00:00 2001
From: Stanley Yuen <102275989+stanleyyconsensys@users.noreply.github.com>
Date: Thu, 20 Aug 2026 11:05:53 +0800
Subject: [PATCH] chore: update stellar docs
---
.gitignore | 1 -
packages/stellar-wallet-snap/README.md | 5 +-
.../docs/misc/synchronization/accounts.md | 95 ++++++++++++++++
.../docs/misc/synchronization/assets.md | 65 +++++++++++
.../misc/synchronization/synchronization.md | 88 +++++++++++++++
.../docs/misc/synchronization/transaction.md | 106 ++++++++++++++++++
.../transaction/send-classic-trustline.md | 61 ++++++++++
.../docs/misc/transaction/send-native.md | 78 +++++++++++++
.../docs/misc/transaction/send-sep41.md | 64 +++++++++++
.../docs/misc/transaction/send-swap.md | 78 +++++++++++++
.../misc/transaction/submit-sequence-retry.md | 80 +++++++++++++
.../docs/use-cases/README.md | 60 ++++++++++
.../docs/use-cases/assets/assets.md | 33 ++++++
.../client-request/changeTrustOpt.md | 100 +++++++++++++++++
.../use-cases/client-request/computeFee.md | 68 +++++++++++
.../use-cases/client-request/confirmSend.md | 96 ++++++++++++++++
.../client-request/onAddressInput.md | 47 ++++++++
.../use-cases/client-request/onAmountInput.md | 77 +++++++++++++
.../client-request/signAndSendTransaction.md | 81 +++++++++++++
.../docs/use-cases/cron-job/cronjob.md | 44 ++++++++
.../cron-job/refreshConfirmationContext.md | 86 ++++++++++++++
.../docs/use-cases/cron-job/syncAccounts.md | 47 ++++++++
.../docs/use-cases/cron-job/syncAssets.md | 40 +++++++
.../use-cases/cron-job/trackTransaction.md | 72 ++++++++++++
.../docs/use-cases/keyring/keyring.md | 50 +++++++++
.../docs/use-cases/keyring/signAuthEntry.md | 58 ++++++++++
.../docs/use-cases/keyring/signMessage.md | 73 ++++++++++++
.../docs/use-cases/keyring/signTransaction.md | 67 +++++++++++
.../docs/use-cases/user-input/userInput.md | 29 +++++
29 files changed, 1845 insertions(+), 4 deletions(-)
create mode 100644 packages/stellar-wallet-snap/docs/misc/synchronization/accounts.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/synchronization/assets.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/synchronization/synchronization.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/synchronization/transaction.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/transaction/send-classic-trustline.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/transaction/send-native.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/transaction/send-sep41.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/transaction/send-swap.md
create mode 100644 packages/stellar-wallet-snap/docs/misc/transaction/submit-sequence-retry.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/README.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/assets/assets.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/client-request/changeTrustOpt.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/client-request/computeFee.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/client-request/confirmSend.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/client-request/onAddressInput.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/client-request/onAmountInput.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/client-request/signAndSendTransaction.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/cron-job/cronjob.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/cron-job/refreshConfirmationContext.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAccounts.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAssets.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/cron-job/trackTransaction.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/keyring/keyring.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/keyring/signAuthEntry.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/keyring/signMessage.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/keyring/signTransaction.md
create mode 100644 packages/stellar-wallet-snap/docs/use-cases/user-input/userInput.md
diff --git a/.gitignore b/.gitignore
index ca324d052..da2292f97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,7 +20,6 @@ examples/*/dist
examples/*/docs
packages/*/coverage
packages/*/dist
-packages/*/docs
scripts/coverage
# yarn v3 (w/o zero-install)
diff --git a/packages/stellar-wallet-snap/README.md b/packages/stellar-wallet-snap/README.md
index 18831bb3c..55bea1acf 100644
--- a/packages/stellar-wallet-snap/README.md
+++ b/packages/stellar-wallet-snap/README.md
@@ -53,9 +53,8 @@ High-level layout of `packages/snap` (nested implementation folders like `servic
## Use cases
-End-to-end flows (handler → services → UI) live under [`docs/use-cases/`](./docs/use-cases/).
-Background synchronization overview: [`docs/misc/synchronization/overview.md`](./docs/misc/synchronization/overview.md).
-Shared transaction build / validate / send: [`docs/misc/transaction/`](./docs/misc/transaction/README.md).
+End-to-end flows (handler → services → UI) live under [`docs/use-cases/`](./docs/use-cases/README.md).
+Background synchronization overview: [`docs/misc/synchronization/synchronization.md`](./docs/misc/synchronization/synchronization.md).
## API examples
diff --git a/packages/stellar-wallet-snap/docs/misc/synchronization/accounts.md b/packages/stellar-wallet-snap/docs/misc/synchronization/accounts.md
new file mode 100644
index 000000000..dbad7efff
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/synchronization/accounts.md
@@ -0,0 +1,95 @@
+# Synchronization: accounts
+
+On-chain account snapshots (balances, trustlines, SEP-41 tokens) for **activated** keyring accounts.
+
+| | |
+| ---------------- | ---------------------------------------------------------------------------------------------------------------- |
+| **Service** | `[OnChainAccountSynchronizeService](../../../src/services/on-chain-account/OnChainAccountSynchronizeService.ts)` |
+| **Orchestrator** | `[SynchronizeService](../../../src/services/sync/SynchronizeService.ts)` |
+| **Snap state** | `[OnChainAccountRepository](../../../src/services/on-chain-account/OnChainAccountRepository.ts)` |
+| **Overview** | [synchronization.md](./synchronization.md) |
+
+## Participants
+
+| Component | Path | Role |
+| ---------------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
+| `SynchronizeService` | `services/sync` | Load activated pairs + SEP-41 catalog; run account + tx sync |
+| `OnChainAccountSynchronizeService` | `services/on-chain-account` | Merge snapshots, persist, emit |
+| `OnChainAccountService` | `services/on-chain-account` | Resolve live on-chain account |
+| `NetworkService` | `services/network` | [Horizon](https://developers.stellar.org/docs/data/apis/horizon/api-reference/retrieve-an-account) account + SEP-41 balance reads |
+| `SyncAccountsHandler` | `handlers/cronjob` | Cron / scheduled entry |
+
+## Request / response
+
+Triggered via `SynchronizeService.synchronize` (see [syncAccounts.md](../../use-cases/cron-job/syncAccounts.md)). Emits keyring events after snap state is persisted:
+
+- `AccountBalancesUpdated`
+- `AccountAssetListUpdated`
+
+SEP-41 token balances are **not** from Horizon — they use Soroban RPC `balance(Address)` simulation.
+
+## Step-by-step
+
+1. `SynchronizeService` loads **activated** account pairs from [Horizon](https://developers.stellar.org/docs/data/apis/horizon/api-reference/retrieve-an-account); unfunded / not-yet-activated accounts are skipped.
+2. Load SEP-41 asset metadata for the scope (shared with transaction sync on the same run).
+3. `OnChainAccountSynchronizeService.synchronize` — batch-fetch SEP-41 token balances (best effort).
+4. Load previous snap-state snapshots as merge baseline.
+5. Per activated account — apply SEP-41 balances, then **merge** persisted gaps (classic tombstones + SEP-41 backfill).
+6. **Compute deltas** — `#computeKeyringSyncDeltas` compares pre-sync snapshot vs merged on-chain view (visibility transitions → balance / asset-list payloads).
+7. Persist snapshots atomically, then emit `AccountBalancesUpdated` and `AccountAssetListUpdated`.
+
+Account sync and transaction sync run **in parallel** when both are enabled on the same `synchronize` call.
+
+## Tombstones, merge, and deltas
+
+Merge and deltas are two linked steps:
+
+1. `#mergePersistedEntriesIntoOnChainAccount` — fill gaps so the in-memory on-chain view is complete before diffing.
+2. `#computeKeyringSyncDeltas` — compare **persisted snapshot** vs **merged on-chain view** for visibility transitions:
+
+- newly visible → `added` (+ balance)
+- no longer visible → `removed` (+ balance `0`)
+- already not visible → omit (avoid flooding zeros)
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Cron as SyncAccountsHandler
+ participant Sync as SynchronizeService
+ participant OnChain as OnChainAccountSynchronizeService
+ participant Network as NetworkService
+ participant State as OnChainAccountRepository
+ participant MM as MetaMask controller
+
+ Cron->>Sync: synchronize(accounts, scope)
+ Sync->>Network: resolve activated pairs (GET /accounts/:id)
+ Sync->>OnChain: synchronize(pairs, scope, sep41Assets)
+ OnChain->>Network: SEP-41 balance simulation
+ OnChain->>State: load last snapshots
+ loop per activated account
+ OnChain->>OnChain: apply SEP-41 balances
+ OnChain->>OnChain: merge (classic tombstones + SEP-41 backfill)
+ OnChain->>OnChain: computeKeyringSyncDeltas
+ end
+ OnChain->>State: saveMany
+ OnChain->>MM: AccountBalancesUpdated (delta balances)
+ OnChain->>MM: AccountAssetListUpdated (delta added/removed)
+```
+
+## Data source
+
+| Data | Source |
+| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Native + classic trustline balances | **Live on-chain** via [Horizon](https://developers.stellar.org/docs/data/apis/horizon/api-reference/retrieve-an-account) `GET /accounts/:account_id` |
+| SEP-41 token balances | **Live on-chain** (Soroban simulation) |
+| Persisted snapshot | **Snap state** (`OnChainAccountRepository`) |
+| Keyring-facing balances / asset list | Emitted from latest snapshot (can be slightly stale until next sync) |
+
+## Related
+
+- [Horizon — Accounts](https://developers.stellar.org/docs/data/apis/horizon/api-reference/resources/accounts)
+- [Horizon — Retrieve an Account](https://developers.stellar.org/docs/data/apis/horizon/api-reference/retrieve-an-account)
+- [syncAccounts.md](../../use-cases/cron-job/syncAccounts.md) — cron entry and params
+- [keyring.md](../../use-cases/keyring/keyring.md) — `listAccountAssets` / `getAccountBalances` read snap snapshots
+- [transaction.md](./transaction.md) — transaction sync on the same run
diff --git a/packages/stellar-wallet-snap/docs/misc/synchronization/assets.md b/packages/stellar-wallet-snap/docs/misc/synchronization/assets.md
new file mode 100644
index 000000000..88f2e4eee
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/synchronization/assets.md
@@ -0,0 +1,65 @@
+# Synchronization: assets
+
+Asset metadata catalog refresh from the token API.
+
+| | |
+| ---------------- | -------------------------------------------------------------------------------------------------- |
+| **Service** | [`AssetMetadataService.synchronize`](../../../src/services/asset-metadata/AssetMetadataService.ts) |
+| **Orchestrator** | [`SynchronizeService.synchronizeAssets`](../../../src/services/sync/SynchronizeService.ts) |
+| **Snap state** | [`AssetMetadataRepository`](../../../src/services/asset-metadata/AssetMetadataRepository.ts) |
+| **Overview** | [synchronization.md](./synchronization.md) |
+
+## Participants
+
+| Component | Path | Role |
+| ---------------------- | ----------------------------------- | ----------------------------------- |
+| `SyncAssetsHandler` | `handlers/cronjob` | Cron entry |
+| `SynchronizeService` | `services/sync` | `synchronizeAssets(scope)` delegate |
+| `AssetMetadataService` | `services/asset-metadata` | Fetch + persist catalog |
+| `TokenApiClient` | `services/asset-metadata/token-api` | Token API |
+
+## Request / response
+
+Triggered by the `synchronizeAssets` cron (see [syncAssets.md](../../use-cases/cron-job/syncAssets.md)). Always uses **mainnet** scope — asset metadata is only available there, regardless of the user's selected network.
+
+Wire format: [SIP-29 Snap Assets API](https://metamask.github.io/SIPs/SIPS/sip-29) (lookup handlers read from the persisted catalog).
+
+## Step-by-step
+
+1. `SyncAssetsHandler` cron fires (always **mainnet** scope).
+2. `SynchronizeService.synchronizeAssets(scope)` delegates to `AssetMetadataService.synchronize`.
+3. Fetch full token list from the token API.
+4. Persist catalog via `AssetMetadataRepository.saveMany`.
+5. Failures are logged / tracked; the cron does not fail the whole Snap lifecycle.
+
+During account / transaction sync, `SynchronizeService` also preloads SEP-41 metadata via `fetchSep41AssetsOrSyncOnce` so transaction mapping and balance reads have catalog data without waiting for the assets cron.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Cron as SyncAssetsHandler
+ participant Sync as SynchronizeService
+ participant Meta as AssetMetadataService
+ participant API as TokenApiClient
+ participant State as AssetMetadataRepository
+
+ Cron->>Sync: synchronizeAssets(mainnet)
+ Sync->>Meta: synchronize(mainnet)
+ Meta->>API: fetch token list
+ API-->>Meta: tokens metadata
+ Meta->>State: saveMany
+```
+
+## Data source
+
+| Data | Source |
+| ----------------------------------------- | ------------------------------------------------ |
+| Asset catalog (symbol, decimals, icon, …) | **Token API** → persisted in **snap state** |
+| On-demand lookup (`onAssetsLookup`) | Snap state catalog (fetch + persist missing ids) |
+
+## Related
+
+- [syncAssets.md](../../use-cases/cron-job/syncAssets.md) — cron entry
+- [assets.md](../../use-cases/assets/assets.md) — `onAssets*` handlers
+- [transaction.md](./transaction.md) — SEP-41 metadata used during tx mapping
diff --git a/packages/stellar-wallet-snap/docs/misc/synchronization/synchronization.md b/packages/stellar-wallet-snap/docs/misc/synchronization/synchronization.md
new file mode 100644
index 000000000..07fed3643
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/synchronization/synchronization.md
@@ -0,0 +1,88 @@
+# Synchronization
+
+How background sync wires accounts, transactions, and asset catalog together.
+
+| | |
+| ---------------- | -------------------------------------------------------------------------------- |
+| **Orchestrator** | [`SynchronizeService`](../../../src/services/sync/SynchronizeService.ts) |
+| **Accounts** | [accounts.md](./accounts.md) — on-chain snapshots (balances, trustlines, SEP-41) |
+| **Transactions** | [transaction.md](./transaction.md) — Horizon history, mapping, pending reconcile |
+| **Assets** | [assets.md](./assets.md) — token metadata catalog |
+
+## Participants
+
+| Component | Path | Role |
+| ------------------------- | ------------------ | ------------------------------------------------------ |
+| `CronjobHandler` | `handlers/cronjob` | Gate — skip if inactive / locked |
+| `SyncAccountsHandler` | `handlers/cronjob` | Cron / scheduled entry for accounts + txs |
+| `SyncAssetsHandler` | `handlers/cronjob` | Cron entry for asset catalog |
+| `TrackTransactionHandler` | `handlers/cronjob` | Poll until terminal → then synchronize |
+| `SynchronizeService` | `services/sync` | Hub — mutex, parallel account + tx sync, asset catalog |
+
+## Step-by-step
+
+### `synchronizeAccounts` run
+
+1. Load **activated** account pairs (skip unfunded).
+2. Preload SEP-41 metadata for the scope.
+3. Run **[accounts](./accounts.md)** and **[transactions](./transaction.md)** sync **in parallel**.
+4. Per-task failures are logged; they do not fail the whole run.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Sync as SynchronizeService
+ participant Assets as assets sync
+ participant Acc as accounts sync
+ participant Tx as transaction sync
+
+ Sync->>Assets: preload SEP-41 metadata
+ Assets-->>Sync: sep41Assets
+ par
+ Sync->>Acc: synchronize
+ and
+ Sync->>Tx: synchronize
+ end
+```
+
+Component detail: [accounts](./accounts.md) · [transactions](./transaction.md) · [assets](./assets.md)
+
+## Skip synchronization / delay synchronization
+
+`SynchronizeService` uses a mutex so only **one exclusive sync** runs at a time:
+
+| Overlapping request | Behavior |
+| ------------------------------------------ | ------------------------------------------------------------------------------------------------- |
+| Same accounts already in the current run | **Skip** (common during onboarding) |
+| Other accounts (e.g. after account switch) | **Delay** — schedule `synchronizeAccounts` background event (~2s) instead of waiting on the mutex |
+
+This avoids Snap request timeouts when syncs overlap.
+
+```mermaid
+sequenceDiagram
+ participant A as Sync request A
+ participant B as Sync request B
+ participant Sync as SynchronizeService
+ participant Cron as delayed synchronizeAccounts
+
+ A->>Sync: synchronize(accounts A)
+ Note over Sync: mutex held
+ B->>Sync: synchronize(accounts B)
+ alt B accounts already in A's run
+ Sync-->>B: skip
+ else B has other accounts
+ Sync->>Cron: schedule (~2s)
+ Note over Sync: mutex released later
+ Cron->>Sync: synchronize(accounts B)
+ end
+```
+
+## Related
+
+| Use case | Doc |
+| ------------------- | ------------------------------------------------------------------- |
+| Cron gate | [cronjob.md](../../use-cases/cron-job/cronjob.md) |
+| Sync accounts entry | [syncAccounts.md](../../use-cases/cron-job/syncAccounts.md) |
+| Sync assets entry | [syncAssets.md](../../use-cases/cron-job/syncAssets.md) |
+| Track submitted tx | [trackTransaction.md](../../use-cases/cron-job/trackTransaction.md) |
diff --git a/packages/stellar-wallet-snap/docs/misc/synchronization/transaction.md b/packages/stellar-wallet-snap/docs/misc/synchronization/transaction.md
new file mode 100644
index 000000000..45868f302
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/synchronization/transaction.md
@@ -0,0 +1,106 @@
+# Synchronization: transactions
+
+Maps [Horizon](https://developers.stellar.org/docs/data/apis/horizon/api-reference/resources/transactions) history to keyring transactions and reconciles snap-state pending txs.
+
+| | |
+| -------------- | ----------------------------------------------------------------------------------------------------- |
+| **Service** | [`TransactionSynchronizeService`](../../../src/services/transaction/TransactionSynchronizeService.ts) |
+| **Mapper** | [`TransactionMapper`](../../../src/services/transaction/TransactionMapper.ts) |
+| **Snap state** | [`TransactionRepository`](../../../src/services/transaction/TransactionRepository.ts) |
+| **Overview** | [synchronization.md](./synchronization.md) |
+
+## Participants
+
+| Component | Path | Role |
+| ------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
+| `TransactionSynchronizeService` | `services/transaction` | Scan, map, reconcile, emit |
+| `TransactionMapper` | `services/transaction` | On-chain tx → keyring tx |
+| `KeyringTransactionBuilder` | `services/transaction` | Build keyring tx shapes |
+| `TransactionRepository` | `services/transaction` | Pending txs + scan cursors |
+| `NetworkService` | `services/network` | [Horizon](https://developers.stellar.org/docs/data/apis/horizon/api-reference/resources/transactions) fetch by account / hash |
+
+## Step-by-step
+
+1. **Create context** — load pending txs from snap state, last-scan cursors, all snap-managed accounts on scope (for SEP-41 receive), SEP-41 metadata map.
+2. **Scan** — paginated [account transactions](https://developers.stellar.org/docs/data/apis/horizon/api-reference/get-transactions-by-account-id) per **activated** account; map each tx; apply SEP-41 synthetic receive when eligible.
+3. **Reconcile pending** — for remaining pending hashes, [fetch by hash](https://developers.stellar.org/docs/data/apis/horizon/api-reference/retrieve-a-transaction); map when found; increment reconcile attempt on 404.
+4. **Save & emit** — emit `AccountTransactionsUpdated`, then persist mapped txs + remaining pending + updated cursors.
+
+First scan for an account uses **DESC** (newest first). Incremental scans use **ASC** from the saved cursor.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Sync as TransactionSynchronizeService
+ participant Horizon as Horizon API
+ participant Mapper as TransactionMapper
+ participant State as TransactionRepository
+ participant MM as MetaMask controller
+
+ Sync->>State: load pending + cursors
+ loop per activated account
+ Sync->>Horizon: GET /accounts/:id/transactions
+ Horizon-->>Sync: on-chain txs
+ Sync->>Mapper: mapTransactionSafe
+ Mapper-->>Sync: keyring tx (or skip)
+ end
+ loop remaining pending
+ Sync->>Horizon: GET /transactions/:hash
+ alt found
+ Sync->>Mapper: map with pending state
+ else 404
+ Sync->>State: increment reconcileAttemptCount
+ end
+ end
+ Sync->>MM: AccountTransactionsUpdated
+ Sync->>State: save pending + cursors
+```
+
+## Transaction mapping
+
+### How we decide what type of activity it is
+
+| Activity type | When we map it as this | Extra mapping conditions |
+| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Send | I am the sender, and the transaction only contains payment or create-account operations. | Send takes priority over swap. If there are multiple operations, we only show the first payment or create-account (recipient, asset, amount). |
+| Token send (SEP-41) | I am the sender, and it is a supported SEP-41 token we recognize. | Unsupported tokens may fall back to unknown. |
+| Swap | I am the sender, the transaction matches our swap pattern, and it includes a path payment that credits back to my own account. | Self-swap is not a receive. If there are multiple path payment operations, we only use the first one for from/to assets and amounts. |
+| Receive | At least one operation credits my account (payment, account creation, or swap). | Self-send / self-swap are not receives. Failed receives are hidden. Dust spam is hidden (very small incoming native XLM <= 0.001 from someone else). If multiple assets are credited, we show the first unique asset only (amounts are not summed). |
+| Token trust (add) | I am the sender, and every operation is adding trust for a token. | If there are multiple change-trust operations, we only show the first token. |
+| Token trust (remove) | I am the sender, and every operation is removing trust for a token. | If there are multiple change-trust operations, we only show the first token. |
+| Unknown | The transaction does not match any rule above, or mapping fails. | We still show it as activity rather than hiding it. |
+
+Notes:
+General rule for multi-operation transactions:
+
+one on-chain transaction = one history entry.
+
+We do not split multiple sends, swaps, or receives in the same transaction into separate rows.
+
+### Fee handling (Only for transactions that made from MetaMask)
+
+| Activity type | Fee while pending | When settled (confirmed / failed) |
+| -------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------- |
+| Send | No fee shown yet. | We read the actual network fee from the settled transaction and show it in XLM. |
+| Token trust (add / remove) | No fee shown yet. | Same as send - actual network fee in XLM is shown after settlement. |
+| Swap | Estimated fee from the signed transaction. | Fee is replaced with the actual network fee from the settled transaction. |
+| Bridge send | Estimated fee from the signed transaction. | Fee is replaced with the actual network fee from the settled transaction. |
+
+### Swap amounts (Only for transactions that made from MetaMask)
+
+| Activity type | Amounts while pending | When settled (confirmed / failed) |
+| ----------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
+| Swap | Estimated amounts from the signed transaction, not the final executed amounts yet. | We re-read actual executed amounts from the on-chain result and update the from and to legs. |
+| Contract-based swap | Amounts shown as `0` - final amounts not known yet. | We try to re-map from on-chain data. If that fails, we keep the pending amounts (still `0`) as best effort. |
+| Cross-chain bridge send | No from/to amounts in the snap. | Handled from transaction history when available. |
+
+## Related
+
+- [Horizon — Transactions](https://developers.stellar.org/docs/data/apis/horizon/api-reference/resources/transactions)
+- [Horizon — Account's Transactions](https://developers.stellar.org/docs/data/apis/horizon/api-reference/get-transactions-by-account-id)
+- [Horizon — Retrieve a Transaction](https://developers.stellar.org/docs/data/apis/horizon/api-reference/retrieve-a-transaction)
+- [Horizon — Pagination](https://developers.stellar.org/docs/data/apis/horizon/api-reference/structure/pagination/page-arguments)
+- [syncAccounts.md](../../use-cases/cron-job/syncAccounts.md) — cron entry
+- [trackTransaction.md](../../use-cases/cron-job/trackTransaction.md) — post-submit poll
+- [keyring.md](../../use-cases/keyring/keyring.md) — `listAccountTransactions` = snap pending only
diff --git a/packages/stellar-wallet-snap/docs/misc/transaction/send-classic-trustline.md b/packages/stellar-wallet-snap/docs/misc/transaction/send-classic-trustline.md
new file mode 100644
index 000000000..0bd1afed2
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/transaction/send-classic-trustline.md
@@ -0,0 +1,61 @@
+# Send classic trustline asset
+
+Payment of a **classic issued asset** (CAIP-19 classic, non-native). Destination must already hold / be able to receive the asset — the Snap does **not** create the destination account for non-native assets.
+
+| | |
+| ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| **Service** | `TransactionService.createValidatedSendTransaction` → `#createValidatedClassicAssetTransfer` |
+| **Builder** | `TransactionBuilder.transfer` → `#send` (`Operation.payment`) |
+| **Client** | [`onAmountInput`](../../use-cases/client-request/onAmountInput.md), [`confirmSend`](../../use-cases/client-request/confirmSend.md) |
+| **Submit** | [Submit & bad-sequence retry](./submit-sequence-retry.md) |
+
+## Build
+
+1. Load destination account from the network.
+2. If destination is **not** activated → `AccountNotActivatedException` (classic non-native cannot use `createAccount`).
+3. Fetch base inclusion fee.
+4. `TransactionBuilder.transfer` with `isActivated: true`:
+ - Normalize amount to human-readable Stellar units (`normalizeAmount`).
+ - `#send` → single `Operation.payment` with `caip19ToStellarAsset(assetId)`.
+5. Source sequence / account id from `OnChainAccount`.
+
+Trustline existence / limits on sender and receiver are enforced in **validate**, not by adding a `changeTrust` op on this path (opt-in/out is [`changeTrustOpt`](../../use-cases/client-request/changeTrustOpt.md)).
+
+### Cache
+
+**Send / submit (`confirmSend`) does not use cache** (`useCache: false`). Destination load is always fresh so the envelope is safe to sign.
+
+**Preflight only (`onAmountInput`)** passes `useCache: true` when building the validated send for amount checks. See [onAmountInput cache note](../../use-cases/client-request/onAmountInput.md#note-cache-usage).
+
+## Validate
+
+Local checks against the sender (and destination when known):
+
+- Sender has enough of the classic asset to send.
+- Sender and destination trustlines allow the transfer (limit / authorization).
+- Sender can cover the network fee in XLM.
+
+## Send
+
+1. `Wallet.signTransaction`.
+2. `TransactionService.sendTransaction` — classic envelopes **can** use one automatic `txBadSeq` rebuild + re-sign when the tx source is this wallet account. See [submit-sequence-retry](./submit-sequence-retry.md).
+
+## Flow
+
+```mermaid
+sequenceDiagram
+ participant Handler
+ participant Tx as TransactionService
+ participant Builder as TransactionBuilder
+ participant Sim as TransactionSimulator
+ participant Wallet
+
+ Handler->>Tx: createValidatedSendTransaction (classic)
+ Tx->>Tx: load destination (must be activated)
+ Tx->>Builder: transfer → payment
+ Builder-->>Tx: unsigned payment
+ Tx->>Sim: validate (balance, trustline, fee)
+ Note over Handler: confirmSend only ↓
+ Handler->>Wallet: signTransaction
+ Handler->>Tx: sendTransaction
+```
diff --git a/packages/stellar-wallet-snap/docs/misc/transaction/send-native.md b/packages/stellar-wallet-snap/docs/misc/transaction/send-native.md
new file mode 100644
index 000000000..f141343ef
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/transaction/send-native.md
@@ -0,0 +1,78 @@
+# Send native XLM
+
+Native asset (slip44) send has two use cases, chosen by whether the destination is already funded on-chain.
+
+| | |
+| ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| **Service** | `TransactionService.createValidatedSendTransaction` → `#createValidatedClassicAssetTransfer` |
+| **Builder** | `TransactionBuilder.transfer` → `#send` or `#createAccount` |
+| **Client** | [`onAmountInput`](../../use-cases/client-request/onAmountInput.md), [`confirmSend`](../../use-cases/client-request/confirmSend.md) |
+| **Submit** | [Submit & bad-sequence retry](./submit-sequence-retry.md) |
+
+Only **native / slip44** can fund a new account. Classic / SEP-41 sends to an unactivated destination fail earlier (`AccountNotActivatedException` / `InvalidAssetForCreateAccountException`).
+
+## Cache
+
+**Send / submit (`confirmSend`) does not use cache** (`useCache: false`). Destination load is always fresh so the envelope is safe to sign.
+
+**Preflight only (`onAmountInput`)** passes `useCache: true` when building the validated send for amount checks. See [onAmountInput cache note](../../use-cases/client-request/onAmountInput.md#note-cache-usage).
+
+---
+
+## Use case A — destination is activated
+
+Send XLM to an account that already exists on the network.
+
+### Build
+
+1. Load destination → activated (`destinationAccount !== null`).
+2. Fetch base inclusion fee.
+3. `TransactionBuilder.transfer` → `#send` → single `Operation.payment` (native asset).
+4. Amount is normalized to human-readable Stellar units; sequence from sender `OnChainAccount`.
+
+### Validate
+
+Checks spendable native balance (after reserves) and that the sender can cover the payment plus network fee.
+
+### Send
+
+Sign → `sendTransaction` ([submit-sequence-retry](./submit-sequence-retry.md)).
+
+---
+
+## Use case B — destination is not activated
+
+Fund a new Stellar account by sending native XLM. The Snap builds a **`createAccount`** op instead of `payment`.
+
+### Build
+
+1. Load destination → not activated (`destinationAccount === null`).
+2. Fetch base inclusion fee.
+3. `TransactionBuilder.transfer` → `#createAccount` → `Operation.createAccount({ destination, startingBalance })`.
+4. **`startingBalance` = the send amount** (same value the user entered / confirmed). There is no separate “funding” field.
+
+### Validate
+
+- **`startingBalance` must be ≥ 1 XLM** (minimum when not sponsoring).
+- Sender must have enough spendable native to cover that starting balance plus fee.
+
+### Send
+
+Sign → `sendTransaction` ([submit-sequence-retry](./submit-sequence-retry.md)).
+
+---
+
+## Flow
+
+```mermaid
+flowchart TD
+ Start[Native send] --> Dest{Destination activated?}
+
+ Dest -->|yes — use case A| A1[Build: payment]
+ A1 --> A2[Validate: spendable XLM + fee]
+ A2 --> Sign[sign + send]
+
+ Dest -->|no — use case B| B1[Build: createAccount
startingBalance = send amount]
+ B1 --> B2[Validate: startingBalance ≥ 1 XLM
+ spendable cover]
+ B2 --> Sign
+```
diff --git a/packages/stellar-wallet-snap/docs/misc/transaction/send-sep41.md b/packages/stellar-wallet-snap/docs/misc/transaction/send-sep41.md
new file mode 100644
index 000000000..f00418f46
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/transaction/send-sep41.md
@@ -0,0 +1,64 @@
+# Send SEP-41
+
+Soroban contract token transfer (`SEP-41` CAIP-19 asset → `invokeHostFunction` calling `transfer`).
+
+| | |
+| ----------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| **Service** | `TransactionService.createValidatedSendTransaction` → `#createValidatedSep41Transfer` |
+| **Builder** | `TransactionBuilder.sep41Transfer` |
+| **Client** | [`onAmountInput`](../../use-cases/client-request/onAmountInput.md), [`confirmSend`](../../use-cases/client-request/confirmSend.md) |
+| **Submit** | [Submit & bad-sequence retry](./submit-sequence-retry.md) |
+
+## Build
+
+1. Destination must already be **activated**; otherwise `AccountNotActivatedException` (no `createAccount` for SEP-41).
+2. Fetch base inclusion fee.
+3. `TransactionBuilder.sep41Transfer`:
+ - Parse contract id from CAIP-19 asset reference.
+ - Build one `invokeHostFunction` op: `transfer(from, to, amount)` with amount in token **smallest units** (i128) — no classic decimal normalize.
+ - Source account + sequence come from the resolved `OnChainAccount`.
+4. If the asset row is missing from the on-chain snapshot (`getRawAsset`), fetch SEP-41 balances from the network and attach a local balance.
+5. Fail early if local balance < amount (`InsufficientBalanceException`).
+6. Network simulation attaches Soroban resource fee / footprint (`sorobanData`).
+
+### Cache
+
+**Send / submit paths (`confirmSend`) never use cache** (`useCache: false`). Destination load and SEP-41 simulation are always fresh so the envelope is safe to sign.
+
+**Preflight only (`onAmountInput`)** passes `useCache: true` so repeated amount checks stay responsive (SEP-41 sim keyed by asset + sender + recipient + scope, not amount). That result must not be signed. See [onAmountInput cache note](../../use-cases/client-request/onAmountInput.md#note-cache-usage).
+
+## Validate
+
+Local checks after network simulation has attached the Soroban resource fee:
+
+- Sender has enough of the SEP-41 token balance.
+- Sender can cover inclusion + resource fees in XLM.
+- Envelope is a single contract `transfer` invoke with a consistent source/sender.
+
+## Send
+
+1. `Wallet.signTransaction`.
+2. `TransactionService.sendTransaction` — see [submit-sequence-retry](./submit-sequence-retry.md).
+3. Sequence-only rebuild does **not** safely preserve Soroban `sorobanData`; on `txBadSeq` for invoke envelopes the caller should re-simulate / rebuild rather than relying on a blind sequence bump.
+
+## Flow
+
+```mermaid
+sequenceDiagram
+ participant Handler
+ participant Tx as TransactionService
+ participant Builder as TransactionBuilder
+ participant Net as NetworkService
+ participant Sim as TransactionSimulator
+ participant Wallet
+
+ Handler->>Tx: createValidatedSendTransaction (SEP-41)
+ Tx->>Builder: sep41Transfer
+ Builder-->>Tx: unsigned invokeHostFunction
+ Tx->>Net: simulate (fresh for confirmSend)
+ Net-->>Tx: assembled envelope (+ resource fee)
+ Tx->>Sim: validate (balance + fees)
+ Note over Handler: confirmSend only ↓
+ Handler->>Wallet: signTransaction
+ Handler->>Tx: sendTransaction
+```
diff --git a/packages/stellar-wallet-snap/docs/misc/transaction/send-swap.md b/packages/stellar-wallet-snap/docs/misc/transaction/send-swap.md
new file mode 100644
index 000000000..b7eda37a6
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/transaction/send-swap.md
@@ -0,0 +1,78 @@
+# Send swap / bridge (from XDR)
+
+Swap and bridge envelopes are **not** built by `TransactionBuilder` inside the Snap. MetaMask CrossChain API supplies Base64 XDR; the Snap decodes, checks the accepted op shape, validates, then (for submit) signs and sends.
+
+| | |
+| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Service** | `TransactionService.createValidatedSwapTransaction` |
+| **Decode** | `Transaction.fromXdr` |
+| **Shape gate** | `SwapTransactionXdrStruct` ([`api/xdr.ts`](../../../src/api/xdr.ts)) |
+| **Client** | [`computeFee`](../../use-cases/client-request/computeFee.md), [`signAndSendTransaction`](../../use-cases/client-request/signAndSendTransaction.md) |
+| **Submit** | [Submit & bad-sequence retry](./submit-sequence-retry.md) |
+
+## Accepted operation patterns from XDR
+
+`SwapTransactionXdrStruct` only checks **operation kind + order** (not balances / memos). Downstream service + simulator do the rest.
+
+| Ops (in order) | Meaning |
+| -------------------------------------- | ---------------------------------------------------------------------------------------- |
+| `[invokeHostFunction]` | Soroban swap (single contract invoke) |
+| `[payment]` | Bridge deposit (single payment to deposit account) **or** swap without a separate fee op |
+| `[pathPayment*]` | Classic swap without a trailing fee payment |
+| `[pathPayment*, payment]` | Classic swap + route fee payment |
+| `[changeTrust, pathPayment*]` | Trustline setup then swap (no fee op) |
+| `[payment, payment]` | Bridge: deposit payment + fee wallet payment |
+| `[changeTrust, pathPayment*, payment]` | Trustline + classic swap + fee payment |
+
+`pathPayment*` = `pathPaymentStrictSend` or `pathPaymentStrictReceive`.
+
+Anything else → rejected at the JSON-RPC struct (`Unsupported swap transaction operation shape`).
+
+## Build / decode
+
+1. Client passes the **same** XDR used for `computeFee` into `signAndSendTransaction`.
+2. `Transaction.fromXdr({ xdr, scope })`.
+3. `computingFee(transaction)`:
+ - If envelope has `invokeHostFunction` → `NetworkService.simulateTransaction` (fresh Soroban assemble / resource fee).
+ - Else → keep fee already on the envelope (Bridge / classic quote trusted).
+4. Preload participating accounts from the network (skipped for invoke-only envelopes).
+
+## Validate
+
+Local checks on the decoded envelope (balances, trustlines, fees) for whichever ops are present — e.g. path-payment amounts, trailing fee payment, leading change-trust, or Soroban invoke after simulation.
+
+## Send
+
+Only `signAndSendTransaction`:
+
+1. `Wallet.signTransaction` (user consent is **client-side** — Snap shows no confirmation).
+2. `sendTransaction` — see [submit-sequence-retry](./submit-sequence-retry.md).
+3. Persist pending keyring tx as `Swap` (same-chain) or `BridgeSend` (cross-chain) from `options.sourceAssetId` / `destAssetId`.
+
+## Flow
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Fee as ComputeFeeHandler
+ participant Sign as SignAndSendTransactionHandler
+ participant Tx as TransactionService
+ participant Net as NetworkService
+ participant Wallet
+
+ Client->>Fee: computeFee { xdr, scope }
+ Fee->>Tx: createValidatedSwapTransaction
+ Tx->>Tx: fromXdr + computingFee
+ opt Soroban invoke
+ Tx->>Net: simulateTransaction
+ end
+ Tx->>Tx: validate (balances / trustlines / fees)
+ Fee-->>Client: fee entries
+
+ Note over Client: User approves in client UI
+ Client->>Sign: signAndSendTransaction { same xdr, scope, options }
+ Sign->>Tx: createValidatedSwapTransaction
+ Sign->>Wallet: signTransaction
+ Sign->>Tx: sendTransaction
+ Sign-->>Client: { transactionId }
+```
diff --git a/packages/stellar-wallet-snap/docs/misc/transaction/submit-sequence-retry.md b/packages/stellar-wallet-snap/docs/misc/transaction/submit-sequence-retry.md
new file mode 100644
index 000000000..e2fb74c7d
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/misc/transaction/submit-sequence-retry.md
@@ -0,0 +1,80 @@
+# Submit & bad-sequence retry (`txBadSeq`)
+
+Shared on-chain **submit** path used after any flow has built (or decoded), validated, and signed an envelope. This doc is only about submission and recovering when the account **sequence is wrong or too old**.
+
+Suggested name vs “general on-chain send”: prefer **submit / sequence retry** — it is not a payment-type chooser; it is the last mile of every successful submit.
+
+| | |
+| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Service** | `TransactionService.sendTransaction` |
+| **Network** | `NetworkService.send` |
+| **Rebuild** | `TransactionBuilder.rebuildTxnWithNewSeq` |
+| **Used by** | [`confirmSend`](../../use-cases/client-request/confirmSend.md), [`changeTrustOpt`](../../use-cases/client-request/changeTrustOpt.md), [`signAndSendTransaction`](../../use-cases/client-request/signAndSendTransaction.md), … |
+
+## Happy path
+
+```text
+assert scope matches envelope
+ → NetworkService.send(signed tx)
+ → optional poll for terminal SUCCESS
+ → return transaction hash
+```
+
+## When sequence is stale (`txBadSeq`)
+
+Stellar rejects the submit with `txBadSeq` when the envelope’s sequence does not match the source account’s current sequence (concurrent txs, race after a long confirmation dialog, etc.).
+
+`NetworkService.send` maps that RPC error to `TransactionRetryableException`.
+
+`TransactionService.sendTransaction` then:
+
+1. Checks the envelope **source** equals the resolved `onChainAccount.accountId` (this wallet consumes the sequence).
+ - If source is **another** account → rethrow (cannot bump someone else’s sequence).
+2. Reloads the account from the network (`getAccount`) for a fresh `sequenceNumber`.
+3. `rebuildTxnWithNewSeq` — clone ops / fee / timebounds onto a new envelope with the new sequence.
+4. `wallet.signTransaction` again.
+5. Submit **once** more.
+
+Only **one** automatic retry.
+
+## Soroban / `invokeHostFunction` caveat
+
+Sequence-only rebuild copies classic-style fields and operations; it does **not** correctly preserve assembled Soroban `sorobanData`. JSDoc on `sendTransaction` states that for invoke envelopes, `txBadSeq` should not be treated as a safe auto-retry — the caller should **re-simulate / re-assemble** (e.g. fresh quote or fresh SEP-41 sim) instead of relying on a blind sequence bump.
+
+## Flow
+
+```mermaid
+sequenceDiagram
+ participant Handler
+ participant Tx as TransactionService
+ participant Net as NetworkService
+ participant Builder as TransactionBuilder
+ participant Wallet
+
+ Handler->>Wallet: signTransaction (initial)
+ Handler->>Tx: sendTransaction
+ Tx->>Net: send
+ alt SUCCESS
+ Net-->>Tx: hash
+ Tx-->>Handler: transactionId
+ else txBadSeq (retryable)
+ Net-->>Tx: TransactionRetryableException
+ alt source === wallet account
+ Tx->>Net: getAccount (fresh sequence)
+ Tx->>Builder: rebuildTxnWithNewSeq
+ Tx->>Wallet: signTransaction
+ Tx->>Net: send (retry once)
+ Net-->>Tx: hash
+ Tx-->>Handler: transactionId
+ else source is another account
+ Tx-->>Handler: rethrow
+ end
+ end
+```
+
+## After submit (callers)
+
+Handlers typically then:
+
+- `savePendingKeyringTransactionSafe`
+- `TrackTransactionHandler.scheduleBackgroundEvent`
diff --git a/packages/stellar-wallet-snap/docs/use-cases/README.md b/packages/stellar-wallet-snap/docs/use-cases/README.md
new file mode 100644
index 000000000..ad094cda4
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/README.md
@@ -0,0 +1,60 @@
+# Use cases
+
+High-level flows for the Stellar Wallet Snap. Each doc focuses on **handlers**, **services**, and **UI** involved in a use case — utility modules are omitted.
+
+## Client request (`onClientRequest`)
+
+| Use case | Entry method | Doc |
+| ----------------------------------- | ------------------------ | ----------------------------------------------------------------------- |
+| Validate send destination | `onAddressInput` | [onAddressInput.md](./client-request/onAddressInput.md) |
+| Preflight send amount | `onAmountInput` | [onAmountInput.md](./client-request/onAmountInput.md) |
+| Confirm & submit send | `confirmSend` | [confirmSend.md](./client-request/confirmSend.md) |
+| Quote swap / bridge fee | `computeFee` | [computeFee.md](./client-request/computeFee.md) |
+| Sign & submit swap / bridge | `signAndSendTransaction` | [signAndSendTransaction.md](./client-request/signAndSendTransaction.md) |
+| Change trustline (opt-in / opt-out) | `changeTrustOpt` | [changeTrustOpt.md](./client-request/changeTrustOpt.md) |
+
+## Cronjob (`onCronjob`)
+
+All methods are no-ops when MetaMask is inactive or the wallet is **locked** — see [cronjob.md](./cron-job/cronjob.md).
+
+| Use case | Entry method | Doc |
+| --------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
+| Cron gate (locked / inactive) | `CronjobHandler` | [cronjob.md](./cron-job/cronjob.md) |
+| Sync overview (accounts + txs + assets) | `SynchronizeService` | [synchronization.md](../misc/synchronization/synchronization.md) |
+| Track submitted transaction | `trackTransaction` | [trackTransaction.md](./cron-job/trackTransaction.md) · [transaction sync](./../misc/synchronization/transaction.md) |
+| Sync selected / listed accounts | `synchronizeAccounts` | [syncAccounts.md](./cron-job/syncAccounts.md) · [accounts sync](./../misc/synchronization/accounts.md) |
+| Sync asset metadata catalog | `synchronizeAssets` | [syncAssets.md](./cron-job/syncAssets.md) · [assets sync](./../misc/synchronization/assets.md) |
+| Refresh open confirmation | `refreshConfirmationContext` | [refreshConfirmationContext.md](./cron-job/refreshConfirmationContext.md) |
+
+## Keyring (`onKeyringRequest`)
+
+Account management is summarized in one place; SEP-43 signing methods have their own docs.
+
+| Use case | Entry method | Doc |
+| ---------------------------------------- | ----------------- | -------------------------------------------------- |
+| Keyring overview (accounts, balances, …) | `KeyringHandler` | [keyring.md](./keyring/keyring.md) |
+| Sign transaction (no broadcast) | `signTransaction` | [signTransaction.md](./keyring/signTransaction.md) |
+| Sign message | `signMessage` | [signMessage.md](./keyring/signMessage.md) |
+| Sign Soroban auth entry | `signAuthEntry` | [signAuthEntry.md](./keyring/signAuthEntry.md) |
+
+## Assets (`endowment:assets`)
+
+| Use case | Entry method | Doc |
+| ----------------------------------- | --------------- | ------------------------------- |
+| Assets overview (lookup, prices, …) | `AssetsHandler` | [assets.md](./assets/assets.md) |
+
+## User input (`onUserInput`)
+
+| Use case | Entry method | Doc |
+| ---------------------------- | ------------------ | ----------------------------------------- |
+| Interactive UI event routing | `UserInputHandler` | [userInput.md](./user-input/userInput.md) |
+
+## Synchronization
+
+Background sync flow and components: [synchronization.md](../misc/synchronization/synchronization.md).
+
+| Component | Doc |
+| -------------------------------- | -------------------------------------------------------- |
+| Accounts (balances / trustlines) | [accounts.md](../misc/synchronization/accounts.md) |
+| Transactions (history / pending) | [transaction.md](../misc/synchronization/transaction.md) |
+| Asset catalog | [assets.md](../misc/synchronization/assets.md) |
diff --git a/packages/stellar-wallet-snap/docs/use-cases/assets/assets.md b/packages/stellar-wallet-snap/docs/use-cases/assets/assets.md
new file mode 100644
index 000000000..1ba144705
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/assets/assets.md
@@ -0,0 +1,33 @@
+# Use case: assets (`AssetsHandler`)
+
+Asset metadata and price entry points via Snap Assets API handlers → `AssetsHandler`.
+
+| | |
+| ---------- | ----------------------------------------------------------------------------------------------------------- |
+| **Entry** | `onAssetsLookup` / `onAssetsConversion` / `onAssetsMarketData` / `onAssetHistoricalPrice` → `AssetsHandler` |
+| **Source** | [`handlers/asset/assets.ts`](../../../src/handlers/asset/assets.ts) |
+
+## Participants
+
+| Component | Path | Role |
+| ---------------------- | ------------------------- | ------------------------------------------- |
+| `AssetsHandler` | `handlers/asset` | Assets API surface |
+| `AssetMetadataService` | `services/asset-metadata` | Resolve CAIP-19 asset metadata |
+| `PriceService` | `services/price` | Conversions, market data, historical prices |
+
+## Request / response
+
+Asset methods follow the MetaMask **Snap Assets API** ([SIP-29](https://metamask.github.io/SIPs/SIPS/sip-29)):
+
+- [Entry points](https://docs.metamask.io/snaps/reference/entry-points/) (`onAssetsLookup`, `onAssetsConversion`, `onAssetsMarketData`, `onAssetHistoricalPrice`)
+
+This Snap implements those handlers in `index.ts` and delegates to `AssetsHandler`. Lookup is restricted to Stellar asset ids.
+
+## Methods
+
+| Method | What it does | Data source |
+| ------------------------ | --------------------------------------------------- | -------------------------------------------------------------------------------- |
+| `onAssetsLookup` | Metadata for requested CAIP-19 asset ids | **Snap state** catalog via `AssetMetadataService` (fetch + persist when missing) |
+| `onAssetsConversion` | Conversion rates for requested asset pairs | **Price API** via `PriceService` (cached) |
+| `onAssetsMarketData` | Market data for requested assets | **Price API** via `PriceService` (cached) |
+| `onAssetHistoricalPrice` | Historical price intervals for a `from` → `to` pair | **Price API** via `PriceService` (cached) |
diff --git a/packages/stellar-wallet-snap/docs/use-cases/client-request/changeTrustOpt.md b/packages/stellar-wallet-snap/docs/use-cases/client-request/changeTrustOpt.md
new file mode 100644
index 000000000..f43277fe8
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/client-request/changeTrustOpt.md
@@ -0,0 +1,100 @@
+# Use case: `changeTrustOpt`
+
+Add or remove a classic Stellar trustline for an asset on a managed account.
+
+| | |
+| ----------- | --------------------------------------------------------------------------------------------------- |
+| **Entry** | `onClientRequest` → `ClientRequestHandler` → `ChangeTrustOptHandler` |
+| **Method** | `changeTrustOpt` (`ClientRequestMethod.ChangeTrustOpt`) |
+| **Actions** | `add` (opt-in) · `delete` (opt-out, limit forced to `0`) |
+| **Source** | [`handlers/clientRequest/changeTrustOpt.ts`](../../../src/handlers/clientRequest/changeTrustOpt.ts) |
+
+## Request / response (shape)
+
+**Request params**
+
+- `accountId` — keyring account UUID
+- `assetId` — CAIP-19 classic asset
+- `scope` — CAIP-2 chain ID
+- `action` — `"add"` `"delete"`
+- `limit` — optional; only for `"add"` (nonzero Stellar amount)
+
+**Response**
+
+- `{ status: true, transactionId }` — built, confirmed, signed, and submitted
+- `{ status: true }` — opt-in already satisfied (trustline exists with limit > 0), or became redundant while the dialog was open
+- `{ status: false }` — account not activated (funding prompt shown; not an RPC error)
+
+User rejection of the confirmation dialog throws `UserRejectedRequestError`.
+
+## Participants
+
+| Component | Path | Role in this flow |
+| ----------------------------------- | --------------------------- | -------------------------------------------------------------------- |
+| `ClientRequestHandler` | `handlers/clientRequest` | Routes `changeTrustOpt` to the handler |
+| `ChangeTrustOptHandler` | `handlers/clientRequest` | Orchestrates the use case |
+| `AccountResolver` | `handlers/` | Loads keyring account + wallet + **live** on-chain account (network) |
+| `AccountService` | `services/account` | Keyring account lookup (via resolver) |
+| `WalletService` / `Wallet` | `services/wallet` | Signing key material + `signTransaction` |
+| `OnChainAccountService` | `services/on-chain-account` | Fetch fresh on-chain balances / trustlines |
+| `AssetMetadataService` | `services/asset-metadata` | Resolve symbol / metadata for UI |
+| `TransactionService` | `services/transaction` | Build + validate change-trust tx; submit; save pending keyring tx |
+| `NetworkService` | `services/network` | Base fee (via `TransactionService`) |
+| `ConfirmationUXController` | `ui/confirmation` | Opt-in / opt-out confirmation dialog |
+| `TransactionScanService` | `services/transaction-scan` | Security scan while dialog is open |
+| `RefreshConfirmationContextHandler` | `handlers/cronjob` | Re-validate tx / fees while dialog is open |
+| `TrackTransactionHandler` | `handlers/cronjob` | Schedule background status tracking after submit |
+
+## Step-by-step
+
+1. **Route** — `onClientRequest` dispatches to `ChangeTrustOptHandler`.
+2. **Resolve** — `AccountResolver` loads keyring account, wallet, and activated on-chain account from the **live network**. Unfunded accounts show the activation prompt and return `{ status: false }`.
+3. **Short-circuit** — If `add` and a trustline with limit > 0 already exists → `{ status: true }`. If `delete` and no trustline → `TrustlineNotFoundException`.
+4. **Build** — Resolve asset metadata; `TransactionService.createValidatedChangeTrustTransaction` builds a change-trust op (`delete` forces limit `"0"`).
+5. **Confirm** — `ConfirmationUXController` shows opt-in or opt-out UI (fee, security scan, local re-validation cron while open).
+6. **Refresh** — After confirm, account is resolved again from the live network; fee must not exceed what the user approved; redundant opt-in returns `{ status: true }` without submit.
+7. **Sign & send** — `Wallet.signTransaction` → `TransactionService.sendTransaction`.
+8. **Post-submit** — Persist pending keyring tx (`ChangeTrustOptIn` / `ChangeTrustOptOut`) and schedule `TrackTransactionHandler`.
+
+## Sequence (happy path)
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Handler as ChangeTrustOptHandler
+ participant Resolver as AccountResolver
+ participant Meta as AssetMetadataService
+ participant Tx as TransactionService
+ participant UI as ConfirmationUXController
+ participant Refresh as RefreshConfirmationContextHandler
+ participant Scan as TransactionScanService
+ participant Wallet
+ participant Track as TrackTransactionHandler
+
+ Client->>Handler: changeTrustOpt (add | delete)
+ Handler->>Resolver: resolve activated account (live on-chain)
+ Resolver-->>Handler: account, wallet, onChainAccount
+ Handler->>Handler: trustline needed?
+ Handler->>Meta: resolve(assetId)
+ Handler->>Tx: createValidatedChangeTrustTransaction
+ Tx-->>Handler: Transaction
+ Handler->>UI: renderConfirmationDialog
+ UI->>Refresh: schedule background refresh
+
+ loop While dialog open (until Client confirms / rejects)
+ Refresh->>Resolver: resolve on-chain account (live balances / trustlines)
+ Refresh->>Tx: rebuild & re-validate change-trust tx
+ Refresh->>Scan: security scan (refreshed envelope)
+ Refresh->>UI: update confirmation context
+ end
+
+ Client-->>UI: confirm
+ UI-->>Handler: confirmed
+ Handler->>Resolver: resolve again (live on-chain)
+ Handler->>Tx: createValidatedChangeTrustTransaction
+ Handler->>Wallet: signTransaction
+ Handler->>Tx: sendTransaction
+ Handler->>Tx: savePendingKeyringTransactionSafe
+ Handler->>Track: scheduleBackgroundEvent
+ Handler-->>Client: { status: true, transactionId }
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/client-request/computeFee.md b/packages/stellar-wallet-snap/docs/use-cases/client-request/computeFee.md
new file mode 100644
index 000000000..69a2ed9c1
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/client-request/computeFee.md
@@ -0,0 +1,68 @@
+# Use case: `computeFee`
+
+Quotes fees for a swap / bridge envelope from MetaMask CrossChain API (same validation path as `signAndSendTransaction`).
+
+| | |
+| ------------------------ | ------------------------------------------------------------------------------------------- |
+| **Entry** | `onClientRequest` → `ClientRequestHandler` → `ComputeFeeHandler` |
+| **Method** | `computeFee` (`ClientRequestMethod.ComputeFee`) |
+| **Source** | [`handlers/clientRequest/computeFee.ts`](../../../src/handlers/clientRequest/computeFee.ts) |
+| **Transaction pipeline** | [Swap / bridge from XDR](../../misc/transaction/send-swap.md) |
+
+## Client workflow
+
+1. After the user selects a quote, obtain the unsigned XDR from MetaMask CrossChain API.
+2. Call **`computeFee`** with that XDR and `scope` so the user can review fees.
+3. After approval in the client UI, call **`signAndSendTransaction`** with the **same** `transaction` XDR and `scope`.
+
+## Request / response (shape)
+
+**Request params**
+
+- `accountId` — keyring account UUID
+- `scope` — CAIP-2 chain ID
+- `transaction` — Base64-encoded swap / bridge XDR
+- `options` — optional (`visible`, `type`, `feeLimit`)
+
+**Response**
+
+- Array of fee entries: `[{ type: FeeType.Base, asset: { unit, type, amount, fungible } }]`
+- On insufficient native balance / fee coverage, still returns a fee entry using the **required** amount (so the client can surface the shortfall)
+
+No confirmation dialog; nothing is signed or submitted.
+
+## Participants
+
+| Component | Path | Role in this flow |
+| ----------------------- | --------------------------- | -------------------------------------------------------------------- |
+| `ClientRequestHandler` | `handlers/clientRequest` | Routes `computeFee` to the handler |
+| `ComputeFeeHandler` | `handlers/clientRequest` | Orchestrates fee quoting |
+| `AccountResolver` | `handlers/` | Loads keyring account + wallet + **live** on-chain account (network) |
+| `AccountService` | `services/account` | Keyring account lookup (via resolver) |
+| `OnChainAccountService` | `services/on-chain-account` | Balances for validation / simulation |
+| `TransactionService` | `services/transaction` | Decode, validate, simulate swap XDR; read `totalFee` |
+| `NetworkService` | `services/network` | Fees / simulation network reads (via `TransactionService`) |
+
+## Step-by-step
+
+1. **Route** — `onClientRequest` dispatches to `ComputeFeeHandler`.
+2. **Resolve** — `AccountResolver` loads keyring account, wallet, and activated on-chain account from the **live network**.
+3. **Validate** — `TransactionService.createValidatedSwapTransaction` (same path as sign-and-send, including Soroban simulation when needed).
+4. **Return** — Base fee as display amount in native XLM; map balance/fee shortfalls to a required-amount fee entry.
+
+## Sequence (happy path)
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Handler as ComputeFeeHandler
+ participant Resolver as AccountResolver
+ participant Tx as TransactionService
+
+ Client->>Handler: computeFee { accountId, scope, transaction }
+ Handler->>Resolver: resolve activated account (live on-chain)
+ Resolver-->>Handler: account, wallet, onChainAccount
+ Handler->>Tx: createValidatedSwapTransaction
+ Tx-->>Handler: Transaction (totalFee)
+ Handler-->>Client: [{ type: Base, asset: XLM fee }]
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/client-request/confirmSend.md b/packages/stellar-wallet-snap/docs/use-cases/client-request/confirmSend.md
new file mode 100644
index 000000000..26a1010a0
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/client-request/confirmSend.md
@@ -0,0 +1,96 @@
+# Use case: `confirmSend`
+
+Confirms and submits a send for Unified Non-EVM Send (live on-chain data at build and submit time).
+
+| | |
+| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Entry** | `onClientRequest` → `ClientRequestHandler` → `ConfirmSendHandler` |
+| **Method** | `confirmSend` (`ClientRequestMethod.ConfirmSend`) |
+| **Source** | [`handlers/clientRequest/confirmSend.ts`](../../../src/handlers/clientRequest/confirmSend.ts) |
+| **Transaction pipeline** | [SEP-41](../../misc/transaction/send-sep41.md) · [classic](../../misc/transaction/send-classic-trustline.md) · [native](../../misc/transaction/send-native.md) |
+
+## Request / response (shape)
+
+**Request params**
+
+- `fromAccountId` — keyring account UUID (coerced to `accountId` internally)
+- `toAddress` — Stellar destination
+- `assetId` — CAIP-19 classic / SEP-41 / slip44 (`scope` derived from `assetId`)
+- `amount` — human-readable amount string
+
+**Response**
+
+- `{ valid: true, errors: [], transactionId }` — confirmed, signed, and submitted
+- `{ valid: false, errors: [{ code }] }` — `Invalid` · `InsufficientBalance` · `InsufficientBalanceToCoverFee`
+
+User rejection of the confirmation dialog throws `UserRejectedRequestError`. Unactivated accounts return `{ valid: false, errors: [{ code: "Invalid" }] }` (no activation prompt).
+
+## Participants
+
+| Component | Path | Role in this flow |
+| ----------------------------------- | --------------------------- | ---------------------------------------------------------- |
+| `ClientRequestHandler` | `handlers/clientRequest` | Routes `confirmSend` to the handler |
+| `ConfirmSendHandler` | `handlers/clientRequest` | Orchestrates the use case |
+| `AccountResolver` | `handlers/` | Loads keyring account + wallet + **live** on-chain account |
+| `AccountService` | `services/account` | Keyring account lookup (via resolver) |
+| `WalletService` / `Wallet` | `services/wallet` | Signing key material + `signTransaction` |
+| `OnChainAccountService` | `services/on-chain-account` | Fresh balances / sequence |
+| `AssetMetadataService` | `services/asset-metadata` | Decimals, symbol, metadata for UI |
+| `TransactionService` | `services/transaction` | Build + validate send; submit; save pending keyring tx |
+| `NetworkService` | `services/network` | Base fee / network reads (via `TransactionService`) |
+| `ConfirmationUXController` | `ui/confirmation` | Send confirmation dialog |
+| `TransactionScanService` | `services/transaction-scan` | Security scan while dialog is open |
+| `RefreshConfirmationContextHandler` | `handlers/cronjob` | Refresh balances, tx, and scan while dialog is open |
+| `TrackTransactionHandler` | `handlers/cronjob` | Schedule background status tracking after submit |
+
+## Step-by-step
+
+1. **Route** — `onClientRequest` dispatches to `ConfirmSendHandler`.
+2. **Resolve** — `AccountResolver` loads keyring account, wallet, and activated on-chain account from the **live network**.
+3. **Build** — Resolve asset metadata; convert amount; `TransactionService.createValidatedSendTransaction`.
+4. **Confirm** — `ConfirmationUXController` shows send UI (fee, estimated changes, security scan, local re-validation cron while open).
+5. **Refresh** — After confirm, account is resolved again from the live network; fee must not exceed what the user approved.
+6. **Sign & send** — `Wallet.signTransaction` → `TransactionService.sendTransaction`.
+7. **Post-submit** — Persist pending keyring tx (`Send`) and schedule `TrackTransactionHandler` for sender + destination.
+
+## Sequence (happy path)
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Handler as ConfirmSendHandler
+ participant Resolver as AccountResolver
+ participant Meta as AssetMetadataService
+ participant Tx as TransactionService
+ participant UI as ConfirmationUXController
+ participant Refresh as RefreshConfirmationContextHandler
+ participant Scan as TransactionScanService
+ participant Wallet
+ participant Track as TrackTransactionHandler
+
+ Client->>Handler: confirmSend { fromAccountId, toAddress, assetId, amount }
+ Handler->>Resolver: resolve activated account (live on-chain)
+ Resolver-->>Handler: account, wallet, onChainAccount
+ Handler->>Meta: resolve(assetId)
+ Handler->>Tx: createValidatedSendTransaction
+ Tx-->>Handler: Transaction
+ Handler->>UI: renderConfirmationDialog
+ UI->>Refresh: schedule background refresh
+
+ loop While dialog open (until Client confirms / rejects)
+ Refresh->>Resolver: resolve on-chain account (live balances)
+ Refresh->>Tx: rebuild & re-validate send tx
+ Refresh->>Scan: security scan (refreshed envelope)
+ Refresh->>UI: update confirmation context
+ end
+
+ Client-->>UI: confirm
+ UI-->>Handler: confirmed
+ Handler->>Resolver: resolve again (live on-chain)
+ Handler->>Tx: createValidatedSendTransaction
+ Handler->>Wallet: signTransaction
+ Handler->>Tx: sendTransaction
+ Handler->>Tx: savePendingKeyringTransactionSafe
+ Handler->>Track: scheduleBackgroundEvent
+ Handler-->>Client: { valid: true, errors: [], transactionId }
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/client-request/onAddressInput.md b/packages/stellar-wallet-snap/docs/use-cases/client-request/onAddressInput.md
new file mode 100644
index 000000000..8b55cf952
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/client-request/onAddressInput.md
@@ -0,0 +1,47 @@
+# Use case: `onAddressInput`
+
+Validates a Stellar destination address for Unified Non-EVM Send (as the user types).
+
+| | |
+| ---------- | --------------------------------------------------------------------------------------------------- |
+| **Entry** | `onClientRequest` → `ClientRequestHandler` → `OnAddressInputHandler` |
+| **Method** | `onAddressInput` (`ClientRequestMethod.OnAddressInput`) |
+| **Source** | [`handlers/clientRequest/onAddressInput.ts`](../../../src/handlers/clientRequest/onAddressInput.ts) |
+
+## Request / response (shape)
+
+**Request params**
+
+- `value` — Stellar address string to validate
+
+**Response**
+
+- `{ valid: true, errors: [] }` — address is a valid Stellar address
+- `{ valid: false, errors: [{ code: "Invalid" }] }` — validation failed
+
+No account resolution, confirmation UI, or network calls.
+
+## Participants
+
+| Component | Path | Role in this flow |
+| ----------------------- | ------------------------ | -------------------------------------- |
+| `ClientRequestHandler` | `handlers/clientRequest` | Routes `onAddressInput` to the handler |
+| `OnAddressInputHandler` | `handlers/clientRequest` | Validates params via Superstruct |
+
+## Step-by-step
+
+1. **Route** — `onClientRequest` dispatches to `OnAddressInputHandler`.
+2. **Validate** — Request is checked against `OnAddressInputJsonRpcRequestStruct` (`value` must be a Stellar address).
+3. **Return** — `{ valid: true }` on success, or `{ valid: false, errors: [{ code: "Invalid" }] }` when params fail.
+
+## Sequence (happy path)
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Handler as OnAddressInputHandler
+
+ Client->>Handler: onAddressInput { value }
+ Handler->>Handler: validate Stellar address
+ Handler-->>Client: { valid: true, errors: [] }
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/client-request/onAmountInput.md b/packages/stellar-wallet-snap/docs/use-cases/client-request/onAmountInput.md
new file mode 100644
index 000000000..eb3a757cc
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/client-request/onAmountInput.md
@@ -0,0 +1,77 @@
+# Use case: `onAmountInput`
+
+Preflight-validates a send amount while the user types (balance and fee checks only; nothing is signed or submitted).
+
+| | |
+| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Entry** | `onClientRequest` → `ClientRequestHandler` → `OnAmountInputHandler` |
+| **Method** | `onAmountInput` (`ClientRequestMethod.OnAmountInput`) |
+| **Source** | [`handlers/clientRequest/onAmountInput.ts`](../../../src/handlers/clientRequest/onAmountInput.ts) |
+| **Transaction pipeline** | [SEP-41](../../misc/transaction/send-sep41.md) · [classic](../../misc/transaction/send-classic-trustline.md) · [native](../../misc/transaction/send-native.md) |
+
+## Request / response (shape)
+
+**Request params**
+
+- `accountId` — keyring account UUID
+- `assetId` — CAIP-19 classic / SEP-41 / slip44 asset (`scope` is derived from `assetId`)
+- `value` — positive amount string (human-readable units)
+- `to` — optional Stellar destination; omitted → self-transfer validation
+
+**Response**
+
+- `{ valid: true, errors: [] }` — amount can fund a send (incl. fee)
+- `{ valid: false, errors: [{ code }] }` — `Invalid` · `InsufficientBalance` · `InsufficientBalanceToCoverFee`
+
+Unactivated accounts return `{ valid: false, errors: [{ code: "Invalid" }] }` (no activation prompt).
+
+## Participants
+
+| Component | Path | Role in this flow |
+| ----------------------- | --------------------------- | --------------------------------------------------------- |
+| `ClientRequestHandler` | `handlers/clientRequest` | Routes `onAmountInput` to the handler |
+| `OnAmountInputHandler` | `handlers/clientRequest` | Orchestrates preflight validation |
+| `AccountResolver` | `handlers/` | Loads account + wallet + on-chain snapshot from **state** |
+| `AccountService` | `services/account` | Keyring account lookup (via resolver) |
+| `OnChainAccountService` | `services/on-chain-account` | Persisted on-chain balances (via resolver) |
+| `AssetMetadataService` | `services/asset-metadata` | Decimals for amount conversion |
+| `TransactionService` | `services/transaction` | Build + validate send tx (`useCache: true`) |
+
+## Step-by-step
+
+1. **Route** — `onClientRequest` dispatches to `OnAmountInputHandler`.
+2. **Resolve** — `AccountResolver` loads keyring account, wallet, and on-chain account from snap state.
+3. **Convert** — Resolve asset metadata; convert `value` to smallest units; reject if sub-unit decimals remain.
+4. **Preflight** — `TransactionService.createValidatedSendTransaction` with cached network reads (destination defaults to sender).
+5. **Return** — Structured validation result; expected balance/fee failures are returned as error codes (not thrown).
+
+## Note: cache usage
+
+`onAmountInput` is the **only** client send path that passes `useCache: true`. Real send/submit (`confirmSend`) always uses `useCache: false` (fresh destination load + fresh SEP-41 simulation).
+
+For **SEP-41**, that preflight cache matters most:
+
+- Fee estimation needs an on-chain **simulation**. Without caching, every keystroke would hit RPC.
+- Simulation is reused and keyed by **asset, sender, recipient, and scope** — **not** by amount. Cached XDR may carry a **stale amount or sequence** — never sign it.
+- Balance is still checked **locally** before simulation, so insufficient funds fail fast.
+
+Classic / native preflight still uses `useCache: true` for destination-account / network reads so typing stays responsive; submit paths do not.
+
+## Sequence (happy path)
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Handler as OnAmountInputHandler
+ participant Resolver as AccountResolver
+ participant Meta as AssetMetadataService
+ participant Tx as TransactionService
+
+ Client->>Handler: onAmountInput { accountId, assetId, value, to? }
+ Handler->>Resolver: resolve from keyring state
+ Resolver-->>Handler: account, wallet, onChainAccount
+ Handler->>Meta: resolve(assetId)
+ Handler->>Tx: createValidatedSendTransaction (useCache)
+ Tx-->>Handler: ok
+ Handler-->>Client: { valid: true, errors: [] }
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/client-request/signAndSendTransaction.md b/packages/stellar-wallet-snap/docs/use-cases/client-request/signAndSendTransaction.md
new file mode 100644
index 000000000..e7abcd6e3
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/client-request/signAndSendTransaction.md
@@ -0,0 +1,81 @@
+# Use case: `signAndSendTransaction`
+
+Signs and submits a swap / bridge envelope previously quoted via `computeFee`. **No Snap confirmation dialog** — the caller must obtain user consent first.
+
+| | |
+| ------------------------ | ------------------------------------------------------------------------------------------------------------------- |
+| **Entry** | `onClientRequest` → `ClientRequestHandler` → `SignAndSendTransactionHandler` |
+| **Method** | `signAndSendTransaction` (`ClientRequestMethod.SignAndSendTransaction`) |
+| **Source** | [`handlers/clientRequest/signAndSendTransaction.ts`](../../../src/handlers/clientRequest/signAndSendTransaction.ts) |
+| **Transaction pipeline** | [Swap / bridge from XDR](../../misc/transaction/send-swap.md) |
+
+## Client workflow
+
+1. Quote fees with **`computeFee`** using the CrossChain API XDR.
+2. Obtain explicit user approval in the **client** UI.
+3. Call **`signAndSendTransaction`** with the **same** `transaction` XDR, `scope`, and swap asset options.
+
+## Request / response (shape)
+
+**Request params**
+
+- `accountId` — keyring account UUID
+- `scope` — CAIP-2 chain ID
+- `transaction` — Base64-encoded swap / bridge XDR (same as `computeFee`)
+- `options.sourceAssetId` — Stellar source asset (CAIP-19 / slip44)
+- `options.destAssetId` — destination asset (CAIP-19; may be another chain for bridges)
+- `options.visible` / `options.type` — optional
+
+**Response**
+
+- `{ transactionId }` — submitted transaction hash
+
+## Security note
+
+This handler does **not** show a Snap confirmation. The client is responsible for displaying details and obtaining approval before calling. Signing without caller-side consent is a critical vulnerability.
+
+## Participants
+
+| Component | Path | Role in this flow |
+| ------------------------------- | --------------------------- | -------------------------------------------------------------------- |
+| `ClientRequestHandler` | `handlers/clientRequest` | Routes `signAndSendTransaction` to the handler |
+| `SignAndSendTransactionHandler` | `handlers/clientRequest` | Orchestrates validate → sign → submit |
+| `AccountResolver` | `handlers/` | Loads keyring account + wallet + **live** on-chain account (network) |
+| `AccountService` | `services/account` | Keyring account lookup (via resolver) |
+| `WalletService` / `Wallet` | `services/wallet` | `signTransaction` |
+| `OnChainAccountService` | `services/on-chain-account` | Balances / sequence for validation |
+| `AssetMetadataService` | `services/asset-metadata` | Same-chain swap asset labels for pending tx |
+| `TransactionService` | `services/transaction` | Validate swap XDR; submit; save pending keyring tx |
+| `TrackTransactionHandler` | `handlers/cronjob` | Schedule background status tracking after submit |
+
+## Step-by-step
+
+1. **Route** — `onClientRequest` dispatches to `SignAndSendTransactionHandler`.
+2. **Resolve** — `AccountResolver` loads keyring account, wallet, and activated on-chain account from the **live network**.
+3. **Validate** — `TransactionService.createValidatedSwapTransaction` on the XDR.
+4. **Sign & send** — `Wallet.signTransaction` → `TransactionService.sendTransaction`.
+5. **Post-submit** — Persist pending keyring tx (`Swap` for same-chain, `BridgeSend` for cross-chain) and schedule `TrackTransactionHandler`.
+
+## Sequence (happy path)
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Handler as SignAndSendTransactionHandler
+ participant Resolver as AccountResolver
+ participant Tx as TransactionService
+ participant Wallet
+ participant Track as TrackTransactionHandler
+
+ Note over Client: User already approved in client UI
+ Client->>Handler: signAndSendTransaction { accountId, scope, transaction, options }
+ Handler->>Resolver: resolve activated account (live on-chain)
+ Resolver-->>Handler: account, wallet, onChainAccount
+ Handler->>Tx: createValidatedSwapTransaction
+ Tx-->>Handler: Transaction
+ Handler->>Wallet: signTransaction
+ Handler->>Tx: sendTransaction
+ Handler->>Tx: savePendingKeyringTransactionSafe (Swap | BridgeSend)
+ Handler->>Track: scheduleBackgroundEvent
+ Handler-->>Client: { transactionId }
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/cron-job/cronjob.md b/packages/stellar-wallet-snap/docs/use-cases/cron-job/cronjob.md
new file mode 100644
index 000000000..2cdf221c7
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/cron-job/cronjob.md
@@ -0,0 +1,44 @@
+# Use case: cronjob gate (`CronjobHandler`)
+
+All background events enter through `onCronjob` → `CronjobHandler`, which **skips work when MetaMask is inactive or the wallet is locked**.
+
+| | |
+| ---------- | ------------------------------------------------------------------------- |
+| **Entry** | `onCronjob` → `CronjobHandler` |
+| **Source** | [`handlers/cronjob/cronjob.ts`](../../../src/handlers/cronjob/cronjob.ts) |
+
+## Behavior
+
+1. Call `getClientStatus()` → `{ active, locked }`.
+2. If **`!active` or `locked`** → return immediately (no method dispatch, no side effects).
+3. Otherwise validate `request.method` against `BackgroundEventMethod` and route to the matching handler.
+
+This gate applies to **every** cron method (`trackTransaction`, `synchronizeAccounts`, `synchronizeAssets`, `refreshConfirmationContext`). Individual handlers do not re-check lock state.
+
+## Cronjob handlers
+
+| Cronjob handlers | Doc |
+| ---------------------------- | ---------------------------------------------------------------- |
+| `trackTransaction` | [trackTransaction.md](./trackTransaction.md) |
+| `synchronizeAccounts` | [syncAccounts.md](./syncAccounts.md) |
+| `synchronizeAssets` | [syncAssets.md](./syncAssets.md) |
+| `refreshConfirmationContext` | [refreshConfirmationContext.md](./refreshConfirmationContext.md) |
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Snap as onCronjob
+ participant Cron as CronjobHandler
+ participant Status as getClientStatus
+ participant Method as Cronjob handler
+
+ Snap->>Cron: background event request
+ Cron->>Status: active? locked?
+ alt not active or locked
+ Status-->>Cron: skip
+ Cron-->>Snap: return (no-op)
+ else unlocked and active
+ Cron->>Method: handle(request)
+ end
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/cron-job/refreshConfirmationContext.md b/packages/stellar-wallet-snap/docs/use-cases/cron-job/refreshConfirmationContext.md
new file mode 100644
index 000000000..92a66ad30
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/cron-job/refreshConfirmationContext.md
@@ -0,0 +1,86 @@
+# Use case: `refreshConfirmationContext`
+
+While a confirmation dialog is open, periodically refresh prices, security scan, and/or rebuild the pending transaction against live on-chain state.
+
+| | |
+| ---------- | ----------------------------------------------------------------------------------------------------------- |
+| **Entry** | `onCronjob` → `CronjobHandler` → `RefreshConfirmationContextHandler` |
+| **Method** | `refreshConfirmationContext` (`BackgroundEventMethod.RefreshConfirmationContext`) |
+| **Source** | [`handlers/cronjob/refreshConfirmationContext/`](../../../src/handlers/cronjob/refreshConfirmationContext/) |
+| **Gate** | Skipped when wallet locked / inactive — see [cronjob.md](./cronjob.md) |
+
+Scheduled by `ConfirmationUXController` when a dialog opens with pricing, security scanning, and/or local simulation enabled (e.g. [`confirmSend`](../client-request/confirmSend.md), [`changeTrustOpt`](../client-request/changeTrustOpt.md)).
+
+## Request params
+
+- `interfaceId` — Snap UI interface id
+- `interfaceKey` — which confirmation view
+- `scope` — CAIP-2 chain ID
+- `refresherKeys` — which slices to run this cycle: `Prices` · `Scan` · `Transaction`
+
+## Participants
+
+| Component | Path | Role |
+| ----------------------------------- | ------------------------------------------- | ----------------------------------------------------- |
+| `RefreshConfirmationContextHandler` | `handlers/cronjob` | Orchestrate refreshers, re-render, reschedule |
+| `ConfirmationPriceRefresher` | `handlers/cronjob/.../priceRefresher` | Spot prices via `PriceService` |
+| `ConfirmationScanRefresher` | `handlers/cronjob/.../scanRefresher` | Blockaid / security scan via `TransactionScanService` |
+| `ConfirmationTransactionRefresher` | `handlers/cronjob/.../transactionRefresher` | Rebuild + re-validate pending tx (live account) |
+| `ConfirmationUXController` | `ui/confirmation` | Apply patched context to the open dialog |
+
+## Refreshers
+
+### Prices
+
+Fetches / updates token spot prices shown on the confirmation (fee asset, send asset, etc.). Requests reschedule while pricing is still needed and not in a terminal error state.
+
+### Security scan
+
+Runs (or refreshes) the remote security scan on the current transaction envelope in context. Uses the **latest** envelope when the transaction refresher has already patched it this cycle.
+
+### Transaction rebuild
+
+Runs **first** when enabled:
+
+1. Resolve live on-chain account.
+2. Rebuild the pending send / change-trust envelope (fresh fee, sequence, time bounds).
+3. Re-validate locally; update fee / validation status in context.
+4. Write the rebuilt XDR into the security-scan request so the scan refresher does not scan a stale snapshot.
+
+## Step-by-step (one cycle)
+
+1. Resolve enabled refreshers from `refresherKeys`.
+2. Load interface context; if the dialog was dismissed → stop (no reschedule).
+3. Run **transaction** refresher alone (if selected), merge its patch.
+4. Run **prices** and **scan** in parallel on the updated context.
+5. Merge patches → `ConfirmationUXController.updateConfirmation`.
+6. If any refresher asks to **reschedule** → schedule the next `refreshConfirmationContext` event.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Cron as RefreshConfirmationContextHandler
+ participant TxR as Transaction refresher
+ participant Price as Price refresher
+ participant Scan as Scan refresher
+ participant UI as ConfirmationUXController
+
+ Cron->>Cron: load interface context
+ alt dialog gone
+ Cron-->>Cron: stop
+ else still open
+ opt Transaction in refresherKeys
+ Cron->>TxR: rebuild + validate (live)
+ TxR-->>Cron: patch (xdr, fee, status)
+ end
+ par
+ Cron->>Price: refresh spot prices
+ Cron->>Scan: security scan (latest xdr)
+ end
+ Cron->>UI: updateConfirmation
+ opt any reschedule
+ Cron->>Cron: schedule next cycle
+ end
+ end
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAccounts.md b/packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAccounts.md
new file mode 100644
index 000000000..93d3aa874
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAccounts.md
@@ -0,0 +1,47 @@
+# Use case: `synchronizeAccounts`
+
+Periodically (or on demand) refresh on-chain account state and transaction history for keyring accounts.
+
+| | |
+| ------------------- | ----------------------------------------------------------------------------------- |
+| **Entry** | `onCronjob` → `CronjobHandler` → `SyncAccountsHandler` |
+| **Method** | `synchronizeAccounts` (`BackgroundEventMethod.SynchronizeAccounts`) |
+| **Source** | [`handlers/cronjob/syncAccounts.ts`](../../../src/handlers/cronjob/syncAccounts.ts) |
+| **Synchronization** | [synchronization](../../misc/synchronization/synchronization.md) |
+| **Gate** | Skipped when wallet locked / inactive — see [cronjob.md](./cronjob.md) |
+
+Also schedulable via `SyncAccountsHandler.scheduleBackgroundEvent` (e.g. after account changes). Declarative cron may omit params → treat as **selected** accounts.
+
+## Request params
+
+- `accountIds` — optional
+ - omitted / `'selected'` → all **selected** keyring accounts
+ - UUID array → those account ids only
+
+Scope comes from `AppConfig.selectedNetwork`.
+
+## Participants
+
+| Component | Path | Role |
+| --------------------- | ------------------ | ---------------------------------------------------------- |
+| `SyncAccountsHandler` | `handlers/cronjob` | Resolve which accounts to sync |
+| `AccountService` | `services/account` | `getAllSelected` / `findByIds` |
+| `SynchronizeService` | `services/sync` | Sync balances, trustlines, transactions for those accounts |
+
+## Step-by-step
+
+1. Resolve account list (`selected` vs explicit ids).
+2. `SynchronizeService.synchronize(accounts, { scope })` — updates on-chain snapshots and related history for the configured network.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Cron as SyncAccountsHandler
+ participant Acc as AccountService
+ participant Sync as SynchronizeService
+
+ Cron->>Acc: getAllSelected() or findByIds(...)
+ Acc-->>Cron: accounts
+ Cron->>Sync: synchronize(accounts, selectedNetwork)
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAssets.md b/packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAssets.md
new file mode 100644
index 000000000..9f6be3b65
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/cron-job/syncAssets.md
@@ -0,0 +1,40 @@
+# Use case: `synchronizeAssets`
+
+Refresh the Snap’s asset metadata catalog from the token API (mainnet only).
+
+| | |
+| ------------------- | ------------------------------------------------------------------------------- |
+| **Entry** | `onCronjob` → `CronjobHandler` → `SyncAssetsHandler` |
+| **Method** | `synchronizeAssets` (`BackgroundEventMethod.SynchronizeAssets`) |
+| **Source** | [`handlers/cronjob/syncAssets.ts`](../../../src/handlers/cronjob/syncAssets.ts) |
+| **Synchronization** | [synchronization](../../misc/synchronization/synchronization.md) |
+| **Gate** | Skipped when wallet locked / inactive — see [cronjob.md](./cronjob.md) |
+
+Declarative cron in `snap.manifest.json` (no params required).
+
+## Participants
+
+| Component | Path | Role |
+| ---------------------- | ------------------------- | ---------------------------- |
+| `SyncAssetsHandler` | `handlers/cronjob` | Cron entry |
+| `SynchronizeService` | `services/sync` | `synchronizeAssets(scope)` |
+| `AssetMetadataService` | `services/asset-metadata` | Pull / persist asset catalog |
+
+## Step-by-step
+
+1. Always use **mainnet** scope (`KnownCaip2ChainId.Mainnet`) — asset metadata is only available there, regardless of the user’s selected network.
+2. `SynchronizeService.synchronizeAssets` → `AssetMetadataService.synchronize`.
+3. Failures are logged / tracked; the cron does not throw through to fail the whole Snap lifecycle aggressively.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Cron as SyncAssetsHandler
+ participant Sync as SynchronizeService
+ participant Meta as AssetMetadataService
+
+ Cron->>Sync: synchronizeAssets(mainnet)
+ Sync->>Meta: synchronize(mainnet)
+ Meta-->>Sync: catalog updated
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/cron-job/trackTransaction.md b/packages/stellar-wallet-snap/docs/use-cases/cron-job/trackTransaction.md
new file mode 100644
index 000000000..2706bb10b
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/cron-job/trackTransaction.md
@@ -0,0 +1,72 @@
+# Use case: `trackTransaction`
+
+After a tx is submitted, keep polling Horizon until it shows up, then refresh the affected accounts’ balances / history.
+
+| | |
+| ------------------- | ------------------------------------------------------------------------------------------- |
+| **Entry** | `onCronjob` → `CronjobHandler` → `TrackTransactionHandler` |
+| **Method** | `trackTransaction` (`BackgroundEventMethod.TrackTransaction`) |
+| **Source** | [`handlers/cronjob/trackTransaction.ts`](../../../src/handlers/cronjob/trackTransaction.ts) |
+| **Synchronization** | [synchronization](../../misc/synchronization/synchronization.md) |
+| **Gate** | Skipped when wallet locked / inactive — see [cronjob.md](./cronjob.md) |
+
+Scheduled right after submit by [`confirmSend`](../client-request/confirmSend.md), [`changeTrustOpt`](../client-request/changeTrustOpt.md), [`signAndSendTransaction`](../client-request/signAndSendTransaction.md).
+
+## Request params
+
+- `txId` — Stellar transaction hash
+- `scope` — CAIP-2 chain ID
+- `accountIdsOrAddresses` — `[senderAccountUuid]` or `[senderAccountUuid, receiverAddress]`
+- `attempt` — optional reschedule counter (default `0`)
+
+## What Horizon returns
+
+| Outcome | Meaning |
+| ------------------- | ------------------------------------------------- |
+| **404 / not found** | Not indexed yet (or unknown hash) |
+| **Found + success** | On-chain succeeded → keyring status **Confirmed** |
+| **Found + fail** | On-chain failed → keyring status **Failed** |
+
+Both found outcomes are **terminal** — settlement is done; sync accounts.
+
+## Participants
+
+| Component | Path | Role |
+| ------------------------- | ------------------ | --------------------------------------------------- |
+| `TrackTransactionHandler` | `handlers/cronjob` | Poll Horizon, reschedule, sync on settle |
+| `NetworkService` | `services/network` | `getTransaction` from Horizon |
+| `AccountService` | `services/account` | Resolve sender / optional receiver keyring accounts |
+| `SynchronizeService` | `services/sync` | Refresh balances / history after settle |
+
+## Step-by-step
+
+1. Ask Horizon for `txId`.
+2. **404 / not found** or **network error**:
+ - If `attempt < trackTransactionMaxReschedules` → reschedule another poll (~2s, `attempt++`).
+ - If **max attempts reached** → **skip** (stop tracking this tx; no further reschedule). Periodic `synchronizeAccounts` may still pick it up later.
+3. **Found (confirmed or failed)** → load sender (and receiver if it is in the keyring) → `SynchronizeService.synchronize`.
+4. Any other unexpected error → log / track; skip further tracking for this run.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Cron as TrackTransactionHandler
+ participant Net as NetworkService
+ participant Acc as AccountService
+ participant Sync as SynchronizeService
+
+ Cron->>Net: getTransaction(txId, scope)
+ alt 404 / network error
+ Net-->>Cron: not found / network error
+ alt attempt < max
+ Cron->>Cron: reschedule poll (attempt++)
+ else attempt >= max
+ Cron->>Cron: Skip — stop tracking
+ end
+ else completed
+ Net-->>Cron: transaction
+ Cron->>Acc: find sender (+ optional receiver)
+ Cron->>Sync: synchronize(accounts)
+ end
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/keyring/keyring.md b/packages/stellar-wallet-snap/docs/use-cases/keyring/keyring.md
new file mode 100644
index 000000000..a2bbd1abd
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/keyring/keyring.md
@@ -0,0 +1,50 @@
+# Use case: keyring (`KeyringHandler`)
+
+Account management and SEP-43 signing entry points via `onKeyringRequest` → `KeyringHandler`.
+
+| | |
+| ---------- | ------------------------------------------------------------------------- |
+| **Entry** | `onKeyringRequest` → `KeyringHandler` |
+| **Source** | [`handlers/keyring/keyring.ts`](../../../src/handlers/keyring/keyring.ts) |
+
+## Participants
+
+| Component | Path | Role |
+| ----------------------- | --------------------------- | ----------------------------------------------------------------------- |
+| `KeyringHandler` | `handlers/keyring` | Keyring API surface + routing |
+| `AccountService` | `services/account` | Persist / derive / select accounts (snap state) |
+| `OnChainAccountService` | `services/on-chain-account` | Snap-state snapshots for balances/assets; live activation for discovery |
+| `TransactionService` | `services/transaction` | Local pending keyring txs for `listAccountTransactions` |
+| `SyncAccountsHandler` | `handlers/cronjob` | Scheduled after selection changes to refresh on-chain snapshots |
+
+## Request / response
+
+Account-management methods follow the MetaMask **Keyring API** (request method names `keyring_*`, params, and return types):
+
+- [Account Management API](https://docs.metamask.io/snaps/reference/keyring-api/account-management/)
+- [`@metamask/keyring-api` docs](https://metamask.github.io/keyring-api/latest/)
+
+This Snap implements the `Keyring` interface; calls arrive via `wallet_invokeKeyring` / `onKeyringRequest` and are dispatched with `handleKeyringRequest`.
+
+`submitRequest` uses **SEP-43** request/response shapes — see [SEP-43](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0043.md).
+
+## Methods
+
+Requests are origin-checked, then dispatched to the methods below.
+
+| Method | What it does | Data source |
+| ------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
+| `listAccounts` | List all Stellar keyring accounts | **Snap state** (`AccountService`) |
+| `getAccount` | Get one account by id | **Snap state** |
+| `createAccount` | Derive / create one account; emit `AccountCreated` for new accounts (rollback delete if emit fails) | **Snap state** (HD derive + persist) |
+| `createAccounts` | Batch BIP-44 create (single index or range); Snap keyring v2 path — no `AccountCreated` events | **Snap state** (HD derive + persist) |
+| `deleteAccount` | Emit `AccountDeleted`, then remove the account | **Snap state** |
+| `setSelectedAccounts` | Validate ids exist, then schedule `synchronizeAccounts` for those accounts | |
+| `listAccountAssets` | Visible CAIP asset ids; if no snapshot yet, returns native slip44 only | **Snap state** on-chain snapshot (background-synced; not a live Horizon read) |
+| `getAccountBalances` | Balances for requested assets; missing / inactive snapshot → native `0` if asked | **Snap state** on-chain snapshot (same as above; can be slightly stale within the sync window) |
+| `listAccountTransactions` | Paginated keyring transactions for the account | **Snap state** (pending / local txs via `TransactionService` — **not** Horizon history) |
+| `discoverAccounts` | Derive BIP-44 address for index; return it only if activated on any requested scope | Derive locally; activation check is **live on-chain** (`NetworkService.getAccount`) |
+| `resolveAccountAddress` | Given an address, return CAIP-10 if this snap owns it; else `null` (MetaMask may fall back) | **Snap state** (keyring account lookup by address) |
+| `filterAccountChains` | Not implemented | Throws `MethodNotSupportedError` |
+| `updateAccount` | Not implemented | Throws `MethodNotSupportedError` |
+| `submitRequest` | [signTransaction.md](./signTransaction.md) · [signMessage.md](./signMessage.md) · [signAuthEntry.md](./signAuthEntry.md) | |
diff --git a/packages/stellar-wallet-snap/docs/use-cases/keyring/signAuthEntry.md b/packages/stellar-wallet-snap/docs/use-cases/keyring/signAuthEntry.md
new file mode 100644
index 000000000..572c6d232
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/keyring/signAuthEntry.md
@@ -0,0 +1,58 @@
+# Use case: `signAuthEntry`
+
+SEP-43: confirm and sign a Soroban authorization preimage (`HashIdPreimage` / `envelopeTypeSorobanAuthorization`).
+
+| | |
+| ------------ | ------------------------------------------------------------------------------------- |
+| **Entry** | `onKeyringRequest` → `KeyringHandler.submitRequest` → `SignAuthEntryHandler` |
+| **Method** | `signAuthEntry` (`MultichainMethod.SignAuthEntry`) |
+| **Source** | [`handlers/keyring/signAuthEntry.ts`](../../../src/handlers/keyring/signAuthEntry.ts) |
+| **Overview** | [keyring.md](./keyring.md) |
+
+## Participants
+
+| Component | Path | Role |
+| -------------------------- | ------------------ | ----------------------------- |
+| `SignAuthEntryHandler` | `handlers/keyring` | Decode, confirm, sign |
+| `AccountResolver` | `handlers/` | Load keyring account + wallet |
+| `Wallet` | `services/wallet` | `signAuthEntry` |
+| `ConfirmationUXController` | `ui/confirmation` | Sign-auth-entry dialog |
+
+## Request / response
+
+Wire format follows **SEP-43** `signAuthEntry` (via keyring `submitRequest`):
+
+- [SEP-43](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0043.md)
+- Keyring transport: [Account Management API](https://docs.metamask.io/snaps/reference/keyring-api/account-management/) (`keyring_submitRequest`)
+
+Local validators: [`handlers/keyring/api.ts`](../../../src/handlers/keyring/api.ts) (`SignAuthEntryRequestStruct` / `SignAuthEntryResponseStruct`).
+
+The dapp supplies a base64 `HashIdPreimage`. The Snap decodes it for the confirmation UI (contract, function, args, nested invocations, nonce, expiry ledger), then on approve signs `sha256(preimage)` with ed25519. Network id is already inside the preimage (mainnet-only validation at the struct layer).
+
+## Step-by-step
+
+1. Resolve account + wallet.
+2. Decode preimage into a readable auth summary for the UI.
+3. Show confirmation.
+4. On approve → `wallet.signAuthEntry` → return signature.
+5. On reject → SEP-43 error envelope.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Dapp
+ participant Handler as SignAuthEntryHandler
+ participant UI as ConfirmationUXController
+ participant Wallet
+
+ Dapp->>Handler: signAuthEntry (SEP-43 via keyring submitRequest)
+ Handler->>Handler: decode Soroban auth preimage
+ Handler->>UI: confirmation dialog
+ alt user rejects
+ Handler-->>Dapp: SEP-43 error envelope
+ else user confirms
+ Handler->>Wallet: signAuthEntry
+ Handler-->>Dapp: SEP-43 success (signedAuthEntry, signerAddress)
+ end
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/keyring/signMessage.md b/packages/stellar-wallet-snap/docs/use-cases/keyring/signMessage.md
new file mode 100644
index 000000000..30e15c155
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/keyring/signMessage.md
@@ -0,0 +1,73 @@
+# Use case: `signMessage`
+
+SEP-43: confirm and sign an arbitrary UTF-8 message.
+
+| | |
+| ------------ | --------------------------------------------------------------------------------- |
+| **Entry** | `onKeyringRequest` → `KeyringHandler.submitRequest` → `SignMessageHandler` |
+| **Method** | `signMessage` (`MultichainMethod.SignMessage`) |
+| **Source** | [`handlers/keyring/signMessage.ts`](../../../src/handlers/keyring/signMessage.ts) |
+| **Overview** | [keyring.md](./keyring.md) |
+
+## Participants
+
+| Component | Path | Role |
+| -------------------------- | ------------------ | ----------------------------- |
+| `SignMessageHandler` | `handlers/keyring` | Confirm + sign |
+| `AccountResolver` | `handlers/` | Load keyring account + wallet |
+| `Wallet` | `services/wallet` | `signMessage` |
+| `ConfirmationUXController` | `ui/confirmation` | Sign-message dialog |
+
+## Request / response
+
+Wire format follows **SEP-43** `signMessage` (via keyring `submitRequest`):
+
+- [SEP-43](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0043.md) — keyring method + params/response envelope
+- Keyring transport: [Account Management API](https://docs.metamask.io/snaps/reference/keyring-api/account-management/) (`keyring_submitRequest`)
+
+Local validators: [`handlers/keyring/api.ts`](../../../src/handlers/keyring/api.ts) (`SignMessageRequestStruct` / `SignMessageResponseStruct`).
+
+This snap accepts **UTF-8 text only** for `message` (non-empty). Base64-encoded binary payloads are not auto-detected.
+
+## How signing works
+
+Signing follows the **Stellar Signed Message** protocol ([SEP-0053](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0053.md)), implemented in [`Wallet.signMessage`](../../../src/services/wallet/Wallet.ts):
+
+1. **Interpret `message`** — always as UTF-8 text (string → UTF-8 bytes).
+2. **Build the payload** — prepend the fixed prefix `Stellar Signed Message:\n`, then append the message bytes.
+3. **Hash** — SHA-256 over that byte sequence.
+4. **Sign** — Ed25519 sign the digest with the account’s keypair.
+5. **Return** — base64-encoded signature as `signedMessage` (SEP-43 response).
+
+The confirmation UI shows the UTF-8 `message` string as given — the same content that gets signed.
+
+**References**
+
+| Spec | Role |
+| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
+| [SEP-43](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0043.md) | Keyring `signMessage` request/response wire format |
+| [SEP-0053](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0053.md) | Stellar Signed Message prefix, hash, and signature algorithm |
+
+## Step-by-step
+
+1. Resolve keyring account + wallet for the signer.
+2. Show confirmation with the UTF-8 message text.
+3. On approve → `Wallet.signMessage` (SEP-0053, UTF-8) → return `signedMessage` + `signerAddress`.
+4. On reject → SEP-43 error envelope.
+
+```mermaid
+sequenceDiagram
+ participant Dapp
+ participant Handler as SignMessageHandler
+ participant UI as ConfirmationUXController
+ participant Wallet
+
+ Dapp->>Handler: signMessage (SEP-43 via keyring submitRequest)
+ Handler->>UI: confirmation dialog (UTF-8 message)
+ alt user rejects
+ Handler-->>Dapp: SEP-43 error envelope
+ else user confirms
+ Handler->>Wallet: signMessage (SEP-0053, UTF-8)
+ Handler-->>Dapp: SEP-43 success (signedMessage, signerAddress)
+ end
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/keyring/signTransaction.md b/packages/stellar-wallet-snap/docs/use-cases/keyring/signTransaction.md
new file mode 100644
index 000000000..61802589d
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/keyring/signTransaction.md
@@ -0,0 +1,67 @@
+# Use case: `signTransaction`
+
+SEP-43: show a confirmation, then return a **signed** transaction XDR to the dapp. The Snap does **not** change the envelope and does **not** broadcast it.
+
+| | |
+| ------------ | ----------------------------------------------------------------------------------------- |
+| **Entry** | `onKeyringRequest` → `KeyringHandler.submitRequest` → `SignTransactionHandler` |
+| **Method** | `signTransaction` (`MultichainMethod.SignTransaction`) |
+| **Source** | [`handlers/keyring/signTransaction.ts`](../../../src/handlers/keyring/signTransaction.ts) |
+| **Overview** | [keyring.md](./keyring.md) |
+
+## Participants
+
+| Component | Path | Role |
+| -------------------------- | --------------------------- | ------------------------------------------------------ |
+| `SignTransactionHandler` | `handlers/keyring` | Decode, confirm, sign |
+| `AccountResolver` | `handlers/` | Load keyring account + wallet |
+| `Wallet` | `services/wallet` | `signTransaction` |
+| `ConfirmationUXController` | `ui/confirmation` | Sign-transaction dialog |
+| `TransactionScanService` | `services/transaction-scan` | Security scan + remote simulation while dialog is open |
+
+## Request / response
+
+Wire format follows **SEP-43** `signTransaction` (and MetaMask keyring `submitRequest` wrapping):
+
+- [SEP-43](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0043.md)
+- Keyring transport: [Account Management API](https://docs.metamask.io/snaps/reference/keyring-api/account-management/) (`keyring_submitRequest`)
+
+Local Superstruct validators live in [`handlers/keyring/api.ts`](../../../src/handlers/keyring/api.ts) (`SignTransactionRequestStruct` / `SignTransactionResponseStruct`).
+
+## Important notes
+
+- **No modification** — the Snap does not rebuild, re-fee, or re-simulate the transaction for signing. It decodes the dapp-supplied XDR, checks scope, and signs as-is. Balance / op-level validation is the caller’s responsibility.
+- **No broadcast** — after signing, the Snap returns the SEP-43 success fields (`signedTxXdr`, `signerAddress`). Submitting to the network is entirely the dapp’s job (unlike [`confirmSend`](../client-request/confirmSend.md) / [`signAndSendTransaction`](../client-request/signAndSendTransaction.md)).
+- Fee on the envelope is trusted as provided by the dapp; security scan / remote simulation may still surface issues in the confirmation UI.
+- Failures / user reject are returned in the SEP-43 `error` envelope (does not throw to the dapp).
+
+## Step-by-step
+
+1. Resolve account + wallet for the signer.
+2. `Transaction.fromXdr` + assert scope matches.
+3. Show confirmation (readable ops, fee, prices, security scan / remote simulation).
+4. On approve → `wallet.signTransaction` → return signed XDR.
+5. On reject → user-rejected path mapped to SEP-43 error response.
+
+## Sequence
+
+```mermaid
+sequenceDiagram
+ participant Dapp
+ participant Handler as SignTransactionHandler
+ participant UI as ConfirmationUXController
+ participant Wallet
+
+ Dapp->>Handler: signTransaction (SEP-43 via keyring submitRequest)
+ Handler->>Handler: fromXdr (no rebuild / no balance validate)
+ Handler->>UI: confirmation dialog
+ alt user rejects
+ UI-->>Handler: rejected
+ Handler-->>Dapp: SEP-43 error envelope
+ else user confirms
+ UI-->>Handler: confirmed
+ Handler->>Wallet: signTransaction
+ Handler-->>Dapp: SEP-43 success (signedTxXdr, signerAddress)
+ Note over Dapp: Dapp broadcasts if needed
+ end
+```
diff --git a/packages/stellar-wallet-snap/docs/use-cases/user-input/userInput.md b/packages/stellar-wallet-snap/docs/use-cases/user-input/userInput.md
new file mode 100644
index 000000000..39b03c6a8
--- /dev/null
+++ b/packages/stellar-wallet-snap/docs/use-cases/user-input/userInput.md
@@ -0,0 +1,29 @@
+# Use case: user input (`UserInputHandler`)
+
+Interactive UI events via `onUserInput` → `UserInputHandler`.
+
+| | |
+| ---------- | ----------------------------------------------------------------------------------- |
+| **Entry** | `onUserInput` → `UserInputHandler.handle` |
+| **Source** | [`handlers/user-input/userInput.ts`](../../../src/handlers/user-input/userInput.ts) |
+
+## Participants
+
+| Component | Path | Role |
+| ------------------------ | -------------------------------- | --------------------------------------------------------------- |
+| `UserInputHandler` | `handlers/user-input` | Route UI events by `event.name` |
+| Confirmation view events | `ui/confirmation/views/*/events` | Confirm / cancel (and related) handlers that resolve the dialog |
+
+## Request / response
+
+Wire format follows the MetaMask **interactive UI** entry point:
+
+- [Entry points — `onUserInput`](https://docs.metamask.io/snaps/reference/entry-points/#onuserinput)
+
+MetaMask calls `onUserInput` with `{ id, event, context }` when the user interacts with a Snap interface. This Snap ignores events without a `name`, then dispatches to a handler map built from confirmation views.
+
+## Methods
+
+| Method | What it does | Data source |
+| ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ----------- |
+| `onUserInput` | Route named UI events to confirmation handlers (sign message / tx / auth entry, change trust, send, malicious acknowledgement) | |