Skip to content
Thyme Docs

Task Result Types

A task's run handler returns a TaskResult: either a decision to execute (with the calls to submit) or a decision to skip (with a reason). You return descriptors — the Thyme executor does the signing and submitting.

TaskResult

type TaskResult = SuccessResult | FailResult

A discriminated union on the canExec field.

SuccessResult

interface SuccessResult {
  canExec: true
  calls: Call[]
}

Return this when the task should act. calls is the ordered list of on-chain calls the executor will submit.

FailResult

interface FailResult {
  canExec: false
  message: string
}

Return this when there is nothing to do. message is recorded in the execution log and the run is marked skipped. Skipping is normal and expected — a task that checks a condition will skip most of the time.

return { canExec: false, message: 'Price below threshold or unchanged' }

Call

interface Call {
  to: Address
  data: Hex
}

A single on-chain call: a target address and ABI-encoded calldata. The public Call type has no value, gas, sender, or operation field. data: '0x' is an empty call: it may invoke a contract's fallback and can revert or have effects. It is not a guaranteed no-op and cannot match a selector-based permission manifest.

return {
  canExec: true,
  calls: [{ to: targetAddress, data: '0x' }],
}

You return; the executor submits

This is the core boundary of the SDK:

This is why a task author never picks a chain, signer, or gas mode in code: those are properties of the executable, configured through the Console or management API.

Building calldata

Use viem's encodeFunctionData to build the data field from an ABI:

import { encodeFunctionData } from 'viem'
 
return {
  canExec: true,
  calls: [{
    to: oracleAddress,
    data: encodeFunctionData({ abi, functionName: 'updatePrice', args: [newPrice] }),
  }],
}

Return multiple calls in the intended order within one execution. Actual submission and atomicity depend on the selected profile and execution path; local simulation does not reproduce every path:

return {
  canExec: true,
  calls: [
    { to: token, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [spender, amount] }) },
    { to: spender, data: encodeFunctionData({ abi: vaultAbi, functionName: 'deposit', args: [amount] }) },
  ],
}

Outcomes

SuccessResult means the task requested execution; it is not a receipt. Use onSuccess to react to confirmation and onFail to handle submission, revert, or timeout outcomes. Despite its historical name, FailResult is a normal skip decision, not a thrown error.

Return a skip result when there are no calls to make rather than an empty successful call list. Keep calldata compatible with the release's permission manifest and the profile's authorization.

  • defineTask — the handler that returns a TaskResult.
  • ThymeContext — reading the chain to make the decision.
  • Gas modes — how the executor pays for submitted calls.