Delegator workflow
As a delegator, you define the task, fund its maximum reward, and choose the signed bid that becomes the on-chain agreement.
The transaction fragments below use ethers v6 contract instances connected to the delegator’s signer. Values such as specHash, inputHash, amounts, deadlines, and specURI come from the task prepared in step 1.
1. Commit the task
Section titled “1. Commit the task”Prepare the complete TaskSpec and task input off-chain. For STATS_V1:
- canonicalize the TaskSpec with RFC 8785 JCS, then compute
specHash = keccak256(JCS(taskSpec)); - encode the
uint64[]input withabi.encode, then computeinputHash = keccak256(abi.encode(values)); - express every USDC amount as an integer with 6 decimals; and
- choose
acceptDeadline,maxComputeWindowSec, and aminBondUSDCat or above the hub’s current minimum.
See TaskSpec commitments and STATS_V1 for the exact encodings.
2. Approve and create
Section titled “2. Approve and create”createTask transfers real USDC into the hub. Confirm the chain, hub address, current fee, verifier route, balance, allowance, and deadlines first. Approve only the exact amount needed, simulate the complete call with staticCall, then submit it:
const createArgs = [ specHash, statsV1VerifierId, inputHash, maxRewardUSDC, minBondUSDC, acceptDeadline, maxComputeWindowSec, specURI,] as const;
await (await usdc.approve(hubAddress, maxRewardUSDC)).wait();await hub.createTask.staticCall(...createArgs);
const receipt = await ( await hub.createTask(...createArgs)).wait();Simulation checks the call against the current state but does not reserve that state. Re-read time-sensitive values before sending the transaction.
Read TaskCreated from the receipt to obtain the taskId. The hub holds the maximum reward in USDC and snapshots the active verifier for that task.
3. Review signed bids
Section titled “3. Review signed bids”Receive bids off-chain and confirm each bid matches the created task:
taskId,specHash, andverifierIdmatch the on-chain task;rewardUSDC,bondUSDC, andcomputeWindowSecmatch the terms you want;validUntilis current; andnoncematchesbidNonce[delegatee].
The delegatee signs the exact EIP-712 bid. Review signed bids for the domain and field order.
4. Select one bid
Section titled “4. Select one bid”Encrypt the task key for the chosen delegatee and call:
await ( await hub.selectBid(taskId, bid, delegateeSignature, encryptedKey)).wait();Selection records the reward, bond, compute window, and fee snapshot. The hub immediately returns escrowedRewardUSDC - rewardUSDC to you and keeps the selected reward in escrow. TaskSelected carries the encrypted key for the delegatee, which retains control of activation.
The encrypted-key byte format is bilateral and outside the on-chain protocol. Agree on the encryption, key-wrap, nonce, and associated-data encoding with the delegatee, and test a round trip before selection. Follow Identity, key delivery, and capabilities for the interoperable baseline.
If a selection is cancelled, the task keeps its current escrow for reselection. OCH-1.1 has no top-up call, so every later bid must set rewardUSDC <= escrowedRewardUSDC.
5. Follow the on-chain result
Section titled “5. Follow the on-chain result”Watch the task and its lifecycle events:
TaskActivatedstarts the selected compute window after the delegatee posts the bond.TaskCompletedcarries the output commitment, completepublicValues, and output URI. A valid proof releases the selected reward, less the snapshotted fee, and returns the bond to the delegatee.TaskSelectionCancelledreturns a selected task toOPEN, ready for another valid bid within the task’s remaining escrow and terms.TaskTimedOutrecords the ACTIVE timeout path, which returns the reward and full bond to you.
Use proof binding to verify the completion payload and events and limits for the exact event fields.
6. Recover funds when a task does not complete
Section titled “6. Recover funds when a task does not complete”Exits are explicit transactions. Call the path that matches the task state, or let another permitted caller do so:
| State | Call | Caller and timing | Funds result |
|---|---|---|---|
OPEN |
cancelUnaccepted(taskId) |
Delegator, while the task is open | Returns current reward escrow to the delegator. |
OPEN |
sweepExpiredOpen(taskId) |
Any caller after acceptDeadline |
Returns current reward escrow to the delegator. |
SELECTED |
cancelSelection(taskId) |
Delegator at any time, or any caller after activateDeadline |
Returns the task to OPEN; current reward escrow remains available for reselection. |
ACTIVE |
claimTimeout(taskId) |
Any caller after submitDeadline |
Returns reward escrow and transfers the full bond to the delegator. |
await (await hub.cancelUnaccepted(taskId)).wait();await (await hub.sweepExpiredOpen(taskId)).wait();await (await hub.cancelSelection(taskId)).wait();await (await hub.claimTimeout(taskId)).wait();Read the task first and submit only the one call valid for its current state and deadline.