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.
ContractsAccess Registry

AccessRegistry

Source of truth for API listings: descriptors, plans (PPC/Subscription), per‑API consensus/freshness parameters, and provider signer. It also manages request IDs, a simple subscription ledger, and emits events that UIs/indexers can follow.

Interact with the proxy address published under Architecture → Addresses & ABIs. This contract is UUPS‑upgradeable, ownable, and pausable.


Responsibilities

  • Register APIs (apiId) with providerOwner, providerSigner, plan, and timing caps.
  • Store descriptor integrity anchors (uri, contentHash, version, updatedAt).
  • Expose plan fields: accessType, price, duration, callLimit, active.
  • Expose per‑API consistency/freshness params: seqMonotonic, maxSkewMs, maxTtlMs, and the effective providerSigner.
  • Guard request creation with expiry windows and per‑consumer nonces (derives requestId).
  • Maintain a subscription ledger (subscriptionEndsAt, remainingCalls).

Data structures

enum AccessType { Subscription, PayPerCall } struct APIPlan { AccessType accessType; // 0=Subscription, 1=PayPerCall uint256 price; // in SYL (18d) uint256 duration; // seconds for subscriptions; 0 for PPC uint256 callLimit; // max calls per period (0 = unlimited) bool active; // listing on/off } struct Descriptor { string uri; // e.g. ipfs://CID bytes32 contentHash; // keccak256(canonical descriptor) uint64 updatedAt; // block.timestamp (s) uint32 version; // 1,2,3... } struct ApiMeta { address providerOwner; // who can update this API's settings address providerSigner;// EIP‑712 signer for Snapshots bool seqMonotonic; // enforce non‑decreasing seqNo at finalize uint64 maxSkewMs; // allowed future skew for providerTs uint64 maxTtlMs; // cap applied to Snapshot.ttl (0 = no cap) bool active; // listing active flag } struct ConsensusParams { uint8 placeholder; } // reserved

Global state

  • paymentToken() → SYL address (discoverability)
  • apiEscrow() / apiConsensus() / nodeRegistry() → wired contract addresses
  • maxRequestExpiryMs (owner‑set; default 60_000 ms; max 10 minutes)
  • enforceSignerTimelock (owner toggle) and signerUpdateUnlockAt[apiId]

Views (read model)

  • API registry
    • apiMeta(apiId) → ApiMeta
    • descriptorOf(apiId) → Descriptor
    • apiPlan(apiId) → APIPlan
    • consensusParams(apiId) → ConsensusParams
  • Per‑API convenience
    • providerSignerOf(apiId) → address
      • If signer timelock is active and not yet elapsed, returns address(0) (snapshots should be rejected during the window).
    • seqMonotonic(apiId) → bool
    • maxSkewMs(apiId) → uint64
    • maxTtlMs(apiId) → uint64
    • isApiActive(apiId) → bool
  • Requests & subscriptions
    • consumerNonce(consumer, apiId) → uint256 (increments on request creation)
    • subscriptionEndsAt(consumer, apiId) → uint64 (unix seconds)
    • hasActiveSubscription(consumer, apiId) → bool
    • remainingCalls(consumer, apiId) → uint256

Writes (by role)

Owner (contract admin)

  • setApiEscrow(address) / setApiConsensus(address) / setNodeRegistry(address)
  • setMaxRequestExpiryMs(uint64) (cap ≤ 10 minutes)
  • setSignerTimelock(bool) (enforce signer rotation delay)
  • pause() / unpause()

Provider owner (per‑API admin)

  • Register
    • registerApi(apiId, providerOwner, providerSigner, seqMonotonic, maxSkewMs, maxTtlMs, plan)
    • registerApiAndDescriptor(..., plan, descriptorUri, descriptorHash) (helper)
    • Emits ApiRegistered
  • Descriptor
    • setDescriptor(apiId, uri, contentHash) → bumps version, sets updatedAt
    • Emits DescriptorSet
  • Signer
    • setProviderSigner(apiId, newSigner) → if timelock enforced and both old/new non‑zero, sets signerUpdateUnlockAt
    • Emits ProviderSignerUpdated
  • Plan & timing
    • setPlan(apiId, APIPlan) (validates PPC duration==0, Sub duration>0, price>0)
    • setTimingCaps(apiId, maxSkewMs, maxTtlMs)
    • Emits PlanUpdated, TimingCapsUpdated
  • Activation
    • setApiActive(apiId, bool)Emits ApiActiveSet

Escrow (protocol hook)

  • recordSubscription(consumer, apiId, startTs, endTs, amountPaid)
    • Extends subscriptionEndsAt monotonically; if callLimit>0, resets remainingCalls.
    • Emits SubscriptionRecorded.

Requests (consumers / escrow)

  • createRequest(apiId, requestHash, expiresAtMs) — uses msg.sender as consumer.
  • createRequestFor(consumer, apiId, requestHash, expiresAtMs) — for Escrow to mirror PPC locks.

Request rules

  • expiresAtMs must be > now and within maxRequestExpiryMs.
  • If plan is Subscription: require hasActiveSubscription(consumer, apiId) and, when callLimit>0, decrement remainingCalls.
  • Nonce increments per (consumer, apiId); see Request ID derivation.
  • Emits RequestCreated.

Request ID derivation

Deterministic and collision‑resistant:

requestId = keccak256( abi.encodePacked( bytes1(0x01), // domain tag address(this), block.chainid, apiId, consumer, nonce // ++consumerNonce[consumer][apiId] ) );

UIs/indexers should join events by requestId across AccessRegistry, APIConsensus, and APIEscrow.


Events

  • ApiRegistered(bytes32 apiId, address providerOwner, address providerSigner)
  • DescriptorSet(bytes32 apiId, string uri, bytes32 contentHash, uint32 version)
  • ProviderSignerUpdated(bytes32 apiId, address oldSigner, address newSigner)
  • ApiActiveSet(bytes32 apiId, bool active)
  • TimingCapsUpdated(bytes32 apiId, uint64 maxSkewMs, uint64 maxTtlMs)
  • PlanUpdated(bytes32 apiId, AccessType accessType, uint256 price, uint256 duration, uint256 callLimit, bool active)
  • SubscriptionRecorded(bytes32 apiId, address consumer, uint64 startTs, uint64 endTs, uint256 amountPaid)
  • RequestCreated(bytes32 requestId, bytes32 apiId, address consumer, bytes32 requestHash, uint64 expiresAtMs, uint256 nonce)

Some builds also declare SubscriptionRequest for UI analytics; it’s ancillary to the core flow.


Minimal ABI (client‑facing reads)

[ {"type":"function","stateMutability":"view","name":"descriptorOf","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"tuple","components":[{"name":"uri","type":"string"},{"name":"contentHash","type":"bytes32"},{"name":"updatedAt","type":"uint64"},{"name":"version","type":"uint32"}]}]}, {"type":"function","stateMutability":"view","name":"apiPlan","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"tuple","components":[{"name":"accessType","type":"uint8"},{"name":"price","type":"uint256"},{"name":"duration","type":"uint256"},{"name":"callLimit","type":"uint256"},{"name":"active","type":"bool"}]}]}, {"type":"function","stateMutability":"view","name":"providerSignerOf","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"address"}]}, {"type":"function","stateMutability":"view","name":"seqMonotonic","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"bool"}]}, {"type":"function","stateMutability":"view","name":"maxSkewMs","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"uint64"}]}, {"type":"function","stateMutability":"view","name":"maxTtlMs","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"uint64"}]}, {"type":"function","stateMutability":"view","name":"isApiActive","inputs":[{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"bool"}]}, {"type":"function","stateMutability":"view","name":"consumerNonce","inputs":[{"name":"consumer","type":"address"},{"name":"apiId","type":"bytes32"}],"outputs":[{"type":"uint256"}]} ]

Integration tips

  • Signer rotation: while signerUpdateUnlockAt[apiId] is in the future, providerSignerOf(apiId) returns 0x0. Nodes should treat snapshots as unauthorized until the window elapses.
  • Expiry windows: clients must set expiresAtMs within maxRequestExpiryMs; the default is 60s, owner‑configurable up to 10 minutes.
  • Subscriptions: after recordSubscription, remainingCalls resets to callLimit (if > 0). UIs can call createRequest(...) for per‑call analytics under subscriptions—no additional funds move.

Admin & security notes

  • Provider mutations are gated by providerOwner; rotate with care. Keep providerSigner in HSM/HW wallet.
  • Owner can pause the registry; UIs should disable writes while paused.
  • Only Escrow should call recordSubscription / createRequestFor (enforced by modifiers).

Out of scope for this page

  • Pricing/escrow semantics → APIEscrow
  • Vote/settlement logic → APIConsensus
  • Node eligibility/slashing → NodeRegistry
  • Addresses & minimal ABIs → Architecture → Addresses & ABIs
Last updated on