Comment on page
The detailed specification on the Job data structure
To achieve efficiency and save on gas during execution, all manipulations with the Job structure are performed in assembly inserts. The binary representation of
struct Jobis as follows:
0x | name | size int | bytes | bits
00000000 | lastExecAt | uint32 | 4 | 0-31
000000 | interval | uint24 | 3 | 32-55
00 | calldataSource | uint8 | 1 | 56-63
00000000 | fixedReward | uint32 | 4 | 64-95
0000 | rewardPct | uint16 | 2 | 96-111
0000000000000000000000 | nativeCredits | uint88 | 11 | 112-199
0000 | maxBaseFeeGwei | uint16 | 2 | 200-215
00000000 | selector | uint32 | 4 | 216-247
00 | config | uint8 | 1 | 248-255
The Job configuration, expanded as a nested struct in the short specification, is a single byte inside the Job structure and defines the properties of the Job. The bits are allocated consecutively in the
uint8 config. The structure of this byte is given below.
0x | name | binary
01 | CFG_ACTIVE | 00000001
02 | CFG_USE_JOB_OWNER_CREDITS | 00000010
04 | CFG_ASSERT_RESOLVER_SELECTOR | 00000100
08 | CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT | 00001000
CFG_ACTIVEFlag of a job being active (i.e., admissible for execution given satisfaction of specified logic).
CFG_USE_JOB_OWNER_CREDITSWhether to use job owner credits in native tokens for payment. This makes a hard switch from using job credits to using job owner credits and not just enables it as an option.
CFG_ASSERT_RESOLVER_SELECTORIndicates whether to enforce the selector of a resolver job function matching between the calldata passed by the Keeper and the job binary representation. This may be desirable because under the hood, resolver jobs work like
PRE_DEFINEDjobs, except the calldata is provided by the Keeper. It would therefore be possible for a malicious Keeper to supply a different selector, which is not checkable unless this flag is set to
True. Has no bearing on interval jobs, since for them, the
CFG_CHECK_KEEPER_MIN_CVP_DEPOSITWhether to enforce conformance of the stake of keepers and slashers to the minimum required stake of the job.
When the job is invoked with some calldata (even if it is just the selector), it is always padded with a few fields, yielding a special binary representation of the calldata as well; the structure is given below.
0x | name | size int | bytes | bits |
00000000 | selector | uint32 | 4 | 0-31 |
0000...0000 x40 | JobContractAddress| uint160 | 20 | 32-191 |
000000 | jobId | uint24 | 3 | 192-215 |
00 | config | uint8 | 1 | 216-225 |
000000 | keeperId | uint24 | 3 | 226-249 |
0000... >=1 | executionCalldata | bytes | >=1 | 250-any |
executionCalldatafield contains the calldata proper that is forwarded to the target contract; for
Selectorjobs, for instance, this field is occupied solely by the four bytes of the target method selector, for
Resolverjobs it contains the ad hoc calldata to pass to the target contract, and for the
Predefined Calldatajobs, it is absent since the fixed calldata is fetched from the job properties inside the execution call.