diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 87f114638f..13e323ca44 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -21,6 +21,7 @@ /contracts/**/*keeper* @smartcontractkit/dev-services /contracts/**/*upkeep* @smartcontractkit/dev-services /contracts/**/*automation* @smartcontractkit/dev-services +/contracts/**/*automation-cre* @smartcontractkit/cld-vault /contracts/**/*functions* @smartcontractkit/dev-services /contracts/**/*l2ep* @smartcontractkit/data-growth /contracts/**/*llo-feeds* @smartcontractkit/data-streams-engineers @@ -32,6 +33,7 @@ /contracts/**/*payments* @smartcontractkit/payments /contracts/src/v0.8/automation @smartcontractkit/dev-services +/contracts/src/v0.8/automation-cre @smartcontractkit/cld-vault /contracts/src/v0.8/functions @smartcontractkit/dev-services /contracts/src/v0.8/l2ep @smartcontractkit/data-growth /contracts/src/v0.8/llo-feeds @smartcontractkit/data-streams-engineers @@ -56,6 +58,7 @@ /gethwrappers/keeper @smartcontractkit/dev-services /gethwrappers/upkeep @smartcontractkit/dev-services /gethwrappers/automation @smartcontractkit/dev-services +/gethwrappers/automation-cre @smartcontractkit/cld-vault /gethwrappers/l2ep @smartcontractkit/data-growth /gethwrappers/vrf @smartcontractkit/dev-services diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index e143e1c368..07f4a941be 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -24,6 +24,7 @@ jobs: cat < matrix.json [ { "name": "automation", "setup": { "run-coverage": false, "min-coverage": 98.5, "run-gas-snapshot": false }}, + { "name": "automation-cre", "setup": { "run-coverage": true, "min-coverage": 98.5, "run-gas-snapshot": true }}, { "name": "dev", "setup": { "run-coverage": true, "extra-coverage-params": "--ir-minimum", "min-coverage": 72.8, "run-gas-snapshot": true, "subfolder": "/cre" }}, { "name": "v1", "setup": { "run-coverage": false, "extra-coverage-params": "--ir-minimum --no-match-coverage='(.*v1/test.*)|(.*v2/test.*)'", "min-coverage": 72.8, "run-gas-snapshot": true, "subfolder": "/cre" }}, { "name": "v2", "setup": { "run-coverage": true, "extra-coverage-params": "--ir-minimum --no-match-coverage='(.*v1/test.*)|(.*v2/test.*)'", "min-coverage": 93, "run-gas-snapshot": true, "subfolder": "/cre" }}, @@ -81,6 +82,8 @@ jobs: - modified|added: 'contracts/src/v0.8/**/!(tests|mocks)/!(*.t).sol' automation: - 'contracts/src/v0.8/automation/**/*.sol' + automation-cre: + - 'contracts/src/v0.8/automation-cre/**/*.sol' functions: - 'contracts/src/v0.8/functions/**/*.sol' cre: diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 537fa78dff..cd83e11ce9 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -1,6 +1,6 @@ # ALL_FOUNDRY_PRODUCTS contains a list of all products that have a foundry # profile defined and use the Foundry snapshots. -ALL_FOUNDRY_PRODUCTS = functions keystone l2ep llo-feeds operatorforwarder payments shared workflow data-feeds +ALL_FOUNDRY_PRODUCTS = automation-cre functions keystone l2ep llo-feeds operatorforwarder payments shared workflow data-feeds # To make a snapshot for a specific product, either set the `FOUNDRY_PROFILE` env var # or call the target with `FOUNDRY_PROFILE=product` diff --git a/contracts/cre/gobindings/go.mod b/contracts/cre/gobindings/go.mod index 0b4c576de7..ff3e84d644 100644 --- a/contracts/cre/gobindings/go.mod +++ b/contracts/cre/gobindings/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink-evm/contracts/cre/gobindings -go 1.24.5 +go 1.25.0 require ( github.com/ethereum/go-ethereum v1.17.3 diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 502b7ec736..81b38ec1cf 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -73,6 +73,20 @@ optimizer_runs = 1_000_000 src = 'src/v0.8/automation' deny_warnings = false +[profile.automation-compile-24] +solc_version = '0.8.24' +optimizer_runs = 1_000_000 +src = 'src/v0.8/automation' +deny_warnings = false + +[profile.automation-cre] +solc_version = '0.8.24' +src = 'src/v0.8/automation-cre' +test = 'src/v0.8/automation-cre/test' +optimizer_runs = 1_000_000 +evm_version = 'paris' +deny_warnings = false + [profile.l2ep] solc_version = '0.8.24' optimizer_runs = 1_000_000 diff --git a/contracts/gas-snapshots/automation-cre.gas-snapshot b/contracts/gas-snapshots/automation-cre.gas-snapshot new file mode 100644 index 0000000000..84c3a87326 --- /dev/null +++ b/contracts/gas-snapshots/automation-cre.gas-snapshot @@ -0,0 +1,37 @@ +AutomationReceiverTest:test_getBlockNumberCheck_ReflectsState() (gas: 129208) +AutomationReceiverTest:test_getters_ReflectState() (gas: 13457) +AutomationReceiverTest:test_isCallAllowed_ReflectsState() (gas: 39680) +AutomationReceiverTest:test_onReport_AllowedCallExecutes() (gas: 111992) +AutomationReceiverTest:test_onReport_BlockNumberCheckDisabledAllowsOutOfOrder() (gas: 121493) +AutomationReceiverTest:test_onReport_BlockNumberCheckEqualBlockAccepted() (gas: 168653) +AutomationReceiverTest:test_onReport_BlockNumberCheckSnapshotUsesCurrentBlock() (gas: 168640) +AutomationReceiverTest:test_onReport_BlockNumberCheckWithExplicitFloor() (gas: 190185) +AutomationReceiverTest:test_onReport_CombinedIdentityAccepted() (gas: 2091079) +AutomationReceiverTest:test_onReport_EIP150TermEnsuresFullGasForwardedAtHighLimit() (gas: 109029) +AutomationReceiverTest:test_onReport_FailingCallDoesNotRevert() (gas: 89395) +AutomationReceiverTest:test_onReport_GasLimitZeroPreservesUnboundedBehavior() (gas: 89398) +AutomationReceiverTest:test_onReport_GasOverheadCorrectlyCoversNoOpConsumer() (gas: 109487) +AutomationReceiverTest:test_onReport_GasOverheadCoversWorstCaseGasBurningConsumer() (gas: 277744) +AutomationReceiverTest:test_onReport_InsufficientGasDoesNotAdvanceBlockNumber() (gas: 200337) +AutomationReceiverTest:test_onReport_OwnerAndNameSufficeWithoutWorkflowId() (gas: 2068944) +AutomationReceiverTest:test_onReport_PausedNonRetryableConsumesReport() (gas: 81382) +AutomationReceiverTest:test_onReport_RequiredIncludesEIP150Buffer() (gas: 83289) +AutomationReceiverTest:test_onReport_SufficientGasWithLimitSucceeds() (gas: 108971) +AutomationReceiverTest:test_onReport_WorkflowIdAloneSuffices() (gas: 2036262) +AutomationReceiverTest:test_paused_ReflectsState() (gas: 42368) +AutomationReceiverTest:test_retryableWhilePaused_ReflectsMode() (gas: 59695) +AutomationReceiverTest:test_setBlockNumberCheck_IsPerPair() (gas: 66447) +AutomationReceiverTest:test_setCallAllowed_RevocationSkipsCodeCheck() (gas: 13520) +AutomationReceiverTest:test_setConsumerGasLimit_IsPerPair() (gas: 44564) +AutomationReceiverTest:test_setConsumerGasLimit_SetAndGet() (gas: 29656) +AutomationReceiverTest:test_supportsInterface_ERC165() (gas: 5785) +AutomationReceiverTest:test_supportsInterface_IReceiver() (gas: 5714) +AutomationReceiverTest:test_supportsInterface_ReturnsFalseForUnknown() (gas: 5742) +AutomationReceiverTest:test_unpause_ResumesDelivery() (gas: 148819) +ReceiverTemplateTest:test_getters_ReflectState() (gas: 1096546) +ReceiverTemplateTest:test_onReport_AcceptsWhenMetadataMatches() (gas: 1169353) +ReceiverTemplateTest:test_setExpectedAuthor_ClearingAuthorWhileNameSetDoesNotRevert() (gas: 1072364) +ReceiverTemplateTest:test_setExpectedWorkflowName_CanBeSetWithoutAuthor() (gas: 1067232) +ReceiverTemplateTest:test_setExpectedWorkflowName_ClearWithEmptyString() (gas: 1051069) +ReceiverTemplateTest:test_setForwarderAddress_ZeroSucceedsAtTemplateLevel() (gas: 998853) +ReceiverTemplateTest:test_supportsInterface() (gas: 1015005) \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all b/contracts/scripts/native_solc_compile_all index 45128b3fb2..0c72a423fa 100755 --- a/contracts/scripts/native_solc_compile_all +++ b/contracts/scripts/native_solc_compile_all @@ -14,6 +14,6 @@ SCRIPTPATH="$( # For each product we have a native_solc_compile_all_$product script # These scripts can be run individually, or all together with this script. # To add new CL products, simply write a native_solc_compile_all_$product script and add it to the list below. -for product in automation functions llo-feeds operatorforwarder payments shared vrf data-feeds l2ep; do +for product in automation automation-cre functions llo-feeds operatorforwarder payments shared vrf data-feeds l2ep; do $SCRIPTPATH/native_solc_compile_all_$product done diff --git a/contracts/scripts/native_solc_compile_all_automation-cre b/contracts/scripts/native_solc_compile_all_automation-cre new file mode 100755 index 0000000000..287d7696a3 --- /dev/null +++ b/contracts/scripts/native_solc_compile_all_automation-cre @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e + +echo " ┌──────────────────────────────────────────────┐" +echo " │ Compiling Automation CRE contracts... │" +echo " └──────────────────────────────────────────────┘" + +PROJECT="automation-cre" +CONTRACTS_DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../ && pwd -P )" + +compileContract() { + local contract=$(basename "$2") + echo "Compiling" "$contract" + + local command + command="env FOUNDRY_PROFILE=$1 forge build $CONTRACTS_DIR/src/v0.8/$PROJECT/$2.sol \ + --root $CONTRACTS_DIR \ + --extra-output-files bin abi \ + -o $CONTRACTS_DIR/solc/$PROJECT/$contract" + $command + + # Copy the generated abi files to a single folder + mkdir -p "$CONTRACTS_DIR"/abi/v0.8/"$PROJECT" + cp "$CONTRACTS_DIR"/solc/$PROJECT/"$contract"/"$contract".sol/"$contract".abi.json "$CONTRACTS_DIR"/abi/v0.8/"$PROJECT"/"$contract".abi.json +} + +compileContract automation-compile-24 AutomationReceiver diff --git a/contracts/src/v0.8/automation-cre/AutomationReceiver.sol b/contracts/src/v0.8/automation-cre/AutomationReceiver.sol new file mode 100644 index 0000000000..b1e0bf0582 --- /dev/null +++ b/contracts/src/v0.8/automation-cre/AutomationReceiver.sol @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import {ReceiverTemplate} from "./ReceiverTemplate.sol"; +import {Pausable} from "@openzeppelin/contracts@5.1.0/utils/Pausable.sol"; + +/** + * @title AutomationReceiver + * @notice Generic bridge that executes Automation-style upkeeps delivered by a CRE workflow. + * + * @dev Two independent authorization layers protect this contract: + * + * 1. INBOUND — answers "who may deliver a report?": + * a) {ReceiverTemplate} enforces the CRE Forwarder address check and optional + * workflowId / workflowName / workflowOwner identity checks. + * b) {_processReport} additionally requires that the forwarder is non-zero (closing + * the gap left by `ReceiverTemplate.setForwarderAddress` which permits address(0)) + * and that at least one complete workflow identity option is configured before any + * report is accepted: either (1) workflowId is set, or (2) both workflowOwner and + * workflowName are set. Neither option alone is sufficient for option 2. + * + * 2. OUTBOUND (this contract) — answers "what may a report make this contract do?": + * a closed-by-default allowlist of (target, function-selector) pairs. The inbound checks + * do NOT constrain the `(target, data)` a report carries, so without this layer any + * authorized report could call any contract/function this receiver is trusted by. The + * owner must explicitly allow each (target, selector) before it can be executed. + * + * Migration rule of thumb: inbound authorizes the workflow; outbound authorizes the action. + */ +contract AutomationReceiver is ReceiverTemplate, Pausable { + // Non-target gas costs reserved by the guard (gasleft() < required). + // GAS_OVERHEAD covers only the post-check path: everything from the gasleft() + // comparison through function return. The s_consumerGasLimit SLOAD immediately + // preceding the check is NOT included — it is already reflected in the lower + // gasleft() value at the check point and must not be double-counted. + // + // [Post-check — must complete with remaining gas at the guard point:] + // Pre-call ops (GAS, ADD, LT, JUMPI, stack) ~50 + // CALL to target (cold account access — in production ~2,600 + // setCallAllowed runs in an earlier transaction, so + // the target account has not yet been touched in the + // delivery transaction and the CALL pays the full + // EIP-2929 cold-access surcharge, not the ~100 warm rate) + // Post-call (success flag, JUMPI, LOG3) ~2,200 + // ├─ LOG3 base + 3 topics (375 + 3×375) 1,500 + // ├─ LOG3 data (64 B ABI-encoded empty bytes) 512 + // └─ misc (returnData mem, JUMPI, stack) 188 + // Misc stack / memory ~50 + // Subtotal: ~4,900 + // Conservative headroom (future opcode repricing, ~2,100 + // estimation error) + // Total: ~7,000 + // + // EIP-150 (63/64 rule): a CALL can forward at most 63/64 of available gas. + // Without the `consumerGasLimit / 63` term, the guard under-provisions whenever + // consumerGasLimit > 63 × GAS_OVERHEAD (~441,000). _processReport therefore adds + // consumerGasLimit / 63 to `required` dynamically so that: + // 63/64 × available ≥ consumerGasLimit + // + // Pre-guard overhead (paid BEFORE the check point, so NOT part of `required`): + // Up to four cold SLOADs in ReceiverTemplate.onReport when identity checks are + // active (s_forwarderAddress, s_expectedWorkflowId, s_expectedAuthor, + // s_expectedWorkflowName: 4 × 2,100 = 8,400 gas), warm re-reads of those slots + // in _processReport (~400 gas), abi.decode of the report (~300 gas), the cold + // nested-mapping read of s_callAllowed (~4,200 gas on first access), a cold + // s_consumerGasLimit SLOAD (~2,100 gas), and paused() (~2,100 gas cold) add up to + // ~17,500 gas on the first delivery to a pair. After slots warm, pre-guard drops to + // ~5,500 gas. When the block-number monotonicity check is enabled for a pair, budget + // a further ~10,000 gas for its two cold SLOADs and the advancing SSTORE. + // + // This pre-guard gas is intentionally NOT added to `required` and needs no per-feature constant: + // it is spent before `gasleft()` is read, so the guard already sees it (it observes the reduced + // remaining gas) and cannot manufacture it. Adding it to `required` would double-count and cause + // spurious InsufficientGas reverts. The only caller-side action is to size writeGasLimit to cover + // this pre-guard overhead on top of consumerGasLimit + GAS_OVERHEAD (see README Gas Limit + // section). Under-budgeting fails cleanly (InsufficientGas if the guard is reached, otherwise + // OOG) — both are recorded by the Forwarder as retryable, so this is a tuning, not a safety, + // concern. + uint256 private constant GAS_OVERHEAD = 7000; + + /// @notice Closed-by-default allowlist of callable (target, selector) pairs. + mapping(address target => mapping(bytes4 selector => bool allowed)) private s_callAllowed; + + /// @notice Per-(target, selector) minimum gas the consumer needs to execute. 0 = no limit. + mapping(address target => mapping(bytes4 selector => uint256 gasLimit)) private s_consumerGasLimit; + + /// @notice Opt-in per-(target, selector) block-number monotonicity switch. Closed by default. + mapping(address target => mapping(bytes4 selector => bool enabled)) private s_blockNumberCheckEnabled; + + /// @notice Highest report block number accepted so far for a (target, selector) pair. Doubles as + /// the configurable initial floor set by {setBlockNumberCheck}. + mapping(address target => mapping(bytes4 selector => uint256 blockNumber)) private s_lastReportBlock; + /// @notice While paused, controls how incoming reports are handled. The owner picks the mode + /// at {pause} time: true = reverts (reports stay unconsumed and retryable, resuming + /// after {unpause}); false = the report is consumed (dropped, not retried). Only + /// meaningful while {paused} is true. + bool private s_retryableWhilePaused; + + /// @notice Emitted when a target call succeeds. + event CallExecuted(address indexed target, bytes4 indexed selector, bytes returnData); + /// @notice Emitted when an allowed target call reverts. The report is still consumed. + event CallFailed(address indexed target, bytes4 indexed selector, bytes reason); + /// @notice Emitted when the owner updates the outbound allowlist. + event CallAllowedSet(address indexed target, bytes4 indexed selector, bool allowed); + /// @notice Emitted when the owner updates the consumer gas limit for a (target, selector) pair. + event ConsumerGasLimitSet(address indexed target, bytes4 indexed selector, uint256 previousLimit, uint256 newLimit); + /// @notice Emitted when the owner enables/disables the block-number monotonicity check for a pair. + /// When enabled, `initialBlockNumber` is the floor the next report must meet or exceed. + event BlockNumberCheckSet(address indexed target, bytes4 indexed selector, bool enabled, uint256 initialBlockNumber); + /// @notice Emitted when a report is skipped because its block number is older than the last + /// accepted one for the pair. The report is consumed (not reverted), mirroring + /// Chainlink Automation's fire-and-forget semantics. + event StaleReportSkipped( + address indexed target, bytes4 indexed selector, uint256 reportBlockNumber, uint256 lastReportBlock + ); + /// @notice Emitted when a report is dropped (consumed, not retried) because the receiver is + /// paused in non-retryable mode (see {pause}). + event ReportSkippedWhilePaused(); + + /// @notice Thrown when the decoded target is the zero address. + error InvalidTargetAddress(); + /// @notice Thrown when the target address has no deployed code (EOA, mistyped address, or never-deployed contract). + error TargetHasNoCode(address target); + /// @notice Thrown when the report carries fewer than 4 bytes of calldata (no selector). + error MissingSelector(); + /// @notice Thrown when (target, selector) is not on the outbound allowlist. + error CallNotAllowed(address target, bytes4 selector); + /// @notice Thrown when there is not enough gas to safely forward consumerGasLimit to the target. + /// Causes the forwarder to record the transmission as failed so it can be retried. + error InsufficientGas(uint256 available, uint256 required); + /// @notice Thrown when onReport is called without a complete workflow identity configuration. + /// The receiver requires at least one of the two valid options to be satisfied + /// (satisfying both is also fine): + /// (1) workflowId is set, or (2) both workflowOwner and workflowName are set. + /// Without at least one complete option the receiver cannot be bound to a specific + /// workflow and would accept reports from any DON-signed payload. + error WorkflowIdentityNotConfigured(); + + constructor( + address _forwarder + ) ReceiverTemplate(_forwarder) {} + + /// @notice Emergency stop: halt all report processing until {unpause} is called. Owner-only. + /// @dev Global equivalent of Chainlink Automation's registry-wide pause. DON pause/delete only + /// stops NEW reports; already-signed reports remain permissionlessly deliverable, and this + /// on-chain switch also rejects those in-flight reports. The owner chooses, per pause, how + /// reports that arrive while paused are handled via `retryable`: + /// - `retryable = true`: `_processReport` reverts with `EnforcedPause`. The revert bubbles + /// up through `onReport`, so the CRE Forwarder records the transmission as failed and it + /// stays retryable — pending reports resume delivery once {unpause} is called. + /// - `retryable = false`: `_processReport` emits `ReportSkippedWhilePaused` and returns, + /// consuming the report. Such reports are dropped and will NOT be redelivered after + /// {unpause}. Use this when a backlog of retried reports would be undesirable. + /// @param retryable Whether reports delivered while paused should remain retryable (true) or be + /// dropped (false). The chosen mode applies until the next {pause} or {unpause}. + function pause( + bool retryable + ) external onlyOwner { + s_retryableWhilePaused = retryable; + _pause(); + } + + /// @notice Resume report processing after a {pause}. Owner-only. + function unpause() external onlyOwner { + _unpause(); + } + + /// @notice Returns the pause mode selected at the last {pause}: true if reports delivered while + /// paused revert (retryable), false if they are dropped. Only meaningful while paused. + function retryableWhilePaused() external view returns (bool) { + return s_retryableWhilePaused; + } + + /// @notice Allow or disallow the receiver to call `selector` on `target`. + /// @dev Closed by default. Register every (target, selector) the migrated upkeep needs, + /// e.g. `performUpkeep(bytes)` for custom-logic/log upkeeps, or your specific + /// time-based function. Owner-only. + /// When `allowed` is true, validates that `target` has deployed code at the time of + /// registration; passing an EOA, a mistyped address, or a never-deployed address reverts + /// with `TargetHasNoCode`. The check is skipped when `allowed` is false so that an + /// allowlist entry can always be revoked, even if the target has since self-destructed + /// and its code has become empty. + /// @param target The contract the receiver is permitted to call. + /// @param selector The 4-byte function selector permitted on `target`. + /// @param allowed True to permit, false to revoke. + function setCallAllowed(address target, bytes4 selector, bool allowed) external onlyOwner { + if (target == address(0)) { + revert InvalidTargetAddress(); + } + if (allowed && target.code.length == 0) { + revert TargetHasNoCode(target); + } + s_callAllowed[target][selector] = allowed; + emit CallAllowedSet(target, selector, allowed); + } + + /// @notice Returns whether the receiver may call `selector` on `target`. + function isCallAllowed(address target, bytes4 selector) external view returns (bool) { + return s_callAllowed[target][selector]; + } + + /// @notice Set the minimum gas required to execute `selector` on `target`. + /// @dev When non-zero, `_processReport` will revert with `InsufficientGas` before calling + /// the target if available gas is below `gasLimit + gasLimit / 63 + GAS_OVERHEAD`. + /// The `gasLimit / 63` term compensates for the EIP-150 (63/64) rule: a CALL can + /// forward at most 63/64 of the available gas, so without this buffer a high gas limit + /// would cause the target to receive less than `gasLimit`. This causes the CRE + /// Forwarder to record the transmission as failed (retryable) rather than permanently + /// consuming the report. Set this to the `performGasLimit` tuned in Automation for the + /// specific function being migrated. Each (target, selector) pair has its own limit. + /// Zero (the default) disables the guard for that pair and preserves fire-and-forget. + /// Note: the on-chain formula only covers costs from the guard check onward. The + /// workflow's writeGasLimit must also budget for pre-guard overhead (~17,500 gas + /// on the first delivery to a pair, ~5,500 gas thereafter) on top of this limit. + /// @param target The contract the limit applies to. Must not be the zero address. + /// @param selector The 4-byte function selector the limit applies to. + /// @param gasLimit Minimum gas required by the consumer. 0 = no guard. + function setConsumerGasLimit(address target, bytes4 selector, uint256 gasLimit) external onlyOwner { + if (target == address(0)) revert InvalidTargetAddress(); + uint256 previous = s_consumerGasLimit[target][selector]; + s_consumerGasLimit[target][selector] = gasLimit; + emit ConsumerGasLimitSet(target, selector, previous, gasLimit); + } + + /// @notice Returns the configured consumer gas limit for a (target, selector) pair (0 = no guard). + function getConsumerGasLimit(address target, bytes4 selector) external view returns (uint256) { + return s_consumerGasLimit[target][selector]; + } + + /// @notice Enable or disable the block-number monotonicity (staleness) check for a (target, selector). + /// @dev Closed by default. When enabled, `_processReport` rejects any report whose encoded block + /// number is strictly less than the last accepted one for the pair (CLA-parity: a report at + /// the same block is still accepted). Stale reports are consumed, not reverted, so the + /// forwarder does not pointlessly retry an always-stale delivery. + /// + /// Under Chainlink Automation the registry rejected any report whose trigger block preceded + /// the last performed block. The CRE delivery path does not preserve this ordering, so this + /// opt-in check restores it for conditional-trigger / log upkeeps that relied on it. The + /// workflow always encodes a block number in the report payload, so this can be turned on + /// later without any workflow change. + /// + /// When enabling, the initial floor is configurable: + /// - `initialBlockNumber == 0`: snapshot the current `block.number` as the floor. Note this + /// does NOT reject reports minted between deployment/config and the moment this check is + /// enabled if they carry a block number above the snapshot; prefer an explicit floor when + /// that matters. + /// - `initialBlockNumber != 0`: use the provided value as the floor. + /// The very first accepted report must have a block number >= this floor. + /// + /// Disabling (enabled = false) resets the floor to 0, so out-of-order reports execute + /// again going forward. This is NOT retroactive: a report already rejected as stale while + /// the check was enabled was consumed at that moment (see `StaleReportSkipped`) and is gone + /// — the CRE Forwarder does not hold it for redelivery. Turning the check off cannot revive + /// it; only reports the workflow re-submits after disabling will be considered. + /// Each (target, selector) pair is configured independently. Owner-only. + /// @param target The contract the check applies to. Must not be the zero address. + /// @param selector The 4-byte function selector the check applies to. + /// @param enabled True to enable the check, false to disable it (and clear the stored floor). + /// @param initialBlockNumber Floor for the first report when enabling; 0 snapshots `block.number`. + function setBlockNumberCheck( + address target, + bytes4 selector, + bool enabled, + uint256 initialBlockNumber + ) external onlyOwner { + if (target == address(0)) revert InvalidTargetAddress(); + s_blockNumberCheckEnabled[target][selector] = enabled; + uint256 floor = enabled ? (initialBlockNumber == 0 ? block.number : initialBlockNumber) : 0; + s_lastReportBlock[target][selector] = floor; + emit BlockNumberCheckSet(target, selector, enabled, floor); + } + + /// @notice Returns the block-number monotonicity configuration for a (target, selector) pair. + /// @return enabled Whether the check is active. + /// @return lastReportBlock The highest report block number accepted so far (or the floor set when + /// the check was enabled, if no report has been accepted since). + function getBlockNumberCheck( + address target, + bytes4 selector + ) external view returns (bool enabled, uint256 lastReportBlock) { + return (s_blockNumberCheckEnabled[target][selector], s_lastReportBlock[target][selector]); + } + + /// @notice Decodes and executes the call on the target contract. + /// @param report ABI-encoded (address target, uint256 blockNumber, bytes data), where + /// `blockNumber` is the block the report was produced for (used only by the opt-in + /// monotonicity check) and `data` is a full function call (4-byte selector followed by its + /// arguments) executed as `target.call(data)`. + /// @dev Two pre-conditions are enforced before any decoding: + /// 1. The forwarder address must not be zero. `ReceiverTemplate.setForwarderAddress` + /// does not block address(0), so this guard closes that gap: if the owner ever + /// sets the forwarder to zero (disabling the caller check in onReport), every + /// subsequent report delivery is rejected here instead. + /// 2. A complete workflow identity option must be configured. Two options are accepted: + /// (a) workflowId is set — binds the receiver to one specific workflow instance; or + /// (b) both workflowOwner and workflowName are set — binds the receiver to a named + /// workflow from a specific owner. Either piece of option (b) alone is insufficient: + /// owner alone allows any workflow from that owner; name alone is globally ambiguous. + /// Requiring a complete option closes the cross-receiver replay vector from audit M-02. + /// Authorization failures (zero target, missing selector, not-allowlisted) revert loudly — + /// they indicate misconfiguration or a malformed report. Execution failures (an allowed call that + /// reverts) are swallowed: `CallFailed` is emitted and the report is consumed, matching + /// Chainlink Automation's fire-and-forget semantics where the next trigger re-evaluates + /// eligibility. + /// Staleness: when the block-number monotonicity check is enabled for the pair (see + /// {setBlockNumberCheck}), a report whose block number is older than the last accepted one + /// is skipped — `StaleReportSkipped` is emitted and the report is consumed without executing + /// the target call or reverting. + /// Gas-guard: when `s_consumerGasLimit[target][selector]` is non-zero, the function + /// reverts with `InsufficientGas` before the target call if available gas is below + /// `gasLimit + gasLimit / 63 + GAS_OVERHEAD`. The `gasLimit / 63` term accounts for + /// the EIP-150 (63/64) rule: a CALL forwards at most 63/64 of available gas, so + /// without this buffer a high gas limit (above ~441,000) would cause the target to + /// receive less than configured. This ensures a low-gas delivery is recorded as failed + /// by the forwarder and can be retried, preventing griefing attacks. Each + /// (target, selector) pair has its own configurable limit. + /// Pause guard: when the contract is paused (see {pause}), this function short-circuits + /// before any decoding or execution, and its behavior depends on the mode the owner + /// selected at pause time. In retryable mode it reverts with `EnforcedPause` (the revert + /// propagates through `onReport`, so the forwarder records the transmission as failed and + /// it resumes after {unpause}). In non-retryable mode it emits `ReportSkippedWhilePaused` + /// and returns, consuming (dropping) the report so it is not redelivered. + function _processReport( + bytes calldata report + ) internal override { + if (paused()) { + if (s_retryableWhilePaused) { + revert EnforcedPause(); + } + emit ReportSkippedWhilePaused(); + return; + } + // Read the inherited permission fields directly (warm SLOADs). ReceiverTemplate.onReport + // already loaded all four slots before dispatching here, so these reads cost ~100 gas + // each — far cheaper than a self-STATICCALL to the external getters. + if (s_forwarderAddress == address(0)) { + revert InvalidForwarderAddress(); + } + if (s_expectedWorkflowId == bytes32(0) && (s_expectedAuthor == address(0) || s_expectedWorkflowName == bytes10(0))) + { + revert WorkflowIdentityNotConfigured(); + } + + (address target, uint256 reportBlockNumber, bytes memory data) = abi.decode(report, (address, uint256, bytes)); + + if (target == address(0)) { + revert InvalidTargetAddress(); + } + if (data.length < 4) { + revert MissingSelector(); + } + + // Read the leading 4-byte selector from the in-memory `data`. Safe: length >= 4 is + // checked above, and a 32-byte mload assigned to bytes4 keeps the high (first) 4 bytes. + bytes4 selector; + assembly { + selector := mload(add(data, 0x20)) + } + if (!s_callAllowed[target][selector]) { + revert CallNotAllowed(target, selector); + } + + // Opt-in staleness protection: reject reports older than the last accepted one for this pair. + // CLA-parity comparison (>=): a report at the same block is still accepted. The stored block + // is updated before the gas guard, but an InsufficientGas revert rolls it back so a retry at + // the same block stays valid. + if (s_blockNumberCheckEnabled[target][selector]) { + uint256 lastReportBlock = s_lastReportBlock[target][selector]; + if (reportBlockNumber < lastReportBlock) { + emit StaleReportSkipped(target, selector, reportBlockNumber, lastReportBlock); + return; + } + s_lastReportBlock[target][selector] = reportBlockNumber; + } + + uint256 consumerGasLimit = s_consumerGasLimit[target][selector]; + bool success; + bytes memory returnData; + if (consumerGasLimit > 0) { + // consumerGasLimit / 63 compensates for EIP-150: a CALL forwards at most + // 63/64 of available gas. Without this term, limits above ~441,000 + // (63 × GAS_OVERHEAD, ~441,000) would cause the target to receive less than requested. + uint256 required = consumerGasLimit + consumerGasLimit / 63 + GAS_OVERHEAD; + if (gasleft() < required) { + revert InsufficientGas(gasleft(), required); + } + // solhint-disable-next-line avoid-low-level-calls + (success, returnData) = target.call{gas: consumerGasLimit}(data); + } else { + // solhint-disable-next-line avoid-low-level-calls + (success, returnData) = target.call(data); + } + + if (success) { + emit CallExecuted(target, selector, returnData); + } else { + emit CallFailed(target, selector, returnData); + } + } +} diff --git a/contracts/src/v0.8/automation-cre/IReceiver.sol b/contracts/src/v0.8/automation-cre/IReceiver.sol new file mode 100644 index 0000000000..95edaf4abe --- /dev/null +++ b/contracts/src/v0.8/automation-cre/IReceiver.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from "@openzeppelin/contracts@5.1.0/utils/introspection/IERC165.sol"; + +/// @title IReceiver - receives keystone reports +/// @notice Implementations must support the IReceiver interface through ERC165. +interface IReceiver is IERC165 { + /// @notice Handles incoming keystone reports. + /// @dev If this function call reverts, it can be retried with a higher gas + /// limit. The receiver is responsible for discarding stale reports. + /// @param metadata Report's metadata. + /// @param report Workflow report. + function onReport(bytes calldata metadata, bytes calldata report) external; +} diff --git a/contracts/src/v0.8/automation-cre/ReceiverTemplate.sol b/contracts/src/v0.8/automation-cre/ReceiverTemplate.sol new file mode 100644 index 0000000000..be1d68e5ce --- /dev/null +++ b/contracts/src/v0.8/automation-cre/ReceiverTemplate.sol @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {IReceiver} from "./IReceiver.sol"; +import {Ownable} from "@openzeppelin/contracts@5.1.0/access/Ownable.sol"; +import {IERC165} from "@openzeppelin/contracts@5.1.0/utils/introspection/IERC165.sol"; + +/// @title ReceiverTemplate - Abstract receiver with optional permission controls +/// @notice Provides flexible, updatable security checks for receiving workflow reports +/// @dev The forwarder address is required at construction time for security. +/// Additional permission fields can be configured using setter functions. +abstract contract ReceiverTemplate is IReceiver, Ownable { + // Required permission field at deployment, configurable after. + // `internal` (not `private`) so concrete receivers can read it directly with a warm SLOAD + // instead of paying for a self-STATICCALL to the external getter. + address internal s_forwarderAddress; // If set, only this address can call onReport + + // Optional permission fields (all default to zero = disabled). + // `internal` for the same reason as s_forwarderAddress above. + address internal s_expectedAuthor; // If set, only reports from this workflow owner are accepted + bytes10 internal s_expectedWorkflowName; // Only validated when s_expectedAuthor is also set + bytes32 internal s_expectedWorkflowId; // If set, only reports from this specific workflow ID are accepted + + // Hex character lookup table for bytes-to-hex conversion + bytes private constant HEX_CHARS = "0123456789abcdef"; + + // Custom errors + error InvalidForwarderAddress(); + error InvalidSender(address sender, address expected); + error InvalidAuthor(address received, address expected); + error InvalidWorkflowName(bytes10 received, bytes10 expected); + error InvalidWorkflowId(bytes32 received, bytes32 expected); + error WorkflowNameRequiresAuthorValidation(); + + // Events + event ForwarderAddressUpdated(address indexed previousForwarder, address indexed newForwarder); + event ExpectedAuthorUpdated(address indexed previousAuthor, address indexed newAuthor); + event ExpectedWorkflowNameUpdated(bytes10 indexed previousName, bytes10 indexed newName); + event ExpectedWorkflowIdUpdated(bytes32 indexed previousId, bytes32 indexed newId); + event SecurityWarning(string message); + + /// @notice Constructor sets msg.sender as the owner and configures the forwarder address + /// @param _forwarderAddress The address of the Chainlink Forwarder contract (cannot be address(0)) + /// @dev The forwarder address is required for security - it ensures only verified reports are processed + constructor( + address _forwarderAddress + ) Ownable(msg.sender) { + if (_forwarderAddress == address(0)) { + revert InvalidForwarderAddress(); + } + s_forwarderAddress = _forwarderAddress; + emit ForwarderAddressUpdated(address(0), _forwarderAddress); + } + + /// @notice Returns the configured forwarder address + /// @return The forwarder address (address(0) if disabled) + function getForwarderAddress() external view returns (address) { + return s_forwarderAddress; + } + + /// @notice Returns the expected workflow author address + /// @return The expected author address (address(0) if not set) + function getExpectedAuthor() external view returns (address) { + return s_expectedAuthor; + } + + /// @notice Returns the expected workflow name + /// @return The expected workflow name (bytes10(0) if not set) + function getExpectedWorkflowName() external view returns (bytes10) { + return s_expectedWorkflowName; + } + + /// @notice Returns the expected workflow ID + /// @return The expected workflow ID (bytes32(0) if not set) + function getExpectedWorkflowId() external view returns (bytes32) { + return s_expectedWorkflowId; + } + + /// @inheritdoc IReceiver + /// @dev Performs optional validation checks based on which permission fields are set + function onReport(bytes calldata metadata, bytes calldata report) external override { + // Security Check 1: Verify caller is the trusted Chainlink Forwarder (if configured) + if (s_forwarderAddress != address(0) && msg.sender != s_forwarderAddress) { + revert InvalidSender(msg.sender, s_forwarderAddress); + } + + // Security Checks 2-4: Verify workflow identity - ID, owner, and/or name (if any are configured) + if (s_expectedWorkflowId != bytes32(0) || s_expectedAuthor != address(0) || s_expectedWorkflowName != bytes10(0)) { + (bytes32 workflowId, bytes10 workflowName, address workflowOwner) = _decodeMetadata(metadata); + + if (s_expectedWorkflowId != bytes32(0) && workflowId != s_expectedWorkflowId) { + revert InvalidWorkflowId(workflowId, s_expectedWorkflowId); + } + if (s_expectedAuthor != address(0) && workflowOwner != s_expectedAuthor) { + revert InvalidAuthor(workflowOwner, s_expectedAuthor); + } + + // ================================================================ + // WORKFLOW NAME VALIDATION - REQUIRES AUTHOR VALIDATION + // ================================================================ + // Do not rely on workflow name validation alone. Workflow names are unique + // per owner, but not across owners. + // Furthermore, workflow names use 40-bit truncation (bytes10), making collisions possible. + // Therefore, workflow name validation REQUIRES author (workflow owner) validation. + // The code enforces this dependency at runtime. + // ================================================================ + if (s_expectedWorkflowName != bytes10(0)) { + // Author must be configured if workflow name is used + if (s_expectedAuthor == address(0)) { + revert WorkflowNameRequiresAuthorValidation(); + } + // Validate workflow name matches (author already validated above) + if (workflowName != s_expectedWorkflowName) { + revert InvalidWorkflowName(workflowName, s_expectedWorkflowName); + } + } + } + + _processReport(report); + } + + /// @notice Updates the forwarder address that is allowed to call onReport + /// @param _forwarder The new forwarder address + /// @dev WARNING: Setting to address(0) disables forwarder validation. + /// This makes your contract INSECURE - anyone can call onReport() with arbitrary data. + /// Only use address(0) if you fully understand the security implications. + function setForwarderAddress( + address _forwarder + ) external onlyOwner { + address previousForwarder = s_forwarderAddress; + + // Emit warning if disabling forwarder check + if (_forwarder == address(0)) { + emit SecurityWarning("Forwarder address set to zero - contract is now INSECURE"); + } + + s_forwarderAddress = _forwarder; + emit ForwarderAddressUpdated(previousForwarder, _forwarder); + } + + /// @notice Updates the expected workflow owner address + /// @param _author The new expected author address (use address(0) to disable this check) + function setExpectedAuthor( + address _author + ) external onlyOwner { + address previousAuthor = s_expectedAuthor; + s_expectedAuthor = _author; + emit ExpectedAuthorUpdated(previousAuthor, _author); + } + + /// @notice Updates the expected workflow name from a plaintext string + /// @param _name The workflow name as a string (use empty string "" to disable this check) + /// @dev IMPORTANT: Workflow name validation REQUIRES author validation to be enabled. + /// The workflow name uses only 40-bit truncation, making collision attacks feasible + /// when used alone. However, since workflow names are unique per owner, validating + /// both the name AND the author address provides adequate security. + /// You must call setExpectedAuthor() before or after calling this function. + /// The name is hashed using SHA256 and truncated to bytes10. + function setExpectedWorkflowName( + string calldata _name + ) external onlyOwner { + bytes10 previousName = s_expectedWorkflowName; + + if (bytes(_name).length == 0) { + s_expectedWorkflowName = bytes10(0); + emit ExpectedWorkflowNameUpdated(previousName, bytes10(0)); + return; + } + + // Convert workflow name to bytes10: + // SHA256 hash → hex encode → take first 10 chars → hex encode those chars + bytes32 hash = sha256(bytes(_name)); + bytes memory hexString = _bytesToHexString(abi.encodePacked(hash)); + bytes memory first10 = new bytes(10); + for (uint256 i = 0; i < 10; i++) { + first10[i] = hexString[i]; + } + s_expectedWorkflowName = bytes10(first10); + emit ExpectedWorkflowNameUpdated(previousName, s_expectedWorkflowName); + } + + /// @notice Updates the expected workflow ID + /// @param _id The new expected workflow ID (use bytes32(0) to disable this check) + function setExpectedWorkflowId( + bytes32 _id + ) external onlyOwner { + bytes32 previousId = s_expectedWorkflowId; + s_expectedWorkflowId = _id; + emit ExpectedWorkflowIdUpdated(previousId, _id); + } + + /// @notice Helper function to convert bytes to hex string + /// @param data The bytes to convert + /// @return The hex string representation + function _bytesToHexString( + bytes memory data + ) private pure returns (bytes memory) { + bytes memory hexString = new bytes(data.length * 2); + + for (uint256 i = 0; i < data.length; i++) { + hexString[i * 2] = HEX_CHARS[uint8(data[i] >> 4)]; + hexString[i * 2 + 1] = HEX_CHARS[uint8(data[i] & 0x0f)]; + } + + return hexString; + } + + /// @notice Extracts all metadata fields from the onReport metadata parameter + /// @param metadata The metadata bytes encoded using abi.encodePacked(workflowId, workflowName, workflowOwner) + /// @return workflowId The unique identifier of the workflow (bytes32) + /// @return workflowName The name of the workflow (bytes10) + /// @return workflowOwner The owner address of the workflow + function _decodeMetadata( + bytes memory metadata + ) internal pure returns (bytes32 workflowId, bytes10 workflowName, address workflowOwner) { + // Metadata structure (encoded using abi.encodePacked by the Forwarder): + // - First 32 bytes: length of the byte array (standard for dynamic bytes) + // - Offset 32, size 32: workflow_id (bytes32) + // - Offset 64, size 10: workflow_name (bytes10) + // - Offset 74, size 20: workflow_owner (address) + assembly { + workflowId := mload(add(metadata, 32)) + workflowName := mload(add(metadata, 64)) + workflowOwner := shr(mul(12, 8), mload(add(metadata, 74))) + } + return (workflowId, workflowName, workflowOwner); + } + + /// @notice Abstract function to process the report data + /// @param report The report calldata containing your workflow's encoded data + /// @dev Implement this function with your contract's business logic + function _processReport( + bytes calldata report + ) internal virtual; + + /// @inheritdoc IERC165 + function supportsInterface( + bytes4 interfaceId + ) public view virtual override returns (bool) { + return interfaceId == type(IReceiver).interfaceId || interfaceId == type(IERC165).interfaceId; + } +} diff --git a/contracts/src/v0.8/automation-cre/test/AutomationReceiver/AutomationReceiver.t.sol b/contracts/src/v0.8/automation-cre/test/AutomationReceiver/AutomationReceiver.t.sol new file mode 100644 index 0000000000..274d6113d1 --- /dev/null +++ b/contracts/src/v0.8/automation-cre/test/AutomationReceiver/AutomationReceiver.t.sol @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +// solhint-disable +// gas-custom-errors,interface-starts-with-i,chainlink-solidity/all-caps-constant-storage-variables,chainlink-solidity/prefix-storage-variables-with-s-underscore + +import {AutomationReceiver} from "../../AutomationReceiver.sol"; + +import {IReceiver} from "../../IReceiver.sol"; +import {ReceiverTemplate} from "../../ReceiverTemplate.sol"; +import {Ownable} from "@openzeppelin/contracts@5.1.0/access/Ownable.sol"; +import {Pausable} from "@openzeppelin/contracts@5.1.0/utils/Pausable.sol"; + +interface Vm { + function prank( + address msgSender + ) external; + + function expectRevert( + bytes4 revertData + ) external; + + function expectRevert( + bytes calldata revertData + ) external; + + /// @dev Marks `target` cold, as if it had never been accessed in the current transaction. + /// Used to simulate production delivery, where setCallAllowed ran in an earlier + /// transaction and the target account is therefore cold at delivery time — unlike a + /// same-transaction Foundry test, which would otherwise leave it warm. + function cool( + address target + ) external; +} + +/// @dev Minimal Automation-style target. `performUpkeep` records the last performData and +/// can be toggled to revert, to exercise the execution-failure path. +contract MockUpkeep { + bool public shouldRevert; + uint256 public performCount; + bytes public lastPerformData; + + function setShouldRevert( + bool value + ) external { + shouldRevert = value; + } + + function performUpkeep( + bytes calldata performData + ) external { + if (shouldRevert) { + revert("upkeep failed"); + } + performCount++; + lastPerformData = performData; + } +} + +/// @dev Burns a fixed amount of gas on every call so we can test the insufficient-gas guard. +contract MockGasHog { + uint256 public callCount; + + function performUpkeep( + bytes calldata + ) external { + callCount++; + } +} + +/// @dev Records the gas remaining at the start of performUpkeep. +contract MockGasRecorder { + uint256 public gasOnEntry; + + function performUpkeep( + bytes calldata + ) external { + gasOnEntry = gasleft(); + } +} + +/// @dev Worst case for GAS_OVERHEAD: consumes every unit of forwarded gas and reverts (OOG). +contract MockGasBurner { + function performUpkeep( + bytes calldata + ) external pure { + // solhint-disable-next-line no-empty-blocks + while (true) {} + } +} + +contract AutomationReceiverTest { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + address private constant FORWARDER = address(uint160(1)); + address private constant ATTACKER = address(uint160(3)); + bytes4 private constant PERFORM_SELECTOR = bytes4(keccak256("performUpkeep(bytes)")); + + bytes32 private constant WORKFLOW_ID = bytes32(uint256(42)); + address private constant WORKFLOW_OWNER = address(uint160(5)); + + uint256 private constant GAS_OVERHEAD = 7000; + + AutomationReceiver private receiver; + MockUpkeep private target; + MockGasHog private gasHog; + MockGasRecorder private gasRecorder; + MockGasBurner private gasBurner; + + constructor() { + receiver = new AutomationReceiver(FORWARDER); + receiver.setExpectedWorkflowId(WORKFLOW_ID); + receiver.setExpectedAuthor(WORKFLOW_OWNER); + target = new MockUpkeep(); + gasHog = new MockGasHog(); + gasRecorder = new MockGasRecorder(); + gasBurner = new MockGasBurner(); + } + + // ─── helpers ──────────────────────────────────────────────── + function _performCall( + bytes memory performData + ) private pure returns (bytes memory) { + return abi.encodeWithSignature("performUpkeep(bytes)", performData); + } + + function _report(address tgt, bytes memory callData) private pure returns (bytes memory) { + return abi.encode(tgt, uint256(0), callData); + } + + function _reportAtBlock(address tgt, uint256 blockNumber, bytes memory callData) private pure returns (bytes memory) { + return abi.encode(tgt, blockNumber, callData); + } + + function _metadata(bytes32 wfId, address wfOwner) private pure returns (bytes memory) { + return abi.encodePacked(wfId, bytes10(0), wfOwner); + } + + function _deliver( + bytes memory report + ) private { + vm.prank(FORWARDER); + receiver.onReport(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report); + } + + function _deliverOutcome(address tgt, uint256 gasAmount, bytes memory report) private returns (uint8) { + vm.cool(tgt); + vm.prank(FORWARDER); + try receiver.onReport{gas: gasAmount}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report) { + return 0; + } catch (bytes memory data) { + bytes4 sel; + if (data.length >= 4) { + assembly { + sel := mload(add(data, 32)) + } + } + return sel == AutomationReceiver.InsufficientGas.selector ? 1 : 2; + } + } + + // ─── inbound auth ──────────────────────────────────────────── + function test_onReport_RevertWhen_InvalidSender() external { + bytes memory report = _report(address(target), _performCall(hex"01")); + + vm.expectRevert(abi.encodeWithSelector(_invalidSenderSelector(), ATTACKER, FORWARDER)); + vm.prank(ATTACKER); + receiver.onReport(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report); + } + + // ─── forwarder-zero guard ──────────────────────────────────── + function test_onReport_RevertWhen_ForwarderIsZero() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.setForwarderAddress(address(0)); + + vm.expectRevert(ReceiverTemplate.InvalidForwarderAddress.selector); + receiver.onReport(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), _report(address(target), _performCall(hex"01"))); + } + + // ─── workflow identity guard ───────────────────────────────── + function test_onReport_WorkflowIdAloneSuffices() external { + AutomationReceiver freshReceiver = new AutomationReceiver(FORWARDER); + freshReceiver.setExpectedWorkflowId(WORKFLOW_ID); + freshReceiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + vm.prank(FORWARDER); + freshReceiver.onReport(_metadata(WORKFLOW_ID, address(0)), _report(address(target), _performCall(hex"01"))); + + _assertEq(target.performCount(), 1); + } + + function test_onReport_OwnerAndNameSufficeWithoutWorkflowId() external { + AutomationReceiver freshReceiver = new AutomationReceiver(FORWARDER); + freshReceiver.setExpectedAuthor(WORKFLOW_OWNER); + freshReceiver.setExpectedWorkflowName("my-workflow"); + freshReceiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + bytes10 wfName = freshReceiver.getExpectedWorkflowName(); + + vm.prank(FORWARDER); + freshReceiver.onReport( + abi.encodePacked(bytes32(0), wfName, WORKFLOW_OWNER), _report(address(target), _performCall(hex"01")) + ); + + _assertEq(target.performCount(), 1); + } + + function test_onReport_RevertWhen_OwnerSetButNameMissing() external { + AutomationReceiver freshReceiver = new AutomationReceiver(FORWARDER); + freshReceiver.setExpectedAuthor(WORKFLOW_OWNER); + freshReceiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + vm.expectRevert(AutomationReceiver.WorkflowIdentityNotConfigured.selector); + vm.prank(FORWARDER); + freshReceiver.onReport(_metadata(bytes32(0), WORKFLOW_OWNER), _report(address(target), _performCall(hex"01"))); + } + + function test_onReport_RevertWhen_NoIdentityConfigured() external { + AutomationReceiver freshReceiver = new AutomationReceiver(FORWARDER); + freshReceiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + vm.expectRevert(AutomationReceiver.WorkflowIdentityNotConfigured.selector); + vm.prank(FORWARDER); + freshReceiver.onReport(_metadata(bytes32(0), address(0)), _report(address(target), _performCall(hex"01"))); + } + + function test_onReport_CombinedIdentityAccepted() external { + AutomationReceiver freshReceiver = new AutomationReceiver(FORWARDER); + freshReceiver.setExpectedWorkflowId(WORKFLOW_ID); + freshReceiver.setExpectedAuthor(WORKFLOW_OWNER); + freshReceiver.setExpectedWorkflowName("my-workflow"); + freshReceiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + bytes10 wfName = freshReceiver.getExpectedWorkflowName(); + vm.prank(FORWARDER); + freshReceiver.onReport( + abi.encodePacked(WORKFLOW_ID, wfName, WORKFLOW_OWNER), _report(address(target), _performCall(hex"01")) + ); + + _assertEq(target.performCount(), 1); + } + + // ─── outbound allowlist ───────────────────────────────────── + function test_onReport_RevertWhen_CallNotAllowed() external { + bytes memory report = _report(address(target), _performCall(hex"01")); + + vm.expectRevert( + abi.encodeWithSelector(AutomationReceiver.CallNotAllowed.selector, address(target), PERFORM_SELECTOR) + ); + _deliver(report); + } + + function test_onReport_AllowedCallExecutes() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + bytes memory performData = hex"deadbeef"; + _deliver(_report(address(target), _performCall(performData))); + + _assertEq(target.performCount(), 1); + _assertEq(keccak256(target.lastPerformData()), keccak256(performData)); + } + + function test_onReport_RevertWhen_CallRevoked() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, false); + + vm.expectRevert( + abi.encodeWithSelector(AutomationReceiver.CallNotAllowed.selector, address(target), PERFORM_SELECTOR) + ); + _deliver(_report(address(target), _performCall(hex"01"))); + } + + function test_onReport_FailingCallDoesNotRevert() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + target.setShouldRevert(true); + + _deliver(_report(address(target), _performCall(hex"01"))); + + _assertEq(target.performCount(), 0); + } + + // ─── malformed reports ────────────────────────────────────── + function test_onReport_RevertWhen_ZeroTarget() external { + vm.expectRevert(AutomationReceiver.InvalidTargetAddress.selector); + _deliver(_report(address(0), _performCall(hex"01"))); + } + + function test_onReport_RevertWhen_MissingSelector() external { + vm.expectRevert(AutomationReceiver.MissingSelector.selector); + _deliver(_report(address(target), hex"010203")); + } + + // ─── allowlist administration ─────────────────────────────── + function test_setCallAllowed_RevertWhen_NotOwner() external { + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, ATTACKER)); + vm.prank(ATTACKER); + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + } + + function test_setCallAllowed_RevertWhen_ZeroTarget() external { + vm.expectRevert(AutomationReceiver.InvalidTargetAddress.selector); + receiver.setCallAllowed(address(0), PERFORM_SELECTOR, true); + } + + function test_setCallAllowed_RevertWhen_CodelessTarget() external { + address eoa = address(uint160(99)); + vm.expectRevert(abi.encodeWithSelector(AutomationReceiver.TargetHasNoCode.selector, eoa)); + receiver.setCallAllowed(eoa, PERFORM_SELECTOR, true); + } + + function test_setCallAllowed_RevocationSkipsCodeCheck() external { + address eoa = address(uint160(99)); + receiver.setCallAllowed(eoa, PERFORM_SELECTOR, false); + _assertFalse(receiver.isCallAllowed(eoa, PERFORM_SELECTOR)); + } + + function test_isCallAllowed_ReflectsState() external { + _assertFalse(receiver.isCallAllowed(address(target), PERFORM_SELECTOR)); + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + _assertTrue(receiver.isCallAllowed(address(target), PERFORM_SELECTOR)); + } + + // ─── emergency pause ──────────────────────────────────────── + function test_pause_RevertWhen_NotOwner() external { + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, ATTACKER)); + vm.prank(ATTACKER); + receiver.pause(true); + } + + function test_unpause_RevertWhen_NotOwner() external { + receiver.pause(true); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, ATTACKER)); + vm.prank(ATTACKER); + receiver.unpause(); + } + + function test_onReport_RevertWhen_PausedRetryable() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.pause(true); + + vm.expectRevert(Pausable.EnforcedPause.selector); + _deliver(_report(address(target), _performCall(hex"01"))); + + _assertEq(target.performCount(), 0); + } + + function test_onReport_PausedNonRetryableConsumesReport() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.pause(false); + + _deliver(_report(address(target), _performCall(hex"01"))); + + _assertEq(target.performCount(), 0); + } + + function test_unpause_ResumesDelivery() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + receiver.pause(true); + vm.expectRevert(Pausable.EnforcedPause.selector); + _deliver(_report(address(target), _performCall(hex"01"))); + + receiver.unpause(); + _deliver(_report(address(target), _performCall(hex"01"))); + + _assertEq(target.performCount(), 1); + } + + function test_paused_ReflectsState() external { + _assertFalse(receiver.paused()); + receiver.pause(true); + _assertTrue(receiver.paused()); + receiver.unpause(); + _assertFalse(receiver.paused()); + } + + function test_retryableWhilePaused_ReflectsMode() external { + receiver.pause(true); + _assertTrue(receiver.retryableWhilePaused()); + receiver.unpause(); + + receiver.pause(false); + _assertFalse(receiver.retryableWhilePaused()); + } + + function test_pause_RevertWhen_AlreadyPaused() external { + receiver.pause(true); + vm.expectRevert(Pausable.EnforcedPause.selector); + receiver.pause(true); + } + + function test_unpause_RevertWhen_NotPaused() external { + vm.expectRevert(Pausable.ExpectedPause.selector); + receiver.unpause(); + } + + // ─── consumer gas limit administration ───────────────────── + function test_setConsumerGasLimit_RevertWhen_NotOwner() external { + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, ATTACKER)); + vm.prank(ATTACKER); + receiver.setConsumerGasLimit(address(gasHog), PERFORM_SELECTOR, 500_000); + } + + function test_setConsumerGasLimit_RevertWhen_ZeroTarget() external { + vm.expectRevert(AutomationReceiver.InvalidTargetAddress.selector); + receiver.setConsumerGasLimit(address(0), PERFORM_SELECTOR, 100_000); + } + + function test_setConsumerGasLimit_SetAndGet() external { + _assertEq(receiver.getConsumerGasLimit(address(target), PERFORM_SELECTOR), 0); + + receiver.setConsumerGasLimit(address(target), PERFORM_SELECTOR, 300_000); + _assertEq(receiver.getConsumerGasLimit(address(target), PERFORM_SELECTOR), 300_000); + + receiver.setConsumerGasLimit(address(target), PERFORM_SELECTOR, 0); + _assertEq(receiver.getConsumerGasLimit(address(target), PERFORM_SELECTOR), 0); + } + + function test_setConsumerGasLimit_IsPerPair() external { + receiver.setConsumerGasLimit(address(gasHog), PERFORM_SELECTOR, 200_000); + + _assertEq(receiver.getConsumerGasLimit(address(gasHog), PERFORM_SELECTOR), 200_000); + _assertEq(receiver.getConsumerGasLimit(address(target), PERFORM_SELECTOR), 0); + _assertEq(receiver.getConsumerGasLimit(address(gasHog), bytes4(keccak256("otherFn()"))), 0); + } + + // ─── gas guard ────────────────────────────────────────────── + function test_onReport_RevertWhen_InsufficientGas() external { + receiver.setCallAllowed(address(gasHog), PERFORM_SELECTOR, true); + uint256 limit = 200_000; + receiver.setConsumerGasLimit(address(gasHog), PERFORM_SELECTOR, limit); + + bytes memory report = _report(address(gasHog), _performCall(hex"")); + bool reverted; + vm.prank(FORWARDER); + try receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD - 1}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report) { + reverted = false; + } catch (bytes memory data) { + bytes4 sel; + assembly { + sel := mload(add(data, 32)) + } + if (sel != AutomationReceiver.InsufficientGas.selector) revert("wrong revert selector"); + reverted = true; + } + _assertTrue(reverted); + } + + function test_onReport_SufficientGasWithLimitSucceeds() external { + receiver.setCallAllowed(address(gasHog), PERFORM_SELECTOR, true); + uint256 limit = 50_000; + receiver.setConsumerGasLimit(address(gasHog), PERFORM_SELECTOR, limit); + + bytes memory report = _report(address(gasHog), _performCall(hex"")); + vm.prank(FORWARDER); + receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD + 50_000}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report); + + _assertEq(gasHog.callCount(), 1); + } + + function test_onReport_GasLimitZeroPreservesUnboundedBehavior() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + target.setShouldRevert(true); + + _deliver(_report(address(target), _performCall(hex"01"))); + _assertEq(target.performCount(), 0); + } + + // ─── EIP-150 (63/64 rule) ──────────────────────────────────── + function test_onReport_RequiredIncludesEIP150Buffer() external { + receiver.setCallAllowed(address(gasHog), PERFORM_SELECTOR, true); + uint256 limit = 200_000; + receiver.setConsumerGasLimit(address(gasHog), PERFORM_SELECTOR, limit); + + bytes memory report = _report(address(gasHog), _performCall(hex"")); + bool reverted; + uint256 emittedRequired; + vm.prank(FORWARDER); + try receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD - 1}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report) { + reverted = false; + } catch (bytes memory errData) { + bytes4 sel; + assembly { + sel := mload(add(errData, 32)) + } + if (sel != AutomationReceiver.InsufficientGas.selector) revert("wrong revert selector"); + assembly { + emittedRequired := mload(add(errData, 68)) + } + reverted = true; + } + _assertTrue(reverted); + _assertEq(emittedRequired, limit + limit / 63 + GAS_OVERHEAD); + } + + function test_onReport_EIP150TermEnsuresFullGasForwardedAtHighLimit() external { + receiver.setCallAllowed(address(gasRecorder), PERFORM_SELECTOR, true); + uint256 limit = 1_000_000; + receiver.setConsumerGasLimit(address(gasRecorder), PERFORM_SELECTOR, limit); + + bytes memory report = _report(address(gasRecorder), _performCall(hex"")); + vm.prank(FORWARDER); + receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD + 60_000}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report); + + uint256 gasReceived = gasRecorder.gasOnEntry(); + _assertTrue(gasReceived >= limit - 500); + _assertTrue(gasReceived <= limit); + } + + // ─── GAS_OVERHEAD accuracy ────────────────────────────────── + function test_onReport_GasOverheadCorrectlyCoversNoOpConsumer() external { + receiver.setCallAllowed(address(gasRecorder), PERFORM_SELECTOR, true); + uint256 limit = 30_000; + receiver.setConsumerGasLimit(address(gasRecorder), PERFORM_SELECTOR, limit); + + bytes memory report = _report(address(gasRecorder), _performCall(hex"")); + vm.cool(address(gasRecorder)); + vm.prank(FORWARDER); + receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD + 60_000}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report); + + uint256 gasReceived = gasRecorder.gasOnEntry(); + _assertTrue(gasReceived >= limit - 500); + _assertTrue(gasReceived <= limit); + } + + function test_onReport_GasOverheadCoversWorstCaseGasBurningConsumer() external { + receiver.setCallAllowed(address(gasBurner), PERFORM_SELECTOR, true); + uint256 limit = 1000; + receiver.setConsumerGasLimit(address(gasBurner), PERFORM_SELECTOR, limit); + bytes memory report = _report(address(gasBurner), _performCall(hex"")); + + uint256 lo = 0; + uint256 hi = 500_000; + _assertEq(_deliverOutcome(address(gasBurner), hi, report), 0); + + while (hi - lo > 1) { + uint256 mid = (lo + hi) / 2; + if (_deliverOutcome(address(gasBurner), mid, report) == 0) { + hi = mid; + } else { + lo = mid; + } + } + + _assertEq(_deliverOutcome(address(gasBurner), lo, report), 1); + } + + // ─── block-number monotonicity ─────────────────────────────── + function test_onReport_BlockNumberCheckDisabledAllowsOutOfOrder() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + + _deliver(_reportAtBlock(address(target), 100, _performCall(hex"01"))); + _deliver(_reportAtBlock(address(target), 50, _performCall(hex"01"))); + + _assertEq(target.performCount(), 2); + } + + function test_onReport_BlockNumberCheckWithExplicitFloor() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, true, 100); + + _deliver(_reportAtBlock(address(target), 99, _performCall(hex"01"))); + _assertEq(target.performCount(), 0); + + _deliver(_reportAtBlock(address(target), 100, _performCall(hex"01"))); + _assertEq(target.performCount(), 1); + + _deliver(_reportAtBlock(address(target), 101, _performCall(hex"01"))); + _assertEq(target.performCount(), 2); + + _deliver(_reportAtBlock(address(target), 100, _performCall(hex"01"))); + _assertEq(target.performCount(), 2); + } + + function test_onReport_BlockNumberCheckEqualBlockAccepted() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, true, 100); + + _deliver(_reportAtBlock(address(target), 100, _performCall(hex"01"))); + _deliver(_reportAtBlock(address(target), 100, _performCall(hex"01"))); + + _assertEq(target.performCount(), 2); + } + + function test_onReport_BlockNumberCheckSnapshotUsesCurrentBlock() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, true, 0); + + (bool enabled, uint256 floor) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertTrue(enabled); + _assertEq(floor, block.number); + + if (block.number > 0) { + _deliver(_reportAtBlock(address(target), block.number - 1, _performCall(hex"01"))); + _assertEq(target.performCount(), 0); + } + + _deliver(_reportAtBlock(address(target), block.number, _performCall(hex"01"))); + _assertEq(target.performCount(), 1); + } + + function test_getBlockNumberCheck_ReflectsState() external { + (bool enabled, uint256 last) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertFalse(enabled); + _assertEq(last, 0); + + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, true, 500); + (enabled, last) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertTrue(enabled); + _assertEq(last, 500); + + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + _deliver(_reportAtBlock(address(target), 600, _performCall(hex"01"))); + (, last) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertEq(last, 600); + + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, false, 0); + (enabled, last) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertFalse(enabled); + _assertEq(last, 0); + } + + function test_setBlockNumberCheck_IsPerPair() external { + receiver.setBlockNumberCheck(address(gasHog), PERFORM_SELECTOR, true, 300); + + (bool enabledHog, uint256 lastHog) = receiver.getBlockNumberCheck(address(gasHog), PERFORM_SELECTOR); + _assertTrue(enabledHog); + _assertEq(lastHog, 300); + + (bool enabledTarget, uint256 lastTarget) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertFalse(enabledTarget); + _assertEq(lastTarget, 0); + } + + function test_setBlockNumberCheck_RevertWhen_NotOwner() external { + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, ATTACKER)); + vm.prank(ATTACKER); + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, true, 0); + } + + function test_setBlockNumberCheck_RevertWhen_ZeroTarget() external { + vm.expectRevert(AutomationReceiver.InvalidTargetAddress.selector); + receiver.setBlockNumberCheck(address(0), PERFORM_SELECTOR, true, 0); + } + + function test_onReport_InsufficientGasDoesNotAdvanceBlockNumber() external { + receiver.setCallAllowed(address(target), PERFORM_SELECTOR, true); + receiver.setBlockNumberCheck(address(target), PERFORM_SELECTOR, true, 100); + uint256 limit = 200_000; + receiver.setConsumerGasLimit(address(target), PERFORM_SELECTOR, limit); + + bytes memory report = _reportAtBlock(address(target), 100, _performCall(hex"01")); + + bool reverted; + vm.prank(FORWARDER); + try receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD - 1}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report) { + reverted = false; + } catch (bytes memory data) { + bytes4 sel; + assembly { + sel := mload(add(data, 32)) + } + if (sel != AutomationReceiver.InsufficientGas.selector) revert("wrong revert selector"); + reverted = true; + } + _assertTrue(reverted); + + (, uint256 lastBlock) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertEq(lastBlock, 100); + _assertEq(target.performCount(), 0); + + vm.prank(FORWARDER); + receiver.onReport{gas: limit + limit / 63 + GAS_OVERHEAD + 100_000}(_metadata(WORKFLOW_ID, WORKFLOW_OWNER), report); + _assertEq(target.performCount(), 1); + (, lastBlock) = receiver.getBlockNumberCheck(address(target), PERFORM_SELECTOR); + _assertEq(lastBlock, 100); + } + + // ─── supportsInterface ─────────────────────────────────────── + function test_supportsInterface_ERC165() external { + _assertTrue(receiver.supportsInterface(0x01ffc9a7)); + } + + function test_supportsInterface_IReceiver() external { + _assertTrue(receiver.supportsInterface(type(IReceiver).interfaceId)); + } + + function test_supportsInterface_ReturnsFalseForUnknown() external { + _assertFalse(receiver.supportsInterface(0xdeadbeef)); + } + + // ─── getters ──────────────────────────────────────────────── + function test_getters_ReflectState() external { + _assertEq(receiver.getForwarderAddress(), FORWARDER); + _assertEq(receiver.getExpectedAuthor(), WORKFLOW_OWNER); + _assertEq(receiver.getExpectedWorkflowId(), WORKFLOW_ID); + } + + // ─── tiny assertion helpers (no forge-std dependency) ─────── + function _invalidSenderSelector() private pure returns (bytes4) { + return bytes4(keccak256("InvalidSender(address,address)")); + } + + function _assertEq(uint256 actual, uint256 expected) private pure { + if (actual != expected) revert("uint mismatch"); + } + + function _assertEq(bytes32 actual, bytes32 expected) private pure { + if (actual != expected) revert("bytes32 mismatch"); + } + + function _assertEq(address actual, address expected) private pure { + if (actual != expected) revert("address mismatch"); + } + + function _assertTrue( + bool value + ) private pure { + if (!value) revert("expected true"); + } + + function _assertFalse( + bool value + ) private pure { + if (value) revert("expected false"); + } +} diff --git a/contracts/src/v0.8/automation-cre/test/ReceiverTemplate/ReceiverTemplate.t.sol b/contracts/src/v0.8/automation-cre/test/ReceiverTemplate/ReceiverTemplate.t.sol new file mode 100644 index 0000000000..ad8d257981 --- /dev/null +++ b/contracts/src/v0.8/automation-cre/test/ReceiverTemplate/ReceiverTemplate.t.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +// solhint-disable +// gas-custom-errors,interface-starts-with-i,chainlink-solidity/all-caps-constant-storage-variables,chainlink-solidity/prefix-storage-variables-with-s-underscore + +import {ReceiverTemplate} from "../../ReceiverTemplate.sol"; + +interface Vm { + function prank( + address msgSender + ) external; + + function expectRevert( + bytes4 revertData + ) external; + + function expectRevert( + bytes calldata revertData + ) external; +} + +contract MockReceiver is ReceiverTemplate { + uint256 public reportCount; + bytes32 public lastReportHash; + + constructor( + address forwarder + ) ReceiverTemplate(forwarder) {} + + function _processReport( + bytes calldata report + ) internal override { + reportCount++; + lastReportHash = keccak256(report); + } +} + +contract ReceiverTemplateTest { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + address private constant FORWARDER = address(uint160(1)); + address private constant AUTHOR = address(uint160(2)); + address private constant ATTACKER = address(uint160(3)); + bytes32 private constant WORKFLOW_ID = bytes32(uint256(0x1234)); + + function test_constructor_RevertWhen_ZeroForwarder() external { + vm.expectRevert(ReceiverTemplate.InvalidForwarderAddress.selector); + new MockReceiver(address(0)); + } + + function test_onReport_RevertWhen_InvalidSender() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + + vm.expectRevert(abi.encodeWithSelector(ReceiverTemplate.InvalidSender.selector, ATTACKER, FORWARDER)); + vm.prank(ATTACKER); + receiver.onReport("", "report"); + } + + /// @dev setForwarderAddress(address(0)) is permitted at the ReceiverTemplate level — + /// it emits a SecurityWarning but does not revert. Concrete contracts such as + /// AutomationReceiver close this gap inside _processReport. + function test_setForwarderAddress_ZeroSucceedsAtTemplateLevel() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setForwarderAddress(address(0)); + } + + /// @dev setExpectedWorkflowName succeeds even without an author set — the dependency is + /// enforced lazily inside onReport (WorkflowNameRequiresAuthorValidation). + function test_setExpectedWorkflowName_CanBeSetWithoutAuthor() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedWorkflowName("game-resolution"); + } + + function test_setExpectedWorkflowName_ClearWithEmptyString() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedWorkflowName("game-resolution"); + receiver.setExpectedWorkflowName(""); + if (receiver.getExpectedWorkflowName() != bytes10(0)) revert("expected empty workflow name"); + } + + /// @dev Clearing the author while a workflow name is set does not revert on the setter itself. + function test_setExpectedAuthor_ClearingAuthorWhileNameSetDoesNotRevert() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedAuthor(AUTHOR); + receiver.setExpectedWorkflowName("game-resolution"); + receiver.setExpectedAuthor(address(0)); + } + + function test_onReport_AcceptsWhenMetadataMatches() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedAuthor(AUTHOR); + receiver.setExpectedWorkflowId(WORKFLOW_ID); + receiver.setExpectedWorkflowName("game-resolution"); + + bytes memory metadata = abi.encodePacked(WORKFLOW_ID, _workflowName("game-resolution"), AUTHOR); + bytes memory report = abi.encode("verified report"); + + vm.prank(FORWARDER); + receiver.onReport(metadata, report); + + _assertEq(receiver.reportCount(), 1); + _assertEq(receiver.lastReportHash(), keccak256(report)); + } + + function test_onReport_RevertWhen_WrongWorkflowOwner() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedAuthor(AUTHOR); + + bytes memory metadata = abi.encodePacked(WORKFLOW_ID, _workflowName("game-resolution"), ATTACKER); + + vm.expectRevert(abi.encodeWithSelector(ReceiverTemplate.InvalidAuthor.selector, ATTACKER, AUTHOR)); + vm.prank(FORWARDER); + receiver.onReport(metadata, "report"); + } + + function test_onReport_RevertWhen_WrongWorkflowId() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedWorkflowId(WORKFLOW_ID); + + bytes32 wrongId = bytes32(uint256(0x9999)); + bytes memory metadata = abi.encodePacked(wrongId, _workflowName(""), AUTHOR); + + vm.expectRevert(abi.encodeWithSelector(ReceiverTemplate.InvalidWorkflowId.selector, wrongId, WORKFLOW_ID)); + vm.prank(FORWARDER); + receiver.onReport(metadata, "report"); + } + + function test_onReport_RevertWhen_WorkflowNameSetButAuthorMissing() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedWorkflowName("game-resolution"); + + bytes memory metadata = abi.encodePacked(bytes32(0), _workflowName("game-resolution"), address(0)); + + vm.expectRevert(ReceiverTemplate.WorkflowNameRequiresAuthorValidation.selector); + vm.prank(FORWARDER); + receiver.onReport(metadata, "report"); + } + + function test_onReport_RevertWhen_WrongWorkflowName() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedAuthor(AUTHOR); + receiver.setExpectedWorkflowName("game-resolution"); + + bytes10 wrongName = _workflowName("other-workflow"); + bytes memory metadata = abi.encodePacked(bytes32(0), wrongName, AUTHOR); + + vm.expectRevert( + abi.encodeWithSelector(ReceiverTemplate.InvalidWorkflowName.selector, wrongName, _workflowName("game-resolution")) + ); + vm.prank(FORWARDER); + receiver.onReport(metadata, "report"); + } + + function test_getters_ReflectState() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + receiver.setExpectedAuthor(AUTHOR); + receiver.setExpectedWorkflowId(WORKFLOW_ID); + receiver.setExpectedWorkflowName("game-resolution"); + + _assertEq(receiver.getForwarderAddress(), FORWARDER); + _assertEq(receiver.getExpectedAuthor(), AUTHOR); + _assertEq(receiver.getExpectedWorkflowId(), WORKFLOW_ID); + } + + function test_supportsInterface() external { + MockReceiver receiver = new MockReceiver(FORWARDER); + // IReceiver interfaceId + _assertTrue(receiver.supportsInterface(0x01ffc9a7)); // ERC165 + } + + function _workflowName( + string memory name + ) private pure returns (bytes10) { + bytes32 hash = sha256(bytes(name)); + bytes16 hexChars = "0123456789abcdef"; + bytes memory hexString = new bytes(64); + + for (uint256 i = 0; i < 32; i++) { + hexString[i * 2] = hexChars[uint8(hash[i] >> 4)]; + hexString[i * 2 + 1] = hexChars[uint8(hash[i] & 0x0f)]; + } + + bytes memory first10 = new bytes(10); + for (uint256 i = 0; i < 10; i++) { + first10[i] = hexString[i]; + } + + return bytes10(first10); + } + + function _assertEq(uint256 actual, uint256 expected) private pure { + if (actual != expected) revert("uint mismatch"); + } + + function _assertEq(bytes32 actual, bytes32 expected) private pure { + if (actual != expected) revert("bytes32 mismatch"); + } + + function _assertEq(address actual, address expected) private pure { + if (actual != expected) revert("address mismatch"); + } + + function _assertTrue( + bool value + ) private pure { + if (!value) revert("expected true"); + } +} diff --git a/gethwrappers/automation-cre/generated/latest/automation_receiver/automation_receiver.go b/gethwrappers/automation-cre/generated/latest/automation_receiver/automation_receiver.go new file mode 100644 index 0000000000..2d98745212 --- /dev/null +++ b/gethwrappers/automation-cre/generated/latest/automation_receiver/automation_receiver.go @@ -0,0 +1,2747 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package automation_receiver + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var AutomationReceiverMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_forwarder\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getBlockNumberCheck\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"enabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"lastReportBlock\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getConsumerGasLimit\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getExpectedAuthor\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getExpectedWorkflowId\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getExpectedWorkflowName\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes10\",\"internalType\":\"bytes10\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getForwarderAddress\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isCallAllowed\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"onReport\",\"inputs\":[{\"name\":\"metadata\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"report\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[{\"name\":\"retryable\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"retryableWhilePaused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setBlockNumberCheck\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"enabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"initialBlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setCallAllowed\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"allowed\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setConsumerGasLimit\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"gasLimit\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setExpectedAuthor\",\"inputs\":[{\"name\":\"_author\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setExpectedWorkflowId\",\"inputs\":[{\"name\":\"_id\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setExpectedWorkflowName\",\"inputs\":[{\"name\":\"_name\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setForwarderAddress\",\"inputs\":[{\"name\":\"_forwarder\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"BlockNumberCheckSet\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"indexed\":true,\"internalType\":\"bytes4\"},{\"name\":\"enabled\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"},{\"name\":\"initialBlockNumber\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CallAllowedSet\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"indexed\":true,\"internalType\":\"bytes4\"},{\"name\":\"allowed\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CallExecuted\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"indexed\":true,\"internalType\":\"bytes4\"},{\"name\":\"returnData\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"CallFailed\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"indexed\":true,\"internalType\":\"bytes4\"},{\"name\":\"reason\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ConsumerGasLimitSet\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"indexed\":true,\"internalType\":\"bytes4\"},{\"name\":\"previousLimit\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newLimit\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ExpectedAuthorUpdated\",\"inputs\":[{\"name\":\"previousAuthor\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newAuthor\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ExpectedWorkflowIdUpdated\",\"inputs\":[{\"name\":\"previousId\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newId\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ExpectedWorkflowNameUpdated\",\"inputs\":[{\"name\":\"previousName\",\"type\":\"bytes10\",\"indexed\":true,\"internalType\":\"bytes10\"},{\"name\":\"newName\",\"type\":\"bytes10\",\"indexed\":true,\"internalType\":\"bytes10\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ForwarderAddressUpdated\",\"inputs\":[{\"name\":\"previousForwarder\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newForwarder\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReportSkippedWhilePaused\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SecurityWarning\",\"inputs\":[{\"name\":\"message\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"StaleReportSkipped\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"indexed\":true,\"internalType\":\"bytes4\"},{\"name\":\"reportBlockNumber\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"lastReportBlock\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"CallNotAllowed\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientGas\",\"inputs\":[{\"name\":\"available\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"required\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidAuthor\",\"inputs\":[{\"name\":\"received\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expected\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"InvalidForwarderAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"expected\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"InvalidTargetAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidWorkflowId\",\"inputs\":[{\"name\":\"received\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"InvalidWorkflowName\",\"inputs\":[{\"name\":\"received\",\"type\":\"bytes10\",\"internalType\":\"bytes10\"},{\"name\":\"expected\",\"type\":\"bytes10\",\"internalType\":\"bytes10\"}]},{\"type\":\"error\",\"name\":\"MissingSelector\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OwnableInvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"OwnableUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"TargetHasNoCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"WorkflowIdentityNotConfigured\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"WorkflowNameRequiresAuthorValidation\",\"inputs\":[]}]", + Bin: "0x608060405234801562000010575f80fd5b50604051620024b7380380620024b7833981016040819052620000339162000136565b8033806200005a57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6200006581620000e7565b506001600160a01b0381166200008d5760405162e0775560e61b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040515f907f039ad854736757070884dd787ef1a7f58db33546639d1f3efddcf4a33fb8997e908290a350506004805460ff1916905562000165565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6020828403121562000147575f80fd5b81516001600160a01b03811681146200015e575f80fd5b9392505050565b61234480620001735f395ff3fe608060405234801561000f575f80fd5b5060043610610184575f3560e01c80638da5cb5b116100dd578063c3c44ac211610088578063d8fb859411610063578063d8fb859414610429578063f2fde38b14610453578063f5c793ef14610466575f80fd5b8063c3c44ac2146103f0578063d60c884b14610403578063d777cc6d14610416575f80fd5b8063b25de11e116100b8578063b25de11e146103bf578063bc1fc27a146103ca578063c2f7510d146103dd575f80fd5b80638da5cb5b146103405780639c1c77ca1461035d578063a619d81814610370575f80fd5b80635c975abb1161013d578063797c8d6911610118578063797c8d6914610250578063805f2132146102b9578063851ca9c1146102cc575f80fd5b80635c975abb1461022a578063715018a61461023557806375483caf1461023d575f80fd5b80633397cf671161016d5780633397cf67146101c55780633441856f146102045780633f4ba83a14610222575f80fd5b806301ffc9a71461018857806302329a29146101b0575b5f80fd5b61019b610196366004611def565b61046e565b60405190151581526020015b60405180910390f35b6101c36101be366004611e1e565b610506565b005b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b60015473ffffffffffffffffffffffffffffffffffffffff166101df565b6101c3610545565b60045460ff1661019b565b6101c3610557565b6101c361024b366004611e58565b610568565b61019b61025e366004611ea2565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526005602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000008516845290915290205460ff1692915050565b6101c36102c7366004611f13565b6106ec565b6103326102da366004611ea2565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526006602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000008516845290915290205492915050565b6040519081526020016101a7565b5f5473ffffffffffffffffffffffffffffffffffffffff166101df565b6101c361036b366004611f7a565b610aab565b60025474010000000000000000000000000000000000000000900460b01b6040517fffffffffffffffffffff0000000000000000000000000000000000000000000090911681526020016101a7565b60095460ff1661019b565b6101c36103d8366004611fbc565b610c2a565b6101c36103eb366004611ffb565b610e98565b6101c36103fe366004612036565b610f85565b6101c361041136600461204d565b610fc5565b6101c361042436600461204d565b611043565b61043c610437366004611ea2565b611170565b6040805192151583526020830191909152016101a7565b6101c361046136600461204d565b6111e5565b600354610332565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f805f213200000000000000000000000000000000000000000000000000000000148061050057507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b61050e611245565b600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821515179055610542611297565b50565b61054d611245565b61055561131c565b565b61055f611245565b6105555f611373565b610570611245565b73ffffffffffffffffffffffffffffffffffffffff84166105bd576040517ff1a492cc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84165f9081526007602090815260408083207fffffffff0000000000000000000000000000000000000000000000000000000087168452909152812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001684151517905582610643575f610651565b811561064f5781610651565b435b73ffffffffffffffffffffffffffffffffffffffff86165f8181526008602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000008a16808552908352928190208590558051881515815291820185905293945090927ff19a6052943cc4c32e1644d475a7b4e6f517bcae63159220028f5de68d6d0364910160405180910390a35050505050565b60015473ffffffffffffffffffffffffffffffffffffffff161580159061072b575060015473ffffffffffffffffffffffffffffffffffffffff163314155b15610789576001546040517fe1130dba00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff90911660248201526044015b60405180910390fd5b6003541515806107b0575060025473ffffffffffffffffffffffffffffffffffffffff1615155b806107f9575060025474010000000000000000000000000000000000000000900460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001615155b15610a9b575f805f61083f87878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506113e792505050565b60035492955090935091501580159061085a57506003548314155b1561089f576003546040517f9bfa39ba000000000000000000000000000000000000000000000000000000008152610780918591600401918252602082015260400190565b60025473ffffffffffffffffffffffffffffffffffffffff16158015906108e1575060025473ffffffffffffffffffffffffffffffffffffffff828116911614155b1561093c576002546040517fb8a98af800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80841660048301529091166024820152604401610780565b60025474010000000000000000000000000000000000000000900460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001615610a975760025473ffffffffffffffffffffffffffffffffffffffff166109d0576040517f4847901100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002547fffffffffffffffffffff000000000000000000000000000000000000000000008381167401000000000000000000000000000000000000000090920460b01b1614610a97576002546040517f6c4609a60000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff0000000000000000000000000000000000000000000084811660048301527401000000000000000000000000000000000000000090920460b01b9091166024820152604401610780565b5050505b610aa58282611400565b50505050565b610ab3611245565b73ffffffffffffffffffffffffffffffffffffffff8316610b00576040517ff1a492cc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808015610b22575073ffffffffffffffffffffffffffffffffffffffff83163b155b15610b71576040517ffff2336100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610780565b73ffffffffffffffffffffffffffffffffffffffff83165f8181526005602090815260408083207fffffffff0000000000000000000000000000000000000000000000000000000087168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f0925d576b7c865d78d7fe746ae46d080d64b9e6b04db5f034f71a79c41dda2e7910160405180910390a3505050565b610c32611245565b60025474010000000000000000000000000000000000000000900460b01b5f829003610cd357600280547fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff1690556040515f907fffffffffffffffffffff000000000000000000000000000000000000000000008316907f1e7ddd09d504c82dcfc784a464b167469f5aad967606ec4822d848ef9141dfa5908390a3505050565b5f60028484604051610ce6929190612068565b602060405180830381855afa158015610d01573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190610d249190612077565b90505f610d5182604051602001610d3d91815260200190565b604051602081830303815290604052611af3565b60408051600a8082528183019092529192505f91906020820181803683370190505090505f5b600a811015610de557828181518110610d9257610d926120bb565b602001015160f81c60f81b828281518110610daf57610daf6120bb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600101610d77565b50610def816120e8565b600280547fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060b093841c81029190911791829055604051910490911b7fffffffffffffffffffff0000000000000000000000000000000000000000000090811691908616907f1e7ddd09d504c82dcfc784a464b167469f5aad967606ec4822d848ef9141dfa5905f90a3505050505050565b610ea0611245565b73ffffffffffffffffffffffffffffffffffffffff8316610eed576040517ff1a492cc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f8181526006602090815260408083207fffffffff00000000000000000000000000000000000000000000000000000000871680855290835292819020805490869055815181815292830186905293917ff3f16b36d6fb2a97e5e66d28e758a4d457e80197e1d455f692a96be32091fa3a910160405180910390a350505050565b610f8d611245565b6003805490829055604051829082907f0dbedcdf21925e053b4c574eae180d7f2883235ab4976ecc0873598a2a999b03905f90a35050565b610fcd611245565b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f3321cda85c145617e47418aa14255e9dcbec53a753778e57591703b89a3cad31905f90a35050565b61104b611245565b60015473ffffffffffffffffffffffffffffffffffffffff9081169082166110fb577f704da7db165c79c1e33d542c079333bbde970a733032d2f95fec8fb7d770cbf76040516110f29060208082526038908201527f466f7277617264657220616464726573732073657420746f207a65726f202d2060408201527f636f6e7472616374206973206e6f7720494e5345435552450000000000000000606082015260800190565b60405180910390a15b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560405190918316907f039ad854736757070884dd787ef1a7f58db33546639d1f3efddcf4a33fb8997e905f90a35050565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526007602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000008616808552908352818420549484526008835281842090845290915290205460ff909116905b9250929050565b6111ed611245565b73ffffffffffffffffffffffffffffffffffffffff811661123c576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f6004820152602401610780565b61054281611373565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610555576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610780565b61129f611d42565b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586112f23390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b611324611d7f565b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa336112f2565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60208101516040820151604a83015160601c9193909250565b60045460ff16156114745760095460ff1615611448576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff37c389ae9f5e13dbbef9f62b1ad0893e89c865ee834b2e221d11ebcf3cacd51905f90a15050565b60015473ffffffffffffffffffffffffffffffffffffffff166114c3576040517f381dd54000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600354158015611530575060025473ffffffffffffffffffffffffffffffffffffffff161580611530575060025474010000000000000000000000000000000000000000900460b01b7fffffffffffffffffffff0000000000000000000000000000000000000000000016155b15611567576040517f8ec26f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f808061157684860186612137565b9194509250905073ffffffffffffffffffffffffffffffffffffffff83166115ca576040517ff1a492cc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481511015611606576040517f47d7741900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208181015173ffffffffffffffffffffffffffffffffffffffff85165f9081526005835260408082207fffffffff0000000000000000000000000000000000000000000000000000000084168352909352919091205460ff166116d6576040517f805043f900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201527fffffffff0000000000000000000000000000000000000000000000000000000082166024820152604401610780565b73ffffffffffffffffffffffffffffffffffffffff84165f9081526007602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000008516845290915290205460ff161561185e5773ffffffffffffffffffffffffffffffffffffffff84165f9081526008602090815260408083207fffffffff0000000000000000000000000000000000000000000000000000000085168452909152902054808410156118085760408051858152602081018390527fffffffff0000000000000000000000000000000000000000000000000000000084169173ffffffffffffffffffffffffffffffffffffffff8816917f96e22437f0b9d1dfe909221668f6ad9813c1128b60a7b4b3dee74e4248df834a910160405180910390a350505050505050565b5073ffffffffffffffffffffffffffffffffffffffff84165f9081526008602090815260408083207fffffffff000000000000000000000000000000000000000000000000000000008516845290915290208390555b73ffffffffffffffffffffffffffffffffffffffff84165f9081526006602090815260408083207fffffffff00000000000000000000000000000000000000000000000000000000851684529091528120549060608215611996575f611b586118c8603f86612248565b6118d29086612280565b6118dc9190612280565b9050805a1015611924575a6040517f23e228cb000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052604401610780565b8773ffffffffffffffffffffffffffffffffffffffff16848760405161194a91906122b5565b5f604051808303815f8787f1925050503d805f8114611984576040519150601f19603f3d011682016040523d82523d5f602084013e611989565b606091505b509093509150611a009050565b8673ffffffffffffffffffffffffffffffffffffffff16856040516119bb91906122b5565b5f604051808303815f865af19150503d805f81146119f4576040519150601f19603f3d011682016040523d82523d5f602084013e6119f9565b606091505b5090925090505b8115611a7957837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff167fbe82131bb3404498c769b0511da41a4ad409fa7152562c2b6669241cbe3bb88483604051611a6c91906122d0565b60405180910390a3611ae8565b837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168773ffffffffffffffffffffffffffffffffffffffff167fefa88af289a36b936ccacf9bd9eaaa185775cd54ae263973d3579c01111593b683604051611adf91906122d0565b60405180910390a35b505050505050505050565b60605f82516002611b049190612320565b67ffffffffffffffff811115611b1c57611b1c61208e565b6040519080825280601f01601f191660200182016040528015611b46576020820181803683370190505b5090505f5b8351811015611d3b576040518060400160405280601081526020017f30313233343536373839616263646566000000000000000000000000000000008152506004858381518110611b9e57611b9e6120bb565b016020015182517fff0000000000000000000000000000000000000000000000000000000000000090911690911c60f81c908110611bde57611bde6120bb565b01602001517fff000000000000000000000000000000000000000000000000000000000000001682611c11836002612320565b81518110611c2157611c216120bb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506040518060400160405280601081526020017f3031323334353637383961626364656600000000000000000000000000000000815250848281518110611c9757611c976120bb565b602091010151815160f89190911c600f16908110611cb757611cb76120bb565b01602001517fff000000000000000000000000000000000000000000000000000000000000001682611cea836002612320565b611cf5906001612280565b81518110611d0557611d056120bb565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600101611b4b565b5092915050565b60045460ff1615610555576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045460ff16610555576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114611dea575f80fd5b919050565b5f60208284031215611dff575f80fd5b611e0882611dbb565b9392505050565b80358015158114611dea575f80fd5b5f60208284031215611e2e575f80fd5b611e0882611e0f565b73ffffffffffffffffffffffffffffffffffffffff81168114610542575f80fd5b5f805f8060808587031215611e6b575f80fd5b8435611e7681611e37565b9350611e8460208601611dbb565b9250611e9260408601611e0f565b9396929550929360600135925050565b5f8060408385031215611eb3575f80fd5b8235611ebe81611e37565b9150611ecc60208401611dbb565b90509250929050565b5f8083601f840112611ee5575f80fd5b50813567ffffffffffffffff811115611efc575f80fd5b6020830191508360208285010111156111de575f80fd5b5f805f8060408587031215611f26575f80fd5b843567ffffffffffffffff80821115611f3d575f80fd5b611f4988838901611ed5565b90965094506020870135915080821115611f61575f80fd5b50611f6e87828801611ed5565b95989497509550505050565b5f805f60608486031215611f8c575f80fd5b8335611f9781611e37565b9250611fa560208501611dbb565b9150611fb360408501611e0f565b90509250925092565b5f8060208385031215611fcd575f80fd5b823567ffffffffffffffff811115611fe3575f80fd5b611fef85828601611ed5565b90969095509350505050565b5f805f6060848603121561200d575f80fd5b833561201881611e37565b925061202660208501611dbb565b9150604084013590509250925092565b5f60208284031215612046575f80fd5b5035919050565b5f6020828403121561205d575f80fd5b8135611e0881611e37565b818382375f9101908152919050565b5f60208284031215612087575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f815160208301517fffffffffffffffffffff000000000000000000000000000000000000000000008082169350600a83101561212f57808184600a0360031b1b83161693505b505050919050565b5f805f60608486031215612149575f80fd5b833561215481611e37565b925060208401359150604084013567ffffffffffffffff80821115612177575f80fd5b818601915086601f83011261218a575f80fd5b81358181111561219c5761219c61208e565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156121e2576121e261208e565b816040528281528960208487010111156121fa575f80fd5b826020860160208301375f6020848301015280955050505050509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f8261227b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b808201808211156105005761050061221b565b5f5b838110156122ad578181015183820152602001612295565b50505f910152565b5f82516122c6818460208701612293565b9190910192915050565b602081525f82518060208401526122ee816040850160208701612293565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b80820281158282048414176105005761050061221b56fea164736f6c6343000818000a", +} + +var AutomationReceiverABI = AutomationReceiverMetaData.ABI + +var AutomationReceiverBin = AutomationReceiverMetaData.Bin + +func DeployAutomationReceiver(auth *bind.TransactOpts, backend bind.ContractBackend, _forwarder common.Address) (common.Address, *types.Transaction, *AutomationReceiver, error) { + parsed, err := AutomationReceiverMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AutomationReceiverBin), backend, _forwarder) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationReceiver{address: address, abi: *parsed, AutomationReceiverCaller: AutomationReceiverCaller{contract: contract}, AutomationReceiverTransactor: AutomationReceiverTransactor{contract: contract}, AutomationReceiverFilterer: AutomationReceiverFilterer{contract: contract}}, nil +} + +type AutomationReceiver struct { + address common.Address + abi abi.ABI + AutomationReceiverCaller + AutomationReceiverTransactor + AutomationReceiverFilterer +} + +type AutomationReceiverCaller struct { + contract *bind.BoundContract +} + +type AutomationReceiverTransactor struct { + contract *bind.BoundContract +} + +type AutomationReceiverFilterer struct { + contract *bind.BoundContract +} + +type AutomationReceiverSession struct { + Contract *AutomationReceiver + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationReceiverCallerSession struct { + Contract *AutomationReceiverCaller + CallOpts bind.CallOpts +} + +type AutomationReceiverTransactorSession struct { + Contract *AutomationReceiverTransactor + TransactOpts bind.TransactOpts +} + +type AutomationReceiverRaw struct { + Contract *AutomationReceiver +} + +type AutomationReceiverCallerRaw struct { + Contract *AutomationReceiverCaller +} + +type AutomationReceiverTransactorRaw struct { + Contract *AutomationReceiverTransactor +} + +func NewAutomationReceiver(address common.Address, backend bind.ContractBackend) (*AutomationReceiver, error) { + abi, err := abi.JSON(strings.NewReader(AutomationReceiverABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationReceiver(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationReceiver{address: address, abi: abi, AutomationReceiverCaller: AutomationReceiverCaller{contract: contract}, AutomationReceiverTransactor: AutomationReceiverTransactor{contract: contract}, AutomationReceiverFilterer: AutomationReceiverFilterer{contract: contract}}, nil +} + +func NewAutomationReceiverCaller(address common.Address, caller bind.ContractCaller) (*AutomationReceiverCaller, error) { + contract, err := bindAutomationReceiver(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationReceiverCaller{contract: contract}, nil +} + +func NewAutomationReceiverTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationReceiverTransactor, error) { + contract, err := bindAutomationReceiver(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationReceiverTransactor{contract: contract}, nil +} + +func NewAutomationReceiverFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationReceiverFilterer, error) { + contract, err := bindAutomationReceiver(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationReceiverFilterer{contract: contract}, nil +} + +func bindAutomationReceiver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationReceiverMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationReceiver *AutomationReceiverRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationReceiver.Contract.AutomationReceiverCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationReceiver *AutomationReceiverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationReceiver.Contract.AutomationReceiverTransactor.contract.Transfer(opts) +} + +func (_AutomationReceiver *AutomationReceiverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationReceiver.Contract.AutomationReceiverTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationReceiver *AutomationReceiverCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationReceiver.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationReceiver *AutomationReceiverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationReceiver.Contract.contract.Transfer(opts) +} + +func (_AutomationReceiver *AutomationReceiverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationReceiver.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationReceiver *AutomationReceiverCaller) GetBlockNumberCheck(opts *bind.CallOpts, target common.Address, selector [4]byte) (GetBlockNumberCheck, + + error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "getBlockNumberCheck", target, selector) + + outstruct := new(GetBlockNumberCheck) + if err != nil { + return *outstruct, err + } + + outstruct.Enabled = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.LastReportBlock = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) GetBlockNumberCheck(target common.Address, selector [4]byte) (GetBlockNumberCheck, + + error) { + return _AutomationReceiver.Contract.GetBlockNumberCheck(&_AutomationReceiver.CallOpts, target, selector) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) GetBlockNumberCheck(target common.Address, selector [4]byte) (GetBlockNumberCheck, + + error) { + return _AutomationReceiver.Contract.GetBlockNumberCheck(&_AutomationReceiver.CallOpts, target, selector) +} + +func (_AutomationReceiver *AutomationReceiverCaller) GetConsumerGasLimit(opts *bind.CallOpts, target common.Address, selector [4]byte) (*big.Int, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "getConsumerGasLimit", target, selector) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) GetConsumerGasLimit(target common.Address, selector [4]byte) (*big.Int, error) { + return _AutomationReceiver.Contract.GetConsumerGasLimit(&_AutomationReceiver.CallOpts, target, selector) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) GetConsumerGasLimit(target common.Address, selector [4]byte) (*big.Int, error) { + return _AutomationReceiver.Contract.GetConsumerGasLimit(&_AutomationReceiver.CallOpts, target, selector) +} + +func (_AutomationReceiver *AutomationReceiverCaller) GetExpectedAuthor(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "getExpectedAuthor") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) GetExpectedAuthor() (common.Address, error) { + return _AutomationReceiver.Contract.GetExpectedAuthor(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) GetExpectedAuthor() (common.Address, error) { + return _AutomationReceiver.Contract.GetExpectedAuthor(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) GetExpectedWorkflowId(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "getExpectedWorkflowId") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) GetExpectedWorkflowId() ([32]byte, error) { + return _AutomationReceiver.Contract.GetExpectedWorkflowId(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) GetExpectedWorkflowId() ([32]byte, error) { + return _AutomationReceiver.Contract.GetExpectedWorkflowId(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) GetExpectedWorkflowName(opts *bind.CallOpts) ([10]byte, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "getExpectedWorkflowName") + + if err != nil { + return *new([10]byte), err + } + + out0 := *abi.ConvertType(out[0], new([10]byte)).(*[10]byte) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) GetExpectedWorkflowName() ([10]byte, error) { + return _AutomationReceiver.Contract.GetExpectedWorkflowName(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) GetExpectedWorkflowName() ([10]byte, error) { + return _AutomationReceiver.Contract.GetExpectedWorkflowName(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) GetForwarderAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "getForwarderAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) GetForwarderAddress() (common.Address, error) { + return _AutomationReceiver.Contract.GetForwarderAddress(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) GetForwarderAddress() (common.Address, error) { + return _AutomationReceiver.Contract.GetForwarderAddress(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) IsCallAllowed(opts *bind.CallOpts, target common.Address, selector [4]byte) (bool, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "isCallAllowed", target, selector) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) IsCallAllowed(target common.Address, selector [4]byte) (bool, error) { + return _AutomationReceiver.Contract.IsCallAllowed(&_AutomationReceiver.CallOpts, target, selector) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) IsCallAllowed(target common.Address, selector [4]byte) (bool, error) { + return _AutomationReceiver.Contract.IsCallAllowed(&_AutomationReceiver.CallOpts, target, selector) +} + +func (_AutomationReceiver *AutomationReceiverCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "owner") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) Owner() (common.Address, error) { + return _AutomationReceiver.Contract.Owner(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) Owner() (common.Address, error) { + return _AutomationReceiver.Contract.Owner(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) Paused(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "paused") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) Paused() (bool, error) { + return _AutomationReceiver.Contract.Paused(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) Paused() (bool, error) { + return _AutomationReceiver.Contract.Paused(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) RetryableWhilePaused(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "retryableWhilePaused") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) RetryableWhilePaused() (bool, error) { + return _AutomationReceiver.Contract.RetryableWhilePaused(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) RetryableWhilePaused() (bool, error) { + return _AutomationReceiver.Contract.RetryableWhilePaused(&_AutomationReceiver.CallOpts) +} + +func (_AutomationReceiver *AutomationReceiverCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _AutomationReceiver.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationReceiver *AutomationReceiverSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AutomationReceiver.Contract.SupportsInterface(&_AutomationReceiver.CallOpts, interfaceId) +} + +func (_AutomationReceiver *AutomationReceiverCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AutomationReceiver.Contract.SupportsInterface(&_AutomationReceiver.CallOpts, interfaceId) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) OnReport(opts *bind.TransactOpts, metadata []byte, report []byte) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "onReport", metadata, report) +} + +func (_AutomationReceiver *AutomationReceiverSession) OnReport(metadata []byte, report []byte) (*types.Transaction, error) { + return _AutomationReceiver.Contract.OnReport(&_AutomationReceiver.TransactOpts, metadata, report) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) OnReport(metadata []byte, report []byte) (*types.Transaction, error) { + return _AutomationReceiver.Contract.OnReport(&_AutomationReceiver.TransactOpts, metadata, report) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) Pause(opts *bind.TransactOpts, retryable bool) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "pause", retryable) +} + +func (_AutomationReceiver *AutomationReceiverSession) Pause(retryable bool) (*types.Transaction, error) { + return _AutomationReceiver.Contract.Pause(&_AutomationReceiver.TransactOpts, retryable) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) Pause(retryable bool) (*types.Transaction, error) { + return _AutomationReceiver.Contract.Pause(&_AutomationReceiver.TransactOpts, retryable) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "renounceOwnership") +} + +func (_AutomationReceiver *AutomationReceiverSession) RenounceOwnership() (*types.Transaction, error) { + return _AutomationReceiver.Contract.RenounceOwnership(&_AutomationReceiver.TransactOpts) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) RenounceOwnership() (*types.Transaction, error) { + return _AutomationReceiver.Contract.RenounceOwnership(&_AutomationReceiver.TransactOpts) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetBlockNumberCheck(opts *bind.TransactOpts, target common.Address, selector [4]byte, enabled bool, initialBlockNumber *big.Int) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setBlockNumberCheck", target, selector, enabled, initialBlockNumber) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetBlockNumberCheck(target common.Address, selector [4]byte, enabled bool, initialBlockNumber *big.Int) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetBlockNumberCheck(&_AutomationReceiver.TransactOpts, target, selector, enabled, initialBlockNumber) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetBlockNumberCheck(target common.Address, selector [4]byte, enabled bool, initialBlockNumber *big.Int) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetBlockNumberCheck(&_AutomationReceiver.TransactOpts, target, selector, enabled, initialBlockNumber) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetCallAllowed(opts *bind.TransactOpts, target common.Address, selector [4]byte, allowed bool) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setCallAllowed", target, selector, allowed) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetCallAllowed(target common.Address, selector [4]byte, allowed bool) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetCallAllowed(&_AutomationReceiver.TransactOpts, target, selector, allowed) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetCallAllowed(target common.Address, selector [4]byte, allowed bool) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetCallAllowed(&_AutomationReceiver.TransactOpts, target, selector, allowed) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetConsumerGasLimit(opts *bind.TransactOpts, target common.Address, selector [4]byte, gasLimit *big.Int) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setConsumerGasLimit", target, selector, gasLimit) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetConsumerGasLimit(target common.Address, selector [4]byte, gasLimit *big.Int) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetConsumerGasLimit(&_AutomationReceiver.TransactOpts, target, selector, gasLimit) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetConsumerGasLimit(target common.Address, selector [4]byte, gasLimit *big.Int) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetConsumerGasLimit(&_AutomationReceiver.TransactOpts, target, selector, gasLimit) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetExpectedAuthor(opts *bind.TransactOpts, _author common.Address) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setExpectedAuthor", _author) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetExpectedAuthor(_author common.Address) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetExpectedAuthor(&_AutomationReceiver.TransactOpts, _author) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetExpectedAuthor(_author common.Address) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetExpectedAuthor(&_AutomationReceiver.TransactOpts, _author) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetExpectedWorkflowId(opts *bind.TransactOpts, _id [32]byte) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setExpectedWorkflowId", _id) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetExpectedWorkflowId(_id [32]byte) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetExpectedWorkflowId(&_AutomationReceiver.TransactOpts, _id) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetExpectedWorkflowId(_id [32]byte) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetExpectedWorkflowId(&_AutomationReceiver.TransactOpts, _id) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetExpectedWorkflowName(opts *bind.TransactOpts, _name string) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setExpectedWorkflowName", _name) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetExpectedWorkflowName(_name string) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetExpectedWorkflowName(&_AutomationReceiver.TransactOpts, _name) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetExpectedWorkflowName(_name string) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetExpectedWorkflowName(&_AutomationReceiver.TransactOpts, _name) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) SetForwarderAddress(opts *bind.TransactOpts, _forwarder common.Address) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "setForwarderAddress", _forwarder) +} + +func (_AutomationReceiver *AutomationReceiverSession) SetForwarderAddress(_forwarder common.Address) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetForwarderAddress(&_AutomationReceiver.TransactOpts, _forwarder) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) SetForwarderAddress(_forwarder common.Address) (*types.Transaction, error) { + return _AutomationReceiver.Contract.SetForwarderAddress(&_AutomationReceiver.TransactOpts, _forwarder) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "transferOwnership", newOwner) +} + +func (_AutomationReceiver *AutomationReceiverSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _AutomationReceiver.Contract.TransferOwnership(&_AutomationReceiver.TransactOpts, newOwner) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { + return _AutomationReceiver.Contract.TransferOwnership(&_AutomationReceiver.TransactOpts, newOwner) +} + +func (_AutomationReceiver *AutomationReceiverTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationReceiver.contract.Transact(opts, "unpause") +} + +func (_AutomationReceiver *AutomationReceiverSession) Unpause() (*types.Transaction, error) { + return _AutomationReceiver.Contract.Unpause(&_AutomationReceiver.TransactOpts) +} + +func (_AutomationReceiver *AutomationReceiverTransactorSession) Unpause() (*types.Transaction, error) { + return _AutomationReceiver.Contract.Unpause(&_AutomationReceiver.TransactOpts) +} + +type AutomationReceiverBlockNumberCheckSetIterator struct { + Event *AutomationReceiverBlockNumberCheckSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverBlockNumberCheckSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverBlockNumberCheckSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverBlockNumberCheckSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverBlockNumberCheckSetIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverBlockNumberCheckSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverBlockNumberCheckSet struct { + Target common.Address + Selector [4]byte + Enabled bool + InitialBlockNumber *big.Int + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterBlockNumberCheckSet(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverBlockNumberCheckSetIterator, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "BlockNumberCheckSet", targetRule, selectorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverBlockNumberCheckSetIterator{contract: _AutomationReceiver.contract, event: "BlockNumberCheckSet", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchBlockNumberCheckSet(opts *bind.WatchOpts, sink chan<- *AutomationReceiverBlockNumberCheckSet, target []common.Address, selector [][4]byte) (event.Subscription, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "BlockNumberCheckSet", targetRule, selectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverBlockNumberCheckSet) + if err := _AutomationReceiver.contract.UnpackLog(event, "BlockNumberCheckSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseBlockNumberCheckSet(log types.Log) (*AutomationReceiverBlockNumberCheckSet, error) { + event := new(AutomationReceiverBlockNumberCheckSet) + if err := _AutomationReceiver.contract.UnpackLog(event, "BlockNumberCheckSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverCallAllowedSetIterator struct { + Event *AutomationReceiverCallAllowedSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverCallAllowedSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverCallAllowedSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverCallAllowedSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverCallAllowedSetIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverCallAllowedSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverCallAllowedSet struct { + Target common.Address + Selector [4]byte + Allowed bool + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterCallAllowedSet(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverCallAllowedSetIterator, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "CallAllowedSet", targetRule, selectorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverCallAllowedSetIterator{contract: _AutomationReceiver.contract, event: "CallAllowedSet", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchCallAllowedSet(opts *bind.WatchOpts, sink chan<- *AutomationReceiverCallAllowedSet, target []common.Address, selector [][4]byte) (event.Subscription, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "CallAllowedSet", targetRule, selectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverCallAllowedSet) + if err := _AutomationReceiver.contract.UnpackLog(event, "CallAllowedSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseCallAllowedSet(log types.Log) (*AutomationReceiverCallAllowedSet, error) { + event := new(AutomationReceiverCallAllowedSet) + if err := _AutomationReceiver.contract.UnpackLog(event, "CallAllowedSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverCallExecutedIterator struct { + Event *AutomationReceiverCallExecuted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverCallExecutedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverCallExecuted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverCallExecuted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverCallExecutedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverCallExecutedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverCallExecuted struct { + Target common.Address + Selector [4]byte + ReturnData []byte + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterCallExecuted(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverCallExecutedIterator, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "CallExecuted", targetRule, selectorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverCallExecutedIterator{contract: _AutomationReceiver.contract, event: "CallExecuted", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchCallExecuted(opts *bind.WatchOpts, sink chan<- *AutomationReceiverCallExecuted, target []common.Address, selector [][4]byte) (event.Subscription, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "CallExecuted", targetRule, selectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverCallExecuted) + if err := _AutomationReceiver.contract.UnpackLog(event, "CallExecuted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseCallExecuted(log types.Log) (*AutomationReceiverCallExecuted, error) { + event := new(AutomationReceiverCallExecuted) + if err := _AutomationReceiver.contract.UnpackLog(event, "CallExecuted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverCallFailedIterator struct { + Event *AutomationReceiverCallFailed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverCallFailedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverCallFailed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverCallFailed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverCallFailedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverCallFailedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverCallFailed struct { + Target common.Address + Selector [4]byte + Reason []byte + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterCallFailed(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverCallFailedIterator, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "CallFailed", targetRule, selectorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverCallFailedIterator{contract: _AutomationReceiver.contract, event: "CallFailed", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchCallFailed(opts *bind.WatchOpts, sink chan<- *AutomationReceiverCallFailed, target []common.Address, selector [][4]byte) (event.Subscription, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "CallFailed", targetRule, selectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverCallFailed) + if err := _AutomationReceiver.contract.UnpackLog(event, "CallFailed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseCallFailed(log types.Log) (*AutomationReceiverCallFailed, error) { + event := new(AutomationReceiverCallFailed) + if err := _AutomationReceiver.contract.UnpackLog(event, "CallFailed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverConsumerGasLimitSetIterator struct { + Event *AutomationReceiverConsumerGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverConsumerGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverConsumerGasLimitSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverConsumerGasLimitSet) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverConsumerGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverConsumerGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverConsumerGasLimitSet struct { + Target common.Address + Selector [4]byte + PreviousLimit *big.Int + NewLimit *big.Int + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterConsumerGasLimitSet(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverConsumerGasLimitSetIterator, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "ConsumerGasLimitSet", targetRule, selectorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverConsumerGasLimitSetIterator{contract: _AutomationReceiver.contract, event: "ConsumerGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchConsumerGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationReceiverConsumerGasLimitSet, target []common.Address, selector [][4]byte) (event.Subscription, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "ConsumerGasLimitSet", targetRule, selectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverConsumerGasLimitSet) + if err := _AutomationReceiver.contract.UnpackLog(event, "ConsumerGasLimitSet", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseConsumerGasLimitSet(log types.Log) (*AutomationReceiverConsumerGasLimitSet, error) { + event := new(AutomationReceiverConsumerGasLimitSet) + if err := _AutomationReceiver.contract.UnpackLog(event, "ConsumerGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverExpectedAuthorUpdatedIterator struct { + Event *AutomationReceiverExpectedAuthorUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverExpectedAuthorUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverExpectedAuthorUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverExpectedAuthorUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverExpectedAuthorUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverExpectedAuthorUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverExpectedAuthorUpdated struct { + PreviousAuthor common.Address + NewAuthor common.Address + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterExpectedAuthorUpdated(opts *bind.FilterOpts, previousAuthor []common.Address, newAuthor []common.Address) (*AutomationReceiverExpectedAuthorUpdatedIterator, error) { + + var previousAuthorRule []interface{} + for _, previousAuthorItem := range previousAuthor { + previousAuthorRule = append(previousAuthorRule, previousAuthorItem) + } + var newAuthorRule []interface{} + for _, newAuthorItem := range newAuthor { + newAuthorRule = append(newAuthorRule, newAuthorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "ExpectedAuthorUpdated", previousAuthorRule, newAuthorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverExpectedAuthorUpdatedIterator{contract: _AutomationReceiver.contract, event: "ExpectedAuthorUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchExpectedAuthorUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverExpectedAuthorUpdated, previousAuthor []common.Address, newAuthor []common.Address) (event.Subscription, error) { + + var previousAuthorRule []interface{} + for _, previousAuthorItem := range previousAuthor { + previousAuthorRule = append(previousAuthorRule, previousAuthorItem) + } + var newAuthorRule []interface{} + for _, newAuthorItem := range newAuthor { + newAuthorRule = append(newAuthorRule, newAuthorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "ExpectedAuthorUpdated", previousAuthorRule, newAuthorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverExpectedAuthorUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ExpectedAuthorUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseExpectedAuthorUpdated(log types.Log) (*AutomationReceiverExpectedAuthorUpdated, error) { + event := new(AutomationReceiverExpectedAuthorUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ExpectedAuthorUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverExpectedWorkflowIdUpdatedIterator struct { + Event *AutomationReceiverExpectedWorkflowIdUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverExpectedWorkflowIdUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverExpectedWorkflowIdUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverExpectedWorkflowIdUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverExpectedWorkflowIdUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverExpectedWorkflowIdUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverExpectedWorkflowIdUpdated struct { + PreviousId [32]byte + NewId [32]byte + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterExpectedWorkflowIdUpdated(opts *bind.FilterOpts, previousId [][32]byte, newId [][32]byte) (*AutomationReceiverExpectedWorkflowIdUpdatedIterator, error) { + + var previousIdRule []interface{} + for _, previousIdItem := range previousId { + previousIdRule = append(previousIdRule, previousIdItem) + } + var newIdRule []interface{} + for _, newIdItem := range newId { + newIdRule = append(newIdRule, newIdItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "ExpectedWorkflowIdUpdated", previousIdRule, newIdRule) + if err != nil { + return nil, err + } + return &AutomationReceiverExpectedWorkflowIdUpdatedIterator{contract: _AutomationReceiver.contract, event: "ExpectedWorkflowIdUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchExpectedWorkflowIdUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverExpectedWorkflowIdUpdated, previousId [][32]byte, newId [][32]byte) (event.Subscription, error) { + + var previousIdRule []interface{} + for _, previousIdItem := range previousId { + previousIdRule = append(previousIdRule, previousIdItem) + } + var newIdRule []interface{} + for _, newIdItem := range newId { + newIdRule = append(newIdRule, newIdItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "ExpectedWorkflowIdUpdated", previousIdRule, newIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverExpectedWorkflowIdUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ExpectedWorkflowIdUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseExpectedWorkflowIdUpdated(log types.Log) (*AutomationReceiverExpectedWorkflowIdUpdated, error) { + event := new(AutomationReceiverExpectedWorkflowIdUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ExpectedWorkflowIdUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverExpectedWorkflowNameUpdatedIterator struct { + Event *AutomationReceiverExpectedWorkflowNameUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverExpectedWorkflowNameUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverExpectedWorkflowNameUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverExpectedWorkflowNameUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverExpectedWorkflowNameUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverExpectedWorkflowNameUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverExpectedWorkflowNameUpdated struct { + PreviousName [10]byte + NewName [10]byte + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterExpectedWorkflowNameUpdated(opts *bind.FilterOpts, previousName [][10]byte, newName [][10]byte) (*AutomationReceiverExpectedWorkflowNameUpdatedIterator, error) { + + var previousNameRule []interface{} + for _, previousNameItem := range previousName { + previousNameRule = append(previousNameRule, previousNameItem) + } + var newNameRule []interface{} + for _, newNameItem := range newName { + newNameRule = append(newNameRule, newNameItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "ExpectedWorkflowNameUpdated", previousNameRule, newNameRule) + if err != nil { + return nil, err + } + return &AutomationReceiverExpectedWorkflowNameUpdatedIterator{contract: _AutomationReceiver.contract, event: "ExpectedWorkflowNameUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchExpectedWorkflowNameUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverExpectedWorkflowNameUpdated, previousName [][10]byte, newName [][10]byte) (event.Subscription, error) { + + var previousNameRule []interface{} + for _, previousNameItem := range previousName { + previousNameRule = append(previousNameRule, previousNameItem) + } + var newNameRule []interface{} + for _, newNameItem := range newName { + newNameRule = append(newNameRule, newNameItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "ExpectedWorkflowNameUpdated", previousNameRule, newNameRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverExpectedWorkflowNameUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ExpectedWorkflowNameUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseExpectedWorkflowNameUpdated(log types.Log) (*AutomationReceiverExpectedWorkflowNameUpdated, error) { + event := new(AutomationReceiverExpectedWorkflowNameUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ExpectedWorkflowNameUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverForwarderAddressUpdatedIterator struct { + Event *AutomationReceiverForwarderAddressUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverForwarderAddressUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverForwarderAddressUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverForwarderAddressUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverForwarderAddressUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverForwarderAddressUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverForwarderAddressUpdated struct { + PreviousForwarder common.Address + NewForwarder common.Address + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterForwarderAddressUpdated(opts *bind.FilterOpts, previousForwarder []common.Address, newForwarder []common.Address) (*AutomationReceiverForwarderAddressUpdatedIterator, error) { + + var previousForwarderRule []interface{} + for _, previousForwarderItem := range previousForwarder { + previousForwarderRule = append(previousForwarderRule, previousForwarderItem) + } + var newForwarderRule []interface{} + for _, newForwarderItem := range newForwarder { + newForwarderRule = append(newForwarderRule, newForwarderItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "ForwarderAddressUpdated", previousForwarderRule, newForwarderRule) + if err != nil { + return nil, err + } + return &AutomationReceiverForwarderAddressUpdatedIterator{contract: _AutomationReceiver.contract, event: "ForwarderAddressUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchForwarderAddressUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverForwarderAddressUpdated, previousForwarder []common.Address, newForwarder []common.Address) (event.Subscription, error) { + + var previousForwarderRule []interface{} + for _, previousForwarderItem := range previousForwarder { + previousForwarderRule = append(previousForwarderRule, previousForwarderItem) + } + var newForwarderRule []interface{} + for _, newForwarderItem := range newForwarder { + newForwarderRule = append(newForwarderRule, newForwarderItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "ForwarderAddressUpdated", previousForwarderRule, newForwarderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverForwarderAddressUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ForwarderAddressUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseForwarderAddressUpdated(log types.Log) (*AutomationReceiverForwarderAddressUpdated, error) { + event := new(AutomationReceiverForwarderAddressUpdated) + if err := _AutomationReceiver.contract.UnpackLog(event, "ForwarderAddressUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverOwnershipTransferredIterator struct { + Event *AutomationReceiverOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverOwnershipTransferred) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverOwnershipTransferred struct { + PreviousOwner common.Address + NewOwner common.Address + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*AutomationReceiverOwnershipTransferredIterator, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return &AutomationReceiverOwnershipTransferredIterator{contract: _AutomationReceiver.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationReceiverOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { + + var previousOwnerRule []interface{} + for _, previousOwnerItem := range previousOwner { + previousOwnerRule = append(previousOwnerRule, previousOwnerItem) + } + var newOwnerRule []interface{} + for _, newOwnerItem := range newOwner { + newOwnerRule = append(newOwnerRule, newOwnerItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverOwnershipTransferred) + if err := _AutomationReceiver.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationReceiverOwnershipTransferred, error) { + event := new(AutomationReceiverOwnershipTransferred) + if err := _AutomationReceiver.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverPausedIterator struct { + Event *AutomationReceiverPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverPaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverPaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationReceiverPausedIterator, error) { + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationReceiverPausedIterator{contract: _AutomationReceiver.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationReceiverPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverPaused) + if err := _AutomationReceiver.contract.UnpackLog(event, "Paused", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParsePaused(log types.Log) (*AutomationReceiverPaused, error) { + event := new(AutomationReceiverPaused) + if err := _AutomationReceiver.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverReportSkippedWhilePausedIterator struct { + Event *AutomationReceiverReportSkippedWhilePaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverReportSkippedWhilePausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverReportSkippedWhilePaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverReportSkippedWhilePaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverReportSkippedWhilePausedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverReportSkippedWhilePausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverReportSkippedWhilePaused struct { + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterReportSkippedWhilePaused(opts *bind.FilterOpts) (*AutomationReceiverReportSkippedWhilePausedIterator, error) { + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "ReportSkippedWhilePaused") + if err != nil { + return nil, err + } + return &AutomationReceiverReportSkippedWhilePausedIterator{contract: _AutomationReceiver.contract, event: "ReportSkippedWhilePaused", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchReportSkippedWhilePaused(opts *bind.WatchOpts, sink chan<- *AutomationReceiverReportSkippedWhilePaused) (event.Subscription, error) { + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "ReportSkippedWhilePaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverReportSkippedWhilePaused) + if err := _AutomationReceiver.contract.UnpackLog(event, "ReportSkippedWhilePaused", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseReportSkippedWhilePaused(log types.Log) (*AutomationReceiverReportSkippedWhilePaused, error) { + event := new(AutomationReceiverReportSkippedWhilePaused) + if err := _AutomationReceiver.contract.UnpackLog(event, "ReportSkippedWhilePaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverSecurityWarningIterator struct { + Event *AutomationReceiverSecurityWarning + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverSecurityWarningIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverSecurityWarning) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverSecurityWarning) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverSecurityWarningIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverSecurityWarningIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverSecurityWarning struct { + Message string + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterSecurityWarning(opts *bind.FilterOpts) (*AutomationReceiverSecurityWarningIterator, error) { + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "SecurityWarning") + if err != nil { + return nil, err + } + return &AutomationReceiverSecurityWarningIterator{contract: _AutomationReceiver.contract, event: "SecurityWarning", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchSecurityWarning(opts *bind.WatchOpts, sink chan<- *AutomationReceiverSecurityWarning) (event.Subscription, error) { + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "SecurityWarning") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverSecurityWarning) + if err := _AutomationReceiver.contract.UnpackLog(event, "SecurityWarning", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseSecurityWarning(log types.Log) (*AutomationReceiverSecurityWarning, error) { + event := new(AutomationReceiverSecurityWarning) + if err := _AutomationReceiver.contract.UnpackLog(event, "SecurityWarning", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverStaleReportSkippedIterator struct { + Event *AutomationReceiverStaleReportSkipped + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverStaleReportSkippedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverStaleReportSkipped) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverStaleReportSkipped) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverStaleReportSkippedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverStaleReportSkippedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverStaleReportSkipped struct { + Target common.Address + Selector [4]byte + ReportBlockNumber *big.Int + LastReportBlock *big.Int + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterStaleReportSkipped(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverStaleReportSkippedIterator, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "StaleReportSkipped", targetRule, selectorRule) + if err != nil { + return nil, err + } + return &AutomationReceiverStaleReportSkippedIterator{contract: _AutomationReceiver.contract, event: "StaleReportSkipped", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchStaleReportSkipped(opts *bind.WatchOpts, sink chan<- *AutomationReceiverStaleReportSkipped, target []common.Address, selector [][4]byte) (event.Subscription, error) { + + var targetRule []interface{} + for _, targetItem := range target { + targetRule = append(targetRule, targetItem) + } + var selectorRule []interface{} + for _, selectorItem := range selector { + selectorRule = append(selectorRule, selectorItem) + } + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "StaleReportSkipped", targetRule, selectorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverStaleReportSkipped) + if err := _AutomationReceiver.contract.UnpackLog(event, "StaleReportSkipped", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseStaleReportSkipped(log types.Log) (*AutomationReceiverStaleReportSkipped, error) { + event := new(AutomationReceiverStaleReportSkipped) + if err := _AutomationReceiver.contract.UnpackLog(event, "StaleReportSkipped", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationReceiverUnpausedIterator struct { + Event *AutomationReceiverUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationReceiverUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverUnpaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(AutomationReceiverUnpaused) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *AutomationReceiverUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationReceiverUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationReceiverUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationReceiver *AutomationReceiverFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationReceiverUnpausedIterator, error) { + + logs, sub, err := _AutomationReceiver.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationReceiverUnpausedIterator{contract: _AutomationReceiver.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationReceiverUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationReceiver.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationReceiverUnpaused) + if err := _AutomationReceiver.contract.UnpackLog(event, "Unpaused", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_AutomationReceiver *AutomationReceiverFilterer) ParseUnpaused(log types.Log) (*AutomationReceiverUnpaused, error) { + event := new(AutomationReceiverUnpaused) + if err := _AutomationReceiver.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetBlockNumberCheck struct { + Enabled bool + LastReportBlock *big.Int +} + +func (AutomationReceiverBlockNumberCheckSet) Topic() common.Hash { + return common.HexToHash("0xf19a6052943cc4c32e1644d475a7b4e6f517bcae63159220028f5de68d6d0364") +} + +func (AutomationReceiverCallAllowedSet) Topic() common.Hash { + return common.HexToHash("0x0925d576b7c865d78d7fe746ae46d080d64b9e6b04db5f034f71a79c41dda2e7") +} + +func (AutomationReceiverCallExecuted) Topic() common.Hash { + return common.HexToHash("0xbe82131bb3404498c769b0511da41a4ad409fa7152562c2b6669241cbe3bb884") +} + +func (AutomationReceiverCallFailed) Topic() common.Hash { + return common.HexToHash("0xefa88af289a36b936ccacf9bd9eaaa185775cd54ae263973d3579c01111593b6") +} + +func (AutomationReceiverConsumerGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xf3f16b36d6fb2a97e5e66d28e758a4d457e80197e1d455f692a96be32091fa3a") +} + +func (AutomationReceiverExpectedAuthorUpdated) Topic() common.Hash { + return common.HexToHash("0x3321cda85c145617e47418aa14255e9dcbec53a753778e57591703b89a3cad31") +} + +func (AutomationReceiverExpectedWorkflowIdUpdated) Topic() common.Hash { + return common.HexToHash("0x0dbedcdf21925e053b4c574eae180d7f2883235ab4976ecc0873598a2a999b03") +} + +func (AutomationReceiverExpectedWorkflowNameUpdated) Topic() common.Hash { + return common.HexToHash("0x1e7ddd09d504c82dcfc784a464b167469f5aad967606ec4822d848ef9141dfa5") +} + +func (AutomationReceiverForwarderAddressUpdated) Topic() common.Hash { + return common.HexToHash("0x039ad854736757070884dd787ef1a7f58db33546639d1f3efddcf4a33fb8997e") +} + +func (AutomationReceiverOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationReceiverPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationReceiverReportSkippedWhilePaused) Topic() common.Hash { + return common.HexToHash("0xf37c389ae9f5e13dbbef9f62b1ad0893e89c865ee834b2e221d11ebcf3cacd51") +} + +func (AutomationReceiverSecurityWarning) Topic() common.Hash { + return common.HexToHash("0x704da7db165c79c1e33d542c079333bbde970a733032d2f95fec8fb7d770cbf7") +} + +func (AutomationReceiverStaleReportSkipped) Topic() common.Hash { + return common.HexToHash("0x96e22437f0b9d1dfe909221668f6ad9813c1128b60a7b4b3dee74e4248df834a") +} + +func (AutomationReceiverUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (_AutomationReceiver *AutomationReceiver) Address() common.Address { + return _AutomationReceiver.address +} + +type AutomationReceiverInterface interface { + GetBlockNumberCheck(opts *bind.CallOpts, target common.Address, selector [4]byte) (GetBlockNumberCheck, + + error) + + GetConsumerGasLimit(opts *bind.CallOpts, target common.Address, selector [4]byte) (*big.Int, error) + + GetExpectedAuthor(opts *bind.CallOpts) (common.Address, error) + + GetExpectedWorkflowId(opts *bind.CallOpts) ([32]byte, error) + + GetExpectedWorkflowName(opts *bind.CallOpts) ([10]byte, error) + + GetForwarderAddress(opts *bind.CallOpts) (common.Address, error) + + IsCallAllowed(opts *bind.CallOpts, target common.Address, selector [4]byte) (bool, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + Paused(opts *bind.CallOpts) (bool, error) + + RetryableWhilePaused(opts *bind.CallOpts) (bool, error) + + SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) + + OnReport(opts *bind.TransactOpts, metadata []byte, report []byte) (*types.Transaction, error) + + Pause(opts *bind.TransactOpts, retryable bool) (*types.Transaction, error) + + RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + SetBlockNumberCheck(opts *bind.TransactOpts, target common.Address, selector [4]byte, enabled bool, initialBlockNumber *big.Int) (*types.Transaction, error) + + SetCallAllowed(opts *bind.TransactOpts, target common.Address, selector [4]byte, allowed bool) (*types.Transaction, error) + + SetConsumerGasLimit(opts *bind.TransactOpts, target common.Address, selector [4]byte, gasLimit *big.Int) (*types.Transaction, error) + + SetExpectedAuthor(opts *bind.TransactOpts, _author common.Address) (*types.Transaction, error) + + SetExpectedWorkflowId(opts *bind.TransactOpts, _id [32]byte) (*types.Transaction, error) + + SetExpectedWorkflowName(opts *bind.TransactOpts, _name string) (*types.Transaction, error) + + SetForwarderAddress(opts *bind.TransactOpts, _forwarder common.Address) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) + + Unpause(opts *bind.TransactOpts) (*types.Transaction, error) + + FilterBlockNumberCheckSet(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverBlockNumberCheckSetIterator, error) + + WatchBlockNumberCheckSet(opts *bind.WatchOpts, sink chan<- *AutomationReceiverBlockNumberCheckSet, target []common.Address, selector [][4]byte) (event.Subscription, error) + + ParseBlockNumberCheckSet(log types.Log) (*AutomationReceiverBlockNumberCheckSet, error) + + FilterCallAllowedSet(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverCallAllowedSetIterator, error) + + WatchCallAllowedSet(opts *bind.WatchOpts, sink chan<- *AutomationReceiverCallAllowedSet, target []common.Address, selector [][4]byte) (event.Subscription, error) + + ParseCallAllowedSet(log types.Log) (*AutomationReceiverCallAllowedSet, error) + + FilterCallExecuted(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverCallExecutedIterator, error) + + WatchCallExecuted(opts *bind.WatchOpts, sink chan<- *AutomationReceiverCallExecuted, target []common.Address, selector [][4]byte) (event.Subscription, error) + + ParseCallExecuted(log types.Log) (*AutomationReceiverCallExecuted, error) + + FilterCallFailed(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverCallFailedIterator, error) + + WatchCallFailed(opts *bind.WatchOpts, sink chan<- *AutomationReceiverCallFailed, target []common.Address, selector [][4]byte) (event.Subscription, error) + + ParseCallFailed(log types.Log) (*AutomationReceiverCallFailed, error) + + FilterConsumerGasLimitSet(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverConsumerGasLimitSetIterator, error) + + WatchConsumerGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationReceiverConsumerGasLimitSet, target []common.Address, selector [][4]byte) (event.Subscription, error) + + ParseConsumerGasLimitSet(log types.Log) (*AutomationReceiverConsumerGasLimitSet, error) + + FilterExpectedAuthorUpdated(opts *bind.FilterOpts, previousAuthor []common.Address, newAuthor []common.Address) (*AutomationReceiverExpectedAuthorUpdatedIterator, error) + + WatchExpectedAuthorUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverExpectedAuthorUpdated, previousAuthor []common.Address, newAuthor []common.Address) (event.Subscription, error) + + ParseExpectedAuthorUpdated(log types.Log) (*AutomationReceiverExpectedAuthorUpdated, error) + + FilterExpectedWorkflowIdUpdated(opts *bind.FilterOpts, previousId [][32]byte, newId [][32]byte) (*AutomationReceiverExpectedWorkflowIdUpdatedIterator, error) + + WatchExpectedWorkflowIdUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverExpectedWorkflowIdUpdated, previousId [][32]byte, newId [][32]byte) (event.Subscription, error) + + ParseExpectedWorkflowIdUpdated(log types.Log) (*AutomationReceiverExpectedWorkflowIdUpdated, error) + + FilterExpectedWorkflowNameUpdated(opts *bind.FilterOpts, previousName [][10]byte, newName [][10]byte) (*AutomationReceiverExpectedWorkflowNameUpdatedIterator, error) + + WatchExpectedWorkflowNameUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverExpectedWorkflowNameUpdated, previousName [][10]byte, newName [][10]byte) (event.Subscription, error) + + ParseExpectedWorkflowNameUpdated(log types.Log) (*AutomationReceiverExpectedWorkflowNameUpdated, error) + + FilterForwarderAddressUpdated(opts *bind.FilterOpts, previousForwarder []common.Address, newForwarder []common.Address) (*AutomationReceiverForwarderAddressUpdatedIterator, error) + + WatchForwarderAddressUpdated(opts *bind.WatchOpts, sink chan<- *AutomationReceiverForwarderAddressUpdated, previousForwarder []common.Address, newForwarder []common.Address) (event.Subscription, error) + + ParseForwarderAddressUpdated(log types.Log) (*AutomationReceiverForwarderAddressUpdated, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*AutomationReceiverOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationReceiverOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationReceiverOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationReceiverPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationReceiverPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationReceiverPaused, error) + + FilterReportSkippedWhilePaused(opts *bind.FilterOpts) (*AutomationReceiverReportSkippedWhilePausedIterator, error) + + WatchReportSkippedWhilePaused(opts *bind.WatchOpts, sink chan<- *AutomationReceiverReportSkippedWhilePaused) (event.Subscription, error) + + ParseReportSkippedWhilePaused(log types.Log) (*AutomationReceiverReportSkippedWhilePaused, error) + + FilterSecurityWarning(opts *bind.FilterOpts) (*AutomationReceiverSecurityWarningIterator, error) + + WatchSecurityWarning(opts *bind.WatchOpts, sink chan<- *AutomationReceiverSecurityWarning) (event.Subscription, error) + + ParseSecurityWarning(log types.Log) (*AutomationReceiverSecurityWarning, error) + + FilterStaleReportSkipped(opts *bind.FilterOpts, target []common.Address, selector [][4]byte) (*AutomationReceiverStaleReportSkippedIterator, error) + + WatchStaleReportSkipped(opts *bind.WatchOpts, sink chan<- *AutomationReceiverStaleReportSkipped, target []common.Address, selector [][4]byte) (event.Subscription, error) + + ParseStaleReportSkipped(log types.Log) (*AutomationReceiverStaleReportSkipped, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationReceiverUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationReceiverUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationReceiverUnpaused, error) + + Address() common.Address +} diff --git a/gethwrappers/automation-cre/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/gethwrappers/automation-cre/generation/generated-wrapper-dependency-versions-do-not-edit.txt new file mode 100644 index 0000000000..80ee200f49 --- /dev/null +++ b/gethwrappers/automation-cre/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -0,0 +1,2 @@ +GETH_VERSION: 1.17.3 +automation_receiver: ../../contracts/solc/automation-cre/AutomationReceiver/AutomationReceiver.sol/AutomationReceiver.abi.json ../../contracts/solc/automation-cre/AutomationReceiver/AutomationReceiver.sol/AutomationReceiver.bin c8d03ed089c8a4734d4cb7146852b3b323177dc0d47f7f3c23d436af3c3a062b diff --git a/gethwrappers/automation-cre/go_generate.go b/gethwrappers/automation-cre/go_generate.go new file mode 100644 index 0000000000..3e01738d2f --- /dev/null +++ b/gethwrappers/automation-cre/go_generate.go @@ -0,0 +1,5 @@ +// Package gethwrappers provides tools for wrapping solidity contracts with +// golang packages, using abigen. +package gethwrappers + +//go:generate go run ../wrap automation-cre AutomationReceiver automation_receiver diff --git a/gethwrappers/go.mod b/gethwrappers/go.mod index 0262e46aa5..ae8d51090b 100644 --- a/gethwrappers/go.mod +++ b/gethwrappers/go.mod @@ -1,6 +1,6 @@ module github.com/smartcontractkit/chainlink-evm/gethwrappers -go 1.24.5 +go 1.25.0 require ( github.com/ethereum/go-ethereum v1.17.3 diff --git a/gethwrappers/go_generate.go b/gethwrappers/go_generate.go index 36f842ca1b..638ff31b0c 100644 --- a/gethwrappers/go_generate.go +++ b/gethwrappers/go_generate.go @@ -8,6 +8,7 @@ package gethwrappers //go:generate go generate go_generate_automation.go //go:generate go generate go_generate_vrf.go +//go:generate go generate ./automation-cre //go:generate go generate ./functions //go:generate go generate ./llo-feeds //go:generate go generate ./operatorforwarder