đź“– 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)
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.
See The Mechanism for how these work from a user perspective.
Gear 1: Wallet
Elena#142)Gear 2: Bulletin Board
Gear 3: Nostr
Gear 4: Notification Bot
Optional Extensions (Not Core Safety):
Gear 5: Stability Layer
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:
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:
What this means:
How it works:
Why it matters:
Problem: Venezuelan internet is unreliable. App must work when network is intermittent.
Solutions:
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()
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
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)
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
Two sources of truth:
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?
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
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
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
What: Detect incoming fiat payments to trigger covenant funding
Android approach:
SmsMessage API (read incoming SMS)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
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
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
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
Every component that touches the network needs:
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"}
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"}
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)
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.
RECEIVE_SMS permission (user must grant)Phase 0 focus: Android implementation. iOS/web/desktop defer to Phase 1+.
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.
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).
Why hard: Multiple users might register same name
Mitigation:
name#number format (number disambiguates)Elena#142, query blockchain for that specific comboElena#143)Why hard: Queue can grow large, might have stale data
Mitigation:
Why hard: Users lose phones, need to recover wallet + Cash Account
Mitigation:
Smart pestering strategy:
Implementation docs are successful if:
Conceptual (read these first):
Implementation (this section):
Research:
/knowledge/research/RS070-android-app-development.md - Design decisions, TightDS feedback| 🏠Home | ↑ Implementation | 📖 Glossary |