214 lines
10 KiB
Markdown
214 lines
10 KiB
Markdown
# ADR-0025 — Litecoin (LTC) trade-only addition
|
|
|
|
**Status:** Accepted (Part 122 cp24)
|
|
**Date:** 2026-05-17
|
|
**Deciders:** project maintainer
|
|
**Supersedes:** none
|
|
**Superseded by:** none
|
|
**Related:** ADR-0023 (USDT multi-network — established the
|
|
Category A/B trade-only pattern), ADR-0024 (Bitcoin Cash — first
|
|
single-network Category-B addition), ADR-0011 (fee model +
|
|
fee_method enum-freeze), Part 122 cp22 (interactive
|
|
disable-trade-only-asset wizard step).
|
|
|
|
## Context
|
|
|
|
Following BCH's successful single-network Category-B integration
|
|
in Part 122 cp21 (ADR-0024), the project maintainer requested
|
|
Litecoin (LTC) as the third Category-B trade-only asset. LTC
|
|
shares BCH's architectural shape — single-network transparent
|
|
chain, no central issuer, BTC-fork heritage — making the cp21
|
|
template directly applicable.
|
|
|
|
The cp21 BCH addition surfaced a CLASS of bugs cp23's fresh
|
|
deep-deep found: canonical-source extensions (asset registry,
|
|
chat payload, primary UI dispatches) but missed downstream
|
|
typed-consumer maps (price store, Coingecko ID map, fallback
|
|
prices, payment-method registry, cheat-sheet, crawler-facing
|
|
static files). Cp24 closes those proactively for LTC rather
|
|
than waiting for a post-addition DD to surface them.
|
|
|
|
## Decision
|
|
|
|
LTC ships as the third Category-B trade-only single-network asset
|
|
following ADR-0024's template, with eight design choices:
|
|
|
|
### 1. Trade-only (Category B), `canPayListingFee: false`
|
|
|
|
Listing-fee payment methods remain frozen at `{blurt, btc, xmr,
|
|
waived_first_buy}` per Memory #23 / ADR-0011. Adding LTC as a
|
|
new fee_method enum value would break the wire-format invariant
|
|
that smokes (`fee-method-enum-frozen-smoke`) explicitly pin.
|
|
|
|
LTC users trade LTC; they pay listing fees in BLURT/BTC/XMR
|
|
like every other Category-B asset.
|
|
|
|
### 2. Single-network mainnet
|
|
|
|
LTC has no production sidechains, L2s, or wrapped-asset variants
|
|
on Morphit's radar. No per-network picker; defaults to mainnet
|
|
and stays there. This is the BCH posture, NOT the USDT posture.
|
|
|
|
### 3. No privacy-warning chip (`privacyWarningKey: null`)
|
|
|
|
LTC is transparent (like BTC and BCH) but the chain is fully
|
|
decentralized and LTC addresses cannot be frozen by an issuer.
|
|
Same posture as BTC/BCH: no warning chip needed.
|
|
|
|
Note: LTC has opt-in privacy via MWEB (MimbleWimble Extension
|
|
Blocks). MWEB is wallet-side and per-transaction, NOT a chain
|
|
property. Users seeking Morphit's strongest privacy posture
|
|
should use XMR. MWEB-enabled trades are not specially flagged
|
|
in Morphit's UI; the operator-counterparty knows the privacy
|
|
posture of the addresses they share.
|
|
|
|
### 4. Address validator accepts ALL four LTC formats
|
|
|
|
LTC has three address-shape eras:
|
|
|
|
1. **Legacy P2PKH** starting with `L` — base58, 26-35 chars.
|
|
Unambiguous with BTC since BTC P2PKH starts with `1`.
|
|
2. **Modern P2SH** starting with `M` — base58, 26-35 chars.
|
|
Introduced 2017 to disambiguate from BTC P2SH.
|
|
3. **Deprecated P2SH** starting with `3` — base58, 26-35 chars.
|
|
**BTC-shape ambiguous.** Still valid on the LTC chain.
|
|
4. **Bech32 / Bech32m** with `ltc1` prefix — 6-87 char body.
|
|
Covers both segwit-v0 (`ltc1q...`) and taproot (`ltc1p...`).
|
|
|
|
Decision: accept all four including the deprecated `3`-prefix
|
|
P2SH form. Recipient wallet does chain-binding on receive —
|
|
this matches ADR-0024 §4's stance for BCH legacy addresses.
|
|
|
|
Refusing the `3`-prefix form would be paternalistic toward LTC
|
|
users whose wallets still emit it. The cost is the same as
|
|
BCH: a user pasting an LTC `3`-address while having selected BTC
|
|
as the asset wouldn't trigger a shape-level rejection. Same
|
|
mitigation: clear UI labels at the picker stage.
|
|
|
|
### 5. Decimals = 8 (satoshi-denominated)
|
|
|
|
LTC inherited BTC's 8-decimal smallest-unit semantics; the
|
|
LTC ecosystem calls it "litoshi" but the encoding is identical.
|
|
|
|
### 6. Bundled explorer default: litecoinspace.org
|
|
|
|
From Ken's seven-explorer candidate list:
|
|
- `blockchair.com/litecoin` — multi-chain (same vendor as BCH default)
|
|
- `oklink.com/litecoin` — OKX exchange-affiliated (centralization concern)
|
|
- `bitinfocharts.com/litecoin/explorer/` — analytics + tracking
|
|
- `chain.so/LTC` — older infrastructure, less actively maintained
|
|
- `litecoinspace.org` — community-led, mempool.space-style, no JS tracking, open-source
|
|
- `blockexplorer.one/litecoin/mainnet` — generic multi-coin
|
|
- `ltc.tokenview.io` — Chinese-operated multi-chain
|
|
|
|
Chosen: **`litecoinspace.org/tx/{txid}`**. Rationale: it's the
|
|
LTC-equivalent of mempool.space (which we already use for BTC).
|
|
Privacy-aligned with Morphit's priority #1 (no JS tracking,
|
|
open-source). Operators wanting a different default override
|
|
via `MORPHIT_FRONTEND_LTC_CHAT_LINK_URL`; all seven candidates
|
|
are enumerated in `docs/OPERATIONS.md` for operator reference.
|
|
|
|
### 7. Default-ON instance-wide; operator opt-out via env var
|
|
|
|
Per Memory #25: every new asset ships ENABLED by default on a
|
|
fresh instance. Operators wishing to refuse LTC set
|
|
`MORPHIT_INDEXER_DISABLED_ASSETS="LTC"` (or include LTC in a
|
|
comma-separated list).
|
|
|
|
The `morphit-ops init` wizard step 13 "Trade-only asset policy"
|
|
(Part 122 cp22) walks new operators through this decision at
|
|
install time; LTC surfaces in the wizard automatically because
|
|
the wizard iterates `ASSETS.filter(a => a.canBeTraded &&
|
|
!a.canPayListingFee)` from the canonical registry.
|
|
|
|
### 8. Operator-approved logo at `apps/web/static/icons/icon-ltc.svg` (updated Part 122 cp27-DD2)
|
|
|
|
Silver-gray disc with stylized "Ł" (the Polish-style L with
|
|
diagonal slash that distinguishes Litecoin's mark from a
|
|
generic L). No `<text>` elements (font-fallback rules from
|
|
ADDING-A-COIN.md). Originally shipped at cp24 as a placeholder
|
|
pending community-blessed artwork from the Litecoin Foundation;
|
|
operator-approved as-is at cp27-DD2 (Ken: "the current ltc icon
|
|
looks great, i do not think u need to change that"). Minified
|
|
via svgo to 0.4 KB while preserving viewBox. Drop-in SVG swap
|
|
remains supported with no other code changes if the Litecoin
|
|
Foundation later publishes a different mark.
|
|
|
|
## Files changed (cp24)
|
|
|
|
Code:
|
|
- `packages/asset-registry/src/index.ts` — `ASSET_TICKERS` extended; LTC `AssetEntry`
|
|
- `apps/web/src/lib/chat/payload.ts` — 4 LTC regex constants, `isValidLtcAddress` + `isValidLtcTxid`, `ChatAssetTicker` union widened, dispatcher widening, 4 dispatch gates widened, `buildPaymentUri` LTC branch (litecoin: URI scheme)
|
|
- `apps/web/src/lib/assets/registry.ts` — `validateLtc` helper, full LTC entry with `accentClass: 'text-slate-400'`
|
|
- `apps/web/src/lib/explorer/urlsCore.ts` — `LTC_TXID_RE`, `BUNDLED_LTC_CHAT_LINK_URL`
|
|
- `apps/web/src/lib/explorer/urls.ts` — `LTC` added to `ExternalAsset`, `EXPLORER_REGISTRY.LTC`
|
|
- `apps/web/src/lib/stores/instance.ts` — `chat_link_urls.ltc` field
|
|
- `apps/indexer/src/config/index.ts` — `frontendLtcChatLinkUrl` Config field + Zod schema + env-var mapping
|
|
- `apps/indexer/src/api/instance.ts` — `ltc: string | null` in `InstanceResponse`
|
|
- `apps/ops-cli/src/init/steps.ts` — `DEFAULT_LTC_CHAT_LINK_URL`, `ChatLinkExplorersResult.ltc`, LTC prompt block, `CATEGORY_B_DESCRIPTIONS` LTC entry
|
|
- `apps/ops-cli/src/init/render.ts` — `MORPHIT_FRONTEND_LTC_CHAT_LINK_URL` emission
|
|
- `apps/ops-cli/src/commands/init.ts` — LTC printReview line
|
|
- `apps/web/src/lib/components/AddressShareModal.svelte` — LTC tab + dispatches
|
|
- `apps/web/src/lib/components/FundsSentModal.svelte` — LTC tab
|
|
- `apps/web/src/lib/components/ChatMessage.svelte` — explorer dispatch, type unions widened, pill dispatches
|
|
- `apps/web/src/lib/components/ConversationView.svelte` — type unions widened
|
|
- `apps/web/src/routes/[lang]/post/+page.svelte` — LTC tooltip block
|
|
- `apps/matrix-bot/scripts/api-response-shape-smoke.ts` — `ltc` in `ChatLinkUrlsSchema`
|
|
|
|
Smokes:
|
|
- `packages/asset-registry/scripts/ltc-trade-only-smoke.ts` — NEW (13 scenarios)
|
|
- `apps/ops-cli/scripts/disabled-assets-wizard-smoke.ts` — Category-B count 2→3
|
|
- `scripts/run-smokes.sh` — `ltc-trade-only-smoke` registered
|
|
|
|
i18n:
|
|
- `apps/web/src/lib/i18n/locales/{en,es,fr,de,it,pl,ru,fa,zh-CN,zh-HK}.json` — 8 LTC keys per locale
|
|
|
|
Logo:
|
|
- `apps/web/static/icons/icon-ltc.svg` — operator-approved
|
|
stylized "Ł" on silver disc, originally shipped cp24 as
|
|
placeholder; operator approval Part 122 cp27-DD2; minified
|
|
via svgo at cp27-DD.
|
|
|
|
cp23-DD-class downstream consumers (the BCH-class bugs cp23 found, closed proactively for LTC):
|
|
- `apps/web/src/lib/prices/index.ts` — `LTC: null` in `internalStore` + `reset()`
|
|
- `apps/web/src/lib/prices/providers/coingecko.ts` — `LTC: 'litecoin'`
|
|
- `apps/web/src/lib/prices/providers/fallback.ts` — `LTC: 100`
|
|
- `apps/web/src/routes/[lang]/cheat-sheet/+page.svelte` — LTC row
|
|
- `apps/web/src/lib/payments/registry.ts` — `pay_ltc` entry
|
|
- `apps/indexer/src/indexer/handlers/operatorPaymentMethod.ts` — `pay_ltc` in `RESERVED_CANONICAL_KEYS`
|
|
- `apps/indexer/src/db/schema.sql` — comments updated
|
|
- `docs/API.md` — asset filter + example
|
|
- `docs/GRANDMA-FRIENDLY-INVESTIGATION.md` — status notes
|
|
- `apps/web/static/llms.txt` + `llms-full.txt` — references updated
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
- **Third Category-B asset shipped** — pattern fully matured.
|
|
Future trade-only additions (Dash, DOGE) will follow the
|
|
same template with even less ceremony.
|
|
- **cp23-DD class closed proactively** — for the first time
|
|
in the asset-addition lifecycle, the downstream typed-consumer
|
|
maps are touched in the SAME checkpoint as the canonical
|
|
registry, rather than days later in a follow-up DD.
|
|
- **Operator stance UX matures** — `morphit-ops init` step 13
|
|
now walks through 3 Category-B assets (USDT, BCH, LTC) in
|
|
alphabetical order with per-ticker Y/n prompts.
|
|
|
|
### Trade-offs accepted
|
|
|
|
- **Legacy `3`-prefix P2SH is BTC-shape ambiguous** (§4 above).
|
|
Wallet does chain-binding on receive. Same posture as BCH.
|
|
- **One more chat-link env var** — `MORPHIT_FRONTEND_LTC_CHAT_LINK_URL`.
|
|
Operators editing the env file have one more line; the wizard
|
|
hides this complexity behind a single prompt.
|
|
|
|
### Future revisits
|
|
|
|
- Possible MWEB awareness chip if/when MWEB-only trades become
|
|
a UX concern (not at launch — wallet-side opt-in, no Morphit
|
|
surface area).
|
|
- Same pattern extends to Dash, DOGE, etc. Each new Category-B
|
|
asset surfaces in the wizard automatically without per-asset
|
|
wizard code.
|