@www.hyperlinks.space/program-kit 1.2.91881 → 18.18.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +19 -0
- package/README.md +3 -3
- package/api/{base.ts → _base.ts} +1 -1
- package/api/wallet/_auth.ts +143 -0
- package/api/wallet/register.ts +151 -0
- package/api/wallet/status.ts +89 -0
- package/app/index.tsx +319 -5
- package/assets/images/PreviewImage.png +0 -0
- package/database/start.ts +0 -1
- package/database/wallets.ts +266 -0
- package/fullREADME.md +142 -71
- package/index.js +3 -0
- package/npmReadMe.md +3 -3
- package/package.json +7 -2
- package/scripts/test-api-base.ts +2 -2
- package/telegram/post.ts +44 -8
- package/docs/ai_and_search_bar_input.md +0 -94
- package/docs/ai_bot_messages.md +0 -124
- package/docs/blue_bar_tackling.md +0 -143
- package/docs/bot_async_streaming.md +0 -174
- package/docs/build_and_install.md +0 -129
- package/docs/database_messages.md +0 -34
- package/docs/fonts.md +0 -18
- package/docs/npm-release.md +0 -46
- package/docs/releases.md +0 -201
- package/docs/releases_github_actions.md +0 -188
- package/docs/scalability.md +0 -34
- package/docs/security_plan_raw.md +0 -244
- package/docs/security_raw.md +0 -345
- package/docs/timing_raw.md +0 -63
- package/docs/tma_logo_bar_jump_investigation.md +0 -69
- package/docs/update.md +0 -205
- package/docs/wallet_telegram_standalone_multichain_proposal.md +0 -192
- package/docs/wallets_hosting_architecture.md +0 -257
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# Unified Wallet Model: Telegram, Standalone, Multi-Chain & DLLR (TON)
|
|
2
|
-
|
|
3
|
-
This document proposes a single coherent setup for the tensions between:
|
|
4
|
-
|
|
5
|
-
- A **Telegram-first** experience (Mini App, bot confirmations, CloudStorage-assisted UX).
|
|
6
|
-
- **Standalone operation** when Telegram is unavailable, blocked, or the user simply prefers not to use it.
|
|
7
|
-
- **Non-custodial** custody: keys and mnemonics never held by our servers.
|
|
8
|
-
- **DLLR** and core product flows anchored on **TON**, where issuance and program logic are expected to live.
|
|
9
|
-
- **Multiple chains** where users may hold assets or use bridges, without fragmenting identity or safety.
|
|
10
|
-
|
|
11
|
-
It complements `wallets_hosting_architecture.md`, `security_raw.md`, and `security_plan_raw.md` by resolving “which path wins when” and how they fit together.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 1. Core idea: one logical wallet, three *surfaces*
|
|
16
|
-
|
|
17
|
-
Think in terms of **one user-owned root of trust** (mnemonic for the primary TON wallet, and optional additional key material for other chains), and **three ways to use it**:
|
|
18
|
-
|
|
19
|
-
| Surface | What it is | Best for |
|
|
20
|
-
|--------|------------|----------|
|
|
21
|
-
| **A. Telegram-hosted (TMA)** | Same non-custodial keys; encrypted material split between Telegram `SecureStorage` + `CloudStorage` (ciphertext only), identity via `initData`. | Smoothest UX inside Telegram, bot-driven tx confirmation, push-to-sign. |
|
|
22
|
-
| **B. Unhosted / standalone** | Keys only on device OS keystore / WebCrypto; no Telegram APIs required to open the app or sign. | Telegram outage, privacy preference, store-review-friendly “works without Telegram”. |
|
|
23
|
-
| **C. Connected** | External wallets via **TON Connect** (TON) and, later, analogous **WalletConnect** / chain-specific SDKs for other networks. | Power users, hardware wallets, assets already elsewhere. |
|
|
24
|
-
|
|
25
|
-
**Important:** Surfaces are **not** different custodial models. They differ only in **where keys live** and **which transport** is used for identity and sync. The backend stores **public** data (addresses, `telegram_username` ↔ address mapping when the user opts in), never mnemonics.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 2. Why Telegram alone is not enough (and how we fix it)
|
|
30
|
-
|
|
31
|
-
Telegram can be unreachable (outage, censorship, user choice). A product that *only* creates or signs inside the Mini App forces a hard dependency on Telegram for custody and signing.
|
|
32
|
-
|
|
33
|
-
**Proposal:**
|
|
34
|
-
|
|
35
|
-
1. **Default recommended path** remains: create primary **TON** wallet in TMA (best onboarding, aligns with bot + DLLR messaging).
|
|
36
|
-
2. **Mandatory parallel capability:** the same app build supports **Create / Restore wallet locally** (standalone) with **no Telegram account** and **no bot call** for key generation.
|
|
37
|
-
3. **Linking layer (optional):** if the user *has* Telegram, they can **link** `telegram_username` ↔ `wallet_address` so CloudStorage sync and bot confirmations work. If they never link, they remain fully standalone; DLLR/Ton features still work on-chain by address.
|
|
38
|
-
4. **Degraded mode:** if Telegram is down but the user already has keys on device, the app runs **full local signing** for TON (and any chain we have implemented client-side). Features that *require* the bot (e.g. push approval via Telegram) show a clear “Unavailable while Telegram is unreachable” with fallback: open pending items in TMA later, or confirm via standalone signing if the flow allows.
|
|
39
|
-
|
|
40
|
-
This matches non-custodial rules: the server never becomes the signing authority.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## 3. DLLR on TON as the canonical product wallet
|
|
45
|
-
|
|
46
|
-
**Clarification to remove confusion:**
|
|
47
|
-
|
|
48
|
-
- **Primary app wallet** = **TON** address derived from the user’s main mnemonic (or from a TON Connect wallet they set as default).
|
|
49
|
-
- **DLLR** is treated as a **TON jetton / program** (or locked-state construct per your issuance design). Balances, locks, and allocations are **read and signed on TON**.
|
|
50
|
-
- “Multi-chain” does **not** mean DLLR exists on every chain. It means:
|
|
51
|
-
- **User may connect other addresses** for portfolio view, bridges, or future features.
|
|
52
|
-
- **Product-critical flows** (rewards, locks, compliance hooks tied to DLLR) stay **TON-first**.
|
|
53
|
-
|
|
54
|
-
**UI rule:** always show a clear **“Primary (TON + DLLR)”** section, then **“Other networks”** as secondary, so expectations stay aligned with issuance on TON.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## 4. Multi-chain matrix (recommended model)
|
|
59
|
-
|
|
60
|
-
Use a single **wallet registry** in the client and the `wallets` table (as in `security_plan_raw.md`), with explicit `blockchain`, `net`, and `type`:
|
|
61
|
-
|
|
62
|
-
| Type | Example | Custody |
|
|
63
|
-
|------|---------|--------|
|
|
64
|
-
| `internal` | App-generated TON keypair | Non-custodial; keys in device/TMA storage |
|
|
65
|
-
| `tonconnect` | Tonkeeper, MyTonWallet | User’s external wallet; we only hold address + session |
|
|
66
|
-
| `walletconnect` / `evm` / `solana` (future) | MetaMask, Phantom, … | Same: address + connection state |
|
|
67
|
-
|
|
68
|
-
**Telegram-hosted vs unhosted** applies only to **`internal`** wallets:
|
|
69
|
-
|
|
70
|
-
- In TMA, `internal` wallet uses SecureStorage + CloudStorage ciphertext split.
|
|
71
|
-
- In standalone app, `internal` wallet uses only OS secure storage (same cryptography, different storage adapters).
|
|
72
|
-
|
|
73
|
-
**Connected** wallets are **always** “hosted” by the third-party provider, not by Telegram and not by us.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## 5. Identity: Telegram as optional glue, not a single gate
|
|
78
|
-
|
|
79
|
-
Today’s docs lean **Telegram-first** for onboarding. The unified model adds:
|
|
80
|
-
|
|
81
|
-
| User state | Can use app? | DLLR / TON actions |
|
|
82
|
-
|------------|--------------|--------------------|
|
|
83
|
-
| Standalone, never linked Telegram | Yes (after local create/restore) | Yes, if keys on device |
|
|
84
|
-
| Telegram user, wallet only in TMA | Yes in TMA; on mobile/web after Telegram Login | Signing in TMA; read-only elsewhere unless mnemonic imported locally (optional advanced) |
|
|
85
|
-
| Linked Telegram + local keys | Yes everywhere | Full: bot confirmations where implemented + local signing fallback |
|
|
86
|
-
|
|
87
|
-
**Backend:**
|
|
88
|
-
|
|
89
|
-
- `users.telegram_username` is **nullable** for standalone-only users, or use a separate **account id** (emailless) keyed by device-chosen identifier only for analytics—not for custody.
|
|
90
|
-
- Linking Telegram is a **deliberate** step: “Connect Telegram for notifications and faster sync.”
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 6. First run and subsequent runs (program behavior)
|
|
95
|
-
|
|
96
|
-
This section describes what the **client program** does on **cold start** (first launch or fresh install) versus **later launches** on the same install, for each major surface. It aligns with the state machine in `wallets_hosting_architecture.md` (e.g. `awallet_v1`, deploy status).
|
|
97
|
-
|
|
98
|
-
### 6.1 Shared startup sequence (all surfaces)
|
|
99
|
-
|
|
100
|
-
1. **Bootstrap UI shell** — Router loads; global providers start (network, wallet context).
|
|
101
|
-
2. **Detect environment** — `TMA` (Telegram WebApp present) vs **standalone** (Expo native / open web) vs **web + Telegram Login** (widget session).
|
|
102
|
-
3. **Resolve wallet presence** — Read local secure storage keys (`awallet_v1` or equivalent): encrypted blob for `internal` wallet, plus any **connected** wallet session handles (TON Connect).
|
|
103
|
-
4. **Branch:**
|
|
104
|
-
- **No wallet record** → onboarding (Section 6.2).
|
|
105
|
-
- **Wallet record present** → main app (Section 6.3).
|
|
106
|
-
|
|
107
|
-
Balances and DLLR/TON state are **always** refreshed asynchronously after UI is usable (do not block first paint on RPC unless product requires it).
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
### 6.2 First run (no wallet on this install)
|
|
112
|
-
|
|
113
|
-
| Entry | What the user sees | What the program does |
|
|
114
|
-
|--------|--------------------|------------------------|
|
|
115
|
-
| **Telegram Mini App** | Intro → **Create wallet** / **Restore wallet** (optional **Connect Tonkeeper** if offered). | Generates mnemonic locally; stores **wallet master key** in Telegram `SecureStorage`; stores **seed ciphertext** in `CloudStorage`; registers **public** `wallet_address` (+ `telegram_username` from `initData`) with backend. Shows address and QR immediately; may show **Deploying** for SMC/jetton setup; nudges **backup seed**. |
|
|
116
|
-
| **Standalone (native / web, no Telegram)** | Same choice: **Create** / **Restore** / **Connect** external wallet. | Generates or imports keys using **only** OS keystore / WebCrypto; **no** `initData`, **no** CloudStorage unless user later links Telegram. Optional backend call with a **non-Telegram** account id or anonymous mode until linked. |
|
|
117
|
-
| **Store mobile app (Telegram-centric onboarding)** | Per `security_raw.md`: “Create wallet in Telegram” vs “I already have a wallet” + **Log in with Telegram**. | First path deep-links to TMA; second uses **Telegram Login** to fetch **public** linkage (`username` → `wallet_address`) for **read-only** until user imports mnemonic on device (if you add that flow). |
|
|
118
|
-
|
|
119
|
-
**First run, new Telegram device (TMA):** `CloudStorage` may already hold **ciphertext** from another device, but **SecureStorage** is empty → program shows **Authorize this device** and asks for **mnemonic once**, then writes local master key and proceeds as normal.
|
|
120
|
-
|
|
121
|
-
**First run, connected wallet only (TON Connect):** No internal blob; program stores connection session + address; primary balance flows use that address until user adds an `internal` wallet.
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
### 6.3 Subsequent runs (wallet already on this device)
|
|
126
|
-
|
|
127
|
-
| Condition | Program behavior |
|
|
128
|
-
|-----------|------------------|
|
|
129
|
-
| **Encrypted blob + device key present** | **Silent load:** decrypt wallet, navigate to **home / wallet** without asking for seed. Poll `/wallet/status` or chain APIs for **deploy status**, **TON balance**, **DLLR** state. If deploy was **pending**, **retry deploy** in background (same as `wallets_hosting_architecture.md`). |
|
|
130
|
-
| **TMA + CloudStorage ciphertext + SecureStorage OK** | Same silent path; CloudStorage may sync updates from other Telegram clients. |
|
|
131
|
-
| **Standalone + keys in local secure storage** | Same as row 1; **no** Telegram dependency for open or sign. |
|
|
132
|
-
| **User opened “Log in with Telegram” on mobile** | After verified login, app loads **cached** `telegram_username` + **addresses** from API; UI is **read-first** until local signing is enabled (mnemonic import), matching your phased plan. |
|
|
133
|
-
| **Telegram unavailable (outage / blocked)** | If keys exist locally: **full app** for signing and reads that do not need the bot. If keys exist **only** in TMA on a device that cannot open Telegram: user must use **restore** on standalone build or wait for Telegram. Features that need the bot show **degraded / queue** messaging. |
|
|
134
|
-
| **App update** | Same storage keys (`awallet_v1` versioning); run **migration** if blob format bumps. Wallet survives update if paths are stable. |
|
|
135
|
-
|
|
136
|
-
**Subsequent run UX expectations:** back up seed remains **dismissible** until acknowledged; high-value actions may still route through **pending tx + bot confirmation** when Telegram is linked and the flow requires it.
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
### 6.4 Summary table
|
|
141
|
-
|
|
142
|
-
| | First run | Subsequent runs |
|
|
143
|
-
|---|-----------|-----------------|
|
|
144
|
-
| **Typical path** | Onboarding → create / restore / connect | Silent unlock → home → background balance/deploy sync |
|
|
145
|
-
| **Telegram required?** | Only for TMA path or Telegram-login shell | No, if standalone keys exist; yes for TMA-specific features |
|
|
146
|
-
| **Seed prompt** | At creation (show once) or restore; optional “authorize device” on new TMA device | Only if blob missing, storage wiped, or user hits **Restore** |
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## 7. “Perfect setup” summary (one paragraph)
|
|
151
|
-
|
|
152
|
-
**Ship one Expo app** with three entry modes: (1) **Telegram Mini App** for best-in-class onboarding, CloudStorage-backed ciphertext sync, and bot-mediated confirmations; (2) **standalone** create/restore so the app **always launches** and can sign TON (and DLLR) without Telegram; (3) **TON Connect + future multi-chain connectors** for imported liquidity and power users. Treat **TON + DLLR** as the single source of truth for product economics; treat other chains as **attached accounts**. Keep **mnemonic / keys** only on the client, **ciphertext** in CloudStorage when Telegram is used, and **public addresses + optional Telegram link** on the server. When Telegram is down, **degrade gracefully**: local signing and read paths keep working; Telegram-only steps queue or hide with clear messaging.
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
## 8. Implementation phases (aligned with existing roadmap)
|
|
157
|
-
|
|
158
|
-
1. **Phase A — Standalone parity (minimum viable resilience)**
|
|
159
|
-
- Unhosted TON create/restore in **Expo web + native** without Telegram.
|
|
160
|
-
- Same `WalletService` abstraction as in `wallets_hosting_architecture.md`; storage backend switches on environment (TMA vs native).
|
|
161
|
-
- Optional “Link Telegram” after the fact.
|
|
162
|
-
|
|
163
|
-
2. **Phase B — Linking & DB**
|
|
164
|
-
- Nullable Telegram on `users`; `wallets` rows for `internal` + `tonconnect`.
|
|
165
|
-
- Telegram Login only for users who want cross-surface sync.
|
|
166
|
-
|
|
167
|
-
3. **Phase C — Bot confirmations + queue**
|
|
168
|
-
- Pending tx from any client; confirmation in TMA when available; standalone users complete via **local sign** without bot where the protocol allows.
|
|
169
|
-
|
|
170
|
-
4. **Phase D — Multi-chain read + selective write**
|
|
171
|
-
- Add connected chains for **display** first; add signing per chain as product requires.
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
|
-
## 9. Security notes (unchanged principles)
|
|
176
|
-
|
|
177
|
-
- No mnemonic on server; CloudStorage holds **ciphertext only**; device-bound keys decrypt.
|
|
178
|
-
- Telegram Login proves **identity**, not possession of keys.
|
|
179
|
-
- Standalone users rely on **seed backup** exactly as in self-custody best practice.
|
|
180
|
-
- DLLR issuance rules remain **on-chain** on TON; our app is a **client**, not an issuer.
|
|
181
|
-
|
|
182
|
-
---
|
|
183
|
-
|
|
184
|
-
## 10. Open decisions (to refine with product/legal)
|
|
185
|
-
|
|
186
|
-
- Whether standalone users get **full** DLLR program participation or **subset** until KYC/Telegram link (if required by issuance policy).
|
|
187
|
-
- Exact **jetton master** and **wallet v4/v5** choices for DLLR display and deploy flows.
|
|
188
|
-
- Whether **one mnemonic** derives only TON or also other chains (prefer **separate mnemonics** per chain unless using a documented multi-chain HD profile).
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
*Proposal doc; iterate with team and adjust table/column names to match the actual migration from `security_plan_raw.md`.*
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
# HyperlinksSpace — Wallet Architecture Doc
|
|
2
|
-
|
|
3
|
-
> High-level system design, UI flow principles, and implementation thoughts.
|
|
4
|
-
> Target: non-custodial TON wallet built into the HyperlinksSpace app (Flutter/TMA/Web).
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## 1. Guiding Principles
|
|
9
|
-
|
|
10
|
-
- **Non-custodial by default.** The mnemonic (seed phrase) never touches the server. Key generation and signing happen on-device.
|
|
11
|
-
- **Telegram-first identity.** Inside Telegram, the user's Telegram account is the identity anchor. Outside Telegram (Windows desktop, Web), Telegram Login is used as the identity bridge.
|
|
12
|
-
- **Small, working steps.** Each wallet feature ships as an isolated, backward-compatible unit that can be deployed without touching existing bot or app flows.
|
|
13
|
-
- **Stable coin built-in.** The wallet is designed from day one to display and eventually allocate DLLR (or another locked stable) alongside the TON balance.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 2. Wallet Types and Entry Points
|
|
18
|
-
|
|
19
|
-
The app supports two wallet modes:
|
|
20
|
-
|
|
21
|
-
| Mode | Description | Who uses it |
|
|
22
|
-
|---|---|---|
|
|
23
|
-
| **Unhosted (non-custodial)** | Created inside the app, keys live on device | New users with no existing wallet |
|
|
24
|
-
| **TON Connect** | Connects an existing external wallet (Tonkeeper, MyTonWallet, etc.) | Power users with existing wallets |
|
|
25
|
-
|
|
26
|
-
TON Connect is treated as an **additional/advanced feature**, not the default. The primary flow is always the unhosted wallet.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## 3. Wallet State Machine
|
|
31
|
-
|
|
32
|
-
Every wallet instance moves through these states:
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
[ No Wallet ]
|
|
36
|
-
│
|
|
37
|
-
├──── "Create wallet" ──────► [ Generating ]
|
|
38
|
-
│ │
|
|
39
|
-
└──── "Restore wallet" ────────────►│
|
|
40
|
-
▼
|
|
41
|
-
[ Created ]
|
|
42
|
-
(address shown instantly, QR + copy)
|
|
43
|
-
│
|
|
44
|
-
▼
|
|
45
|
-
[ Deploying ]
|
|
46
|
-
(SMC deploy call in progress)
|
|
47
|
-
│
|
|
48
|
-
┌─────────┴─────────┐
|
|
49
|
-
▼ ▼
|
|
50
|
-
[ Ready ] [ Deploy Failed ]
|
|
51
|
-
(fully operational) (retry available)
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**State storage key:** `awallet_v1` (encrypted blob in SecureStorage)
|
|
55
|
-
**Metadata stored separately (plaintext):**
|
|
56
|
-
```
|
|
57
|
-
wallet_address
|
|
58
|
-
created_at
|
|
59
|
-
last_seen_at
|
|
60
|
-
deploy_status ← "pending" | "deployed" | "failed"
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## 4. First Launch — Unhosted Wallet
|
|
66
|
-
|
|
67
|
-
**Goal:** User has no wallet. They open the app for the first time (any platform).
|
|
68
|
-
|
|
69
|
-
### UI Flow
|
|
70
|
-
|
|
71
|
-
1. **Wallet tab / panel opens** → app checks `awallet_v1` in local SecureStorage.
|
|
72
|
-
2. Nothing found → show two CTAs:
|
|
73
|
-
- **"Create new wallet"** (primary, prominent)
|
|
74
|
-
- **"Restore wallet"** (secondary, text link — visible only if device has an encrypted blob from a previous session or the user chooses to enter a mnemonic)
|
|
75
|
-
3. User taps **"Create new wallet"**:
|
|
76
|
-
- Spinner shown: _"Creating wallet…"_
|
|
77
|
-
- App generates a BIP39 mnemonic + TON keypair **entirely in-memory** (no server call at this step).
|
|
78
|
-
- Address is computed and displayed **instantly**.
|
|
79
|
-
- Encrypted blob is written to SecureStorage.
|
|
80
|
-
4. App shows **"Your wallet is ready"** screen:
|
|
81
|
-
- Address (truncated + copy button)
|
|
82
|
-
- QR code
|
|
83
|
-
- DLLR status: `Allocated / Locked / Available` (placeholders until deploy completes)
|
|
84
|
-
- `"Deploying…"` status badge
|
|
85
|
-
5. SMC deploy call fires in the background (POST `/wallet/deploy`). When complete, status badge updates to ✅ `"Active"`.
|
|
86
|
-
6. A **"Back up your seed phrase"** nudge is shown — non-blocking, dismissible, but persistent until the user acknowledges.
|
|
87
|
-
|
|
88
|
-
### Key decisions
|
|
89
|
-
- Address generation is instant and shown before deploy. This is intentional UX — users can copy the address to receive funds immediately, even before the contract is deployed.
|
|
90
|
-
- Mnemonic is shown **once**, at creation time. After acknowledgement it is never shown again (only recoverable via "Export seed phrase" with auth).
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## 5. Second Launch — Loading Existing Wallet
|
|
95
|
-
|
|
96
|
-
**Goal:** User returns to the app on the same device. Wallet was created previously.
|
|
97
|
-
|
|
98
|
-
### UI Flow
|
|
99
|
-
|
|
100
|
-
1. App reads `awallet_v1` from SecureStorage on startup.
|
|
101
|
-
2. Encrypted blob found → decrypt using device key (Secure Enclave / Android Keystore).
|
|
102
|
-
3. Wallet panel loads directly to **Ready state** — no mnemonic prompt needed.
|
|
103
|
-
4. App polls `/wallet/status?address=...` to refresh balances and deploy status.
|
|
104
|
-
5. If `deploy_status === "pending"` (e.g., deploy was interrupted), app auto-retries the deploy silently.
|
|
105
|
-
|
|
106
|
-
### Key decisions
|
|
107
|
-
- The device key (used to decrypt the blob) **never leaves the device**. It is stored in the OS-level secure keystore.
|
|
108
|
-
- No mnemonic entry is needed on the same device — the encrypted blob handles re-authentication transparently.
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## 6. New Device / Re-connect Scenario (Mnemonic Required)
|
|
113
|
-
|
|
114
|
-
**Goal:** User opens the app on a new phone, new PC, or after clearing app data.
|
|
115
|
-
|
|
116
|
-
### UI Flow
|
|
117
|
-
|
|
118
|
-
1. App finds no `awallet_v1` in SecureStorage (it's a fresh install).
|
|
119
|
-
2. Wallet panel shows:
|
|
120
|
-
- **"Create new wallet"** (primary)
|
|
121
|
-
- **"Restore wallet"** (secondary, prominent here)
|
|
122
|
-
3. User taps **"Restore wallet"** → input field: _"Enter your 24-word seed phrase"_
|
|
123
|
-
4. Words entered → app validates mnemonic → re-derives keypair → re-encrypts blob into the new device's SecureStorage.
|
|
124
|
-
5. App calls `/wallet/restore` to confirm address matches expectation.
|
|
125
|
-
6. Wallet loads at **Ready state** (deploy was already done on the original device).
|
|
126
|
-
|
|
127
|
-
### Key decisions
|
|
128
|
-
- The mnemonic is the **single recovery factor**. There is no server-side recovery.
|
|
129
|
-
- Mnemonic input should use a native secure text field (no clipboard suggestions, no autocorrect logging).
|
|
130
|
-
- CloudStorage (Telegram's `telegram.cloudStorage` API) can optionally store the **ciphertext** (not the key), so restore can be assisted without the user typing all 24 words. The device key is still required to decrypt it — CloudStorage alone is not sufficient to reconstruct the wallet.
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 7. Telegram Wallet — Inside Telegram (TMA)
|
|
135
|
-
|
|
136
|
-
**Goal:** User accesses the wallet via the Telegram Mini App (TMA).
|
|
137
|
-
|
|
138
|
-
### How identity and storage work inside TMA
|
|
139
|
-
|
|
140
|
-
- **Identity:** `initData.user.id` (Telegram user ID) is the identity anchor. No separate login needed.
|
|
141
|
-
- **Storage:**
|
|
142
|
-
- `telegram.cloudStorage` is used for the encrypted wallet blob — it is synced across Telegram sessions automatically.
|
|
143
|
-
- The device key (to decrypt the blob) is stored in the browser's IndexedDB / WebCrypto key store scoped to the TMA origin.
|
|
144
|
-
- **First launch in TMA:** Same as Section 4, but blob goes to `cloudStorage` instead of native SecureStorage.
|
|
145
|
-
- **Re-open in TMA on same device:** Blob in `cloudStorage` + device key in IndexedDB → loads wallet silently.
|
|
146
|
-
- **TMA on a new device:** CloudStorage has the ciphertext, but the device key is absent → user is prompted to enter mnemonic once. New device key is generated and stored. From then on, that device works silently.
|
|
147
|
-
|
|
148
|
-
### Key decisions
|
|
149
|
-
- `telegram.cloudStorage` is **not end-to-end encrypted by Telegram** — it is accessible to the bot's server-side in theory. This is why we store only the **ciphertext** there, not the plaintext key or mnemonic.
|
|
150
|
-
- The split: _ciphertext in CloudStorage, key in device_ ensures neither half alone can reconstruct the wallet.
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## 8. Outside Telegram — Web / Windows Setup
|
|
155
|
-
|
|
156
|
-
**Goal:** User uses the app via browser or Windows desktop (Electron/Tauri wrapper), outside of Telegram context.
|
|
157
|
-
|
|
158
|
-
### How identity works outside TMA
|
|
159
|
-
|
|
160
|
-
Since there is no `initData` from Telegram, identity is established via **Telegram Login Widget** (OAuth-style flow):
|
|
161
|
-
|
|
162
|
-
1. User is shown a "Log in with Telegram" button.
|
|
163
|
-
2. Telegram sends a signed hash to the app confirming the user's Telegram ID and username.
|
|
164
|
-
3. App uses the Telegram ID as the identity anchor — same as inside TMA.
|
|
165
|
-
|
|
166
|
-
### Storage outside Telegram
|
|
167
|
-
|
|
168
|
-
- **Web browser:** Encrypted blob is stored in `localStorage` (or IndexedDB for larger payloads). Device key in WebCrypto non-extractable key store.
|
|
169
|
-
- **Windows desktop:** Encrypted blob stored in the OS credential manager or app's local data directory. Device key in Windows DPAPI or Keychain equivalent.
|
|
170
|
-
|
|
171
|
-
### First launch on Windows
|
|
172
|
-
|
|
173
|
-
1. App opens → Telegram Login flow → identity confirmed.
|
|
174
|
-
2. App checks local storage for `awallet_v1`.
|
|
175
|
-
3. **No wallet found:** Same "Create / Restore" UI as Section 4.
|
|
176
|
-
4. **Wallet found (transferred or restored):** Loads to Ready state.
|
|
177
|
-
|
|
178
|
-
### Re-launch on Windows
|
|
179
|
-
|
|
180
|
-
Same device → blob in local storage + device key still present → silent load, no mnemonic needed.
|
|
181
|
-
|
|
182
|
-
### Key decisions
|
|
183
|
-
- Windows is primarily a **reading/management surface** — send, receive, view balances. Heavy transaction flows remain on mobile/TMA first.
|
|
184
|
-
- The GitHub auto-updater (workflow-based releases) is already in place for the Windows build. Wallet state must survive app updates — storage paths must not change across versions, or migration logic must be included.
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## 9. API Contract (Wallet Endpoints)
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
POST /wallet/create
|
|
192
|
-
Body: { address, encrypted_blob, public_key }
|
|
193
|
-
Response: { ok: true }
|
|
194
|
-
|
|
195
|
-
POST /wallet/deploy
|
|
196
|
-
Body: { address }
|
|
197
|
-
Response: { status: "pending" | "deployed" | "failed" }
|
|
198
|
-
|
|
199
|
-
GET /wallet/status?address=...
|
|
200
|
-
Response: { deployed: bool, dllr_status: {...}, balances: { ton, dllr } }
|
|
201
|
-
|
|
202
|
-
POST /wallet/restore
|
|
203
|
-
Body: { encrypted_blob }
|
|
204
|
-
Response: { address }
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
The backend is **optional** for the read path — balances can be fetched directly from TON APIs (toncenter/tonapi) on the client side. The backend is primarily needed for:
|
|
208
|
-
- SMC deploy coordination
|
|
209
|
-
- DLLR allocation logic
|
|
210
|
-
- Caching and rate-limit protection for API calls
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## 10. WalletService Abstraction (Flutter)
|
|
215
|
-
|
|
216
|
-
The Flutter app uses a `WalletService` interface so the UI never depends directly on whether we're in mock, front-only (direct TON API), or backend-connected mode:
|
|
217
|
-
|
|
218
|
-
```dart
|
|
219
|
-
abstract class WalletService {
|
|
220
|
-
Future<WalletState> loadFromStorage();
|
|
221
|
-
Stream<WalletStatus> watchStatus(String address);
|
|
222
|
-
Future<WalletInfo> createWallet();
|
|
223
|
-
Future<WalletInfo> restoreWallet(String mnemonic);
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
Swap between implementations via a flag (`kUseMockWalletState` for dev, env-driven for prod). No UI refactor needed when switching providers.
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
## 11. Security Summary
|
|
232
|
-
|
|
233
|
-
| Concern | Approach |
|
|
234
|
-
|---|---|
|
|
235
|
-
| Mnemonic exposure | Shown once at creation, never stored in plaintext |
|
|
236
|
-
| Key storage | OS Secure Enclave / Android Keystore / WebCrypto non-extractable |
|
|
237
|
-
| Server-side secrets | None — server never sees mnemonic or private key |
|
|
238
|
-
| Cross-device restore | Mnemonic re-entry required OR ciphertext from CloudStorage + device key |
|
|
239
|
-
| Telegram identity outside TMA | Telegram Login Widget (signed hash verification) |
|
|
240
|
-
| Duplicate deploy | State machine prevents re-deploy if `deploy_status === "deployed"` |
|
|
241
|
-
| App update survivability | Storage keys versioned (`awallet_v1`), migration path required for `v2` |
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## 12. Phase Roadmap
|
|
246
|
-
|
|
247
|
-
| Phase | Scope |
|
|
248
|
-
|---|---|
|
|
249
|
-
| **Phase 1** | Unhosted wallet: create, display address, deploy SMC, show TON balance |
|
|
250
|
-
| **Phase 2** | DLLR integration: allocated/locked/available display, stable coin status |
|
|
251
|
-
| **Phase 3** | TON Connect (connect existing wallets as secondary option) |
|
|
252
|
-
| **Phase 4** | Send/receive flows, transaction history |
|
|
253
|
-
| **Phase 5** | Cross-device CloudStorage assist, backup/export UX hardening |
|
|
254
|
-
|
|
255
|
-
---
|
|
256
|
-
|
|
257
|
-
*Last updated: April 2026. Maintained in repo at `docs/wallets_hosting_architecture.md`.*
|