Skip to Content
⚠️ Alert: Sylan is under active development—only trust contract/wallet addresses announced on our official channels; we will never DM you, ask for funds, or run surprise airdrops/presales.
ConceptsRequest Lifecycle

Request Lifecycle

This page walks through how a single Pay‑Per‑Call (PPC) request moves from funding → consensus → settlement. Subscription flows are noted where they differ.

Terminology used here: apiId (bytes32), requestHash (bytes32), expiresAtMs (uint64). Event names are listed to help you trace on explorers and in your app logs.


0) Pre‑flight (client)

  • Fetch descriptor via AccessRegistry.descriptorOf(apiId){ uri, contentHash, updatedAt, version }.
  • Build your request payload (path/params/headers/body). Compute a deterministic requestHash (e.g., keccak256 of canonical JSON).
  • Pick an expiry: expiresAtMs = nowMs + Δ where Δ ≤ maxRequestExpiryMs from AccessRegistry.
  • Ensure the wallet has SYL and the Escrow contract has allowance.

1) Lock funds (PPC)

Caller: Consumer → APIEscrow.lockForCall(apiId, requestHash, expiresAtMs)

What happens on‑chain:

  1. Price & plan check (AccessRegistry.apiPlan) → must be PayPerCall and active.
  2. Pull funds from the consumer (SYL = price).
  3. Create requestId in AccessRegistry (increments consumerNonce) and emit:
    • AccessRegistry.RequestCreated (contains requestId, apiId, consumer, requestHash, expiresAtMs, nonce).
  4. Register with ConsensusAPIConsensus.registerRequest(...) emits:
    • APIConsensus.RequestRegistered (mirrors metadata above).
  5. Escrow emits:
    • APIEscrow.Locked (requestId, apiId, consumer, price, expiresAtMs).

Subscriptions: The consumer purchases once via APIEscrow.purchaseSubscription(apiId). Escrow allocates fees and AccessRegistry records the period. Individual calls don’t lock funds; clients may (optionally) record usage with AccessRegistry.registerSubRequest.


2) Nodes fetch & attest (off‑chain + on‑chain)

Off‑chain: Registered Nodes retrieve the Provider’s response per the descriptor. Providers sign snapshots using EIP‑712.

On‑chain (per Node): APIConsensus.submitSnapshot(requestId, Snapshot, providerSig, pointerURI)

  • Snapshot fields: { apiId, seqNo, providerTs, ttl, contentHash }.
  • Checks performed:
    • API is active; a providerSigner exists for apiId.
    • EIP‑712 signature matches providerSigner.
    • Freshness: providerTs within maxSkewMs; if ttl != 0, not stale (capped by maxTtlMs).
    • One vote per node; votes tally by (msgHash → votes).
    • Provider equivocation is detected: if two different contentHash are seen for the same (apiId, seqNo), emit ProviderEquivocation.
  • Emits: APIConsensus.ResponseSubmitted per snapshot.

Fork‑choice: the candidate with the most votes becomes topHash. If seqMonotonic is enabled for the API, finalization also requires seqNo not regress.


3) Finalization (consensus)

Consensus can finalize early when quorum is reached, or later after expiry + a grace window.

  • Early path: Once any digest reaches quorum, consensus finalizes immediately.
  • Deadline path: Anyone may call APIConsensus.finalize(requestId) when nowMs ≥ expiresAtMs and nowMs ≤ expiresAtMs + requestExpiryGraceMs.
  • Outcomes:
    • RequestFinalized (success) with { apiId, seqNo, providerTs, contentHash, msgHash, votes }.
    • RequestFailed with reason:
      • 1 = NoQuorum
      • 2 = InactiveAPI

4) Settlement (escrow)

Consensus notifies escrow in both cases (idempotent calls):

  • On successAPIEscrow.settleSuccess(requestId)
    • Escrow marks the request settled and splits funds per BPS snapshot taken at lock time: Provider / NodePool / Platform.
    • Emits: APIEscrow.Settled.
  • On failureAPIEscrow.settleFailure(requestId, reason)
    • Escrow refunds the consumer.
    • Emits: APIEscrow.Refunded.

Recipients withdraw accumulated balances via APIEscrow.withdraw()APIEscrow.Withdrawn.

Node slashing & rewards: During finalization, mismatching Nodes may be slashed (via NodeRegistry). Slashed funds can be redistributed to honest participants, and reputation is increased for honest Nodes.


Sequence (PPC)


Status model (conceptual)


Subscription differences

  • Purchase onceAPIEscrow.purchaseSubscription(apiId) allocates fees immediately and records [startTs, endTs] in AccessRegistry.
  • Per‑call usage under a subscription does not lock funds. Your app may emit AccessRegistry.registerSubRequest(apiId, requestHash) for accounting/analytics.
  • Consensus flow for subscription calls can be added by Providers/Nodes off‑chain; on‑chain settlement is not per call in the base flow.

Operational tips

  • Choose expiresAtMs conservatively; allow enough time for nodes to reach quorum but keep it within maxRequestExpiryMs.
  • Watch RequestRegistered, ResponseSubmitted, RequestFinalized/Failed, and Settled/Refunded to drive UI state.
  • Idempotency: settlement functions are safe to call again; your indexer can retry without double‑spending.

See also

  • Consensus (scoring, quorum, EIP‑712 details)
  • Data Integrity (hashing, content addressing)
  • Events (full reference)
  • Node & Provider guides (ops & best practices)
Last updated on