Security model
Who is trusted, how authority and replay protection work, and what the contracts deliberately leave out.
This page explains the design. Reporting, audit status and the list of known issues are in SECURITY.md.
Trust assumptions
- Curation is one immutable address in
ProviderRegistryandJobRegistry, and is fully trusted. It controls provider registration, listing, capacity ceilings, reputation, the model catalog, the allowlist, fees (protocol fee capped at 10%), allowed SLAs, the treasury, and whichJobRegistrymay move reputation.AskRegistryhas no curation surface. - The payment token is trusted to behave as described in Payment token requirements.
- Relayers have no authority. They can delay, reorder or drop transactions, but cannot change signed terms.
- Signers of protocol operations are EOAs. ERC-1271 contract signatures are not supported.
Authority
No client or provider entry point reads msg.sender. Each recovers an EIP-712 signer and refuses address(0) before any comparison. Provider operations resolve the signer to a provider id through ProviderRegistry.idOf; claimant checks, designation and ask ownership compare ids, not addresses, so they survive an operator key rotation.
reclaim is unsigned and permissionless on purpose: a job past its SLA must be resolvable by anyone, so no single party can strand escrow by doing nothing.
Each contract has its own EIP-712 domain name (VORQ Jobs, VORQ Providers, VORQ Asks), so a signature for one contract never verifies at another, even if addresses are misconfigured.
Replay and freshness
| Types | Rule | Replay guard |
|---|---|---|
Claim, Settle, Fail, Cancel | issuedAt within ±600 s of block.timestamp, inclusive; otherwise StaleOp. | The one-shot job state machine. No nonce. |
RequestCapacity, SetIdentity | issuedAt above that type's per-provider floor (lastCapacityAt, lastIdentityAt) and at most block.timestamp + 3600; otherwise StaleOp. | Per-provider monotonic timestamp, one per type. |
AskSnapshot | signedAt above lastSignedAt[providerId] and at most block.timestamp + 3600; otherwise the entry is skipped. | Per-provider monotonic timestamp. |
Order | No issuedAt; bounded by expiresAt. | A jobId can be posted once. |
| Payment authorization | nonce = jobId, validBefore = expiresAt + 1. | The token's per-authorizer nonce. |
A signature with a far-future issuedAt / signedAt blocks further updates of that type until that time passes; the +3600 s ceiling bounds this to one hour.
Signature format
- Exactly 65 bytes,
r || s || v, withv27 or 28. Anything else recoversaddress(0)and is refused (a revert, or a skip insetAsks). - Recovery uses
ecrecoverwithout a low-scheck, so both the low-sand high-sform of a signature are accepted. Never use signature bytes as an identifier. Sign with lows.
Unsigned parameters
taskCid (in post) and resultCid (in submitAndSettle) are not covered by any signature. Both must be non-empty and are recorded in storage and events, but they are location hints, not attestations.
- Payload integrity rests on
c. A consumer that fetches the task, recomputesc, and checkskeccak256(abi.encodePacked(owner, c)) == jobIdrejects substituted content. - The result has no on-chain commitment.
authSiginpostis not covered byorderSigeither. Anyone can copy a pendingpost, swaptaskCidorauthSig, and land it first. No funds are at risk, but the client'scis spent. Treat acas used once anypostfor it lands, and re-post with a freshcrather than retrying.
Ordering and arithmetic
- State and reputation changes precede every token call. A reentrant token sees a terminal row and is refused.
- Narrowing casts are either bounded or guarded (
CapOverflow). postManyruns each line as an external self-call. A line that runs out of gas is reported asPostSkippedlike any other refusal and the transaction succeeds, so size the gas limit for the whole batch.
Not supported
- ERC-1271 or other contract-account signers for protocol operations.
- Provider stake and slashing; reputation is the only economic signal.
- Multi-signature curation inside the contracts;
curationis one address. - Replacing a parked payment authorization.
- Upgradeability; a new
JobRegistryis a new deployment.