AutomationRegistry
The automation registry lets a contract be called on a schedule without anyone sending a transaction. A user registers a task describing a call to make and a condition gating it, pays a fee up front, and the chain schedules that call for execution in every committed block of a running cycle until the task ends. A task ends by expiring, by being cancelled or stopped, by the runtime removing it, by the owner’s balance or allowance falling short of a cycle fee, by its fee cap falling below the cycle fee, or by the registry being suspended. System tasks pay no fee. See How Automation Works.
Registration eligibility, fees and capacity are governed by automation cycles, which are independent of block production. See How Automation Works for the cycle and fee model behind this page’s reference material.
Each execution appears on chain as an automated transaction, which is visible over RPC alongside ordinary transactions — see Automated Transactions over RPC.
The registry is an EIP-2535 diamond. Its functionality is split across seven facets, but every call goes to the single diamond address.
Finding it
Read the address under the contract registry key AutomationRegistry — the
contract registry being the
0x1::evm_config::EvmContractsDetails resource, not this registry.
The examples on this page use these shell variables. RPC is a JSON-RPC endpoint, not a host. The
values here are Devnet’s; its contract addresses are also listed in
Addresses on Devnet:
RPC=https://rpc-devnet.supra.com/rpc/v1/eth/wallet_integration
WSUPRA=0x6a042b8a99cdd407669ce5d124416007f323afdd
AUTOMATION_REGISTRY=0xa75a2cd8e61992526ed2eeaf1e1ab3b9ec472400
USER="<address of the task owner>"PAYLOAD_TX and PREDICATE are the encodings built under
Encoding the call, as 0x-prefixed hex. EXPIRY_TIME and GAS_PRICE_CAP
are the task’s _expiryTime and _gasPriceCap, set as the table under
Registering describes. FEE_CAP, CYCLES and TOTAL_FEE are set under
Paying.
Before using it, check that it is both initialized and switched on:
cast call "$AUTOMATION_REGISTRY" "isAutomationReadyEnabled()(bool)" --rpc-url "$RPC"A chain configured without automation parameters has no automation registry at all, and the
AutomationRegistry key is absent from the contract registry.
On a newly created chain, no automation cycle ends until monitorCycleEnd() has been
registered in BlockMeta. Genesis does not register it; a foundation-wallet
action does afterwards. Until then the cycle stays STARTED past its end time and every registered task
stays PENDING. Genesis also sets the automation flag from the chain’s automation
parameters, so check isAutomationEnabled() as well — registration reverts with
AutomationNotEnabled while it is off.
Calling a diamond
Send every call to the diamond address. Its fallback looks the function selector up in
its own storage and delegates to the facet that implements it. The facets are separate
contracts, but they hold no state and are not meant to be called directly; a call sent to a
facet address operates on that facet’s own empty storage.
The diamond’s fallback is not payable, so the registry cannot receive native SUPRA. Fees
are paid in WSUPRA, the token of the WrappedSupra contract — contract registry key
WrappedSupra — documented in
Predeployed Contracts. The automation
registry returns that contract’s address from erc20Supra().
Which facet serves a selector is discoverable at runtime:
cast call "$AUTOMATION_REGISTRY" "facets()((address,bytes4[])[])" --rpc-url "$RPC"
cast call "$AUTOMATION_REGISTRY" "facetAddress(bytes4)(address)" 0xdda12a93 --rpc-url "$RPC"A selector that is not registered reverts with FunctionDoesNotExist.
supportsInterface reports IERC165, IDiamondCut, IDiamondLoupe, IERC173 and
IRegistryStatus. These ids are registered once when the diamond is initialized and are
not reconciled when a later diamondCut adds or removes functions, so a true result
means the interface was registered at genesis rather than that every one of its functions
is currently routed. Use the loupe to determine what is actually callable.
IFacetSelectors.getSelectors() is implemented by the facets but is not registered on the
diamond, so it can only be called on a facet address directly.
Registering a task
Encoding the call
The task’s action is ABI-encoded into _payloadTx:
bytes memory payloadTx = abi.encode(
uint128(value), // native value to send with the call
address(target), // contract to call
bytes(abi.encodeCall(ITarget.doWork, ())), // calldata
new LibCommon.AccessListEntry[](0) // access list, may be empty
);Every task also carries a predicate, checked before each execution; the action runs only
when the predicate returns true:
bytes memory predicate = abi.encode(
address(predicateTarget),
bytes(abi.encodeCall(IPredicate.isReady, ()))
);With Foundry, for a TARGET contract whose doWork() is the action and whose isReady() is the
predicate:
PAYLOAD_TX=$(cast abi-encode "f(uint128,address,bytes,(address,bytes32[])[])" \
0 "$TARGET" "$(cast calldata "doWork()")" "[]")
PREDICATE=$(cast abi-encode "f(address,bytes)" "$TARGET" "$(cast calldata "isReady()")")The Solidity blocks on this page omit their import lines and the declarations of the types they
name, such as ITarget, IPredicate and LibCommon.
A predicate is mandatory. An empty _predicate passes the size and length checks, then
fails to decode as (address, bytes), and registration reverts with no named error.
At execution, the action and the predicate are transactions sent by the task owner, so
msg.sender, tx.origin and the transaction sender are the owner, and nonce is the task
index. At registration the predicate is called by the registry, so msg.sender inside it is
the registry. A predicate that reverts, halts or attempts a state change at execution removes
the task; an action that reverts, halts or is discarded leaves it registered, and a user
task’s action pays gas from the owner’s native balance. See
What an execution looks like.
Both values must be whole ABI encodings: their lengths must be multiples of 32 bytes, or
registration reverts with PayloadNotWordAligned or PredicateNotWordAligned. Output of
abi.encode always satisfies this; a hand-built value with trailing bytes does not.
The predicate is staticcalled at registration time to validate it, under the task’s
_maxGasAmount, and must return a single 32-byte value that is 0 or 1. See
How Automation Works for what happens when it
reverts or returns false at execution time.
Paying
Registration charges flatRegistrationFeeWei + _automationFeeCapForCycle in WSUPRA, taken
with transferFrom. The flat fee is a registry setting, so read it from getConfig() rather than
assuming a value. It is the fourth field of the returned Config
struct, after registryMaxGasCap, sysRegistryMaxGasCap and automationBaseFeeWeiPerSec.
Estimate the per-cycle component before choosing _automationFeeCapForCycle, which is FEE_CAP
in the registration command below:
# The flat fee, in wei: the fourth value of getConfig().
FLAT_FEE=$(cast call "$AUTOMATION_REGISTRY" "getConfig()(uint128,uint128,uint128,uint128)" \
--rpc-url "$RPC" | sed -n 4p | cut -d' ' -f1)
# The per-cycle fee for a task with a gas ceiling of 500000, in wei.
ESTIMATE=$(cast call "$AUTOMATION_REGISTRY" "estimateAutomationFee(uint128)(uint128)" 500000 \
--rpc-url "$RPC" | cut -d' ' -f1)Choose FEE_CAP at or above the estimate. _automationFeeCapForCycle is held as the task’s
deposit; it does not pay for a cycle. Each cycle’s fee is charged separately, by transferFrom from
the owner’s WSUPRA balance and allowance at the boundary that starts the cycle, the first cycle
included, and is at most FEE_CAP. If either the balance or the allowance is below the fee, the
task is removed with TaskCancelledInsufficientBalanceAllowance and the registry keeps the deposit.
Wrap and approve the flat fee, the deposit and CYCLES cycle fees, with CYCLES the number of
cycles the task should run. ./k is a keystore file made with
cast wallet import k --keystore-dir . --interactive, which prompts for the private key and a
password:
FEE_CAP=$ESTIMATE
CYCLES=2
TOTAL_FEE=$((FLAT_FEE + FEE_CAP + CYCLES * FEE_CAP))
# Wrap native SUPRA into WSUPRA, then approve the registry for the total fee.
cast send "$WSUPRA" "deposit()" --value "$TOTAL_FEE" --keystore ./k --rpc-url "$RPC"
cast send "$WSUPRA" "approve(address,uint256)" "$AUTOMATION_REGISTRY" "$TOTAL_FEE" \
--keystore ./k --rpc-url "$RPC"A task that runs for more than CYCLES cycles needs its balance and its allowance raised before
the boundary that starts each further cycle.
The fee rises with how much of the cycle’s gas capacity is already committed, so an
estimate taken now can be too low by the time the next cycle starts. The cap is the maximum
the task will pay per cycle; a task whose cap falls below the cycle’s actual fee is
cancelled rather than executed, and emits TaskCancelledCapacitySurpassed.
Two further bounds come from the chain’s EVM gas config rather than the registry:
_maxGasAmount may not exceed the per-transaction gas cap, and a user task’s
_gasPriceCap may not be below the minimum gas price. Both are checked at registration
and again whenever the gas config changes; see
Gas and Fees.
Registering
The task runs with its owner as the transaction sender, and a sender with code (other than an
EIP-7702 delegation) is refused. A task registered by a contract is removed at its first
predicate evaluation, so call register from an account without code.
EXPIRY_TIME below is the end of the last cycle that CYCLES covers, and GAS_PRICE_CAP is in
wei:
CYCLE_INFO=$(cast call "$AUTOMATION_REGISTRY" "getCycleInfo()(uint64,uint64,uint64,uint8)" \
--rpc-url "$RPC")
CYCLE_START=$(echo "$CYCLE_INFO" | sed -n 2p | cut -d' ' -f1)
CYCLE_DURATION=$(echo "$CYCLE_INFO" | sed -n 3p | cut -d' ' -f1)
EXPIRY_TIME=$((CYCLE_START + (CYCLES + 1) * CYCLE_DURATION))
GAS_PRICE_CAP=1000000000000cast send "$AUTOMATION_REGISTRY" \
"register(bytes,bytes,uint64,uint128,uint128,uint128,uint64,bytes[])" \
"$PAYLOAD_TX" "$PREDICATE" "$EXPIRY_TIME" 500000 "$GAS_PRICE_CAP" "$FEE_CAP" 0 "[]" \
--keystore ./k --rpc-url "$RPC"| Parameter | Meaning |
|---|---|
_payloadTx | The encoded action, as above |
_predicate | The encoded predicate. Required |
_expiryTime | Absolute timestamp after which the task stops running |
_maxGasAmount | Gas ceiling for one execution, shared by the predicate and the action, each transaction’s intrinsic gas included. At most the chain’s per-transaction gas cap |
_gasPriceCap | Highest gas price the task will pay. At least the chain’s minimum gas price |
_automationFeeCapForCycle | Maximum fee the task will pay per cycle |
_priority | Ignored for a user task, whose priority is always its task index. Only registerSystemTask honours a nonzero value |
_auxData | Auxiliary data. Capped at zero entries at genesis, so pass an empty array |
_expiryTime must be later than the end of the registration cycle; otherwise,
registration reverts with TaskExpiresBeforeNextCycle.
Reading tasks back
TASK_INDEX is an index returned by getTasksByAddress.
cast call "$AUTOMATION_REGISTRY" "getTasksByAddress(address)(uint256[])" "$USER" --rpc-url "$RPC"
cast call "$AUTOMATION_REGISTRY" "getTaskDetails(uint64)" "$TASK_INDEX" --rpc-url "$RPC"
cast call "$AUTOMATION_REGISTRY" "getActiveTaskIds()(uint64[])" --rpc-url "$RPC"Over JSON-RPC without Foundry:
curl -X POST "$RPC" -H 'Content-Type: application/json' -d '{
"jsonrpc": "2.0", "id": 1, "method": "eth_call",
"params": [{ "to": "'"$AUTOMATION_REGISTRY"'", "data": "0x2321cca3" }, "latest"]
}'Stopping a task
| Function | Effect |
|---|---|
cancelTasks(uint64[]) | Cancels tasks owned by the caller. A PENDING task is removed immediately; an ACTIVE task becomes CANCELLED and keeps executing until the current cycle ends |
stopTasks(uint64[]) | Stops tasks owned by the caller, removing them immediately whatever their state, and refunds |
To halt an active task at once, stop it rather than cancel it; see Cancelling versus stopping.
The refund depends on both which function is called and the task’s current state — a
PENDING task refunds only half its deposit on either path, while an ACTIVE task refunds
in full and, through stopTasks, also refunds half the residual cycle fee. See
How Automation Works for the complete table.
Task indexes that do not exist are skipped rather than causing a revert, so a batch containing a stale index still processes the rest.
TaskMetadata
getTaskDetails and getTaskDetailsBulk return:
| Field | Type | Meaning |
|---|---|---|
maxGasAmount | uint128 | Gas ceiling for one execution |
gasPriceCap | uint128 | Highest gas price the task will pay |
automationFeeCapForCycle | uint128 | Maximum fee per cycle |
depositFee | uint128 | Deposit currently locked |
txHash | bytes32 | Hash of the registration transaction |
taskIndex | uint64 | The task’s identifier |
registrationTime | uint64 | When it was registered |
expiryTime | uint64 | When it stops running |
priority | uint64 | Ordering hint. Always the task index for UST; a supplied nonzero value for GST |
owner | address | Who may cancel or stop it |
taskType | TaskType | UST or GST |
taskState | TaskState | PENDING, ACTIVE or CANCELLED |
payloadTx | bytes | The encoded action |
predicate | bytes | The encoded predicate |
auxData | bytes[] | Auxiliary data |
Enum values as they appear on the wire:
CycleState | TaskState | TaskType | TaskRemovalReason | ||||
|---|---|---|---|---|---|---|---|
0 | READY | 0 | PENDING | 0 | UST (user-submitted) | 0 | ERROR |
1 | STARTED | 1 | ACTIVE | 1 | GST (governance-submitted, gasless) | 1 | GAS_CONFIG_UPDATE |
2 | FINISHED | 2 | CANCELLED | ||||
3 | SUSPENDED |
Registration is only accepted while the cycle state is STARTED. While automation is
enabled, a call during a transition reverts with CycleTransitionInProgress; while it is
disabled, the error is AutomationNotEnabled.
Who can call what
Anyone
| Function | Effect |
|---|---|
register(...) | Registers a user task. Requires a WSUPRA approval. A task registered by a caller with code cannot run |
All get*, if*, has*, total*, is*, estimate* and calculate* functions | Reads |
facets, facetAddresses, facetFunctionSelectors, facetAddress, supportsInterface, isInitialized | Diamond introspection |
Task owners
| Function | Effect |
|---|---|
cancelTasks(uint64[]), stopTasks(uint64[]) | On UST tasks the caller owns |
cancelSystemTasks(uint64[]), stopSystemTasks(uint64[]) | On GST tasks the caller owns |
When the caller owns the task, calling the UST variant on a GST task, or the reverse,
reverts with UnsupportedTaskOperation. A caller that does not own the task reverts with
UnauthorizedAccount.
Authorized submitters
| Function | Effect |
|---|---|
registerSystemTask(...) | Registers a GST task. No fee is charged |
System tasks are a governance mechanism for protocol upkeep, not a service users apply for.
A system task also runs with its owner as the transaction sender, so a system task registered
by a contract, including a multisig authorized submitter, is removed at its first predicate
evaluation; register it from an account without code.
The authorized set is managed by the owner through grantAuthorization and
revokeAuthorization. Check membership with isAuthorizedSubmitter(address).
Owner
The owner is the foundation wallet, so each of these requires a multisig proposal.
| Function | Effect |
|---|---|
enableAutomation(), disableAutomation() | Enables automation, or disables it, which suspends the registry and removes and refunds every task |
enableRegistration(), disableRegistration() | Turns new registrations on or off |
grantAuthorization(address), revokeAuthorization(address) | Changes the authorized submitter set |
updateConfigBuffer(...) | Stages a configuration change, applied at the next cycle boundary |
updateDataLengthCaps(...) | Changes payload, predicate and auxiliary-data size caps, effective immediately. The payload and predicate caps must be multiples of 32 |
withdrawFees(uint256,address) | Withdraws collected fees, bounded by the locked balance |
diamondCut(...) | Adds, replaces or removes facet functions |
transferOwnership(address) | One-step. Renouncing is not supported |
updateConfigBuffer is buffered rather than immediate, so a configuration change is adopted at
the next cycle boundary. The exceptions are nextCycleRegistryMaxGasCap and
nextCycleSysRegistryMaxGasCap, which take effect immediately and change what registration
accepts. Read the staged values with getConfigBuffer() and the active
ones with getConfig().
VM signer
These are driven by block production and cannot be called by any account, because no transaction can be sent from a reserved address. They are listed so they can be recognised in traces and in RPC responses.
| Function | Effect |
|---|---|
monitorCycleEnd() | Checks whether the cycle has ended. Called each block through BlockMeta once it is registered there, which happens after genesis |
processTasks(uint64,uint64[]) | Bookkeeping applied at a cycle transition — activates and charges tasks, does not execute a task’s payload |
removeRegisteredTask(uint64,uint64,uint8,string) | Removes a task, giving a TaskRemovalReason and a details string: ERROR for a task the runtime found invalid, GAS_CONFIG_UPDATE for one a new EVM gas config no longer admits |
monitorCycleEnd() checks tx.origin rather than msg.sender, because it is reached
through BlockMeta.blockPrologue() and so its immediate caller is BlockMeta.
When calls fail
Registration, which has the largest set of preconditions:
| Error | Condition |
|---|---|
AutomationNotEnabled() | Automation is switched off |
RegistrationDisabled() | Registration is switched off |
CycleTransitionInProgress() | Automation is enabled and the cycle is not in STARTED |
PayloadTooLarge() | _payloadTx exceeds maxPayloadLength |
PayloadNotWordAligned() | _payloadTx’s length is not a multiple of 32 |
InvalidPayloadLength() | The decoded call data is under 4 bytes — checked separately for the action payload inside _payloadTx and for the predicate’s payload inside _predicate |
AddressCannotBeZero(), AddressCannotBeEOA() | The payload or predicate target is zero or has no code |
InvalidMaxGasAmount() | _maxGasAmount is zero |
MaxGasAmountExceedsChainCap(uint128,uint64) | _maxGasAmount exceeds the chain’s per-transaction gas cap. Applies to user and system tasks, and is checked before the predicate is called |
PredicateTooLarge() | _predicate exceeds maxPredicateLength |
PredicateNotWordAligned() | _predicate’s length is not a multiple of 32 |
| — (no named error) | _predicate is empty bytes. It passes the two checks above, then fails to decode as (address, bytes) |
StaticCallToPredicateFailed() | The predicate reverted when validated |
InvalidReturnLengthOfPredicate() | The predicate returned other than 32 bytes |
InvalidReturnTypeOfPredicate() | The predicate returned a value other than 0 or 1 |
TaskCapacityReached() | The number of registered tasks of that type, in any state, has reached taskCapacity (sysTaskCapacity for a system task) |
InvalidGasPriceCap() | _gasPriceCap is zero |
GasPriceCapBelowMinimum(uint128,uint256) | A user task’s _gasPriceCap is below the chain’s minimum gas price. System tasks are exempt |
InsufficientFeeCapForCycle(uint128) | _automationFeeCapForCycle is below the current cycle fee. The payload is the required amount |
InvalidExpiryTime() | _expiryTime is in the past |
InvalidTaskDuration() | The lifetime exceeds the configured duration cap |
TaskExpiresBeforeNextCycle() | _expiryTime is not later than the end of the registration cycle, so the task would expire before it could ever run |
GasCommittedExceedsMaxGasCap() | The gas committed for the next cycle would exceed nextCycleRegistryMaxGasCap (nextCycleSysRegistryMaxGasCap for a system task) |
AuxDataTooLarge() | _auxData exceeds the configured caps |
TransferFailed() | The WSUPRA token returned false from transferFrom |
UnauthorizedAccount() | registerSystemTask from an address that is not an authorized submitter |
A missing WSUPRA approval or balance reverts with the token’s own error,
ERC20InsufficientAllowance(address,uint256,uint256) or ERC20InsufficientBalance, which
register forwards.
Cancelling and stopping:
| Error | Condition |
|---|---|
TaskIndexesCannotBeEmpty() | An empty array was passed |
UnauthorizedAccount() | The caller does not own the task |
UnsupportedTaskOperation() | The owner used the UST variant on a GST task, or the reverse |
AlreadyCancelled() | The task is already cancelled (cancelTasks and cancelSystemTasks only; the stop functions accept a cancelled task) |
AutomationNotEnabled() | Automation is switched off |
CycleTransitionInProgress() | The cycle is mid-transition |
Configuration and ownership:
| Error | Condition |
|---|---|
MustBeContractOwner() | An owner-gated function called by another account |
AlreadyEnabled(), AlreadyDisabled() | A toggle set to its current value |
AddressAlreadyExists(), AddressDoesNotExist() | Granting or revoking authorization redundantly |
InsufficientBalance(), RequestExceedsLockedBalance() | withdrawFees beyond the unlocked balance |
UnacceptableRegistryMaxGasCap(), UnacceptableSysRegistryMaxGasCap() | A staged gas cap below what is already committed |
PayloadLengthCapNotWordAligned(), PredicateLengthCapNotWordAligned() | updateDataLengthCaps with a payload or predicate cap that is not a multiple of 32 |
FunctionDoesNotExist() | The selector is not routed by the diamond |
Events
| Event | Emitted when | Indexed |
|---|---|---|
TaskRegistered(uint64,address,uint128,uint128,TaskMetadata) | A user task is registered | taskIndex, owner |
SystemTaskRegistered(uint64,address,uint256,TaskMetadata) | A system task is registered | taskIndex, owner |
TasksCancelled(TaskCancelled[],address) | Tasks are cancelled | owner |
TasksStopped(TaskStopped[],address) | Tasks are stopped | owner |
TaskFeeRefund(uint64,address,uint128) | A cycle fee is refunded | taskIndex, owner |
TaskDepositFeeRefund(uint64,address,uint128) | A deposit is refunded | taskIndex, owner |
AutomationCycleEvent(uint64,CycleState,uint64,uint64,CycleState) | A cycle changes state | index, state, oldState |
ActiveTasks(uint64,uint64[]) | A cycle starts with tasks active in it, listing them; not emitted for a cycle with none | cycleIndex |
RemovedTasks(uint64,CycleState,uint64[]) | Tasks are dropped at a cycle transition (state FINISHED) or on suspension (SUSPENDED) | cycleIndex, state |
TaskCycleFeeWithdraw(uint64,uint64,address,uint128) | A task’s cycle fee is taken. cycleIndex is the cycle the fee pays for | cycleIndex, taskIndex, owner |
TaskCancelledCapacitySurpassed(uint64,address,uint128,uint128,bytes32) | A task’s fee cap was below the cycle fee | taskIndex, owner |
TaskCancelledInsufficientBalanceAllowance(uint64,address,uint128,uint256,uint256,bytes32) | A task’s owner lacked balance or allowance | taskIndex, owner |
TaskRemovedBySystem(uint64,address,TaskType,bytes32,TaskRemovalReason,string) | The runtime removed an invalid task | taskIndex, owner |
TaskRemovedByGasConfigUpdate(uint64,address,TaskType,uint128,uint128,uint64,uint256,uint128,uint128,bytes32) | A new EVM gas config no longer admits a task | taskIndex, owner, taskType |
ErrorUnlockTaskCycleFee, ErrorUnlockTaskDepositFee, ErrorInsufficientBalanceToRefund | A refund could not be paid in full; diagnostic | taskIndex, and on the last also owner and refundType |
AutomationEnabled(bool), AutomationDisabled(bool) | Automation toggled | status |
TaskRegistrationEnabled(bool), TaskRegistrationDisabled(bool) | Registration toggled | status |
AuthorizationGranted(address,uint256), AuthorizationRevoked(address,uint256) | Authorized set changed | account, timestamp |
RegistryFeeWithdrawn(address,uint256) | Fees withdrawn | recipient |
ConfigBufferUpdated(Config) | Configuration staged | none |
DataLengthCapsUpdated(uint16,uint16,uint16,uint16) | Size caps changed | none |
DiamondCut(FacetCut[],address,bytes) | Facet functions changed | none |
OwnershipTransferred(address,address) | Ownership changed | previousOwner, newOwner |
No registry event indexes a struct, array, string, bytes value or amount. Those parameters
are ABI-encoded in the log data, so taskMetadata, the cancelled and stopped task lists,
the task-index arrays and every fee and refund amount decode directly from the log. Filter
by the indexed task index, owner or cycle, and read the rest from the data.
Four events tell a task owner why a task stopped running:
TaskCancelledCapacitySurpassed when the fee cap was too low for the cycle,
TaskCancelledInsufficientBalanceAllowance when the owner’s WSUPRA balance or allowance was
insufficient at charging time, TaskRemovedBySystem when the runtime rejected the task, and
TaskRemovedByGasConfigUpdate when a new EVM gas config no longer admits it.
Interfaces
Selector map
| Facet | Selectors |
|---|---|
DiamondCutFacet | diamondCut |
DiamondLoupeFacet | facets, facetFunctionSelectors, facetAddresses, facetAddress, supportsInterface, isInitialized |
OwnershipFacet | owner, transferOwnership |
ConfigFacet | grantAuthorization, revokeAuthorization, enableRegistration, disableRegistration, withdrawFees, updateConfigBuffer, updateDataLengthCaps, erc20Supra, isRegistrationEnabled, getConfig, getConfigBuffer, getDataLengthCaps |
CoreFacet | processTasks, monitorCycleEnd, removeRegisteredTask, enableAutomation, disableAutomation, getCycleInfo, getCycleDuration, getTransitionInfo, isAutomationEnabled, getCycleStateDetails, isAutomationReadyEnabled |
RegistryFacet | register, registerSystemTask, cancelTasks, cancelSystemTasks, stopTasks, stopSystemTasks, isAuthorizedSubmitter, calculateAutomationFeeMultiplierForCommittedOccupancy, calculateAutomationFeeMultiplierForCurrentCycle, estimateAutomationFee, estimateAutomationFeeWithCommittedOccupancy |
RegistryViewFacet | getTaskIdList, getSystemTaskIds, getTaskOwner, getNextTaskIndex, totalTasks, totalSystemTasks, getTaskDetails, getTaskDetailsBulk, getTotalActiveTasks, getActiveTaskIds, hasActiveUserTask, hasActiveSystemTask, hasActiveTaskOfType, getGasCommittedForNextCycle, getGasCommittedForCurrentCycle, getSystemGasCommittedForNextCycle, getSystemGasCommittedForCurrentCycle, getNextCycleRegistryMaxGasCap, getNextCycleSysRegistryMaxGasCap, getCycleLockedFees, getTotalDepositedAutomationFees, getTotalLockedBalance, ifTaskExists, ifSysTaskExists, getTasksByAddress |
The live mapping is whatever the loupe reports; this table describes the genesis wiring.
Signatures and selectors
| Signature | Selector | Mutability |
|---|---|---|
register(bytes,bytes,uint64,uint128,uint128,uint128,uint64,bytes[]) | 0xdda12a93 | nonpayable |
registerSystemTask(bytes,bytes,uint64,uint128,uint64,bytes[]) | 0x45147fe4 | nonpayable |
cancelTasks(uint64[]) | 0x71d35334 | nonpayable |
stopTasks(uint64[]) | 0xaf783c6d | nonpayable |
getTaskDetails(uint64) | 0xb2ef6896 | view |
getTaskIdList() | 0xec82b429 | view |
getActiveTaskIds() | 0x2321cca3 | view |
getTasksByAddress(address) | 0xe6ef3231 | view |
getTaskOwner(uint64) | 0xb36b5fe9 | view |
ifTaskExists(uint64) | 0x8aaa404e | view |
estimateAutomationFee(uint128) | 0xf8b6f14f | view |
isAuthorizedSubmitter(address) | 0x09479e8c | view |
getCycleInfo() | 0x873dc71d | view |
getCycleStateDetails() | 0x6b5d8c56 | view |
isAutomationEnabled() | 0xe48e0e98 | view |
isAutomationReadyEnabled() | 0x105176ce | view |
isInitialized() | 0x392e53cd | view |
getConfig() | 0xc3f909d4 | view |
getDataLengthCaps() | 0xd55df358 | view |
isRegistrationEnabled() | 0x1fdfe815 | view |
owner() | 0x8da5cb5b | view |
facets() | 0x7a0ed627 | view |
facetAddress(bytes4) | 0xcdffacc6 | view |
facetAddresses() | 0x52ef6b2c | view |
facetFunctionSelectors(address) | 0xadfca15e | view |
supportsInterface(bytes4) | 0x01ffc9a7 | view |
diamondCut((address,uint8,bytes4[])[],address,bytes) | 0x1f931c1c | nonpayable |
monitorCycleEnd() | 0x1b87619c | nonpayable |
processTasks(uint64,uint64[]) | 0x7f69c35c | nonpayable |
removeRegisteredTask(uint64,uint64,uint8,string) | 0x256e4e4d | nonpayable |
Solidity
The interfaces are IRegistryFacet.sol, IRegistryViewFacet.sol, ICoreFacet.sol,
IConfigFacet.sol, IDiamondCut.sol, IDiamondLoupe.sol, IERC173.sol, IERC165.sol and
IRegistryStatus.sol. The task-owner surface follows. The blocks omit the imports of the published
files: TaskMetadata is declared in LibAppStorage.sol and LibCommon in LibCommon.sol, both in
the registry’s libraries directory.
interface IRegistryFacet {
function register(
bytes memory _payloadTx,
bytes memory _predicate,
uint64 _expiryTime,
uint128 _maxGasAmount,
uint128 _gasPriceCap,
uint128 _automationFeeCapForCycle,
uint64 _priority,
bytes[] memory _auxData
) external;
function cancelTasks(uint64[] memory _taskIndexes) external;
function stopTasks(uint64[] memory _taskIndexes) external;
function estimateAutomationFee(uint128 _taskOccupancy) external view returns (uint128);
}
interface IRegistryViewFacet {
function getTaskDetails(uint64 _taskIndex) external view returns (TaskMetadata memory);
function getTaskDetailsBulk(uint64[] memory _taskIndexes) external view returns (TaskMetadata[] memory);
function getTasksByAddress(address _addr) external view returns (uint256[] memory);
function getActiveTaskIds() external view returns (uint64[] memory);
function getTaskOwner(uint64 _taskIndex) external view returns (address);
function ifTaskExists(uint64 _taskIndex) external view returns (bool);
}interface ICoreFacet {
event AutomationCycleEvent(
uint64 indexed index,
LibCommon.CycleState indexed state,
uint64 startTime,
uint64 durationSecs,
LibCommon.CycleState indexed oldState
);
function getCycleInfo() external view returns (uint64, uint64, uint64, LibCommon.CycleState);
function getCycleDuration() external view returns (uint64);
function getCycleStateDetails() external view returns (LibCommon.CycleDetails memory);
function isAutomationEnabled() external view returns (bool);
function isAutomationReadyEnabled() external view returns (bool);
}JSON ABI
A diamond has no single compiled ABI, because its surface is the union of its facets.
Generate each facet interface’s ABI from the solidity/supra_contracts directory, as
described in Interfaces and ABIs, and
concatenate them into one an EVM client can bind to the diamond address:
for i in IRegistryFacet IRegistryViewFacet ICoreFacet IConfigFacet IDiamondLoupe IDiamondCut; do
forge inspect "$i" abi --json > "$i.json"
done
jq -s 'add' IRegistryFacet.json IRegistryViewFacet.json ICoreFacet.json IConfigFacet.json \
IDiamondLoupe.json IDiamondCut.json > AutomationRegistry.jsonThe fragment for registering a task:
[
{
"type": "function",
"name": "register",
"inputs": [
{ "name": "_payloadTx", "type": "bytes" },
{ "name": "_predicate", "type": "bytes" },
{ "name": "_expiryTime", "type": "uint64" },
{ "name": "_maxGasAmount", "type": "uint128" },
{ "name": "_gasPriceCap", "type": "uint128" },
{ "name": "_automationFeeCapForCycle", "type": "uint128" },
{ "name": "_priority", "type": "uint64" },
{ "name": "_auxData", "type": "bytes[]" }
],
"outputs": [],
"stateMutability": "nonpayable"
}
]Related
- How Automation Works — the feature model: cycles versus blocks, configuration parameters, fees, task validity, and UST versus GST.
- Automated Transactions over RPC — observing task executions and cycle bookkeeping through the RPC APIs.
- Predeployed Contracts — Wrapped SUPRA, the token fees are paid in.
- Gas and Fees — how the chain’s EVM gas config bounds automation tasks.
- BlockMeta — runs
monitorCycleEnd()once per block, once it is registered. - Using Native Randomness from an EVM Contract — randomness inside an automation task, where a predicate’s read is charged differently from an action’s.