|
| 1 | +--- |
| 2 | +title: "Session 15: dApp Architecture: From Wallet to Backend - Notes" |
| 3 | +sidebar_label: Session Notes |
| 4 | +slug: /working-group/q2-2026/sessions/15-dapp-architecture-demo/session-notes |
| 5 | +--- |
| 6 | + |
| 7 | +# Session 15: dApp Architecture: From Wallet to Backend - Notes |
| 8 | + |
| 9 | +Notes and architectural breakdown for building full-stack applications on Cardano using Mesh SDK and Blockfrost. |
| 10 | + |
| 11 | +## Overview |
| 12 | +Building on Cardano requires a different mental model than traditional "server-centric" applications. In a dApp, the blockchain is the **immutable source of truth**, while the frontend, wallet, and backend act as specialized interfaces to that truth. |
| 13 | + |
| 14 | +--- |
| 15 | + |
| 16 | +## 🏗 Sequence Diagram: The Full Flow |
| 17 | + |
| 18 | +The following diagram illustrates the interaction between the four layers during a typical payment-to-mint lifecycle. |
| 19 | + |
| 20 | +```mermaid |
| 21 | +sequenceDiagram |
| 22 | + participant U as User / Wallet |
| 23 | + participant F as Frontend (Next.js) |
| 24 | + participant B as Backend (API) |
| 25 | + participant L as Blockchain (Cardano) |
| 26 | + participant BF as Blockfrost API |
| 27 | +
|
| 28 | + U->>F: 1. Click "Send Payment" |
| 29 | + F->>U: 2. Request Signature (CIP-30) |
| 30 | + U->>U: 3. User Approves / Signs |
| 31 | + U->>L: 4. Submit Tx to Node |
| 32 | + U->>F: 5. Return TxHash |
| 33 | + F->>B: 6. Register TxHash |
| 34 | + loop Every 10s |
| 35 | + B->>BF: 7. Get Tx Status & UTxOs |
| 36 | + BF->>B: 8. Return Confirmation Depth |
| 37 | + end |
| 38 | + Note over B: 9. Payment Verified (2+ Blocks) |
| 39 | + B->>B: 10. Build Mint Tx (Server Wallet) |
| 40 | + B->>L: 11. Submit Mint Tx |
| 41 | + L->>U: 12. Token Arrives in Wallet |
| 42 | +``` |
| 43 | + |
| 44 | +--- |
| 45 | + |
| 46 | +## 🧩 Deep Dive: The 4 Layers |
| 47 | + |
| 48 | +### 1. User Wallet (The Signing Authority) |
| 49 | +The wallet's primary job is **Key Management**. The dApp *never* sees the user's private key. |
| 50 | +- **Protocol**: [CIP-30](https://cips.cardano.org/cips/cip30/) defines how the browser talks to the wallet. |
| 51 | +- **UX**: Whenever a dApp wants to move funds, the wallet pops up a "Confirm" dialog. This is the ultimate security barrier. |
| 52 | + |
| 53 | +### 2. Frontend (The Orchestrator) |
| 54 | +The frontend uses the [Mesh SDK](https://meshjs.dev) to build transactions. |
| 55 | +- **Transaction Building**: The SDK gathers UTxOs from the wallet, adds outputs, and calculates fees. |
| 56 | +- **State Management**: The frontend must handle the "Waiting" UX, keeping the user informed while the blockchain confirms the transaction. |
| 57 | + |
| 58 | +### 3. Backend (The Verification Engine) |
| 59 | +The backend's role is **Trustless Verification**. It must never trust the frontend's claim that "I paid". |
| 60 | +- **Verification Logic**: The backend queries Blockfrost for the `txHash` and inspects the **UTxO Outputs**. |
| 61 | +- **The Checklist**: |
| 62 | + 1. Does the transaction exist on-chain? |
| 63 | + 2. Does it have enough confirmations (e.g., 2 for demo, 15+ for production)? |
| 64 | + 3. Is there an output to our **App Wallet Address**? |
| 65 | + 4. Does that output contain the **correct ADA amount**? |
| 66 | + |
| 67 | +### 4. Blockchain (The Source of Truth) |
| 68 | +The Cardano network (Ouroboros) provides the settlement layer. |
| 69 | +- **Mempool**: Where transactions live before being included in a block. |
| 70 | +- **Propagation**: The time it takes for a transaction to spread across nodes (usually a few seconds). |
| 71 | +- **Finality**: As more blocks are added on top of a transaction, it becomes mathematically impossible to reverse. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## 🔍 Code Spotlight: Verification Logic |
| 76 | + |
| 77 | +The heart of this architecture lies in how the backend confirms a payment without trusting the user's claimed transaction state. |
| 78 | + |
| 79 | +### 1. Polling via Blockfrost (poll-status.ts) |
| 80 | +The frontend triggers a polling loop every 10 seconds. The backend then performs a "live" check on the blockchain: |
| 81 | + |
| 82 | +```typescript |
| 83 | +// pages/api/poll-status.ts snippet |
| 84 | +const { confirmed, confirmations, amountLovelace } = await verifyPayment( |
| 85 | + txHash, |
| 86 | + APP_WALLET_ADDRESS |
| 87 | +); |
| 88 | + |
| 89 | +if (!confirmed) { |
| 90 | + // If not on-chain or not enough confirmations, keep waiting |
| 91 | + const newStatus = confirmations > 0 ? "CONFIRMING" : "PENDING"; |
| 92 | + // ... update local record and return status |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +### 2. Identifying the Payment (blockfrost.ts) |
| 97 | +Verification isn't just about the transaction *existing*; it's about checking the **UTxO outputs** to ensure the funds reached their destination. |
| 98 | + |
| 99 | +```typescript |
| 100 | +// lib/blockfrost.ts logic |
| 101 | +// 1. Get all outputs for the transaction |
| 102 | +const utxos = await getTxUTxOs(txHash); |
| 103 | + |
| 104 | +// 2. Find the specific output directed to our App Wallet |
| 105 | +const paymentOutput = utxos.outputs.find( |
| 106 | + (output) => output.address === appWalletAddress |
| 107 | +); |
| 108 | + |
| 109 | +// 3. Compare the sent ADA (lovelace) against the required price |
| 110 | +const sentLovelace = paymentOutput?.amount.find(a => a.unit === "lovelace")?.quantity; |
| 111 | +if (BigInt(sentLovelace) < BigInt(REQUIRED_LOVELACE)) { |
| 112 | + throw new Error("Insufficient payment amount"); |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## 🛡 Security Best Practices |
| 119 | + |
| 120 | +> [!CAUTION] |
| 121 | +> **Server Wallet Security**: In this demo, the server wallet mnemonic is stored in an environment variable. In production, use a dedicated signing service, HSM (Hardware Security Module), or a vault like HashiCorp Vault. |
| 122 | +
|
| 123 | +* **API Key Safety**: Never expose your `BLOCKFROST_PROJECT_ID` in the frontend code. Keep it strictly on the server-side (`.env`). |
| 124 | +* **Input Validation**: Sanitize and validate every `txHash` received from the frontend to prevent injection or spam. |
| 125 | +* **Rate Limiting**: Implement rate limiting on your API routes to prevent users from flooding the polling engine. |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +## 🛰 Indexing & Event Listeners (Production Scale) |
| 130 | + |
| 131 | +While polling Blockfrost is excellent for smaller dApps and demos, production systems require higher throughput and lower latency. This is achieved by shifting from a **Pull** mechanism (polling) to a **Push** mechanism (event-driven). |
| 132 | + |
| 133 | +### 1. The Case for Indexers |
| 134 | +Standard nodes provide raw chain data, but they aren't optimized for complex queries (e.g., "Find all NFTs owned by this address"). Indexers consume raw chain data and transform it into a searchable database. |
| 135 | + |
| 136 | +### 2. Event Listeners (Oura) |
| 137 | +[Oura](https://github.com/txpipe/oura) is a popular tool for "tailing" the Cardano blockchain. It listens for events in real-time and routes them to different sinks (Elasticsearch, Kafka, Webhooks). |
| 138 | +- **Use Case**: Real-time notifications ("Your payment was just received!") before the transaction is even fully confirmed. |
| 139 | +- **Benefit**: Extremely low latency compared to polling. |
| 140 | + |
| 141 | +### 3. Purpose-Built Indexers |
| 142 | +* **[Kupo](https://github.com/Cardano-Solutions/kupo)**: A lightweight indexer focused on the UTxO model. Ideal for dApps that need to quickly find available funds or specific script outputs. |
| 143 | +* **[Ogmios](https://ogmios.dev/)**: A bridge that provides a JSON-RPC interface to the Cardano node, making it easier for web-based tools to query the node directly. |
| 144 | +* **[Cardano DB Sync](https://github.com/intersectmbo/cardano-db-sync)**: The "heavyweight" champion. It mirrors the entire chain into a PostgreSQL database. Essential for analytics platforms or explorers. |
| 145 | +* **[Yaci Store](https://store.yaci.xyz/)**: A developer-focused indexing solution providing high-level APIs for blockchain data, designed for rapid application development. |
| 146 | + |
| 147 | +### 4. Hybrid Architecture |
| 148 | +In many production dApps, companies use a hybrid approach: |
| 149 | +- **Blockfrost** for quick features and mobile compatibility. |
| 150 | +- **Oura** for real-time UI updates (Optimistic UI). |
| 151 | +- **Kupo/Ogmios** for complex transaction building and backend verification. |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +*These notes belong to the Q2 2026 Developer Experience Working Group.* |
0 commit comments