asgayapedia

Android App: Implementation Architecture

đź“– Unfamiliar terms? See the glossary for definitions.

Purpose: Technical reference for developers building Asgaya clients (Android, iOS, web, desktop)

Approach: Protocol-agnostic architecture with platform-specific notes where needed

Status: Phase 0 - Architecture documentation (app development not started)


Overview

The Asgaya app implements a peer-to-peer Bitcoin Cash remittance protocol with no backend servers. All coordination happens through:

Key principle: Any competent developer (not necessarily a blockchain expert) should be able to build an Asgaya client from these docs.


The Five Gears → Code Components

Conceptual Layer (What Components Do)

See The Mechanism for how these work from a user perspective.

Implementation Layer (How to Build Them)

Gear 1: Wallet

Gear 2: Bulletin Board

Gear 3: Nostr

Gear 4: Notification Bot

Optional Extensions (Not Core Safety):

Gear 5: Stability Layer


Data Flow: How the Gears Connect

Active Mode (Sender - María sends €100 to Elena)

1. MarĂ­a opens Wallet
   ↓ [User Input: Elena#142, €100]
   
2. Wallet creates covenant template
   ↓ [Covenant: recipient=Elena's address, amount=€100, buffer=7%, expiry=8h]
   
3. Bulletin Board queries for BCH sellers
   ↓ [Electrum: "Find NFTs with currency=EUR, payment_method=Bizum"]
   💡 Note: Corridor (EUR→VES) irrelevant for seller - Isabel accepts EUR regardless of where María is sending
   
4. User selects Isabel (passive seller)
   ↓ [Selection: Isabel#256, rate=0.5%, amount_limit=€500]
   
5. Nostr sends payment request to Isabel
   ↓ [Encrypted DM: covenant_id, amount=€100.50, reference=Elena#142]
   
6. Isabel's Nostr client receives, sends payment instructions
   ↓ [Encrypted DM: full_name="Isabel García", phone_number=+34600123456, reference=Elena#142, expiry=1h]
   💡 Full name critical: María's notification listener verifies "Has enviado €100 a Isabel García" matches to detect wrong-person payments
   
7. MarĂ­a pays via Bizum
   ↓ [Banking app: €100.50 to +34600123456, concept=Elena#142]
   
8. Isabel's Notification Bot detects payment
   ↓ [SMS parse: amount=€100.50, reference=Elena#142]
   
9. Notification Bot matches to covenant
   ↓ [Electrum query: "Find covenant with recipient=Elena's address"]
   
10. Notification Bot auto-funds covenant
    ↓ [Broadcast TX: lock €107 BCH into covenant]
    
11. Elena's Wallet detects funded covenant (PRIMARY: Electrum monitoring)
    ↓ [Electrum query: "Monitor my address for new covenants"]
    ↓ [Covenant detected on-chain: funded, €100 BCH locked]
    
12. Optional: Nostr notification prompts immediate query
    ↓ [Nostr DM from María: "Covenant funded" - triggers immediate Electrum query]
    ↓ [Benefit: Avoids waiting for next polling cycle, faster UX]
    ↓ [Elena's app shows: "€100 from María available, expires in 8h"]
    
đź’ˇ Electrum monitoring is canonical detection. Nostr DM is optional enhancement to reduce polling frequency.

Key observations:


Passive Mode (Merchant - Carlos receives remittance cash-outs)

1. Carlos posts listing once (setup)
   ↓ [Bulletin Board: Create NFT with payment_method=cash, currency=VES, rate=0.5%]
   đź’ˇ Note: Currency (VES) not corridor - Carlos handles remittances from Europe, US, Chile (any BCH source)
   
2. Elena (recipient) queries bulletin board
   ↓ [Electrum: "Find BCH buyers accepting cash in Caracas"]
   
3. Elena selects Carlos
   ↓ [Selection: Carlos#487, location=Caracas, hours=9am-8pm]
   
4. Elena's Wallet sends payment request (same as sender step 5)
   ↓ [Encrypted DM to Carlos: "Cash-out request: €100 BCH, reference=Elena#142"]
   
5. Carlos's Nostr client auto-replies with merchant details
   ↓ [Encrypted DM: full_name="Carlos Méndez", location="Bodega Carlos, Av. Bolívar 123, Caracas", hours="9am-8pm", bring_reference="Elena#142"]
   
6. Elena visits store (in-person)
   ↓ [Physical: Elena shows Cash Account Elena#142 in wallet]
   
7. Carlos types Elena#142 in app
   ↓ [Wallet: "Find covenant with recipient=Elena#142, type=remittance"] 
   
8. Carlos taps "Accept cash-out"
   ↓ [Covenant state change: pending → accepted]
   
9. Carlos hands Elena cash (2 million VES)
   ↓ [Physical exchange]
   
10. Both confirm transaction
    ↓ [Co-sign covenant: Elena releases BCH → Carlos receives BCH]
    
11. Carlos's Stability Layer prompts
    ↓ [UI: "Stabilize as H€, HAu, or keep BCH?"]
    
12. Carlos chooses H€
    ↓ [AnyHedge contract created, H€ tokens minted to Carlos's wallet]

Key observations:


Architecture Principles

1. No Backend (Fully Peer-to-Peer)

What this means:

How it works:

Why it matters:


2. Offline-First (Venezuelan Connectivity Reality)

Problem: Venezuelan internet is unreliable. App must work when network is intermittent.

Solutions:

A. Queue Operations When Offline

offline_queue = []

function createCovenant(recipient, amount):
  covenant = buildCovenantScript(recipient, amount)
  if (network_available):
    broadcast(covenant)
  else:
    offline_queue.push({type: "covenant", data: covenant})
  
function onNetworkReconnect():
  for item in offline_queue:
    if item.type == "covenant":
      broadcast(item.data)
    else if item.type == "nostr_message":
      sendNostrMessage(item.data)
  offline_queue.clear()

B. Cache Bulletin Board Queries

bulletin_board_cache = {
  last_updated: null,
  listings: []
}

function queryBulletinBoard():
  if (network_available):
    listings = electrumQuery("getNFTs", {...})
    bulletin_board_cache.listings = listings
    bulletin_board_cache.last_updated = now()
    return listings
  else:
    return bulletin_board_cache.listings  // Use cached data

C. Handle Electrum Timeouts Gracefully

function electrumQuery(method, params, timeout=10000):
  try:
    result = await electrum.call(method, params, {timeout})
    return result
  catch (TimeoutError):
    // Try backup server
    result = await backup_electrum.call(method, params, {timeout})
    return result
  catch (NetworkError):
    // Return cached data or queue for retry
    return getCachedOrQueue(method, params)

D. Sync State When Reconnecting

function onNetworkReconnect():
  // 1. Process offline queue
  processOfflineQueue()
  
  // 2. Sync covenant states
  my_covenants = getLocalCovenants()
  for covenant in my_covenants:
    on_chain_state = electrumQuery("getCovenantState", covenant.id)
    if (on_chain_state != covenant.local_state):
      updateLocalState(covenant.id, on_chain_state)
  
  // 3. Refresh bulletin board cache
  refreshBulletinBoard()

See: offline-first.md for complete patterns


3. State Management (What’s Local vs Blockchain)

Two sources of truth:

  1. Blockchain = canonical state (covenants, listings, Cash Accounts)
  2. Local database = performance cache (avoid repeated Electrum queries)

What’s Stored Locally (SQLite/Room)

Table: covenants

id              TEXT PRIMARY KEY    // Covenant transaction ID
recipient       TEXT                // Elena#142 or BCH address
amount          INTEGER             // Satoshis (€100 worth of BCH)
buffer          INTEGER             // 7% buffer in satoshis
expiry          INTEGER             // Block height or timestamp
state           TEXT                // "created" | "funded" | "claimed" | "expired"
created_at      INTEGER             // Local timestamp
last_synced     INTEGER             // Last blockchain check

Table: listings (bulletin board cache)

nft_id          TEXT PRIMARY KEY    // NFT UTXO identifier
cash_account    TEXT                // Isabel#256
corridor        TEXT                // "EUR→VES"
payment_method  TEXT                // "Bizum"
rate            REAL                // 0.5%
amount_limit    INTEGER             // €500
active          BOOLEAN             // Still valid?
cached_at       INTEGER             // When cached

Table: cash_accounts (resolution cache)

name            TEXT PRIMARY KEY    // "Elena#142"
address         TEXT                // BCH address (P2PKH)
registered_at   INTEGER             // Block height
verified        BOOLEAN             // Confirmed on-chain?

What’s Reconstructed from Blockchain

Covenant lifecycle:

Bulletin board freshness:

Cash Account resolution:

Trade-off: More local state = faster UX, less blockchain truth = potential drift. Solution: periodic sync (every 10 minutes or on user action).

See: state-management.md for complete patterns


External Dependencies

1. Electrum Servers (Blockchain Queries)

What: Public BCH Electrum servers for reading blockchain state

Why needed:

Recommendation: Use existing ElectrumX client library, connect to 3-5 public servers for redundancy

Alternatives:

Protocol specs: Electrum JSON-RPC (see wallet.md and bulletin-board.md)

Phase 0 testing: Run own Electrum server for controlled testing environment, then switch to public servers for production


2. Nostr Relays (P2P Messaging)

What: Public Nostr relays for encrypted P2P coordination

Why needed:

Recommendation: Raw WebSocket implementation (simpler than full Nostr SDK for limited message types). Connect to 3-5 public relays for redundancy.

Alternatives:

Protocol specs: Nostr NIP-04 (encrypted DMs) - see nostr.md


3. Bank Notification Parsing (Platform-Specific)

What: Detect incoming fiat payments to trigger covenant funding

Android approach:

iOS limitation:

Why needed:

Recommendation: Android SmsMessage API for Phase 0. No library needed, just regex patterns.

Protocol specs: SMS parsing patterns per bank - see notification-bot.md

Research completed: See /knowledge/research/RS026_android_notifications.md for Android notification architecture analysis


4. Kraken API (BCH Buying/Selling)

What: Exchange API for passive sellers to replenish BCH inventory

Why needed:

Recommendation: Direct REST API via HTTP client (OkHttp or equivalent)

Alternatives:

Protocol specs: Kraken REST API v2 - see notification-bot.md


5. CashTokens SDK (H€/HAu Stability)

What: BCH library for creating/managing fungible tokens

Why needed:

Recommendation: Use bitcoincashj or CashScript SDK (whichever has better CashTokens support)

Protocol specs: CashTokens category IDs, minting/burning transactions - see stability-layer.md

Research completed: See /knowledge/research/RS057_bitcoin_cash_laila.md (BCH/Cash Accounts deep-dive) and related RS files for BCH implementation details


6. AnyHedge Oracle (Price Feeds)

What: Decentralized oracle for EUR/BCH and XAU/BCH price feeds

Why needed:

Recommendation: Use existing AnyHedge oracle (General Protocols or equivalent)

Protocol specs: AnyHedge contract structure - see stability-layer.md


Component Documentation

Core Components (Build These First)

  1. wallet.md - Key management, Cash Accounts, covenant creation (~350 lines)
  2. bulletin-board.md - Electrum queries, listing discovery (~300 lines)
  3. nostr.md - Relay management, encrypted messaging (~250 lines)
  4. notification-bot.md - SMS parsing, auto-funding (~450 lines, most complex)
  5. stability-layer.md - H€/HAu integration (~300 lines)

Cross-Cutting Concerns

  1. state-management.md - Local persistence, covenant tracking (~250 lines)
  2. offline-first.md - Queue strategies, cache patterns (~300 lines)

Future (Phase 1+)

  1. testing.md - Unit tests, integration tests, mocks (defer until reference app exists)

Error Handling Patterns

Every component that touches the network needs:

1. Timeout Handling

function queryWithTimeout(server, query, timeout=10000):
  try:
    result = await server.call(query, {timeout})
    return {success: true, data: result}
  catch (TimeoutError):
    return {success: false, error: "timeout"}

2. Retry Logic (with Exponential Backoff)

function retryWithBackoff(operation, max_retries=3):
  for attempt in 1..max_retries:
    result = operation()
    if result.success:
      return result
    
    wait_time = (2 ^ attempt) * 1000  // 2s, 4s, 8s
    sleep(wait_time)
  
  return {success: false, error: "max_retries_exceeded"}

3. Fallback Strategies

function electrumQueryWithFallback(query):
  // Try primary server
  result = electrum_primary.call(query)
  if result.success:
    return result
  
  // Try backup servers
  for backup in electrum_backups:
    result = backup.call(query)
    if result.success:
      return result
  
  // All servers failed - use cached data or queue
  return getCachedOrQueue(query)

4. User-Facing Error Messages

function handleError(error):
  if error.type == "timeout":
    showMessage("Network slow. Retrying...")
  else if error.type == "offline":
    showMessage("Offline. Transaction queued.")
  else if error.type == "covenant_expired":
    showMessage("Payment window expired. Try again.")
  else:
    showMessage("Error: " + error.message)

See component docs for specific error scenarios.


Platform-Specific Notes

Android

iOS

Web/Desktop

Phase 0 focus: Android implementation. iOS/web/desktop defer to Phase 1+.


Key Implementation Challenges

Challenge 1: Notification Bot Reliability

Why hard: Must not miss payments (passive seller loses money)

Mitigation:

PoC validation: Tested with Raspberry Pi (early 2026) - smsbridge_loop.py was highly reliable at parsing SMS notifications. Android implementation should achieve similar reliability.

Challenge 2: Covenant State Synchronization

Why hard: Local state can drift from blockchain

Mitigation:

Optimization: Event-driven queries (user opens covenant view → query blockchain) rather than constant polling. Nostr messages trigger blockchain verification (e.g., “covenant funded” message → query to confirm).

Challenge 3: Cash Account Collisions

Why hard: Multiple users might register same name

Mitigation:

Challenge 4: Offline Queue Management

Why hard: Queue can grow large, might have stale data

Mitigation:

Challenge 5: Key Recovery UX

Why hard: Users lose phones, need to recover wallet + Cash Account

Mitigation:

Smart pestering strategy:


Success Criteria

Implementation docs are successful if:

  1. âś… Clarity: A competent developer (not blockchain expert) can build an Asgaya client
  2. âś… Completeness: All five gears have implementation guidance
  3. âś… Protocols: Electrum queries, Nostr messages, SMS patterns are specified
  4. âś… Error handling: What to do when things fail is clear
  5. âś… Platform-agnostic: Any platform can implement (with platform notes where needed)
  6. âś… AI-readable: External AI can understand and summarize the architecture

Conceptual (read these first):

Implementation (this section):

Research:


🏠 Home ↑ Implementation 📖 Glossary