QubicShield — Smart Contract Guide
Lernjournal — alles erklärt, zum Nachlesen
01

🧠 Was ist ein Qubic Smart Contract? What is a Qubic Smart Contract?

Ein Smart Contract (SC) auf Qubic ist eine einzelne C++-Datei, die mit der Qubic Public Interface (QPI) geschrieben wird. Der Code läuft nicht auf einem Server — er läuft gleichzeitig auf allen 676 Qubic-Computern (den sogenannten "Computors") im Netzwerk.

  • Kein Server nötig — der Code ist immer online, solange das Qubic-Netzwerk läuft
  • Unveränderlich — einmal deployed kann der Code nicht heimlich geändert werden
  • Transparent — jeder kann den Code lesen und prüfen
  • Kein Vertrauen nötig — der SC erzwingt die Regeln, kein Mensch entscheidet

A Smart Contract (SC) on Qubic is a single C++ file written using the Qubic Public Interface (QPI). The code does not run on a server — it runs simultaneously on all 676 Qubic computers ("Computors") in the network.

  • No server needed — the code is always online as long as the Qubic network runs
  • Immutable — once deployed, the code cannot be secretly changed
  • Transparent — anyone can read and verify the code
  • Trustless — the SC enforces the rules; no human decides
02

Warum funktioniert QubicShield nur auf Qubic? Why does QubicShield only work on Qubic?

Das Herzstück von QubicShield ist die Rückzahlung des Deposits an legitime Nutzer. Das kostet auf anderen Blockchains Geld:

The core of QubicShield is the refund of the deposit to legitimate users. On other blockchains this costs money:

Blockchain ProblemProblem
Ethereum Jede transfer()-Transaktion kostet Gas. Bei einem Deposit von 0,001 EUR kostet die Rückzahlung oft mehr als der Deposit → Modell kaputt Every transfer() transaction costs gas. With a deposit of $0.001, the refund gas fee often exceeds the deposit itself → model breaks
Bitcoin Keine Smart Contracts mit dieser Logik möglich No smart contracts with this kind of logic
Qubic
Zero Transaction Fees — Rückzahlungen kosten nichts. Das Modell funktioniert. Zero Transaction Fees — refunds cost nothing. The model works.

Ursprung der IdeeOrigin of the Idea

Die Grundidee — Rechenarbeit oder Zahlung als Schutz vor Missbrauch — ist nicht neu. Aber niemand hat sie bisher als vollständiges Webprodukt umgesetzt:

The core idea — work or payment as a barrier against abuse — is not new. But nobody has realized it as a complete web product:

JahrYear WerWho WasWhat
1993 Dwork & Naor „Pricing via Processing" — erste Idee, Rechenarbeit als Anti-Spam-Kosten"Pricing via Processing" — first idea of computation as anti-spam cost
1997 Adam Back Hashcash — Proof-of-Work für E-Mail-Spam (Vorläufer von Bitcoin-Mining). Rechenarbeit statt Geld, nicht rückerstattbar.Hashcash — proof-of-work for email spam (predecessor of Bitcoin mining). Computation instead of money, not refundable.
~2015+ Lightning Network HTLCs — rückerstattbare Zahlungen technisch möglich, aber kein fertiges Web-Proxy-ProduktHTLCs — refundable payments technically possible, but no finished web proxy product
2026 QubicShield
Erste vollständige Umsetzung — rückzahlbares Deposit + Web-Zugang + wirtschaftlicher Spam-Schutz + Konfiszierung bei Angriff. Möglich durch Qubics Zero-Fee-Architektur. First complete implementation — refundable deposit + web access + economic spam protection + forfeit on attack. Made possible by Qubic's zero-fee architecture.
03

🔄 Der Unterschied: Mock vs. echter Smart Contract The Difference: Mock vs. Real Smart Contract

Im Demo-Server gibt es eine Datei src/depositManager.ts. Die sieht professionell aus, aber sie ist ein Mock — alle Daten leben nur im RAM:

The demo server has a file src/depositManager.ts. It looks professional but it is a mock — all data lives only in RAM:

depositManager.ts (Mock)
  • Deposits: JavaScript Map() — weg bei NeustartDeposits: JavaScript Map() — lost on restart
  • Transfers: simuliert, kein echtes GeldTransfers: simulated, no real money
  • Vertrauen: du musst dem Server vertrauenTrust: you must trust the server operator
QubicShield.h (Smart Contract)
  • Deposits: Blockchain — permanent, unveränderlichDeposits: Blockchain — permanent, immutable
  • Transfers: qpi.transfer() — echtes GeldTransfers: qpi.transfer() — real money
  • Vertrauen: niemand nötig — der Code ist die RegelTrust: nobody needed — the code is the rule
04

🗺️ Die Übersetzung: Mock → Smart Contract The Translation: Mock → Smart Contract

Jede Funktion im Mock hat ein Gegenstück im SC:

Every function in the mock has a counterpart in the SC:

depositManager.ts QubicShield.h Typ
createDeposit()PUBLIC_PROCEDURE(Deposit)Procedure
refundDeposit()PUBLIC_PROCEDURE(Refund)Procedure
forfeitDeposit()PUBLIC_PROCEDURE(Forfeit)Procedure
validateToken()PUBLIC_FUNCTION(ValidateSession)Function
getStats()PUBLIC_FUNCTION(GetStats)Function
Auto-Expire (setTimeout)Auto-Expire (setTimeout)BEGIN_TICK HookTick-Hook
05

⚖️Procedure vs. Function

In Qubic gibt es zwei Arten von Entry Points — der wichtigste Unterschied:

In Qubic there are two types of entry points — the most important distinction:

PUBLIC_PROCEDURE
  • Darf State verändernMay modify state
  • Darf QUBIC transferierenMay transfer QUBIC
  • Kostet ComputeCosts compute
  • Beispiele: Deposit, Refund, ForfeitExamples: Deposit, Refund, Forfeit
PUBLIC_FUNCTION
  • Darf State nur lesenMay only read state
  • Kein Transfer möglichNo transfers allowed
  • Günstig, sicher öffentlichCheap, safely public
  • Beispiele: ValidateSession, GetStatsExamples: ValidateSession, GetStats
Merkregel: Procedure = schreiben. Function = lesen. Memory aid: Procedure = write. Function = read.
06

🔒 QPI-Einschränkungen — und warum sie existieren QPI Constraints — and why they exist

QPI ist kein normales C++. Die Einschränkungen sind Absicht — sie machen den SC sicher und deterministisch:

QPI is not regular C++. The constraints are intentional — they make the SC safe and deterministic:

EinschränkungConstraint WarumWhy LösungSolution
#include verbotenforbidden Keine externen Libraries → keine versteckte LogikNo external libraries → no hidden logic QPI Built-in TypenQPI built-in types
/ undand % Undefined Behaviour bei Division durch 0Undefined behaviour on division by zero div(a,b) / mod(a,b)
string Variable Länge → nicht deterministischVariable length → not deterministic id Typ (60-Byte Hash)type (60-byte hash)
new / Pointerpointers Dynamischer Speicher nicht vorhersehbarDynamic memory is unpredictable Array<T, N>
bool / int / char Plattformabhängige GrößenPlatform-dependent sizes bit, sint64, uint32, uint8
UTC-ZeitUTC time Server-Uhren nicht konsistent über 676 NodesClocks not consistent across 676 nodes qpi.tick()
07

🗄️ Die Datenstruktur: DepositEntry The Data Structure: DepositEntry

Jedes Deposit wird als DepositEntry Struct gespeichert. Da es keinen string-Typ gibt, nutzen wir QPI-eigene Typen:

Every deposit is stored as a DepositEntry struct. Since there is no string type, we use QPI-native types:

struct DepositEntry
{
    id       owner;           // Wallet-Adresse (60-byte Hash)wallet address (60-byte hash)
    id       token;           // Session-Token (K12-Hash)session token (K12 hash)
    sint64   amount;          // Betrag in QUBIC-Einheitenamount in QUBIC units
    uint32   createdTick;     // qpi.tick() beim Erstellenat creation
    uint32   expiresAtTick;   // createdTick + 3600 ticks (≈ 30 Minmin)
    uint8    status;          // 0=leerempty  1=held  2=refunded  3=forfeited
    uint32   requestCount;    // Anzahl Requestsnumber of requests
};

Warum 512 Slots? Das ist die maximale Anzahl gleichzeitiger Sessions. Mehr kostet mehr Speicher auf jedem der 676 Nodes.

Why 512 slots? That is the maximum number of concurrent sessions. More costs more storage on each of the 676 nodes.

Array<DepositEntry, 512> deposits;
08

#️⃣ Der id Typ und K12-Hashing The id Type and K12 Hashing

id ist ein QPI Built-in Typ — ein 60-Byte-Wert der typischerweise eine Wallet-Adresse oder einen Hash darstellt.

Wie wird der Session-Token erzeugt?

id is a QPI built-in type — a 60-byte value that typically represents a wallet address or hash.

How is the session token generated?

id caller       = qpi.invocator();   // Wallet-Adresse des Aufruferswallet address of the caller
id sessionToken = qpi.K12(caller);   // K12-Hash → einzigartiges Tokenunique token

qpi.K12() ist Qubics eigene Hash-Funktion. Der Token ist:

  • Einzigartig pro Wallet
  • Nicht vorhersagbar von außen
  • Verifizierbar — der Proxy prüft ihn mit ValidateSession()

qpi.K12() is Qubic's own hash function. The token is:

  • Unique per wallet
  • Unpredictable from outside
  • Verifiable — the proxy checks it with ValidateSession()
09

⏱️ Tick-basierte Zeit Tick-Based Time

Qubic hat keine Echtzeituhr. Stattdessen gibt es Ticks — einen globalen Zähler der vom Netzwerk hochgezählt wird.

  • Aktuell mehr als 2 Ticks pro Sekunde (Intervall < 1 Sek)
  • 3.600 Ticks ≈ weniger als 30 Minuten (je nach aktueller Tick-Rate)
  • qpi.tick() gibt den aktuellen Tick zurück

Qubic has no real-time clock. Instead there are ticks — a global counter incremented by the network.

  • Currently more than 2 ticks per second (interval < 1 sec)
  • 3,600 ticks ≈ less than 30 minutes (depends on current tick rate)
  • qpi.tick() returns the current tick
entry.expiresAtTick = qpi.tick() + SESSION_DURATION_TICKS;  // +3600
Im BEGIN_TICK Hook läuft automatisch ein Scan — abgelaufene Sessions werden forfeitiert ohne dass jemand aktiv etwas tun muss. The BEGIN_TICK hook runs an automatic scan — expired sessions are forfeited without anyone having to do anything.
10

🔁Hooks: BEGIN_EPOCH & BEGIN_TICK

Qubic ruft diese Blöcke automatisch auf — kein externer Trigger nötig.

Qubic calls these blocks automatically — no external trigger needed.

BEGIN_EPOCH / END_EPOCH

Läuft ca. einmal pro Woche. Bei uns: Initialisierung des Operators beim ersten Deploy.

Runs approx. once per week. Here: operator initialization on first deploy.

BEGIN_EPOCH
{
    id zeroId;
    if (operator_ == zeroId)   // Erste Epoche = noch nicht initialisiertfirst epoch = not yet initialized
    {
        operator_ = qpi.originator();   // Deployer wird Operatordeployer becomes operator
    }
}
END_EPOCH

BEGIN_TICK / END_TICK

Läuft aktuell mehr als 2× pro Sekunde (Intervall < 1 Sek). Bei uns: automatisches Expire abgelaufener Sessions.

Currently runs more than 2× per second (interval < 1 sec). Here: automatic expiry of stale sessions.

11

🛡️ Sicherheit: Wie verhindert der SC Betrug? Security: How does the SC prevent fraud?

Problem: Fremde Deposits zurückfordern Problem: Claiming someone else's deposit

Beim Refund() müssen BEIDE Werte übereinstimmen:

For Refund() BOTH values must match:

  • Der korrekte sessionIndex (Position im Array)The correct sessionIndex (position in array)
  • Das korrekte token (K12-Hash) — kennt nur der originale DepositorThe correct token (K12 hash) — only the original depositor knows it
if (entry.token != input.token)
{
    output.success   = 0;
    output.errorCode = 2;  // falsches Token → abgelehntwrong token → rejected
    return;
}

Forfeit: Nur der Operator darf forfeitten Forfeit: Only the operator may forfeit

if (qpi.invocator() != operator_)
{
    output.success   = 0;
    output.errorCode = 2;  // nicht der Operator → abgelehntnot the operator → rejected
    return;
}
12

📋 Registrierung der Entry Points Registering Entry Points

Jede Procedure und Function muss mit einem fixen Index registriert werden. Der Index ist die "Telefonnummer" über die externe Aufrufer den Entry Point adressieren.

Every procedure and function must be registered with a fixed index. The index is the "phone number" external callers use to address the entry point.

REGISTER_USER_FUNCTIONS_AND_PROCEDURES
{
    REGISTER_USER_PROCEDURE(Deposit,           1);
    REGISTER_USER_PROCEDURE(Refund,            2);
    REGISTER_USER_PROCEDURE(Forfeit,           3);
    REGISTER_USER_PROCEDURE(WithdrawForfeited, 6);  // NEW — index 6
    REGISTER_USER_FUNCTION(ValidateSession,    4);
    REGISTER_USER_FUNCTION(GetStats,           5);
}
Wichtig: Die Indizes dürfen nach dem Deployment nie geändert werden. Ändert man sie, bricht jeder bestehende Client. Important: Indices must never change after deployment. Changing them breaks every existing client.
13

🌐 Gesamtbild: Wie alles zusammenspielt Big Picture: How everything works together

Nutzer-Browser Web-Proxy (Node.js) Qubic Smart Contract | | | | (0. Schlüssel aus Seed ableiten — lokal, nie gesendet)| |-- Deposit + PublicKey ->| | | |-- Deposit(amount) ---------->| | | speichert Entry + PublicKey | |<-- token + index ------------| |<-- token --------------| | | | | |-- token + SchnorrQ-Sig →| | | | prüft Signatur (PublicKey) | | |-- ValidateSession(token) --->| | |<-- valid=1 / valid=0 --------| |<-- 200 OK / 401/403 ---| | | | | |-- sauberes Verlassen ->| | | |-- Refund(index, token) ----->| | | qpi.transfer() ------+--> QUBIC zurück |<-- "Deposit zurück" ---| |User Browser Web-Proxy (Node.js) Qubic Smart Contract | | | | (0. derive keys from seed — local, never sent) | |-- Deposit + publicKey ->| | | |-- Deposit(amount) ---------->| | | stores Entry + publicKey | |<-- token + index ------------| |<-- token --------------| | | | | |-- token + SchnorrQ sig →| | | | verifies signature (pubKey) | | |-- ValidateSession(token) --->| | |<-- valid=1 / valid=0 --------| |<-- 200 OK / 401/403 ---| | | | | |-- clean exit --------->| | | |-- Refund(index, token) ----->| | | qpi.transfer() ------+--> QUBIC back |<-- "Deposit returned"--| |

⚔️ QubicShield vs. Cloudflare QubicShield vs. Cloudflare

Cloudflare QubicShield
AnsatzApproach Technik filtert AngriffeTechnology filters attacks Wirtschaft verhindert AngriffeEconomics prevents attacks
ArchitekturArchitecture ZentralisiertCentralized DezentralDecentralized
Traffic-SichtbarkeitTraffic visibility Cloudflare sieht allesCloudflare sees everything Kein Traffic-Routing nötigNo traffic routing needed
Single Point of FailureSingle point of failure JaYes NeinNo
Kosten ohne AngriffCost without attack Monatliches AboMonthly subscription Nahezu nichtsNear zero
DatenschutzPrivacy Traffic läuft über fremde ServerTraffic passes through their servers DSGVO-konform by DesignGDPR-friendly by design
LangfristzielLong-term goal Angriffe managenManage attacks Angriffe irrational machenMake attacks irrational
Wichtige Einschränkung: QubicShield schützt authentifizierten API-Zugang. Für volumetrischen Netzwerk-DDoS (SYN-Floods, UDP-Amplification) ist QubicShield ergänzend zu Cloudflare — kein vollständiger Ersatz. Nicht authentifizierter Traffic erreicht weiterhin den Server. Important limitation: QubicShield protects authenticated API access. For volumetric network-layer DDoS (SYN floods, UDP amplification), QubicShield is complementary to Cloudflare — not a full replacement. Unauthenticated traffic still reaches the server.

🔗 QubicShield vs. QubicShield Node QubicShield vs. QubicShield Node

Die beiden Projekte sind keine Konkurrenten — das eine ist das Protokoll, das andere ist die Infrastruktur. QubicShield läuft heute als Middleware direkt im Web-Server und funktioniert vollständig ohne einen Node.

The two projects are not competitors — one is the protocol, the other is the infrastructure. QubicShield runs today as middleware directly inside the web server and works fully without any node.

Ohne Node (jetzt): Mit Node (Vision): Internet Internet │ │ ▼ ▼ Web-Server Shield Node (Reverse Proxy) └─ QubicShield Middleware ├── Kein Token → 402 / blockieren ├── Deposit-Check ├── Ungültige Signatur → 401 ├── Signatur-Prüfung ├── Angriffsmuster → Forfeit() └── Forfeit bei Angriff └── Legitimer Traffic → weiter │ │ ▼ ▼ Geschützte API Web-Server + QubicShieldWithout Node (now): With Node (vision): Internet Internet │ │ ▼ ▼ Web Server Shield Node (Reverse Proxy) └─ QubicShield Middleware ├── No token → 402 / block ├── Deposit check ├── Invalid signature → 401 ├── Signature verify ├── Attack pattern → Forfeit() └── Forfeit on attack └── Legitimate traffic → forward │ │ ▼ ▼ Protected API Web Server + QubicShield
QubicShield (dieser PoC)QubicShield (this PoC) QubicShield NodeQubicShield Node
EbeneLayer L7 (AnwendungApplication) L3–L7 (Netzwerk + AnwendungNetwork + Application)
PositionPosition Im Web-ServerInside the web server Vor dem Web-ServerIn front of the web server
Unauthentifizierter TrafficUnauthenticated traffic Erreicht den ServerReaches the server Wird davor blockiertBlocked before the server
Standalone nutzbarUsable standalone JaYes Nein — braucht das Protokoll als KernNo — needs the protocol as its core
Status Funktionierender PoCWorking PoC Konzept / VisionConcept / Vision
Entwicklungsreihenfolge: (1) QubicShield PoC beweist, dass das Protokoll funktioniert → (2) Testnet-Deploy validiert gegen echten SC → (3) QubicShield Node baut auf dem validierten Protokoll auf und erweitert auf Infrastruktur-Ebene. Der Node macht den PoC nicht obsolet — er setzt ihn tiefer um. Development sequence: (1) QubicShield PoC proves the protocol works → (2) Testnet deploy validates against a real SC → (3) QubicShield Node builds on the validated protocol and extends it to the infrastructure layer. The node does not make the PoC obsolete — it implements it deeper.
14

💸 WithdrawForfeited — Wie der Operator QUBIC abheben kann WithdrawForfeited — How the Operator Withdraws QUBIC

Forfeitierte QUBIC blieben bisher für immer im Contract. Die neue PUBLIC_PROCEDURE(WithdrawForfeited) erlaubt es dem Operator, dieses QUBIC auf seine Wallet zu transferieren.

Forfeited QUBIC previously stayed locked in the contract forever. The new PUBLIC_PROCEDURE(WithdrawForfeited) lets the operator transfer this QUBIC to their wallet.

Was ist qpi.contractBalance()?

Jeder SC hat eine eigene Wallet-Adresse auf der Blockchain. qpi.contractBalance() gibt den echten, aktuellen On-Chain-Saldo zurück — also das QUBIC das wirklich dort liegt.

What is qpi.contractBalance()?

Every SC has its own wallet address on the blockchain. qpi.contractBalance() returns the real, current on-chain balance — the QUBIC that is actually there.

Interne BuchhaltungInternal Accounting

totalForfeitedwas laut unserem Code dort sein solltewhat our code says should be there

On-Chain-RealitätOn-Chain Reality

contractBalance()was wirklich dort istwhat is actually there

Defensives Programmieren: Wir prüfen beide Werte. Falls ein Bug in der Buchhaltungslogik wäre, verhindert der contractBalance()-Check, dass wir mehr transferieren als wirklich vorhanden ist. Defensive programming: We check both values. If there were a bug in accounting logic, the contractBalance() check prevents transferring more than actually exists.
PUBLIC_PROCEDURE(WithdrawForfeited)
{
    if (qpi.invocator() != operator_)  { /* reject */ return; }
    if (input.amount > totalForfeited) { /* reject */ return; }
    if (input.amount > qpi.contractBalance()) { /* reject */ return; }

    qpi.transfer(operator_, input.amount);
    totalForfeited = totalForfeited - input.amount;
}
15

🏛️ IPO, 676 Anteile & Forfeit-Verteilung IPO, 676 Shares & Forfeit Distribution

Wenn QubicShield als echter Qubic Smart Contract veröffentlicht wird, durchläuft er eine Dutch Auction (IPO). Alle QUBIC aus dem IPO werden sofort verbrannt — das ist Protokoll. Der SC bekommt dabei genau 676 Anteile, einer für jeden der 676 Computors im Netzwerk.

When QubicShield is published as a real Qubic smart contract, it goes through a Dutch Auction (IPO). All QUBIC from the IPO is immediately burned — that is the protocol. The SC receives exactly 676 shares, one for each of the 676 Computors in the network.

QubicShield — Forfeit-VerteilungQubicShield — Forfeit Distribution

Wenn ein Angreifer forfeitiert wird, soll sein Deposit so verteilt werden:

When an attacker is forfeited, their deposit will be distributed as follows:

EmpfängerRecipient % WarumWhy QPI
🔥 VerbrennenBurn 35% Bestrafungssignal — Token dauerhaft vernichtet, deflationärPunishment signal — tokens permanently destroyed, deflationary qpi.burn()
🛡️ Angegriffener Dienst (Operator)Attacked service (operator) 40% Direkte Entschädigung des Opfers — größter EinzelanteilDirect compensation for the victim — largest single share qpi.transfer(operator_)
🏛️ Aktionäre (Shareholders)Shareholders 20% Passives Einkommen für IPO-Investoren — ähnlich wie QSwap (16%)Passive income for IPO investors — similar to QSwap (16%) qpi.distributeDividends()
⚙️ PlattformPlatform 5% Entwicklung & Betrieb — nachhaltig ohne InteressenskonfliktDevelopment & operations — sustainable without conflict of interest qpi.transfer(platform_)
Designentscheidung: Vergleichbar mit QSwap (16% Shareholders). Der Plattformanteil (5%) hält die Entwicklung nachhaltig — das Modell hängt aber nicht davon ab, dass Angriffe stattfinden. Kein Angriff = kein Forfeit = keine Ausschüttung. Die Verteilung läuft automatisch in END_EPOCH (~wöchentlich), kein manueller Aufruf nötig. Design decision: Comparable to QSwap (16% shareholders). The platform share (5%) keeps development sustainable — but the model does not depend on attacks happening. No attack = no forfeit = no distribution. Distribution runs automatically in END_EPOCH (~weekly), no manual call needed.
// Called automatically once per epoch (~weekly)
END_EPOCH
{
    if (totalForfeited == 0) { return; }

    sint64 toBurn         = div(pending * 35, 100);
    sint64 toOperator     = div(pending * 40, 100);
    sint64 toShareholders = div(pending * 20, 100);
    sint64 toPlatform     = div(pending * 5,  100);

    qpi.burn(toBurn);                          // 35% — permanently destroyed (deflationary)
    qpi.transfer(operator_, toOperator);       // 40% — compensation for the attacked service
    qpi.distributeDividends(toShareholders);   // 20% — passive income for IPO shareholders
    qpi.transfer(platform_, toPlatform);       // 5%  — development & operations

    totalForfeited = 0;
}
16

🔑 Token-Entropie — Was ist ein Struct? Token Entropy — What is a Struct?

Was ist ein Struct?What is a Struct?

Ein Struct (kurz für "Structure") ist ein Behälter für mehrere zusammengehörige Werte — wie eine Kiste mit beschrifteten Fächern. Alle Felder liegen hintereinander im Speicher.

A struct (short for "structure") is a container for multiple related values — like a box with labelled compartments. All fields are stored consecutively in memory.

struct TokenSeed
{
    id     owner;      // Fach 1: Wallet-Adresse (32 Bytes)slot 1: wallet address (32 bytes)
    uint32 tick;       // Fach 2: Zeitstempel    (4 Bytes)slot 2: timestamp      (4 bytes)
    sint64 slotIndex;  // Fach 3: Array-Position (8 Bytes)slot 3: array position (8 bytes)
};
//  → 44 Bytes am Stück im Speicher→ 44 bytes in one block in memory
qpi.K12() nimmt genau einen Parameter. Ein Struct bündelt mehrere Werte zu einem Block — K12 hasht dann alle 44 Bytes auf einmal. Kein String-Zusammenkleben nötig. qpi.K12() takes exactly one parameter. A struct bundles multiple values into one block — K12 then hashes all 44 bytes at once. No string concatenation needed.

Warum K12(owner) allein nicht reichtWhy K12(owner) alone is not enough

ALT — eine Entropie-QuelleOLD — one entropy source
qpi.K12(caller)
// gleiche Wallet → immer gleicher Token
// Kollision bei gleichem Tick!
NEU — drei Entropie-QuellenNEW — three entropy sources
qpi.K12(seed)  // owner+tick+slot
// alle drei müssen gleichzeitig
// kollidieren → praktisch unmöglich
QuelleSource Kollidiert wenn...Collides when...
ownergleiche Wallet — gewollt, aber allein nicht genugsame wallet — intended, but not enough alone
tickexakt gleicher Tick (½ Sekunde) — sehr unwahrscheinlichexact same tick (½ second) — very unlikely
slotIndexgleicher freier Slot — unmöglich wenn owner gleichsame free slot — impossible if owner is same
18

🔌 TypeScript SDK

Warum ein SDK?Why an SDK?

Der Mock-Server verwaltet Deposits in einem In-Memory-Array. Für echtes Qubic brauchen wir HTTP-Requests an einen RPC-Node. Das offizielle Paket @qubic-lib/qubic-ts-library v0.1.6 stellt Klassen bereit, um Transaktionen zu bauen, zu signieren und zu broadcasten.The mock server stores deposits in an in-memory array. For real Qubic we need HTTP requests to an RPC node. The official package @qubic-lib/qubic-ts-library v0.1.6 provides classes to build, sign, and broadcast transactions.

Zwei Arten von SC-AufrufenTwo types of SC calls

TypTypeHTTPSignatur?Signature?Sofortiges Ergebnis?Immediate result?
ProcedurePOST /v1/broadcast-transaction✅ JaNein — nach TickNo — after tick
FunctionPOST /v1/querySmartContract❌ NeinSofortImmediate

Procedure: TX bauen, signieren, broadcastenProcedure: build, sign, broadcast TX

const tx = new QubicTransaction()
  .setSourcePublicKey(new PublicKey(senderPublicId))
  .setDestinationPublicKey(new PublicKey(CONTRACT_ADDRESS))
  .setAmount(new Long(Number(amount)))
  .setTick(currentTick + 15)   // TX valid for next ~15 ticks
  .setInputType(IDX_DEPOSIT)
  .setPayload(dynPayload);

const built   = await tx.build(senderSeed);
const encoded = tx.encodeTransactionToBase64(built);

await fetch('/v1/broadcast-transaction', {
  method: 'POST',
  body: JSON.stringify({ encodedTransaction: encoded }),
});

Wichtige Einschränkung: kein synchroner Procedure-OutputImportant limitation: no synchronous procedure output

broadcast-transaction liefert nur eine Eingangsbestätigung — nicht das SC-Ergebnis. Ablauf: TX broadcasten → txId erhalten → warten → validateSession() pollen.broadcast-transaction returns only a submission acknowledgement — not the SC result. Flow: broadcast TX → receive txId → wait → poll validateSession().

Function: Base64-Query

await fetch('/v1/querySmartContract', {
  method: 'POST',
  body: JSON.stringify({
    contractIndex: CONTRACT_INDEX,
    inputType:     IDX_VALIDATE_SESSION,
    inputSize:     32,
    requestData:   toBase64(token),  // 32-byte token as Base64
  }),
});
// Response: { responseData: "<base64>" }
// → fromBase64() → Uint8Array → readUint32LE()

Struct-Größen: exakte Übereinstimmung mit QubicShield.hStruct sizes: must match QubicShield.h exactly

const SIZE_DEPOSIT_INPUT  = 8;   // sint64
const SIZE_REFUND_INPUT   = 36;  // uint32 + id
const SIZE_VALIDATE_INPUT = 32;  // id
const SIZE_VALIDATE_OUT   = 45;  // uint8+uint32+uint32+id+uint32
const SIZE_STATS_OUT      = 32;  // uint32+uint32+sint64*3

USE_REAL_SC Env-Varenv var

# Mock (default)
npm run dev

# Real SC (needs CONTRACT_ADDRESS + CONTRACT_INDEX in .env)
USE_REAL_SC=true npm run dev

Beim Start zeigt der Server: Backend: 🔗 Qubic SC (real) oder Backend: 🧪 In-Memory Mock.On startup the server shows: Backend: 🔗 Qubic SC (real) or Backend: 🧪 In-Memory Mock.

19

Demo starten & API Tester bedienen Running the Demo & Using the API Tester

Der QubicShield-Server ist ein einzelner Express-Prozess, der gleichzeitig das Frontend ausliefert und die API-Endpunkte bereitstellt. Es gibt keinen separaten Frontend-Server.

Server starten

cd qubicshield
npm run dev

Die Konsole zeigt dann:

QubicShield Demo Server running at http://localhost:3000
Backend: 🧪 In-Memory Mock

Routes:
  POST /api/deposit          – create deposit
  GET  /api/validate/:token  – validate token
  POST /api/refund           – refund deposit
  GET  /api/protected        – access protected resource
  GET  /api/stats            – system statistics
  GET  /                     – demo UI

Was du siehst

Der Server liefert drei Seiten unter http://localhost:3000:

URLSeiteBeschreibung
/ API Tester Interaktive Demo: Deposit erstellen, Token validieren, Protected Resource aufrufen, Angriff simulieren, Live-Statistiken. Tabs für jeden Schritt.
/demo.html Simulation Vollautomatischer Ablauf mit Stepper-Anzeige und Aktivitäts-Log. Wähle eine Ziel-URL (erreichbar → Refund, nicht erreichbar → DDoS-Forfeit). Browser-Vorschau zeigt HTTP-Status.
/dashboard.html Dashboard Live-Übersicht: Stat-Karten (Deposits, Sessions, gebundene QU, Forfeits), Forfeit-Split-Balken, aktive Sessions-Tabelle, Event-Log mit allen Ereignissen. Aktualisiert alle 8 Sekunden.

Alle Seiten: DE / EN Sprachumschalter oben rechts · grüner Punkt = Server online · Navigation zwischen den Seiten über die Buttons Home / Simulation / Dashboard.

Typischer Ablauf

  1. Deposit erstellen — beliebige Wallet-Adresse eingeben, Betrag wählen, Button klicken. Server gibt sessionId + accessToken zurück — werden automatisch in alle anderen Felder übertragen.
  2. Token validieren — prüft ob der Token noch gültig ist (Ablaufzeit, Request-Zähler).
  3. Protected Resource aufrufen — simuliert einen API-Aufruf unter dieser Session. Bei zu vielen Anfragen wird der Deposit einbehalten (DDoS-Erkennung).
  4. Refund anfordern — gibt den Deposit zurück, solange kein Angriffsmuster erkannt wurde.
  5. Stats abrufen — Übersicht aller Deposits, Forfeits und Gesamtzahlen.

Jede Karte zeigt außerdem den äquivalenten curl-Befehl zum Aufklappen — nach einem Deposit werden die echten Werte automatisch eingesetzt.

Grundprinzip

1 Deposit = 1 Session = 1 Token. Das ist die Sicherheitslogik — jeder API-Zugriff hat einen eigenen Einsatz. Mehrmals auf „Deposit erstellen" klicken erzeugt mehrere unabhängige Sessions mit je eigenem Token und heldAmount. Ein Token verfällt nach 30 Minuten — danach ist ein neuer Deposit nötig.

Mock-Modus vs. echter SC

Standardmäßig läuft alles im Mock-Modus — kein echtes Wallet nötig, Deposits leben nur im RAM (weg bei Neustart). Für den echten Smart Contract:

USE_REAL_SC=true npm run dev

The QubicShield server is a single Express process that simultaneously serves the frontend and provides the API endpoints. There is no separate frontend server.

Starting the server

cd qubicshield
npm run dev

The console will show:

QubicShield Demo Server running at http://localhost:3000
Backend: 🧪 In-Memory Mock

Routes:
  POST /api/deposit          – create deposit
  GET  /api/validate/:token  – validate token
  POST /api/refund           – refund deposit
  GET  /api/protected        – access protected resource
  GET  /api/stats            – system statistics
  GET  /                     – demo UI

What you see

The server serves three pages under http://localhost:3000:

URLPageDescription
/ API Tester Interactive demo: create deposit, validate token, call protected resource, simulate attack, view live statistics. One tab per step.
/demo.html Simulation Fully automated flow with stepper display and activity log. Choose a target URL (reachable → refund, unreachable → DDoS forfeit). Browser preview shows the HTTP status.
/dashboard.html Dashboard Live overview: stat cards (deposits, sessions, held QU, forfeits), forfeit split bar, active sessions table, event log with all events. Auto-refreshes every 8 seconds.

All pages: DE / EN language toggle top right · green dot = server online · navigation between pages via the Home / Simulation / Dashboard buttons.

Typical workflow

  1. Create deposit — enter any wallet address, choose an amount, click the button. The server returns a sessionId + accessToken — auto-filled into all other fields.
  2. Validate token — checks if the token is still valid (expiry time, request counter).
  3. Call protected resource — simulates an API call under this session. Too many requests trigger DDoS detection and the deposit is forfeited.
  4. Request refund — returns the deposit as long as no attack pattern was detected.
  5. Fetch stats — overview of all deposits, forfeits, and totals.

Each card also shows the equivalent curl command — click to expand. After a deposit, the real values are automatically substituted.

Core principle

1 Deposit = 1 Session = 1 Token. This is the security logic — every API access has its own stake. Clicking "Create Deposit" multiple times creates multiple independent sessions, each with its own token and heldAmount. A token expires after 30 minutes — a new deposit is required after that.

Mock mode vs. real SC

By default everything runs in mock mode — no real wallet needed, deposits live in RAM only (gone on restart). To use the real smart contract:

USE_REAL_SC=true npm run dev
20

🛡 DDoS-Erkennung & Deposit-Forfeit DDoS Detection & Deposit Forfeit

QubicShield erkennt Angriffsmuster automatisch in zwei unabhängigen Schichten und behält den Deposit des Angreifers ein (forfeit). Der Angreifer verliert sein Geld — der Dienst bleibt verfügbar.

Schicht 1 — Rate Limiter Middleware

Datei: src/middleware/rateLimiter.ts

Implementiert ein Sliding Window pro Access-Token:

  • Fenster: 60 Sekunden
  • Schwellwert: 50 Anfragen → setzt isAttacking = true
  • Setzt Response-Header: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Window
  • Blockt nicht sofort — gibt dem Route-Handler die Möglichkeit, den Deposit zuerst einzubehalten

Schicht 2 — DepositManager

Datei: src/depositManager.ts → Methode isAttacking()

Zweiter unabhängiger Zähler mit eigenem Schwellwert:

  • Fenster: 60 Sekunden
  • Schwellwert: 100 Anfragen → Deposit wird einbehalten
  • Wird auch beim Refund-Versuch geprüft — wer angreift und dann Geld zurückfordert, verliert den Deposit trotzdem

Ablauf bei erkanntem Angriff

1. Request kommt rein → rateLimiter prüft (50 req/min)
2. Route: depositManager.isAttacking() prüft (100 req/min)
3. Bei Überschreitung → forfeitDeposit() → Deposit einbehalten
4. HTTP 403: "Attack pattern detected. Deposit has been forfeited."

Live-Demo im API Tester

Im API Tester (localhost:3000) gibt es die Karte „DDoS-Angriff simulieren". Ein Klick auf „Angriff starten" sendet automatisch 110 Anfragen in schneller Folge. Ein Fortschrittsbalken zeigt den Verlauf — sobald der Server den Angriff erkennt (typisch nach ~100 Anfragen), wird der Deposit einbehalten und der Balken springt auf rot.

QubicShield automatically detects attack patterns in two independent layers and forfeits the attacker's deposit. The attacker loses their money — the service stays available.

Layer 1 — Rate Limiter Middleware

File: src/middleware/rateLimiter.ts

Implements a sliding window per access token:

  • Window: 60 seconds
  • Threshold: 50 requests → sets isAttacking = true
  • Sets response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Window
  • Does not block immediately — lets the route handler forfeit the deposit first

Layer 2 — DepositManager

File: src/depositManager.ts → method isAttacking()

Second independent counter with its own threshold:

  • Window: 60 seconds
  • Threshold: 100 requests → deposit is forfeited
  • Also checked on refund attempts — an attacker trying to reclaim their deposit still loses it

Flow when attack is detected

1. Request arrives → rateLimiter checks (50 req/min)
2. Route: depositManager.isAttacking() checks (100 req/min)
3. Threshold exceeded → forfeitDeposit() → deposit held
4. HTTP 403: "Attack pattern detected. Deposit has been forfeited."

Live demo in the API Tester

The API Tester at localhost:3000 has a card "Simulate DDoS Attack". One click on "Start Attack" automatically fires 110 requests in rapid succession. A progress bar shows the progress — once the server detects the attack (typically after ~100 requests), the deposit is forfeited and the bar turns red.

17

🚀 Nächste Schritte Next Steps

Qubic Community / Team kontaktierenVorhaben im Discord vorstellen (#developers), Feedback einholen, Testnet-Deploy-Prozess klärenpresent project in Discord (#developers), gather feedback, clarify testnet deploy process
Testnet DeployContract auf Qubic Testnet deployen und testendeploy contract to Qubic testnet and test
21

⚠️ Offene Probleme & bekannte Einschränkungen Open Issues & Known Limitations

Diese Punkte wurden bei der Analyse des PoC identifiziert. Sie sind kein Blocker für das Konzept, müssen aber vor einem produktiven Einsatz gelöst werden. These issues were identified during PoC analysis. They are not blockers for the concept, but must be resolved before production use.

1. Epochenwechsel (jeden Mittwoch ~12:00 UTC) 1. Epoch Change (every Wednesday ~12:00 UTC)
Das Qubic-Netzwerk startet wöchentlich neu. Der Ausfall kann bis zu 45 Minuten dauern. Die aktuelle Retry-Logik in scClient.ts deckt nur 5 × 8 s = 40 Sekunden ab. Während des Ausfalls gibt der Server 502-Fehler zurück — kein Fallback-Modus ist implementiert. Das Qubic-Team arbeitet an einer Lösung. The Qubic network restarts weekly. The outage can last up to 45 minutes. The current retry logic in scClient.ts covers only 5 × 8 s = 40 seconds. During the full outage window the server returns 502 errors — no degraded-mode fallback is implemented. The Qubic team is working on a fix.
2. Leere Ticks (stille Transaktion-Verwerfung) 2. Empty Ticks (silent transaction drop)
Qubic-Ticks produzieren gelegentlich keinen Block. Eine Transaktion, die in so einen Tick gesendet wird, wird stillschweigend verworfen. scClient.ts erkennt veraltete Ticks und wiederholt den Versuch bis zu 5-mal — aber der Client erhält nur eine txId zurück und muss /api/validate/<token> manuell pollen. Wenn alle Versuche in leeren Ticks landen, bleibt der Deposit unbestätigt. Qubic ticks occasionally produce no block. A transaction broadcast to such a tick is silently discarded. scClient.ts detects stale ticks and retries up to 5 times — but the client only receives a txId and must manually poll /api/validate/<token>. If all retries land in empty ticks, the deposit never confirms.
3. On-Chain Forfeit nicht implementiert ⚠️ Testnet-Blocker 3. On-Chain Forfeit not implemented ⚠️ Testnet blocker
Die Angriffserkennung läuft lokal im Server. Wenn ein Angriff erkannt wird, wird depositManager.forfeitDeposit() aufgerufen — das betrifft aber nur den Mock-Zustand. Die Forfeit()-Procedure im Smart Contract wird nie aufgerufen. Im SC-Modus behält ein Angreifer seine Kaution on-chain. Muss vor dem Testnet-Deploy implementiert werden. Attack detection runs locally in the server. When an attack is detected, depositManager.forfeitDeposit() is called — but this only updates mock state. The Forfeit() procedure on the smart contract is never invoked. In SC mode an attacker keeps their deposit on-chain. Must be implemented before a meaningful testnet test.
4. Session-Slot-Limit (MAX_DEPOSITS = 512) 4. Session slot limit (MAX_DEPOSITS = 512)
PoC-Wert. Wenn alle Slots belegt sind, werden neue Deposits mit einem kryptischen Fehlercode abgelehnt. Kein Warteschlangen-Mechanismus, keine Überlaufstrategie und keine benutzerfreundliche Fehlermeldung vorhanden. Für Produktion erhöhen und Überlaufverhalten definieren. PoC value. When all slots are occupied, new deposits are rejected with a cryptic error code. No queue, overflow strategy, or user-facing message is implemented. Raise for production and define overflow behavior.
5. False Positives — kein Einspruchsprozess 5. False positives — no dispute mechanism
Ein legitimer Nutzer könnte durch aggressives Browser-Polling, Monitoring-Tools oder eine falsch kalibrierte Schwelle als Angreifer erkannt werden und seine Kaution verlieren. Es gibt keinen dokumentierten Einspruchs- oder Rückerstattungsprozess für solche Fälle. A legitimate user could be flagged as an attacker due to aggressive browser polling, monitoring tools, or a miscalibrated threshold and lose their deposit. No dispute or appeal process is documented for such cases.
6. Event-Log nur im Mock-Modus 6. Event log only in mock mode
GET /api/events funktioniert nur im Mock. Im echten SC-Modus gibt es keinen Audit-Trail für Deposits, Rückerstattungen oder Konfiszierungen — das Dashboard zeigt dann keine Events. GET /api/events only works in mock mode. In real SC mode there is no audit trail for deposits, refunds, or forfeit decisions — the dashboard shows no events.