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 | FailResultA 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.
Related
- defineTask — the handler that returns a
TaskResult. - ThymeContext — reading the chain to make the decision.
- Gas modes — how the executor pays for submitted calls.