Users can now tap any row in the wallet history and see the full
transaction detail, matching what the block explorer shows for the
same tx. Covers every visible activity — transfers, contact
requests, likes, posts, follows, relay proofs, contract calls.
Components
lib/api.ts
- New TxDetail interface mirroring node/api_explorer.go's
txDetail JSON (id, type, from/to + their DC addresses, µT
amount + display string, fee, block coords, gas, payload,
signature hex).
- getTxDetail(txID) with 404→null handling.
app/(app)/tx/[id].tsx — new screen
- Hero row: icon + type label + local-time timestamp
- Big amount pill (only for txs that move tokens) — signed by
the viewer's perspective (+ when you received, − when you
paid, neutral when it's someone else's tx or a non-transfer)
- Info card rows with tap-to-copy on hashes and addresses:
Tx ID, From (highlighted "you" when it's the signed-in user),
To (same), Block, Fee, Gas used (when > 0), Memo (when set)
- Collapsible Payload section — renders JSON with 2-space
indent if the node could decode it, otherwise the raw hex
- Signature copy row at the bottom (useful for debugging / audits)
- txMeta() covers all EventTypes from blockchain/types.go
(TRANSFER, CONTACT_REQUEST/ACCEPT/BLOCK, REGISTER_KEY/RELAY,
BIND_WALLET, RELAY_PROOF, BLOCK_REWARD, HEARTBEAT, CREATE_POST,
DELETE_POST, LIKE_POST/UNLIKE_POST, FOLLOW/UNFOLLOW,
CALL_CONTRACT, DEPLOY_CONTRACT, STAKE/UNSTAKE) with
distinct icons + in/out/neutral tone.
- Nested Stack layout so router.back() pops to the caller;
safeBack() fallback when entered via deep link.
app/(app)/wallet.tsx
- TxTile's outer Pressable was a no-op onPress handler; now
router.push(`/(app)/tx/${tx.hash}`). Entire row is the
touch target (icon + type + addr + time + amount).
app/(app)/_layout.tsx
- /tx/* added to hideNav regex so the detail screen is
full-screen without the 5-icon bar at the bottom.
Translation quirk
The screen is English to match the rest of the UI (what the user
just asked for in the previous commit). Handles copying via
expo-clipboard — tapping an address/hash shows "Copied" for 1.5s
with a green check, then reverts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DChain Messenger — React Native Client
E2E-encrypted mobile/desktop messenger built on the DChain blockchain stack.
Stack: React Native · Expo · NativeWind (Tailwind) · TweetNaCl · Zustand
Quick Start
cd client-app
npm install
npx expo start # opens Expo Dev Tools
# Press 'i' for iOS simulator, 'a' for Android, 'w' for web
Requirements
- Node.js 18+
- Expo Go on your phone (for Expo tunnel), or iOS/Android emulator
- A running DChain node (see root README for
docker compose up --build -d)
Project Structure
client-app/
├── app/
│ ├── _layout.tsx # Root layout — loads keys, sets up nav
│ ├── index.tsx # Welcome / onboarding
│ ├── (auth)/
│ │ ├── create.tsx # Generate new Ed25519 + X25519 keys
│ │ ├── created.tsx # Key created — export reminder
│ │ └── import.tsx # Import existing key.json
│ └── (app)/
│ ├── _layout.tsx # Tab bar — Chats · Wallet · Settings
│ ├── chats/
│ │ ├── index.tsx # Chat list with contacts
│ │ └── [id].tsx # Individual chat with E2E encryption
│ ├── requests.tsx # Incoming contact requests
│ ├── new-contact.tsx # Add contact by @username or address
│ ├── wallet.tsx # Balance + TX history + send
│ └── settings.tsx # Node URL, key export, profile
├── components/ui/ # shadcn-style components (Button, Card, Input…)
├── hooks/
│ ├── useMessages.ts # Poll relay inbox, decrypt messages
│ ├── useBalance.ts # Poll token balance
│ └── useContacts.ts # Load contacts + poll contact requests
└── lib/
├── api.ts # REST client for all DChain endpoints
├── crypto.ts # NaCl box encrypt/decrypt, Ed25519 sign
├── storage.ts # SecureStore (keys) + AsyncStorage (data)
├── store.ts # Zustand global state
├── types.ts # TypeScript interfaces
└── utils.ts # cn(), formatAmount(), relativeTime()
Cryptography
| Operation | Algorithm | Library |
|---|---|---|
| Transaction signing | Ed25519 | TweetNaCl sign |
| Key exchange | X25519 (Curve25519) | TweetNaCl box |
| Message encryption | NaCl box (XSalsa20-Poly1305) | TweetNaCl box |
| Key storage | Device secure enclave | expo-secure-store |
Messages are encrypted as:
Envelope {
sender_pub: <X25519 hex> // sender's public key
recipient_pub: <X25519 hex> // recipient's public key
nonce: <24-byte hex> // random per message
ciphertext: <hex> // NaCl box(plaintext, nonce, sender_priv, recipient_pub)
}
Connect to your node
- Start the DChain node:
docker compose up --build -d - Open the app → Settings → Node URL →
http://YOUR_IP:8081 - If using Expo Go on physical device: your PC and phone must be on the same network, or use
npx expo start --tunnel
Key File Format
The key.json exported/imported by the app:
{
"pub_key": "26018d40...", // Ed25519 public key (64 hex chars)
"priv_key": "...", // Ed25519 private key (128 hex chars)
"x25519_pub": "...", // X25519 public key (64 hex chars)
"x25519_priv": "..." // X25519 private key (64 hex chars)
}
This is the same format as the Go node's --key flag.