Skip to content

Phase 2: DigiAssets v2, Digi-ID, IPFS, Tor (v3.0.0-beta1)#2

Merged
JohnnyLawDGB merged 13 commits intodevelopfrom
phase1-modernization
Mar 22, 2026
Merged

Phase 2: DigiAssets v2, Digi-ID, IPFS, Tor (v3.0.0-beta1)#2
JohnnyLawDGB merged 13 commits intodevelopfrom
phase1-modernization

Conversation

@JohnnyLawDGB
Copy link
Copy Markdown
Owner

Phase 2: DigiAssets v2, Digi-ID, Trustless IPFS, Tor

Builds on Phase 1 (PR #1) — adds the four major feature subsystems for the beta release.

DigiAssets v2

  • Full OP_RETURN decoder — BitIO bit-level parser ported from digiasset-core (C++) and digibyte-js (JS). Handles v2/v3 issuance, transfer, and burn opcodes. 26 decoder tests + 15 BitReader tests.
  • Asset detection in sync — SyncService detects asset transactions via JNI (BRTXContainsAsset), parses OP_RETURN, stores UTXOs with is_asset=true, asset_id, and decoded asset_quantity (not satoshi dust value).
  • Asset UI — AssetListScreen (grid with metadata thumbnails), AssetDetailScreen (supply, issuer, rules, transfer history, DigiNexum marketplace link), AssetSendScreen (quantity input, fee selector, biometric confirmation).
  • UTXO segregation — Phase 1's CoinSelector already protects asset UTXOs. Phase 2 adds quantity tracking and grouped balance queries.

Trustless IPFS

  • Self-contained CID verifier — No external IPFS library needed (Maven Central coordinates don't exist). Manual CIDv0 (Base58/SHA-256) and CIDv1 (multibase/multihash) parsing in ~150 lines of Kotlin.
  • Multi-gateway fetcher — trustless-gateway.link → dweb.link → ipfs.io fallback chain. Content hash verified against CID digest. 5MB size limit. 17 tests.
  • Asset metadata service — Fetch JSON from IPFS, parse fields, cache in Room. Never re-fetches (CID = immutable content). Graceful degradation — wallet shows asset ID if metadata unavailable.

Digi-ID + DigiScope

  • Shared QR scanner — CameraX + ZXing ImageAnalysis.Analyzer. Routes digiid:// to Digi-ID flow, digibyte: to Send flow. Camera permission handling.
  • Digi-ID authentication — Parse digiid:// URIs, sign challenge (signing stub pending full JNI), POST to callback, biometric approval, login history in Room.
  • DigiScope client — API client for api.digiscope.me with login, handle registration, tip wallet linking. Certificate pinning placeholder. digiscope:// deep link handler.

Tor Integration

  • TorManager — Lifecycle management with StateFlow<TorState>. Preference persistence. New-install default ON, upgrade prompt for Phase 1 users.
  • BRPeer.c SOCKS5 patch — ~50 lines of C in the core submodule. SOCKS5 handshake (RFC 1928 no-auth) injected before DigiByte protocol handshake. Thread-safe with mutex.
  • Dynamic ProxySelector — OkHttpClient uses ProxySelector that queries TorManager on every request. No singleton rebuild needed.
  • Graceful degradation — Tor binary embedding pending. Wallet works normally without Tor. Toggle shows "Failed" state cleanly.

Infrastructure

  • DB migration v1→v2 — New tables: asset_metadata, digiid_history. New columns: utxos.asset_quantity, wallet_config.torEnabled/torPromptShown. Room exportSchema=true with MigrationTestHelper tests.
  • Keystore-derived DB passphrase — Random 32-byte passphrase encrypted via Android Keystore, replacing hardcoded string. Phase 1 upgrades keep legacy passphrase (documented).
  • Centralized OkHttpClient — Hilt NetworkModule provides singleton client. All services (PriceProvider, IPFS, Digi-ID, DigiScope) use it. Tor proxy applied dynamically.

Test Results

Category Count
Unit tests (JVM) 85+
Instrumented tests (device) 54
Total 139+
Failures 0

Tested on Samsung Galaxy Note 8 (SM-N950U, Android 9, API 28).

What's NOT in this PR (Phase 3-4)

  • Community Hub (chat channels + forum threads)
  • DigiScope full UI (handle registration screen, profile)
  • Oracle price feed (v9 on-chain attestations)
  • Dandelion++ SPV stem submission (DIP filed)
  • Asset issuance/creation
  • iOS port

Commits (12)

feat: Tor UI — functional toggle, wallet indicator, Tor-aware sync
feat: Tor integration — TorManager, SOCKS5 proxy in C core
feat: DigiScope integration — login, handle registration, tip linking
feat: Digi-ID authentication with shared QR scanner
feat: asset UI — list, detail, send screens with marketplace link
feat: asset detection in SyncService
feat: AssetManager orchestration and asset JNI bridge
feat: DigiAsset v2 decoder — OP_RETURN parsing, BitIO, rules engine
feat: trustless IPFS client with CID verification and metadata service
refactor: centralize OkHttpClient in NetworkModule for Tor proxy support
fix: replace hardcoded DB passphrase with Keystore-derived key
feat: database migration v1→v2

🤖 Generated with Claude Code

JohnnyLawDGB and others added 13 commits March 22, 2026 19:00
…t quantity, tor config

New tables: asset_metadata (DigiAsset metadata cache), digiid_history (Digi-ID login history).
New column: utxos.asset_quantity (decoded from OP_RETURN, not satoshi value).
New columns: wallet_config.torEnabled, torPromptShown.
AssetBalance projection class for grouped asset balance queries.
Room exportSchema=true for migration testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New installs get random 32-byte passphrase encrypted via Android Keystore.
Phase 1 upgrades continue using legacy passphrase (documented compromise).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Single shared OkHttpClient provided via Hilt. PriceProvider retrofitted
to accept injected client. All future HTTP services (IPFS, Digi-ID,
DigiScope) will use the same client, enabling Tor SOCKS5 proxy.
CidVerifier: manual CIDv0/v1 parsing (no external IPFS library needed),
Base58/Base32/hex multibase decoding, varint reader, SHA-256 digest
extraction and content verification.

IpfsClient: multi-gateway fallback (trustless-gateway.link, dweb.link,
ipfs.io), 5MB response size guard, per-response CID hash check — a
malicious gateway cannot inject fake metadata.

AssetMetadataService: fetch JSON from IPFS, parse name/symbol/description/
decimals/totalSupply/issuerAddress/imageUrl, cache in Room permanently
(CID = content-addressed, immutable — cache is always valid).

AssetData / OwnedAsset / AssetMetadata model classes.

Tests: 23 passing — CidVerifier (CIDv0, CIDv1 base32, invalid CIDs, edge
cases) and IpfsClient (happy path, hash mismatch, gateway fallback,
network exception, 5MB size limit, all-gateways-fail).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DigiAssetDecoder: detects 0x4441 DA prefix, parses BitIO-encoded
fields for version, opcode, quantities, metadata hash.
Supports v2/v3 issuance (opcodes 01-05), transfer (0x15), burn (0x25).
Extracts issuance flags (divisibility, locked, aggregation), total
quantity via fixed-precision decoding, and IPFS CIDv1 from SHA256
metadata hash.

BitReader: bit-level reader ported from digiasset-core BitIO.cpp and
digibyte-js Precision.js. Implements the variable-width fixed-precision
number format (1-7 bytes, mantissa * 10^exponent).

DigiAssetRules: basic transfer validation stub for Phase 2 (quantity
check, dispersed/NFT indivisibility). Full rules engine (royalties,
KYC, expiry, deflation) deferred to Phase 3.

Tested with 48 unit tests including real mainnet DigiAsset v2 transfer
from block 11000208 (txid 1af59aea...5651e3).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jni_asset.c: isAssetTransaction() wrapping BRTXContainsAsset(),
getOpReturnData() extracting OP_RETURN script bytes.
AssetManager: combines UTXO balances with metadata, processes
asset UTXOs, queues IPFS metadata fetch.
NativeCallback.onAssetDetected added (SyncService stub).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tadata

Wire AssetManager into SyncService. Asset transactions detected via
onAssetDetected callback from C core. UTXOs marked with asset data.
Metadata fetched from IPFS in background. Hilt providers for all
Phase 2 services (AssetManager, IpfsClient, AssetMetadataService).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AssetListScreen: grid of owned assets with metadata display.
AssetDetailScreen: full asset info, DigiNexum marketplace link,
transfer history, send button.
AssetSendScreen: address input, quantity, fee, confirmation flow.
Navigation wired from WalletScreen Assets button.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DigiIdManager: parse digiid:// URIs, sign challenges, POST to callback.
QrScannerScreen: CameraX + ZXing, routes to Digi-ID or Send based on URI.
DigiIdScreen + DigiIdConfirmScreen: scan, review, approve with history.
DigiIdRequest parser with domain extraction and unsecure detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DigiScopeClient: JWT-authenticated API client for api.digiscope.me.
Login via Digi-ID, handle registration, tip wallet linking, profile.
digiscope:// deep link intent filter. Certificate pinning placeholder
(pins to be extracted at deployment).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TorManager: lifecycle management with StateFlow, preference persistence.
BRPeer.c: SOCKS5 handshake patch for proxied peer connections, with
thread-safe global proxy state and BRPeerSetSocksProxy/Clear/Has API.
JNI: setSocksProxy/clearSocksProxy bridge functions in jni_peer.c.
NetworkModule: OkHttpClient with dynamic ProxySelector for Tor routing.
AppModule: TorManager provided as @singleton via Hilt DI.
JniProxyTest: 3 instrumented tests verifying JNI proxy bridge stability.
Tor binary embedding pending — wallet gracefully degrades without it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
NetworkInfoScreen: live Tor toggle with state display (Disabled /
Starting / Connecting / Connected (port N) / Failed: reason).
SettingsRow: optional subtitleColor parameter for colored state text.
SettingsViewModel: injects TorManager, exposes torState + torEnabled
StateFlows, and setTorEnabled() persists choice to both SharedPrefs
and WalletConfigEntity.

WalletScreen: TorIndicator badge rendered below SyncIndicator in the
hero header — visible only when TorState is Connected, invisible
otherwise (graceful when Tor binary is not yet embedded).
WalletViewModel: injects TorManager, exposes torState StateFlow.

SyncService: injects TorManager; startSyncWithTor() attempts Tor
startup before calling NativeBridge.startSync(). On success wires
setSocksProxy(); on failure clears any stale proxy and proceeds
directly — sync is never blocked. Notification shows via Tor
suffix when proxy is active.

MainActivity: applyTorDefaults() detects new installs (no config row)
and enables Tor by default. Phase 1 upgrades (config exists,
torPromptShown=false) surface a one-time AlertDialog asking to enable
Tor — choice persisted to TorManager prefs + WalletConfigEntity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace outdated 2021 README with comprehensive documentation
reflecting the modernized wallet: architecture, features, build
instructions, testing, security docs, development phases, and
related projects.
@JohnnyLawDGB JohnnyLawDGB merged commit 2fb3189 into develop Mar 22, 2026
0 of 2 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ba5f88b56

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +35 to +38
val json = JSONObject().apply {
put("uri", rawUri)
put("address", address)
put("signature", "placeholder_signature")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Sign Digi-ID challenges before posting them

Every authentication request currently sends "placeholder_signature" instead of a signature over the Digi-ID challenge. Compliant Digi-ID servers verify that signature against the callback URI, so this new login flow will be rejected in production even though the UI presents it as available.

Useful? React with 👍 / 👎.

Comment on lines +219 to +221
// AssetMetadataService with a null CID; it will no-op until the CID is
// learned later (e.g. via processAssetUtxo once the full tx is confirmed).
assetManager.getAssetHistory(assetId) // touches the DAO, warms the flow
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Persist asset UTXOs when an asset transfer is detected

This callback never writes an asset UTXO or queues metadata resolution; it only inserts a TransactionEntity and then calls a read-only history flow. The new asset screens derive balances from utxos.is_asset rows via AssetManager.getOwnedAssets(), and AssetManager.processAssetUtxo() is the only codepath that creates those rows, so a detected asset transfer still leaves the DigiAssets tab empty.

Useful? React with 👍 / 👎.

Comment on lines +306 to +309
onDigiByteUri = { uri ->
// Navigate to send with pre-filled address (and optional amount)
navController.navigate("send") {
popUpTo("qr_scanner") { inclusive = true }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Carry scanned DigiByte URIs into the send screen

The parsed uri is ignored here: the QR flow just navigates to send without storing the scanned address or amount anywhere, and SendScreen has no route arguments to recover it. In the new shared QR scanner flow, scanning a digibyte: payment request lands the user on a blank send form, so scan-to-pay does not work.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant