Ward Protocol v0.2.4

Protocol Specification

Technical reference for Ward Protocol: architecture, 9-step claim validation, VaultMonitor, escrow settlement, and all 15 attack-vector mitigations.

204/204 Python · 40/40 Rust · 45/45 TypeScriptSDK v0.2.415 AVs Mitigated

1. Overview

Ward Protocol is an open specification and SDK for deterministic default protection
on XLS-66 institutional lending vaults on the XRP Ledger.

Core invariant: ward_signed = False
Ward constructs unsigned transactions. Institutions sign; XRPL settles.
Ward never holds, touches, or stores private keys.

2. Architecture

Five modules:

  Module 1 — WardClient         High-level SDK entrypoint
  Module 2 — VaultMonitor       WebSocket default detection (3-ledger confirmation)
  Module 3 — ClaimValidator     9-step on-chain claim validation
  Module 4 — EscrowSettlement   PREIMAGE-SHA-256 escrow lifecycle
  Module 5 — PoolHealthMonitor  Coverage ratio + reserve accounting

Shared: ward/primitives.py, ward/constants.py, ward/tx_builder.py

3. 9-Step Claim Validation

Step 1NFT existence & taxon (WARD_POLICY_TAXON = 281)
Step 2Policy expiry — XRPL ledger close_time, never server clock
Step 3Vault address binding — metadata vault == defaulted_vault
Step 4LSF_LOAN_DEFAULT flag on LedgerEntry(index=loan_id)
Step 5Vault loss > 0 drops
Step 6Pool coverage breach — usable = balance − XRPL reserve ≥ 0
Step 7Replay protection — NFT still live (burn-on-settlement)
Step 8Claimant holds NFT — AccountNFTs(account=claimant_address)
Step 9Pool solvency + rate limit (≤ 3/NFT/300 s, ratio ≥ 1.5×)

4. VaultMonitor

Subscribes to XRPL ledger stream via wss:// (TLS required).

Default detection:
  1. WebSocket transaction message received (hint only)
  2. _verify_default_on_chain(): LedgerEntry(index=loan_id) via independent RPC
  3. 3 consecutive ledger closes with LSF_LOAN_DEFAULT set → VerifiedDefault

Reconnect: exponential backoff (1 s → 60 s max)
Heartbeat:  reconnects if no ledger event in MONITOR_HEARTBEAT_TIMEOUT_S (60 s)
URL allow-list: ALLOWED_WS_URLS — rejects unknown or non-TLS endpoints

5. Escrow Settlement

PREIMAGE-SHA-256 (RFC 3230 / IETF Crypto-Conditions):

  1. Claimant: preimage = secrets.token_bytes(32)
  2. Claimant: condition_hex, fulfillment_hex = make_preimage_condition(preimage)
  3. Claimant sends condition_hex to Ward API — preimage never transmitted
  4. Ward builds unsigned EscrowCreate (pool → claimant, condition=condition_hex)
  5. Pool institution signs + submits EscrowCreate
  6. Ward builds unsigned EscrowFinish (fulfillment=fulfillment_hex)
  7. Claimant signs + submits EscrowFinish
  8. Policy NFT burned (NFTokenBurn) — replay protection

ward_signed = False at every step

6. Attack Vector Mitigations

AV 2.1   Policy Forgery         — NFTokenTaxon == 281 enforced at step 1
AV 2.2   Replay / Double-Spend  — NFT burned on settlement; step 1 re-checks
AV 2.3   Policy Transfer        — TF_TRANSFERABLE (0x8) absent; TF_BURNABLE only
AV 2.4   Signal Manipulation    — Independent LedgerEntry RPC on every event
AV 2.5   Clock Manipulation     — XRPL ledger close_time; no time.time()
AV 2.6   Front-Running Escrow   — Ward never receives or stores preimage
AV 2.7   Monitor Spoofing       — wss:// + ALLOWED_WS_URLS allow-list
AV 2.8   Pool Drainage          — Step 6 + Step 9 dual solvency checks
AV 2.9   Coverage Ratio Manip   — Health ratio re-fetched from ledger at step 4
AV 2.10  Address Injection       — validate_xrpl_address() at every API boundary
AV 2.11  Key Exfiltration        — WardClient stores no wallet; per-call only
AV 2.12  Rate Limit Bypass       — Sliding window: 3 attempts/NFT/300 s
AV 2.13  NFT Taxon Spoofing      — _WRONG_TAXON sentinel; taxon check at step 1
AV 2.14  Drops Unit Confusion    — validate_drops() rejects floats, bools, negatives
AV 2.15  Silent Network Failure  — asyncio.wait_for heartbeat; 60 s timeout

7. Protocol Constants

WARD_POLICY_TAXON = 281 # XLS-20 NFT taxon for policy NFTs
WARD_CREDENTIAL_TAXON = 282 # XLS-70 credential NFT taxon
TF_BURNABLE = 0x00000001
TF_TRANSFERABLE = 0x00000008 # deliberately ABSENT from policy NFTs
LSF_LOAN_DEFAULT = 0x00010000
MIN_COVERAGE_RATIO = 1.5
CLAIM_RATE_LIMIT_MAX = 3
CLAIM_RATE_LIMIT_WINDOW_S = 300
MONITOR_HEARTBEAT_TIMEOUT_S = 60
XRPL_BASE_RESERVE_DROPS = 2_000_000
XRPL_OWNER_RESERVE_DROPS = 200_000
RIPPLE_EPOCH_OFFSET = 946_684_800