Event-Driven Everything: DUAL's Event Bus Architecture

Event-Driven Everything: DUAL's Event Bus Architecture

Part 3 of 6

A construction project manager stares at a spreadsheet showing 47 subcontractors working on different phases. When contractor A finishes their phase, contractor B can't start until someone manually verifies A's completion, approves the payment, and notifies B. This "waterfall with lag" is built into every construction workflow.

The lag isn't caused by incompetence. It's caused by disconnected systems. The milestone proof lives in one system. The payment rules live in another. The notification system is a third. Payment can't be released until a human manually confirms the proof matches the rules, then triggers the notification.

DUAL's Event Bus inverts this: events flow through a single shared channel. Every token subscribes to events it cares about. When an event fires, all dependent systems react atomically, instantly, and in order.

A Concrete Cascade: From Milestone to Payment to Notification

Let's trace a BuildFinance milestone from submission to downstream contractor notification:

1. MILESTONE_SUBMITTED Subcontractor uploads inspection photos, GPS location, timestamp. Event fires: event_type="MILESTONE_SUBMITTED", source_token="build_phase_042801" 2. COMPLIANCE_CHECKS_EXECUTE Payment release token subscribes to MILESTONE_SUBMITTED. Three rules execute in parallel (photo metadata, inspector cert, insurance). All complete in < 500ms. 3. MILESTONE_VERIFIED Compliance passed. Token emits: event_type="MILESTONE_VERIFIED" 4. PAYMENT_TRIGGERED Lender's payment token subscribes to MILESTONE_VERIFIED. Calculate: milestone_value × 95% = payment, emit PAYMENT_READY 5. FUNDS_TRANSFERRED Escrow executes blockchain transaction. Emit: PAYMENT_EXECUTED 6. NOTIFICATIONS_FIRE Three subscribers react to PAYMENT_EXECUTED: → Subcontractor (SMS/email): "Payment received" → Lender accounting: update balance sheet → Next contractor token: state → READY_TO_START 7. READY_TO_START Next phase contractor token receives notification. State changes from BLOCKED to READY. Dashboard updates.

The entire cascade completes in < 2 seconds. Every step is logged immutably. If any step fails, the cascade stops and emits a diagnostic event. No human intervention needed.

Why Event Bus Beats Webhooks

Traditional webhook systems are fragile:

Property REST Webhooks DUAL Event Bus
Delivery Guarantee No — if receiver is down, event is lost Yes — queues until receiver ready
Order Preservation No — concurrent requests may reorder Yes — strict ordering per token
Replay No — events disappear Yes — full history queryable
Idempotency No — duplicates possible Yes — de-duplicated by token state

Real consequence: With REST webhooks, if the lender's system briefly goes offline, the PAYMENT_EXECUTED event is lost. Subcontractors don't get paid notifications. The next phase contractor incorrectly starts work. Disputes ensue.

With DUAL Event Bus, the event queues. When lender comes back online, PAYMENT_EXECUTED processes normally. All downstream notifications fire. The state machine stays consistent with reality.

Event Message Format: Self-Describing, Cryptographically Signed

Every event follows this canonical structure:

{
  // Unique event ID for replay protection
  "event_id": "evt_042801_1712689301_001",

  // What happened
  "event_type": "MILESTONE_VERIFIED",

  // Which token generated this event
  "source_token_id": "build_phase_042801",

  // Event-specific data
  "payload": {
    "verified_at": 1712689302,
    "checks_passed": [
      "photo_metadata_valid",
      "inspector_certified",
      "insurance_coverage_active"
    ],
    "milestone_value_cents": 500000
  },

  // Who authorized this event
  "actor_did": "subcontractor_001_did",

  // Cryptographic proof of authenticity
  "signature": "0x...",

  // Timestamp from clock oracle (prevents replay)
  "timestamp": 1712689302,

  "network": "dual_mainnet_v1"
}

This ensures every event is:

  • Authentic: Signature proves actor authorization
  • Tamper-proof: Any change invalidates the signature
  • Timestamped: Clock oracle prevents replay attacks
  • Queryable: Event ID allows historical lookup
  • Traceable: Links back to source token

Real Example: Auction to Delivery Event Flow

An e-commerce auction completes. This single event triggers a cascade across multiple token types:

Event Token Affected Result
AUCTION_WON Product token state → SOLD, owner → buyer
INVOICE_CREATED Invoice token amount = final_bid + tax + shipping, state → ISSUED
PAYMENT_EXECUTED Escrow account Funds held, seller notified payment pending
SHIPMENT_CREATED Shipment token, inventory Inventory decremented, shipment → IN_TRANSIT
DELIVERY_CONFIRMED Product, seller reputation Escrow → seller, buyer review enabled, seller rating +1

Each event is independent, but causally connected. The Event Bus ensures:

  1. Events process in order (auction won before payment)
  2. If a step fails (insufficient buyer funds), downstream events halt
  3. All state changes are atomic from the distributed system's perspective

Token Subscriptions: Fine-Grained Event Filtering

Not every token cares about every event. DUAL provides fine-grained filtering:

// "Next phase" contractor token
token "phase_b_contractor" {
  subscribe_to: [
    {
      "event_type": "MILESTONE_VERIFIED",
      "source_token": "phase_a_token",
      "on_fire": transition_to("READY_TO_START")
    }
  ]
}

This token only reacts to one event: MILESTONE_VERIFIED from phase A. When it fires, this token automatically transitions to READY_TO_START. No polling, no manual checks.

Failure Recovery and Compensation Events

If payment execution fails (insufficient funds), the Event Bus emits a compensation event:

{
  "event_type": "PAYMENT_FAILED",
  "source_token_id": "build_phase_042801",
  "failure_reason": "insufficient_lender_funds",
  "timestamp": 1712689305
}

Tokens subscribed to PAYMENT_EXECUTED don't receive it. They receive PAYMENT_FAILED instead:

if (event.type == "PAYMENT_FAILED") {
  token.state = "PAYMENT_PENDING"
  emit "ALERT_LENDER_INSUFFICIENT_FUNDS"
}

Next phase contractor token stays BLOCKED (not READY_TO_START). Lender is alerted. The system is correct: it reflects reality.

Scaling: Why Event Bus is Fast

Concern: With hundreds of milestones submitting simultaneously, won't the Event Bus become a bottleneck?

Answer: No, because events process in parallel.

  • 50 milestone submissions → 50 parallel event streams
  • Each stream: photo check (parallel), inspector cert (parallel), insurance check (parallel)
  • Total time: ~1 second for all 50 milestones to complete compliance

Compare to manual: 50 milestones × 1 hour coordination per milestone = 50 hours. DUAL: 1 second. That's a 180,000× speedup.

Comparison: Manual Coordination vs. Event-Driven

Manual Coordination

Process: Human reviews proof, checks rules, sends notifications

Time: 1-2 hours per milestone

Reliability: Depends on human attention

Auditability: Implicit; hard to reconstruct decisions

Event Bus Automation

Process: Tokens react to events automatically

Time: < 2 seconds per milestone

Reliability: Guaranteed delivery, ordered execution

Auditability: Full event history, immutable

Key Takeaway
The Event Bus is DUAL's nervous system. It decouples systems through a single ordered, reliable event channel. When a state change occurs (milestone verified, payment executed, location confirmed), every dependent system reacts atomically. Traditional systems achieve coordination through polling, batch jobs, and human intervention. DUAL makes it event-driven and instant.

What's Next

Events are asynchronous signals. But some events carry special information: location data. In Part 4, we'll explore how DUAL tokens embed geo-positioning, enabling location-aware economies where tokens behave differently based on where they are in the physical world.

Continue to Part 4: Geo-Positioning Unlocks →