Skip to main content
A client submits a location claim to the backend, which creates a Sepolia task. Each operator measures RTT, responds onchain and returns its own signed attestation. The indexer stores records in Postgres.

Task submission

The authenticated client sends coordinates to Offline Protocol’s backend. The backend generates a random task id and a secret per-commitment nonce, derives a precision-5 geohash and keccak256(username, geoHash, nonce) commitment, and calls LocationServiceManager.createNewTask. The nonce is never published. Contracts are on Ethereum Sepolia. A contract upgrade to restrict task creation to the backend is pending; the current contract does not establish that restriction. The backend returns the operator URLs configured in AVS_OPERATOR_URLS. This is a centrally configured list, not permissionless operator discovery; the default list has one entry.

Task identifiers

id is a fresh random 32-byte value per commitment, encoded as 0x followed by 64 hexadecimal characters. The commitment is keccak256(username, geoHash, nonce) using a secret per-commitment nonce that is never published, so the onchain identifiers and commitments do not group tasks by user or identify the username. Tasks created before random IDs were introduced retain their old linkable IDs. Correlate each submission with its id and transaction, then verify the attestation against the intended task and commitment.

Witness measurement

The raw client opens a WebSocket to each selected operator and sends id and claimed coordinates. The operator keys its Redis lookup by the random task id. Follow the raw protocol. A ping/pong/ack exchange lets the operator measure round-trip time with a high-resolution timer and compare inferred distance with the distance from its configured coordinates to the client’s claim. The implemented rule accepts a claim if either:
  • the absolute difference between claimed distance and RTT-inferred distance is below 20 km; or
  • the measured RTT is between 0.8 and 1.5 times the theoretical minimum RTT for the claimed distance.
These tolerances do not prevent spoofing. A client can add delay, and the operator trusts client-supplied claim fields. See security boundaries.

Individual results

Each operator calls respondToTask with its own signed response. It separately creates an EIP-191 attestation binding the chain/deployment, task, result and issue time, and pushes { type: "attestation", attestation } over the WebSocket. The serialized attestation is cached in Redis for 24 hours; that cache is not a documented public retrieval API. The operator also writes attestations to Postgres when LOCATION_DATABASE_URL is set. Each onchain witness response costs the operator Sepolia gas. The result identifies the operator, chainId, service manager, stake registry, task index, task fields, isOk, issuedAtMs and signature. A consumer must verify the signer, deployment, task binding, freshness and its own acceptance policy. The signature authenticates the witness’s statement, not the truth of a location claim.

Indexing

The commitment service stores the username, id, commitment, transaction and secret nonce in location_db. The indexer records contract events in Postgres with the centre point of each task’s public geohash cell. Neither service stores the submitted coordinates. These database copies have no time-based expiry; the 24-hour TTL applies to Redis only. The indexer does not aggregate witness responses or publish a final proof onchain. The presence of a slashing method in an ABI is not evidence of an active slashing workflow; no service implements that workflow. Account deletion purges the user’s commitment rows (including the nonce), indexed task rows and stored attestations. Onchain geohashes and task times remain permanent. Tasks created before the random-id change retain their linkable identifiers.