Escrow and fees
How a job's cap, charge, protocol fee and gas fee are computed, pulled and paid out.
Rates and units
An order carries rateIn and rateOut (uint128) and unitsIn and unitsOut (uint32). Rates are in atomic payment-token units per unit, multiplied by RATE_SCALE = 1,000,000. With USDC (6 decimals), a rateOut of 1,000,000 is 1 atomic unit (0.000001 USDC) per output unit.
Formulas
cap = max(1, ceilDiv(rateIn·unitsIn + rateOut·unitsOut, RATE_SCALE))
tok = min(completionTok, unitsOut)
charge = min(cap, max(1, ceilDiv(rateIn·unitsIn + rateOut·tok, RATE_SCALE)))
feeCap = floor(cap · feeBps / 10000)
fee = floor(charge · feeBps / 10000) // fee <= feeCapcapis computed atclaim. Acapthat does not fituint128revertsCapOverflow. A zero-priced order still escrows 1 atomic unit.unitsOutis a ceiling: the provider reportscompletionTokat settlement and is paid for at mostunitsOut. The storedcompletionTokis the clampedtok.unitsInis charged in full.
The escrow
claim pulls cap + feeCap + gasFeeSnap from the client once, by executing the payment authorization parked at post. gasFeeSnap is gasFee as of post. The escrow resolves once:
| Exit | Operator | Treasury | Client |
|---|---|---|---|
submitAndSettle | charge | fee + gasFeeSnap | (cap − charge) + (feeCap − fee) |
fail | — | gasFeeSnap | cap + feeCap |
reclaim | — | gasFeeSnap | cap + feeCap |
cancel (from Open) | — | — | nothing was pulled |
- Each funded exit pays out exactly
cap + feeCap + gasFeeSnap, providedfeeBpshas not changed since the claim. - The gas fee goes to the treasury on every funded exit, including
failandreclaim. The protocol fee is only taken at settlement. - Zero legs are skipped.
- The operator leg goes to
operatorOf(providerId)as resolved at settlement, not to the key that signed or sent the settle.
JobView omits gasFeeSnap, and capOf(jobId) returns cap only. The gas fee in force at any block can be rebuilt from FeesChanged logs.
Fee parameters
| Parameter | Set by | Initial | Bounds | Read when |
|---|---|---|---|---|
feeBps | setFees (curation) | 100 (1%) | ≤ 1000 (10%), else FeeTooHigh | live, at claim and again at the exit |
gasFee | setFees (curation) | 0 | none | at post, snapshotted per job |
There is no per-job feeBps snapshot, so a fee change affects work in flight:
- A job claimed under one
feeBpsand resolved under another pays out a different total than it pulled. - An order posted but not yet claimed when
feeBpschanges can no longer be claimed: its payment authorization was signed for the old amount, and the token rejects it insideclaim.
Read the live values from the contract; do not copy them. See Read contract state with cast.
Payment authorization amount
The client signs a USDC ReceiveWithAuthorization for exactly the amount claim will pull:
value = cap + floor(cap · feeBps / 10000) + gasFeegasFee must be the value at the moment post lands, and feeBps the value at the moment claim lands. The full field list is on Signing.