Skip to content

Phase 3 — Kredit gegen REALU-Collateral (Analyse-First) #688

Description

@TaprootFreak

Kontext & Ziel

Umsetzung von Phase 3 des RealUnit-App-Projekts: ein Kredit-/Lombard-Feature. Der Nutzer hinterlegt RealUnit-Token (REALU) als Sicherheit (Collateral) — vertraglich „analog WBTC" — und erhält im Gegenzug einen Stablecoin-Kredit, der via DFX-Off-Ramp aufs Bankkonto ausgezahlt wird. Die Rückzahlung gibt das Collateral wieder frei.

Der Auftraggeber hat Frankencoin (ZCHF) als Referenzmodell für „analog WBTC" benannt: ein oracle-freies, collateralized-minting-System, in dem ein beliebiges ERC-20 (heute u.a. WBTC) als Pfand dient, um ZCHF zu leihen.

⚠️ Dieses Issue startet NICHT mit Implementierung. Schritt 0 ist eine vollständige, tiefe Analyse der beteiligten Repos und der regulatorischen Rahmenbedingungen. Erst danach wird der genaue Architektur-/Implementierungsweg festgelegt (als Folge-Spec / Sub-Issues). Nicht vorher mit Code beginnen.

🔒 Architektur-Leitplanke (HART, nicht verhandelbar)

Die RealUnit-App spricht ausschliesslich mit api.dfx.swiss — niemals direkt mit Frankencoin, Ponder, einem Chain-RPC oder einem anderen Drittservice. Die DFX-API ist die alleinige Vermittlungs-/Autoritätsschicht. Sie nutzt ihrerseits api.frankencoin.com / ponder.frankencoin.com als Datenquelle oder betreibt ein eigenes passendes Backend. Die App bleibt reine Client-/Rendering-Schicht (vgl. API-as-Decision-Authority).

RealUnit-App  ──►  api.dfx.swiss  ──►  api.frankencoin.com / ponder.frankencoin.com
 (nur Client)      (Integrations-/        (Read: Positionen, Kurse, Status)
                    Autoritätsschicht)  ──►  Frankencoin Contracts (Write: openPosition/mint/repay)
                                          └►  oder eigenes DFX-Backend

Konsequenz: Jede Frankencoin-Interaktion (Reads wie Writes) wird hinter neuen api.dfx.swiss-Endpoints gekapselt. Die App kennt Frankencoin nicht — sie kennt nur RealUnit-/DFX-Loan-Endpoints. Tx-Signing bleibt im Wallet (non-custodial), aber der unsigned-Tx-Bau + Broadcast laufen über die DFX-API (genau wie heute im Sell-Flow).

„analog WBTC" = Frankencoin-Position (Richtung: Variante B)

Das Verlinken der Frankencoin-Repos weist die Richtung auf das Frankencoin-Collateral-Modell: REALU wird als Collateral in eine Frankencoin-Position eingebracht (analog wie WBTC), ZCHF wird geliehen und via bestehendem DFX-Off-Ramp aufs Bankkonto ausgezahlt. Weil REALU→ZCHF bereits Teil des Verkaufs-Flows ist, wird maximal Bestehendes wiederverwendet.

Die Alternative (A) rein zentral/DFX-vermittelt (DFX hält Collateral, eigenes Loan-Buch, kein Frankencoin) bleibt als Vergleichsmassstab/Fallback in der Analyse — sie ist aber nicht die signalisierte Richtung.

Beteiligte Repositories / Elemente

Element Rolle Zugriff durch
RealUnitCH/app Wallet-App (Flutter). Kredit-Einstieg + Screen/Cubit/Service/DTO, Collateral-Signing (REALU-ERC-20), Loan-/Positions-Status, Rückzahlung. Kein Kredit-Code heute. spricht nur api.dfx.swiss
DFXswiss/api Integrations- & Autoritätsschicht (Kern dieser Phase). Neue Loan-/Position-Endpoints; kapselt Frankencoin-Reads + Tx-Bau; Off-Ramp-Auszahlung; Loan-Domänenlogik. Hat RealUnit-Subdomain + Payout-Infra, kein Loan-Modul. von der App
Frankencoin-ZCHF/Frankencoin Die Contracts (Write/On-Chain-Mechanik): MintingHub, Position, Frankencoin. nur via DFX-API (Tx-Bau/Broadcast)
Frankencoin-ZCHF/frankencoin-api NestJS-Read-API auf api.frankencoin.com; aufbereitete Positionen/Kurse/Stats (konsumiert den Indexer + CoinGecko). nur via DFX-API
Frankencoin-ZCHF/ponder Indexer (Ponder) auf ponder.frankencoin.com; indiziert Frankencoin-Events (multichain Mainnet/Polygon) → DB. Datenquelle für die frankencoin-api. nur via DFX-API

Frankencoin-Mechanik (Voruntersuchung — das, was die DFX-API kapselt)

Aus den Contracts (Frankencoin-ZCHF/Frankencoin, Top-Level-Version gelesen — deployte V2-Adressen nicht einzeln verifiziert):

  • Position eröffnen: MintingHub.openPosition(...) (in contracts/minting/MintingHub.sol) erzeugt via PositionFactory einen Position-Contract, zieht OPENING_FEE = 1000 ZCHF, transferiert Collateral hinein. Mindestgrösse ~5000 ZCHF-Gegenwert. Frontend-Referenz: frankencoin-dapp pages/mint/create.tsx.
  • Parameter setzt der Eröffner selbst: liqPrice (Liquidationspreis), riskPremium (PPM Zins-Aufschlag; effektiver Zins = Leadrate + riskPremium, als upfront fee), reservePPM (Borrower-Reserve), minCollateral, mintingMaximum, initPeriod (≥3 Tage Veto, UI-Default 5), expiration, challengePeriod („länger für illiquides Collateral").
  • Minten/Leihen: Position.mint(); ausgezahlt = totalMint*(1e6 − reserve − fee)/1e6. LTV-Invariante collateral*price >= minted*1e18.
  • Oracle-frei (bestätigt, README): Kein Price-Feed. Position.price wird vom Owner gesetzt; Marktkorrektur nur über Challenges.
  • Liquidation = Challenge/Dutch-Auction: beliebiger Challenger hinterlegt Collateral → bid → entweder ChallengeAverted (Position gesund) oder Dutch-Auction → ChallengeSucceeded (Collateral verkauft, Schuld getilgt, CHALLENGER_REWARD = 2%). Fehlbetrag deckt zuerst Borrower-Reserve, dann die Pool-/FPS-Halter (coverLoss).
  • Neues Collateral zulassen: Ist der MintingHub aktiver Minter, kann jeder ohne Whitelist ein beliebiges ERC-20 via openPosition als Collateral nutzen (permissionless), mit positionsweisem Veto-Fenster (Position.deny). Ein eigenes Minter-Modul ginge über Frankencoin.suggestMinter(...) mit MIN_APPLICATION_PERIOD = 14 Tagen Veto durch qualifizierte FPS-Halter.

Kernrisiko für REALU: Das oracle-freie Challenge-Modell setzt einen liquiden Markt + Arbitrage-Anreiz voraus. REALU ist (vermutlich) illiquide und hat keinen öffentlichen Preis-Feed (Kurs nur via Brokerbot). Folge: unterbesicherte REALU-Positionen werden evtl. nie gechallenged → Bad Debt landet bei FPS-Haltern. Der Brokerbot-Kurs ist gerade nicht, was Frankencoin nutzt. Ob REALU im offiziellen Frankencoin-System überhaupt erwünscht/duldbar ist (soziale Governance der FPS-Halter), ist offen — eventuell braucht es einen eigenen, DFX-betriebenen Hub/Fork statt des Live-Mainnet-Systems.

Schritt 0 — Pflicht-Tiefenanalyse (vor jeder Implementierung)

A. RealUnitCH/app (Wallet, reiner Client)

  • Sell-Flow als bestes Muster (lib/packages/service/dfx/real_unit_sell_payment_info_service.dart, Kette PUT /v1/realunit/sell…/unsigned-transactions…/broadcast…/confirm): er kombiniert on-chain Token-Bewegung und Bankauszahlung — exakt die zwei Loan-Bausteine. Was ist wiederverwendbar?
  • Schichtung Screen→Cubit→Service→DTO (lib/screens/buy/, lib/screens/sell/, …/cubits/buy_confirm/buy_confirm_cubit.dart).
  • EVM-Signing: REALU-Approve/Transfer + ggf. MintingHub-Calls als unsigned-tx empfangen, signieren, zurückgeben (lib/packages/wallet/eip712_signer.dart, eip7702_signer.dart, web3dart; BitBox-Pfad). Asset-Konstanten lib/packages/utils/default_assets.dart.
  • Loan-/Positions-Statusanzeige + Rückzahlungs-Flow: rein über DFX-API-DTOs rendern.
  • Navigation: Einstieg „Kredit" (lib/setup/routing/routes/app_routes.dart + router_config.dart).

B. DFXswiss/api (Integrations- & Autoritätsschicht — Kern)

  • RealUnit-Subdomain (src/subdomains/supporting/realunit/) als Muster (sell/buy/registration); kein Loan-DTO/-Service vorhanden → neu.
  • Frankencoin-Reads kapseln: welche Endpoints von api.frankencoin.com (bzw. ponder.frankencoin.com) liefern Positions-/Kurs-/Status-Daten, die die DFX-API für die App aufbereitet? Genau auflisten.
  • Frankencoin-Writes kapseln: unsigned-Tx-Bau für openPosition/mint/repay/Rückzahlung mit REALU-Collateral; Broadcast wie im Sell-Flow.
  • Off-Ramp: geliehenes ZCHF → Fiat aufs Bankkonto über bestehende Payout-Infra (src/subdomains/supporting/payout/). Lücken?
  • Loan-Domänenmodell: LTV/liqPrice, Zins, Laufzeit, Zustände, Margin-Call/Liquidationswarnung; was muss DFX-seitig persistiert/überwacht werden (Position-Monitoring)?
  • Eigenes Backend vs. Frankencoin-Live-System: Entscheidung, ob DFX die öffentliche Frankencoin-Infra nutzt oder einen eigenen Hub/Fork betreibt (siehe Kernrisiko REALU).

C. Frankencoin-Elemente (extern — NUR über DFX-API anzusprechen)

  • Frankencoin Contracts: exakte openPosition/mint/repay/challenge-Signaturen + deployte V2-Adressen verifizieren.
  • frankencoin-api (api.frankencoin.com): verfügbare Read-Endpoints (Positionen, Preise, Stats) dokumentieren.
  • ponder (ponder.frankencoin.com): welche indizierten Daten, multichain-Setup (Mainnet relevant).
  • Klären, ob REALU als Collateral im offiziellen System zulässig ist (permissionless openPosition vs. suggestMinter 14-Tage-Veto vs. eigener DFX-Hub).

Bekannter Ist-Stand (Voruntersuchung — Startpunkt, nicht abschliessend)

Baustein App DFXswiss/api Frankencoin
Kredit-Feature 🔴 nicht vorhanden (Grep loan/credit/collateral leer) 🔴 kein Loan-Modul 🟢 Position/Mint-Mechanik produktiv
On-chain Token-Bewegung + Signing 🟢 EIP-712/7702 + REALU-Transfer aus Sell-Flow 🟢 unsigned-tx/broadcast-Pfad
Off-Ramp ZCHF→Bankkonto 🟢 Confirm-Muster 🟡 Payout-Infra (auf Verkaufserlös ausgelegt)
Collateral-Bewertung 🟡 Brokerbot-Kurs (kein öffentl. Feed) 🟡 Brokerbot/Pricing 🔴 oracle-frei, Owner setzt Preis (REALU-Risiko)
Loan-Domänenlogik (LTV/Zins/Liquidation) 🔴 fehlt 🔴 fehlt 🟢 im Contract (Challenge-Modell)

Loan-Flow-Skizze (analog Sell-Flow, alles über api.dfx.swiss — Diskussionsgrundlage)

  1. Kredit anfragen → DFX-API liefert Konditionen (Max-Betrag aus Collateral/liqPrice, Zins, benötigtes REALU).
  2. Collateral-Lock + Mint → DFX-API baut unsigned-tx (openPosition/mint mit REALU) → App signiert → DFX broadcastet.
  3. Auszahlung → DFX-API löst Off-Ramp ZCHF→Bankkonto aus.
  4. Rückzahlung → Fiat-Einzahlung → DFX-API tilgt Position (repay) → Collateral-Freigabe.
  5. Risiko → DFX-API überwacht liqPrice/Challenge-Status, warnt den Nutzer.

Offene Fragen, die die Analyse beantworten muss (NICHT vorab entscheiden)

  • Offizielles Frankencoin-System vs. eigener DFX-Hub/Fork — wegen REALU-Illiquidität + oracle-freiem Challenge-Risiko (Bad Debt zu FPS-Haltern).
  • Custody: Non-Custodial-Anspruch — der Position-Owner (= User-Wallet) kontrolliert die Position on-chain; reicht das, oder braucht DFX Eingriffsrechte (Liquidationsschutz)?
  • Preisbildung: REALU hat keinen öffentlichen Feed — wie wird liqPrice konservativ gesetzt (Brokerbot als de-facto-Oracle widerspricht dem Design)?
  • LTV/Zins/Laufzeit/Liquidationswarnung — wo berechnet/überwacht (DFX-API), wie wird der Nutzer gewarnt?
  • Rückzahlung: Fiat-Einzahlung → Collateral-Freigabe; Teilrückzahlung; vorzeitige Tilgung.
  • Regulatorik (potenziell grösster Blocker): Kreditvergabe gegen Token-Pfand lizenz-/auflagenpflichtig? Früh mit Legal & Compliance (David Lehner, RealUnit) klären — als Go/No-Go.
  • KYC-Level für Kreditnehmer.

Deliverable von Schritt 0

Eine entschiedene Architektur (offizielles Frankencoin vs. eigener Hub; Custody-Modell) plus ein konkreter, abgestimmter Implementierungsplan (gerne Folge-Issues), inkl. klarer Aufteilung welche Änderung in welches Repo gehört — wobei alle App↔Backend-Kommunikation über api.dfx.swiss läuft — und ein dokumentiertes Go/No-Go aus Legal/Compliance. Erst dann Implementierung.

Workflow

  • Analyse-Ergebnis + Architekturentscheid + Plan hier im Issue (oder verlinkten Sub-Issues) dokumentieren, bevor Code entsteht.
  • Implementierung später: RealUnitCH/app → Feature-Branch → PR gegen staging (Draft); DFXswiss/api → Feature-Branch → PR gegen develop (Draft). 3-Subagent-Review. DEV/PRD-Parität beachten.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions