PRD - TON Wallet Ownership Proof.md:
- Status updated from ready-to-implement -> backend-implemented.
- Added Implementation Status section documenting what is complete
(challenge endpoint, tonProofService.ts, User model fields, 15 tests)
and what remains (frontend proof wiring, verified badge).
- Acceptance criteria updated: backend items checked, frontend pending.
Handoff - Telegram Mini App Debug - 2026-05-24.md:
- New Implemented sections for session 3:
- TON Wallet Ownership Proof backend (full detail of tonProofService,
userController changes, User model fields, 15 unit tests).
- Telegram Mini App shell dir="ltr" + smart displayName fallback.
- Socket status suppressed on /telegram paths.
- EVM WalletConnect stub card (disabled until project ID configured).
- Known Issues: TON proof updated to "frontend wiring pending";
EVM WalletConnect section added with activation steps.
- Current Git State updated to Session 3.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
24 KiB
Handoff - Telegram Mini App Debug - 2026-05-24
Scope
This handoff covers the work done after bringing the app up under the consolidated https://amn.gg URL and debugging the Telegram Mini App flow.
Primary user-reported issues:
- The red
Nbadge in the Telegram webview was interpreted as backend/socket failure. - Telegram-created users without an existing Amanat account were blocked by the link/sign-in screen instead of being treated as buyer users.
- Wallet connect did not support Telegram Wallet / TON.
- Profile email updates for Telegram-created users did not persist and did not send confirmation email.
- The page needed visible debug statistics to identify which subsystem is working.
Repositories Touched
Backend:
backend/src/models/User.tsbackend/src/services/user/userController.tsbackend/src/services/user/userControllerRoutes.tsbackend/src/services/user/userRoutes.ts
Frontend:
frontend/next.config.tsfrontend/package.jsonfrontend/yarn.lockfrontend/public/tonconnect-manifest.jsonfrontend/src/actions/account.tsfrontend/src/app/layout.tsxfrontend/src/auth/context/jwt/auth-provider.tsxfrontend/src/auth/types.tsfrontend/src/components/debug/telegram-debug-panel.tsxfrontend/src/lib/axios.tsfrontend/src/sections/account/account-general.tsxfrontend/src/sections/account/account-wallet-connection.tsxfrontend/src/types/user.tsfrontend/src/web3/tonconnect-provider.tsx
Vault:
- This file.
Implemented
Debug Statistics
Added TelegramDebugPanel to account/profile and wallet pages.
It reports:
- API URL
- Socket URL
- socket connected/disconnected state and socket id
- auth state
- user id, role, email, email verification state
- Telegram Mini App detection, platform, version, and initData presence
- saved wallet type/address
- last frontend account/wallet action and result
Visibility:
- Always visible in development.
- Visible inside Telegram Mini App.
- Visible in production browser with
?debug=1orlocalStorage.setItem('amn-debug', '1').
Red N Badge
The red N indicator is the Next.js development indicator, not the backend/socket status.
Change:
frontend/next.config.tsnow setsdevIndicators: false.
The actual socket status should be read from the debug panel or the app socket status component.
Telegram User / Buyer Flow
Frontend auth mapping was changed so users without an email are not treated as email-unverified blockers:
isEmailVerifiedis treated as true when the user has no email.- If an email exists, normal verification state applies.
This supports Telegram-created buyer accounts without forcing immediate email collection.
Profile Email Update And Verification
Backend profile update now accepts email and handles verification:
- Normalizes email to lowercase.
- Rejects duplicate email.
- Stores a six-digit verification code on the user.
- Sets
isEmailVerified=falsewhen email changes. - Attempts to send a confirmation email.
- Returns
verificationEmailQueued.
New authenticated endpoints:
POST /api/user/profile/email/resend-verificationPOST /api/user/profile/email/verify
Frontend:
updateUserProfilenow unwraps the backend{ user, verificationEmailQueued }response correctly.- Profile page shows a verification code input and resend/verify controls when a user has an unverified email.
- Debug events are emitted for profile update/resend/verify actions.
Telegram Wallet / TON Support
Frontend:
- Added
@tonconnect/ui-reactand@ton/core. - Added
TonWalletProviderin the root layout. - Added
public/tonconnect-manifest.json. - Wallet connection page now offers Telegram Wallet / TON connection inside Telegram Mini App.
- Connected TON wallet can be saved as
walletType: "ton"with provider metadata.
Backend:
- User profile schema now supports:
profile.walletType: "evm" | "ton"profile.walletProvider
- Current
/user/wallet-addresscontroller supports TON address validation. - Legacy
/users/wallet-addressroute also accepts TON. - EVM still requires signature verification.
- TON currently validates address format only and skips EVM signature.
Frontend Typecheck — All Pre-Existing Errors Resolved
All 13 pre-existing TypeScript errors in the frontend were fixed. npx tsc --noEmit now passes clean and can be used as a release gate.
Fixes applied:
src/web3/components/provider-payment.tsx— changed invalid iconsolar:wallet-money-boldtosolar:wallet-bold.src/components/payment/shkeeper-payment-widget.tsx— movedsellerIdfrommetadatato top-level payload (matchesIPaymentIntentPayload).src/sections/address/address-form.tsx— addedas unknown as Resolver<AddressFormData>double cast for Zod v4 +@hookform/resolversv5 type mismatch.src/sections/address/address-new-form.tsx— same resolver cast fix.src/sections/request-template/request-template-checkout-payment.tsx— same resolver cast fix.src/sections/request-template/request-template-new-edit-form.tsx— added explicituseForm<RequestTemplateSchemaType>generic and resolver cast.
Backend Tests for Email Verification and Wallet
Created backend/__tests__/user-profile-email-wallet.test.ts — 27 tests, all passing.
Coverage:
- Profile email update stores normalized email, sets
isEmailVerified=false, returnsverificationEmailQueued. - Duplicate email rejected with 409.
- Resend verification: fails when no email, fails when already verified, succeeds otherwise.
- Verify email code: rejects malformed, rejects expired/wrong, sets
isEmailVerified=trueon correct code. - TON wallet save: accepts valid friendly address, stores
walletType,walletAddress,walletProvider. - TON wallet save: rejects malformed address.
- EVM wallet save: rejects missing signature, rejects wrong signature.
emailService is mocked — no Resend calls are made during tests.
Email Delivery Confirmed
Resend SMTP relay verified end-to-end. Configuration: port 465 SSL (SMTP_SECURE=true), sender noreply@amn.gg. Test email delivered successfully during session.
Telegram Bot Command Handlers and Notification Foundation (Task 5.3)
Created backend/src/services/telegram/botService.ts (~480 lines).
Implemented:
sendBotMessage(chatId, text, options)— raw Telegram Bot API call with inline keyboard support.answerCallbackQuery(id, text?)— acknowledges callback queries.sendTelegramNotification(telegramUserId, text, options)— looks up activeTelegramLink, sends message, detects 403 (bot blocked by user) and marks link asstatus: 'blocked'to prevent future sends.dispatchBotUpdate(update)— routes incoming webhook updates to command handlers or callback handler.- Command handlers:
/start(welcome + Mini App button),/help,/link,/status,/requests,/offers,/payments,/settings. - Per-chat rate limiter (10 messages per 10-second window) to prevent abuse.
- Mini App buttons use
web_appinline keyboard type pointing tohttps://amn.gg/telegram/.
Modified telegramService.ts:
- Expanded
TelegramWebhookUpdatetype to includemessage.from,message.chat,callback_query.message. - Wired
handleTelegramWebhookto firedispatchBotUpdateasynchronously (dynamic import) so Telegram always receives HTTP 200 immediately.
Updated index.ts:
- Exports:
sendTelegramNotification,sendBotMessage,NotificationDeliveryResult,BotSendOptions,InlineKeyboard.
Created backend/__tests__/telegram-bot-service.test.ts — 17 tests, all passing.
Committed: "Implement Telegram bot command handlers and notification foundation (task 5.3)" — 4 files, 1092 insertions.
Telegram Bot Commands Registered
Registered bot commands with Telegram Bot API (setMyCommands):
/start— Open Amanat escrow marketplace/help— Show help and command list/link— Link your Amanat account/status— Check your active escrow status/requests— Browse service requests/offers— View your offers/payments— Check payment status/settings— Account settings
PRD — TON Wallet Ownership Proof
Created nick-doc/07 - Development/PRD - TON Wallet Ownership Proof.md.
Covers: challenge nonce endpoint, TonConnect proof request flow, backend ed25519 verification with @ton/ton + tweetnacl, new User model fields, frontend badge/CTA, migration notes, acceptance criteria, and tests.
TON Wallet Ownership Proof — Backend Implemented
Full backend implementation completed in session 3.
New file: backend/src/services/user/tonProofService.ts
- In-memory TTL challenge store keyed by
userId(5-minute TTL). generateChallenge(userId)— generates 32-byte hex nonce, returns{ payload, domain, timestamp }.verifyTonProof(userId, walletAddress, proof)— full ed25519 verification:- Nonce match and expiry check.
- Domain must equal
amn.gg. - Timestamp within ±300 s of now.
stateInitrequired; its hash must match the claimed wallet address hash (anti-substitution).- Public key extracted from wallet data cell (skip 64-bit seqno+subwallet_id, read 32-byte pubkey — works for v3/v4/v5 standard wallets).
- Signed message reconstructed:
ton-proof-item-v2/ + workChain (BE int32) + address.hash + domainLen (LE uint32) + domain + timestamp (LE int64) + payload (hex). sha256(0xff0xff + "ton-connect" + sha256(message))— verified withnacl.sign.detached.verify.- Nonce cleared only on success (allows retry on failure within TTL).
Modified backend/src/services/user/userController.ts:
updateWalletAddressextracts optionaltonProoffrom body; callsverifyTonProofwhen present; setsprofile.walletProofVerifiedandprofile.walletProofTimestamp; returnsINVALID_TON_PROOFon failure.- New
getTonProofChallengehandler callsgenerateChallenge(userId)and returns the nonce object.
Modified backend/src/services/user/userControllerRoutes.ts:
POST /api/user/wallet-address/ton-proof/challengeregistered (authenticated).
Modified backend/src/models/User.ts:
- Added
walletProofVerified?: booleanandwalletProofTimestamp?: Dateto both IUser interface and Mongoose schema.
Added @ton/ton@16.2.4, @ton/crypto@3.3.0, tweetnacl@1.0.3 to backend package.json.
New file: backend/__tests__/ton-proof.test.ts — 15 tests, all passing:
- Challenge generation (uniqueness, TTL invalidation).
- Valid proof accepted, nonce cleared (replay rejected).
- Rejection cases: no challenge, nonce mismatch, wrong domain, expired timestamp, missing stateInit, stateInit/address mismatch, bad signature, wrong keypair.
- Nonce preserved on failure (allows retry).
Telegram Mini App Shell — LTR Fix and Smart Display Name
Modified frontend/src/sections/telegram/telegram-mini-app-shell.tsx:
- Added
dir="ltr"to all three Container states (linked, unlinked, unsupported) so English content does not inherit the page-level RTL direction. - Added smart
displayNamelogic: falls back from Telegram name → auth user name →"there"if Telegram returns a generic or empty name (e.g., the literal string"Telegram user").
Socket Status — Suppressed Inside Telegram Mini App
Modified frontend/src/socket/components/socket-status.tsx:
- Added
usePathnameimport; added path-guardif (pathname?.startsWith('/telegram')) return null. - The "قطع" (disconnected) chip that briefly appeared on Mini App load was caused by normal Socket.IO connection latency (~0.5 s before handshake). Suppressing it on
/telegramroutes eliminates the false alarm without hiding useful status on other pages.
EVM WalletConnect Stub Card
Telegram Wallet is TON-only. Request Network requires EVM. MetaMask is not available in Telegram; WalletConnect is the right approach but requires a project ID from cloud.walletconnect.com.
Added EvmWalletStubCard to frontend/src/sections/account/account-wallet-connection.tsx:
- Always rendered below the TON wallet card on the Account › Wallet page.
- Shows WalletConnect logo, "به زودی" (coming soon) chip, and explanation.
- Connect button is disabled when
NEXT_PUBLIC_WALLETCONNECT_PROJECT_IDis not set; tooltip tells developer what to configure. - Button activates automatically when the env var is added — wire the wagmi
walletConnect()connector (already commented out insrc/web3/config.ts) at that point.
Rendered from frontend/src/sections/account/view/account-wallet-view.tsx.
Verification Completed
Backend:
cd backend
npm run typecheck --if-present
Result: passed.
Frontend focused tests:
cd frontend
npm test -- __tests__/account-test/account-actions.test.ts __tests__/auth/telegram-auth-action.test.ts __tests__/sections/telegram/telegram-mini-app-shell.test.tsx --runInBand
Result:
- 3 suites passed
- 38 tests passed
Diff hygiene:
git diff --check
Result: passed in backend and frontend after whitespace cleanup.
Public smoke checks completed during the session:
https://amn.gg/returned HTTP 200.https://amn.gg/tonconnect-manifest.jsonreturned HTTP 200 with JSON.https://amn.gg/socket.io/?EIO=4&transport=pollingreturned HTTP 200 polling handshake.https://amn.gg/dashboard/account/wallet/returned HTTP 200 after compilation.
Known Issues Left
TON Wallet Ownership Proof — Frontend Wiring Pending
Backend is fully implemented and tested (see "Implemented" section above, and PRD 07 - Development/PRD - TON Wallet Ownership Proof.md — status: backend-implemented).
Remaining frontend work:
- Add
getTonProofChallengeaction insrc/actions/account.ts(callsPOST /api/user/wallet-address/ton-proof/challenge). - In
handleConnectTelegramWalletinaccount-wallet-connection.tsx:- Fetch challenge nonce before opening modal.
- Call
tonConnectUI.setConnectRequestParameters({ state: 'ready', value: { tonProof: payload } }). - After connection, read
tonWallet.connectItems?.tonProof?.proofand send toPATCH /api/user/wallet-addresswithtonProoffield.
- Show "Verified ✅" badge when
walletProofVerified: true; show "Verify ownership" CTA when wallet is saved but unverified.
Until the frontend proof flow is wired, the backend accepts wallet saves without proof (legacy path — walletProofVerified will be absent/false). TON wallet addresses saved without proof must not be used for automatic payout routing.
EVM Wallet (WalletConnect) Not Yet Functional
A stub card is now rendered on the wallet page with a disabled connect button. To activate:
- Register at
cloud.walletconnect.com(free), get a project ID. - Add
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=<id>to.env.local(and server env). - Uncomment the
walletConnect()connector insrc/web3/config.ts. - Wire the connect handler in
EvmWalletStubCardto open the WalletConnect modal.
Profile Update UX Needs Manual Telegram Test
The backend email verification endpoints are implemented and covered by tests. The UI flow in the actual Telegram Mini App has not been end-to-end verified manually:
- Start with a Telegram-created buyer without email.
- Add email in profile.
- Confirm warning/verification controls appear.
- Confirm Resend works.
- Enter verification code.
- Confirm session refresh shows verified state.
Pangolin/Newt Routing Not Re-Verified
The desired public shape is one URL:
- Browser and Telegram app:
https://amn.gg - Backend proxied by path under the same host.
Expected route intent:
/*→ frontend container/service/api/*→ backend container/service/socket.io/*→ backend container/service with WebSocket support/uploads/*→ backend container/service/health→ backend container/service
If Telegram shows network errors, open https://amn.gg/?debug=1 and check the debug panel API/Socket fields.
Package Manager State
The frontend project declares Yarn 1 as package manager and yarn.lock was updated for TON dependencies.
package-lock.json was intentionally restored to avoid unrelated massive lockfile churn.
Next agent should continue using Yarn for dependency changes unless the project standard changes.
Dev Runtime Note
During dependency installation, the mounted node_modules was temporarily broken by an Alpine/Yarn install attempt involving native packages. It was repaired on the host with dependency install and the public app recovered.
If the container shows stale Next errors in logs, check for a later successful startup before treating them as current.
Current Git State At Handoff (Updated 2026-05-24 Session 3)
Backend — Session 3 Changes (Uncommitted)
New files:
src/services/user/tonProofService.ts— full TON proof verification service__tests__/ton-proof.test.ts— 15 unit tests (all passing)
Modified files:
src/models/User.ts— addedwalletProofVerified,walletProofTimestampfieldssrc/services/user/userController.ts— TON proof challenge handler + proof verification in wallet savesrc/services/user/userControllerRoutes.ts— challenge endpoint registeredpackage.json/package-lock.json—@ton/ton,@ton/crypto,tweetnacladded
Still uncommitted from earlier sessions:
src/services/user/userRoutes.ts__tests__/user-profile-email-wallet.test.ts(27 tests)
Frontend — Session 3 Changes (Uncommitted)
Modified:
src/sections/account/account-wallet-connection.tsx— addedEvmWalletStubCardcomponentsrc/sections/account/view/account-wallet-view.tsx— rendersEvmWalletStubCardsrc/sections/telegram/telegram-mini-app-shell.tsx—dir="ltr"on all containers, smartdisplayNamefallbacksrc/socket/components/socket-status.tsx— suppressed on/telegrampaths
Other files still uncommitted from earlier sessions (listed in Session 2 handoff).
Vault — Session 3 Changes (Uncommitted)
07 - Development/PRD - TON Wallet Ownership Proof.md— status updated tobackend-implemented, acceptance criteria checked08 - Operations/Handoff - Telegram Mini App Debug - 2026-05-24.md— this file
Recommended Commit Split
-
Backend commit A — user/email/wallet:
src/models/User.tssrc/services/user/userController.tssrc/services/user/userControllerRoutes.tssrc/services/user/userRoutes.ts__tests__/user-profile-email-wallet.test.ts
-
Frontend commit:
- All frontend files above.
-
Vault commit:
- All vault files above.
Before committing, rerun:
cd /Users/manwe/CascadeProjects/escrow/backend
npm run typecheck --if-present
npx jest --testPathPattern='user-profile-email-wallet|telegram-bot-service' --runInBand
cd /Users/manwe/CascadeProjects/escrow/frontend
npx tsc --noEmit -p tsconfig.json
Do not include secrets, local .env files, or regenerated package-lock.json churn.
Suggested Next Steps
- Implement TON wallet ownership proof per
07 - Development/PRD - TON Wallet Ownership Proof.md. This is the only remaining security-critical backend item. - Manually test profile email update + verification flow in the Telegram Mini App.
- Recheck Pangolin/Newt routing and confirm Mini App loads via
https://amn.gg/telegram/. - Build Telegram Mini App shell for marketplace workflows (Taskmaster task 5.4).
- Add frontend tests for
updateWalletAddressandTelegramDebugPanel. - Rebuild/redeploy frontend container after dependency changes (
@tonconnect/ui-react,@ton/core). - Commit pending vault changes (PRD file, updated handoff).
Detailed Remaining Work
1. Confirm Telegram Bot Web App URL ✓ Done
Bot commands registered via setMyCommands. Mini App buttons in /start and /help use web_app type pointing to https://amn.gg/telegram/. No BotFather URL change was needed for command dispatch.
If the menu button URL still points to an old URL, update it via BotFather → Bot Settings → Menu Button.
2. Recheck Pangolin/Newt Routing
Not touched this session. See "Known Issues Left" section above for routing checklist.
3. Finish Email Verification Test Coverage ✓ Done
27 tests in backend/__tests__/user-profile-email-wallet.test.ts cover all email verification cases. See "Implemented" section above.
4. Finish Wallet Test Coverage ✓ Done (format-only)
Backend tests for TON format validation and EVM signature enforcement are in user-profile-email-wallet.test.ts.
Ownership proof tests will be added when TonConnect proof verification is implemented (see item 5).
Recommended frontend tests still pending:
updateWalletAddresssends legacy EVM payload unchanged when no options are passed.updateWalletAddresssends TON payload without signature when{ walletType: "ton" }is passed.TelegramDebugPanelrenders socket/auth/TG fields when debug is enabled.- Account profile page renders email verification controls for an unverified email.
5. Implement TON Ownership Proof
PRD written: 07 - Development/PRD - TON Wallet Ownership Proof.md.
Implementation not started. See PRD for full spec. Summary:
- Add
yarn add @ton/ton @ton/crypto tweetnaclto backend. - Add
POST /api/user/wallet-address/ton-proof/challenge(generates TTL nonce). - Update
PATCH /api/user/wallet-addressto verify ed25519 proof whentonProofis present. - Add
profile.walletProofVerifiedandprofile.walletProofTimestampto User model. - Frontend: request proof via
tonConnectUI.connectWallet({ tonProof: payload }), send proof to backend. - Frontend: show "Verified" badge or "Verify ownership" CTA.
6. Check Profile Update UX in Telegram
Backend and tests done. Manual Telegram Mini App test not yet done:
- Start with a Telegram-created buyer without email.
- Add email in profile, confirm page does not discard it.
- Confirm warning/verification controls appear.
- Confirm Resend works and email arrives from
noreply@amn.gg. - Enter verification code, confirm
isEmailVerified=true.
7. Resolve Existing Typecheck Debt ✓ Done
All 13 pre-existing frontend TypeScript errors fixed. npx tsc --noEmit passes clean. Add it to the frontend verification gate.
8. Deployment/Container Follow-Up
Because dependencies changed in frontend/package.json and yarn.lock, the deployed frontend image/container should be rebuilt from a clean dependency install.
Recommended sequence:
cd /Users/manwe/CascadeProjects/escrow/frontend
yarn install --frozen-lockfile
yarn test __tests__/account-test/account-actions.test.ts __tests__/auth/telegram-auth-action.test.ts __tests__/sections/telegram/telegram-mini-app-shell.test.tsx --runInBand
cd /Users/manwe/CascadeProjects/escrow
docker compose build frontend backend
docker compose up -d frontend backend
If the existing compose setup relies on mounted node_modules, verify the mounted dependencies include @tonconnect/ui-react and @ton/core.
9. Spark Agent Status
The user asked to use codex-spark agents. Earlier in this session, existing subagents were already active and a fresh spark verifier could not be spawned because the agent thread limit was reached.
Next agent can continue with spark workers once capacity is available. Good isolated assignments:
- Worker A: backend tests for profile email verification.
- Worker B: backend tests for wallet address EVM/TON behavior.
- Worker C: frontend tests for debug panel and TON wallet action payload.
- Worker D: manual Telegram/Pangolin runtime verification report.
10. Safety Notes
- Do not commit Telegram bot token, Resend API key, Pangolin/Newt secret, or any
.envfile. - Do not revert unrelated vault audit files; they predate this handoff and should be reviewed as separate documentation work.
- Do not regenerate package locks casually. The frontend project declares Yarn 1 and
yarn.lockis the relevant lockfile for this change. - Keep Trezor optional; this pass did not modify Trezor safekeeping behavior.
- Payment adapter remains optional; this pass did not force SHKeeper or Request Network.