# Modifiers

## ConfigFlags check

A few times the function `ConfigFlags.check` is invoked to check whether a certain flag is true. This is done by storing a predefined library of possible flags and taking bitwise AND between the given flag and the provided config byte.&#x20;

### ConfigFlags code

```solidity
library ConfigFlags {
  function check(uint256 cfg, uint256 flag) internal pure returns (bool) {
    return (cfg & flag) != 0;
  }
}
```

## Wrapped modifiers

Modifiers herein listed are wrapped in distinct functions.&#x20;

### \_assertOnlyOwner

This is a modifier on the agent ownership (incorporated via inheritance from the well-known Ownable.sol) which is used to keep unauthorized users from performing important function calls (slashing, agent parameter modification, accumulated fee withdrawal).

```solidity
function _assertOnlyOwner() internal view {
    if (msg.sender != owner()) {
      revert OnlyOwner();
    }
  }
```

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function slash(uint256 keeperId_, address to_, uint256 currentAmount_, uint256 pendingAmount_) external
```

{% endcode %}

```solidity
function withdrawFees(address payable to_) external
```

{% code overflow="wrap" %}

```solidity
 function setAgentParams(uint256 minKeeperCvp_, uint256 timeoutSeconds_, uint256 feePpm_) external
```

{% endcode %}

### \_assertOnlyJobOwner

This is a modifier on job ownership (incorporated via a custom jobkey-owner mapping) used to prevent unauthorized users from changing the settings of the job or withdrawing credits from its balance. Mind that they are still allowed to deposit credits therein, though).&#x20;

```solidity
function _assertOnlyJobOwner(bytes32 jobKey_) internal view {
    if (msg.sender != jobOwners[jobKey_]) {
      revert OnlyJobOwner();
    }
  }
```

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function updateJob(bytes32 jobKey_, uint16 maxBaseFeeGwei_, uint16 rewardPct_, uint32 fixedReward_, uint256 jobMinCvp_, uint24 intervalSeconds_) external
```

{% endcode %}

```solidity
function setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) external
```

{% code overflow="wrap" %}

```solidity
function setJobPreDefinedCalldata(bytes32 jobKey_, bytes calldata preDefinedCalldata_) external
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function setJobConfig(bytes32 jobKey_, bool isActive_, bool useJobOwnerCredits_, bool assertResolverSelector_) public virtual
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function initiateJobTransfer(bytes32 jobKey_, address to_) external
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function withdrawJobCredits(bytes32 jobKey_, address payable to_, uint256 amount_) external
```

{% endcode %}

### \_assertOnlyKeeperAdmin

This is a modifier that checks whether the calling user is an Admin of the supplied keeper (incorporated via a custom keeperId-admin mapping) in order to prevent unauthorized users to change the parameters of a keeper or withdraw some of the CVP stake. Mind that withdrawal of native-token compensation uses a laxer version of this modifier, described in the next subsection.&#x20;

```solidity
function _assertOnlyKeeperAdmin(uint256 keeperId_) internal view {
    if (msg.sender != keeperAdmins[keeperId_]) {
      revert OnlyKeeperAdmin();
    }
  }
```

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function setWorkerAddress(uint256 keeperId_, address worker_) external
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function initiateRedeem(uint256 keeperId_, uint256 amount_) external returns (uint256 pendingWithdrawalAfter)
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function finalizeRedeem(uint256 keeperId_, address to_) external returns (uint256 redeemedCvp)
```

{% endcode %}

### \_assertOnlyKeeperAdminOrWorker

This is a modifier that checks whether the calling user is an Admin or Worker of the supplied keepers (incorporated via a custom keeperId-admin mapping and Keeper data structure, respectively; in both cases an object, `address` or Keeper struct, is associated via some mapping with the keeperId), being a laxer version of the preceding one. In the base contract, it has the only use of providing pre-compensation withdrawal checks.&#x20;

```solidity
function _assertOnlyKeeperAdminOrWorker(uint256 keeperId_) internal view {
    if (msg.sender != keeperAdmins[keeperId_] && msg.sender != keepers[keeperId_].worker) {
      revert OnlyKeeperAdminOrWorker();
    }
  }
```

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function withdrawCompensation(uint256 keeperId_, address payable to_, uint256 amount_) external
```

{% endcode %}

### \_assertKeeperIdExists

This checks whether a keeper with a given ID exists at all by comparing the ID supplied with the ID of the latest registered keeper, since keepers are enumerated in order. Used to prevent staking to a non-existent keeper.&#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function stake(uint256 keeperId_, uint256 amount_) external
```

{% endcode %}

### \_assertWorkerNotAssigned

This checks that a worker with a given address is not already extant. Used to prevent setting two different keepers to have the same address. &#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerAsKeeper(address worker_, uint256 initialDepositAmount_) public virtual returns (uint256 keeperId)
```

{% endcode %}

```solidity
function setWorkerAddress(uint256 keeperId_, address worker_) external
```

### \_assertNonZeroAmount

Asserts that the amount supplied is not zero. Used to cut off cases of attempts to invoke the deposition or withdrawal operator in a trivial setting.&#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function withdrawJobCredits(bytes32 jobKey_, address payable to_, uint256 amount_) external
```

{% endcode %}

```solidity
function withdrawJobOwnerCredits(address payable to_, uint256 amount_) external
```

{% code overflow="wrap" %}

```solidity
function stake(uint256 keeperId_, uint256 amount_) external
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function initiateRedeem(uint256 keeperId_, uint256 amount_) external returns (uint256 pendingWithdrawalAfter)
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function slash(uint256 keeperId_, address to_, uint256 currentAmount_, uint256 pendingAmount_) external
```

{% endcode %}

### \_assertNonZeroValue

Similar to the preceding assertion, but for functions with the `payable` property instead (i.e. differs in that the amount is not passed explicitly, but rather inferred from the message value). Used to perform the same check for payable functions (e.g. credit deposition in native tokens).&#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function depositJobCredits(bytes32 jobKey_) external virtual payable
```

{% endcode %}

```solidity
function depositJobOwnerCredits(address for_) external payable
```

### \_assertJobCalldataSource

Asserts that the calldatasource field of the provided (by key) job is in concord with the specified source. Used to check that a job for which a type-specific property is set actually belongs to that type.&#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) external
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function setJobPreDefinedCalldata(bytes32 jobKey_, bytes calldata preDefinedCalldata_) external
```

{% endcode %}

### \_assertJobParams

Asserts that the provided `maxBaseFeeGwei_` is nonzero, and that the fixed and dynamic parts of the reward (given correspondingly by the parameters `fixed_reward_` and `rewardPcts_`) is not zero, i.e., the components thereof are not zero simultaneously.&#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob(RegisterJobParams calldata params_, Resolver calldata resolver_, bytes calldata preDefinedCalldata_) public payable virtual returns (bytes32 jobKey, uint256 jobId)
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function updateJob(bytes32 jobKey_, uint16 maxBaseFeeGwei_, uint16 rewardPct_, uint32 fixedReward_, uint256 jobMinCvp_, uint24 intervalSeconds_) external
```

{% endcode %}

### \_assertInterval

Asserts that the provided (by key) job is either of `RESOLVER` type AND does not have intervals or  not of `RESOLVER` type AND has nonzero `interval` size specified.&#x20;

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob(RegisterJobParams calldata params_, Resolver calldata resolver_, bytes calldata preDefinedCalldata_) public payable virtual returns (bytes32 jobKey, uint256 jobId)
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function updateJob(bytes32 jobKey_, uint16 maxBaseFeeGwei_, uint16 rewardPct_, uint32 fixedReward_, uint256 jobMinCvp_, uint24 intervalSeconds_) external
```

{% endcode %}

## Ad-hoc modifiers

Modifiers listed hereafter are not wrapped in distinct functions of their own, being instead implemented as ad-hoc logic inside of the functions that utilise them, and are listed under the provisional names given by us.&#x20;

### \_msg\_sender\_is\_pending\_owner\_assertion

Asserts that the user other than a pending owner can not accept the job transfer.

#### Code of the assertion

```solidity
if (msg.sender != jobPendingTransfers[jobKey_]) {
      revert OnlyPendingOwner();
    }
```

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function acceptJobTransfer(bytes32 jobKey_, address to_) external
```

{% endcode %}

### \_fee\_adjusted\_credits\_after\_deposit\_do\_not\_overflow\_uint88\_assertion

Asserts that after the fee (specified by the Agent parameter `feePpm`) has been deducted, the final balance after depositing additional tokens does not overflow the type used to store it (`uint88`).

#### Code of the assertion

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity"><strong>//return the fee in accordance with the Agent parameter and the amount remaining after deduction thereof
</strong><strong>(uint256 fee, uint256 amount) = _calculateDepositFee();
</strong>uint256 creditsAfter = jobs[jobKey_].credits + amount;
if (creditsAfter > type(uint88).max) {
<strong>    revert CreditsDepositOverflow();
</strong>}
</code></pre>

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _processJobCreditsDeposit(bytes32 jobKey_) internal
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

```solidity
function depositJobCredits(bytes32 jobKey_) external virtual payable
```

</details>

### \_initial\_credits\_deposit\_does\_not\_overflow\_uint88\_assertion

Asserts that for the newly registered job, the initial token balance does not overflow the type used to store it (`uint88`).

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
//revert if the proposed job credit amount is not storable in uint88
if (msg.value > type(uint88).max) {
      revert CreditsDepositOverflow();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob( RegisterJobParams calldata params_, Resolver calldata resolver_, bytes calldata preDefinedCalldata_ ) public payable virtual
```

{% endcode %}

### \_job\_id\_no\_uint24\_overflow\_assertion

Asserts that after the ID of a newly registered job does not overflow the `uint24` variable used to store it. Employed at registration, though it is unlikely that any owner ever registers `type(uint24).max` jobs.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (jobId > type(uint24).max) {
      revert JobIdOverflow();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity"><strong>function registerJob(
</strong>    RegisterJobParams calldata params_,
    Resolver calldata resolver_,
    bytes calldata preDefinedCalldata_
  ) public payable virtual returns (bytes32 jobKey, uint256 jobId)
</code></pre>

### \_credits\_deposit\_overflow\_assertion

Asserts that the initial job credit deposit does not overflow the uint88 value used to store it. Registration analogue of other deposit checkers.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (jobId > type(uint24).max) {
      revert JobIdOverflow();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob(
    RegisterJobParams calldata params_,
    Resolver calldata resolver_,
    bytes calldata preDefinedCalldata_
  ) public payable virtual returns (bytes32 jobKey, uint256 jobId)
```

{% endcode %}

### \_job\_address\_exists\_assertion

Asserts that the job address provided in the registration parameters is extant and nonzero.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (params_.jobAddress == address(0)) {
      revert MissingJobAddress();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob(
    RegisterJobParams calldata params_,
    Resolver calldata resolver_,
    bytes calldata preDefinedCalldata_
  ) public payable virtual returns (bytes32 jobKey, uint256 jobId)
```

{% endcode %}

### \_calldata\_source\_within\_0\_2\_assertion

Asserts that the specified calldata source is within the \[0;2] range, since they are encoded by the first three nonnegative integers (SELECTOR, PRE\_DEFINED, RESOLVER in that exact order).

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (params_.calldataSource > 2) {
      revert InvalidCalldataSource();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob(
    RegisterJobParams calldata params_,
    Resolver calldata resolver_,
    bytes calldata preDefinedCalldata_
  ) public payable virtual returns (bytes32 jobKey, uint256 jobId)
```

{% endcode %}

### \_job\_address\_not\_cvp\_or\_agent\_assertion

Asserts that the specified job address does not correspond to the CVP token or the Agent instance in order to prevent possible arbuses.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (params_.jobAddress == address(CVP) || params_.jobAddress == address(this)) {
      revert InvalidJobAddress();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerJob(
    RegisterJobParams calldata params_,
    Resolver calldata resolver_,
    bytes calldata preDefinedCalldata_
  ) public payable virtual returns (bytes32 jobKey, uint256 jobId)
```

{% endcode %}

### \_sender\_is\_authorised\_as\_keeper\_assertion

Asserts that the message sender that invokes `execute_44g58pv` is the keeper authorised to do so (checked via bytes reserved for technical variables in `execute` calldata). Enforces compliance with the selection made.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
 // load jobAddress, cfg, and keeperId from calldata to the stack
 actualKeeperId := shr(232, calldataload(28))
}
Keeper memory keeper = keepers[actualKeeperId];
if (keeper.worker != msg.sender) {
  revert KeeperWorkerNotAuthorized();
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_executing\_keeper\_stake\_sufficient\_assertion

Asserts that the message sender that invokes `execute_44g58pv` has at least the minimal stake demanded by the global level set by the Agent. Ensures a keeper has stake to slash even if the job does not specify any demands in this regard.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
 // load jobAddress, cfg, and keeperId from calldata to the stack
 actualKeeperId := shr(232, calldataload(28))
}
Keeper memory keeper = keepers[actualKeeperId];
if (keeper.cvpStake < minKeeperCvp) {
  revert InsufficientKeeperStake();
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_job\_is\_active\_assertion

Asserts that the invoked job is active and therefore potentially executable.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
    // size of (address(bytes20)+id(uint24/bytes3))
    let size := 23
    
    // keccack256(address+id(uint24)) to memory to generate jobKey
    calldatacopy(0, 4, size)
    jobKey := keccak256(0, size)
}
uint256 binJob = getJobRaw(jobKey);
if (!ConfigFlags.check(binJob, CFG_ACTIVE)) {
    revert InactiveJob(jobKey);
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_keeper\_satisfies\_job\_stake\_demand\_assertion

Asserts that the keeper invoking `execute_44g58pv` has sufficient amount of stake with respect to the demands made by the job, given such demands.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
    // size of (address(bytes20)+id(uint24/bytes3))
    let size := 23
    
    // keccack256(address+id(uint24)) to memory to generate jobKey
    calldatacopy(0, 4, size)
    jobKey := keccak256(0, size)
}
assembly ("memory-safe") {
 // load jobAddress, cfg, and keeperId from calldata to the stack
 actualKeeperId := shr(232, calldataload(28))
}
Keeper memory keeper = keepers[actualKeeperId];
uint256 binJob = getJobRaw(jobKey);
if (ConfigFlags.check(binJob, CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT) && keepers[actualKeeperId].cvpStake < jobMinKeeperCvp[jobKey]) {
      revert InsufficientJobScopedKeeperStake();
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_execution\_interval\_reached\_assertion

Asserts that if the job being executed is of one of two interval types, at least a full interval duration has elapsed since this job was last executed.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
    // size of (address(bytes20)+id(uint24/bytes3))
    let size := 23
    
    // keccack256(address+id(uint24)) to memory to generate jobKey
    calldatacopy(0, 4, size)
    jobKey := keccak256(0, size)
}
uint256 binJob = getJobRaw(jobKey);
{ 
    //the interval size occupies bytes 4-6, or bits 32-55. For this reason we first shift left by 32, making interval size the leading bytes, and then shift right by 232, retaining thereby only the first 24 bits (or exactly 3 bytes)
    uint256 intervalSeconds = (binJob << 32) >> 232;
    
    if (intervalSeconds > 0) {
        //since lastExecutionAt is the leading byte and has field size bytes4 (uint32), we shift right by 224 and retain only the leading 32 bits, or 4 bytes
        uint256 lastExecutionAt = binJob >> 224;
        if (lastExecutionAt > 0) {
            uint256 nextExecutionAt;
            unchecked {
                nextExecutionAt = lastExecutionAt + intervalSeconds;
            }
            if (nextExecutionAt > block.timestamp) {
                revert IntervalNotReached(lastExecutionAt, intervalSeconds, block.timestamp);
            }
        }
    }
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_msg\_sender\_is\_EoA\_assertion

Asserts that the message sender invoking `execute_44g58pv` is an externally-owned address (i.e. not an automatic contract).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
//if the sender is not an EoA, the origin will be the EoA which started the chain of transactions that led to the sender's activation and code execution and thereby the message transmission
if (msg.sender != tx.origin) {
      revert NonEOASender();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_invalid\_source\_type\_catcher

The \_calldata\_source\_within\_0\_2\_assertion only makes sure the calldata numerical value is betwen 0 and 2. It will normally coincide with one of the three defined job types (SELECTOR, PRE\_DEFINED, RESOLVER), but in a hypothetical case when this does not occur for any reason whatsoever, we need a catcher to raise an error.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
    // size of (address(bytes20)+id(uint24/bytes3))
    let size := 23
    
    // keccack256(address+id(uint24)) to memory to generate jobKey
    calldatacopy(0, 4, size)
    jobKey := keccak256(0, size)
}
uint256 binJob = getJobRaw(jobKey);
CalldataSourceType calldataSource = CalldataSourceType((binJob << 56) >> 248);
if (calldataSource == CalldataSourceType.SELECTOR) {
    ...
} else if (calldataSource == CalldataSourceType.PRE_DEFINED) {
        ...
    } else if (calldataSource == CalldataSourceType.RESOLVER) {
            ...
        } else {
                //catcher that should never be reached under normal operation
                revert InvalidCalldataSource();
            }     
    

```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_job\_has\_enough\_credits\_assertion

Asserts that the job has enough credits to cover the keeper's reward for executing it.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
compensation = _calculateCompensation(ok, binJob, actualKeeperId, min, gasUsed);
uint256 creditsBefore = (binJob << 128) >> 168;
if (creditsBefore < compensation) {
    if (ok) {
        revert InsufficientJobCredits(creditsBefore, compensation);
        }
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_block\_base\_fee\_within\_limits\_or\_accept\_exceeding\_assertion

This modifier asserts that the block base gas fee is either not in excess of the job-specified limit or accepted anyway by the appropriately configured flag `FLAG_ACCEPT_MAX_BASE_FEE_LIMIT` passed along with the execute call in the `config` calldata byte.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 maxBaseFee;
    unchecked {
      maxBaseFee = ((binJob_ << 112) >> 240)  * 1 gwei;
    }
    if (block.basefee > maxBaseFee && !ConfigFlags.check(cfg_, FLAG_ACCEPT_MAX_BASE_FEE_LIMIT)) {
      revert BaseFeeGtGasPrice(block.basefee, maxBaseFee);
    }
    return maxBaseFee;
  }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _checkBaseFee(uint256 binJob_, uint256 cfg_) internal view virtual returns (uint256)
```

{% endcode %}

### \_job\_revert\_handler

In some cases, job reverts will give traceback messages. Occasionally, however, they will give no traceback, and both occasion need to be handled properly. This code provides such a functionality. It is not properly a modifier, since it does not condition execution of anything and merely serves as an error handler, but we include it here on the basis of collecting on one page all revert-capable routines.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (executionResponse_.length == 0) {
      revert JobCallRevertedWithoutDetails();
    } else {
      assembly ("memory-safe") {
        revert(add(32, executionResponse_), mload(executionResponse_))
      }
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _afterExecutionReverted(
    bytes32 jobKey_,
    CalldataSourceType calldataSource_,
    uint256 keeperId_,
    bytes memory executionResponse_
  ) internal virtual
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

```solidity
function execute_44g58pv() external
```

</details>

### \_job\_owner\_has\_enough\_credits\_assertion

Asserts that the job owner has enough credits to cover the keeper's reward for executing it. Is only invoked when the `CFG_USE_JOB_OWNER_CREDITS` job config flag is set to `True`.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 jobOwnerCreditsBefore = jobOwnerCredits[jobOwners[jobKey_]];
    if (jobOwnerCreditsBefore < compensation_) {
      if (ok_) {
        revert InsufficientJobOwnerCredits(jobOwnerCreditsBefore, compensation_);
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _useJobOwnerCredits(bool ok_, bytes32 jobKey_, uint256 compensation_) internal
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

```solidity
function execute_44g58pv() external
```

</details>

### \_job\_owner\_has\_enough\_credits\_assertion

Asserts that the job owner has enough credits to cover the keeper's reward for executing it. Is only invoked when the `CFG_USE_JOB_OWNER_CREDITS` job config flag is set to `True`.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 jobOwnerCreditsBefore = jobOwnerCredits[jobOwners[jobKey_]];
    if (jobOwnerCreditsBefore < compensation_) {
      if (ok_) {
        revert InsufficientJobOwnerCredits(jobOwnerCreditsBefore, compensation_);
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _useJobOwnerCredits(bool ok_, bytes32 jobKey_, uint256 compensation_) internal
```

{% endcode %}

### \_resolver\_address\_extant\_assertion

Asserts that the address of the supplied resolver is extant (i.e. nonzero).

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (resolver_.resolverAddress == address(0)) {
      revert MissingResolverAddress();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) internal
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

{% code overflow="wrap" %}

```solidity
function setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) external
```

{% endcode %}

</details>

### \_target\_job\_has\_owner\_assertion

Asserts that the job for which credits are deposited has an owner (i.e. the owner is not a zero address).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (jobOwners[jobKey_] == address(0)) {
      revert JobWithoutOwner();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) internal
```

{% endcode %}

### \_sufficient\_credits\_to\_withdraw

Asserts that the job/job owner has enough credits (in native chain tokens) to withdraw the specifeid amount.

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (creditsBefore < amount_) {
      revert CreditsWithdrawalUnderflow();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function withdrawJobCredits(
    bytes32 jobKey_,
    address payable to_,
    uint256 amount_
  ) external
```

{% endcode %}

{% code overflow="wrap" %}

```solidity
function withdrawJobOwnerCredits(address payable to_, uint256 amount_) external
```

{% endcode %}

### \_minKeeperCvp\_assertion

Asserts that the registering keeper has a sufficient initial deposit value to stake at least the `minKeeperCvp` value demanded by the Agent parameter of the same name.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (initialDepositAmount_ < minKeeperCvp) {
      revert InsufficientAmount();
    }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function registerAsKeeper(address worker_, uint256 initialDepositAmount_) public virtual returns (uint256 keeperId)
```

{% endcode %}

### \_amount\_not\_exceeds\_available\_assertion

Asserts that a keeper has accrued enough compensation in native chain tokens to withdraw the specified amount.&#x20;

#### Code of the assertion

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity">uint256 available = compensations[keeperId_];
if (amount_ > available) {
<strong>    revert WithdrawAmountExceedsAvailable(amount_, available);
</strong>}
</code></pre>

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function withdrawCompensation(uint256 keeperId_, address payable to_, uint256 amount_) external
```

{% endcode %}

### \_stake\_amount\_does\_not\_overflow\_assertion

Asserts that, should the provided stake amount be added to the extant stake, the resultant value shall not exceed the maximal value admitted by the type `uint88`, which is used to store stakes.

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 amountAfter = keepers[keeperId_].cvpStake + amount_;
if (amountAfter > type(uint88).max) {
  revert StakeAmountOverflow();
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _stake(uint256 keeperId_, uint256 amount_) internal
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

```solidity
function stake(uint256 keeperId_, uint256 amount_) external
```

</details>

### \_amount\_sufficient\_to\_compensate\_slashed\_stake\_assertion

Asserts that the amount of CVP stake the keeper wishes to withdraw is at least sufficient to compensate the totality of the slashed stake penalty he has accrued by now.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 slashedStakeOfBefore = slashedStakeOf[keeperId_];
if (amount_ < slashedStakeOfBefore) {
    revert InsufficientAmountToCoverSlashedStake(amount_, slashedStakeOfBefore);
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function initiateRedeem(uint256 keeperId_, uint256 amount_) external returns (uint256 pendingWithdrawalAfter)
```

{% endcode %}

### \_amount\_not\_exceeds\_stake\_assertion

Asserts that the amount of CVP stake the keeper wishes to withdraw is not in excess of the totality of his stake.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 stakeOfBefore = keepers[keeperId_].cvpStake;
uint256 slashedStakeOfBefore = slashedStakeOf[keeperId_];
uint256 totalStakeBefore = stakeOfBefore + slashedStakeOfBefore;
if (amount_ > totalStakeBefore) {
    revert AmountGtStake(amount_, stakeOfBefore, slashedStakeOfBefore);
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function initiateRedeem(uint256 keeperId_, uint256 amount_) external returns (uint256 pendingWithdrawalAfter)
```

{% endcode %}

### \_withdrawal\_time\_limit\_elapsed\_assertion

Asserts that the time delay between the keeper calling `initiateRedeem` and `finalizeRedeem` is not exceeded by the Agent-specified constant `pendingWithdrawalTimeoutSeconds`, i.e. that at least the minimum demanded time has elapsed since the stake redemption was initiated.&#x20;

#### Code of the assertion

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity">if (pendingWithdrawalEndsAt[keeperId_] > block.timestamp) {
<strong>    revert WithdrawalTimoutNotReached();
</strong>}
</code></pre>

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function finalizeRedeem(uint256 keeperId_, address to_) external returns (uint256 redeemedCvp)
```

{% endcode %}

### \_pending\_withdrawal\_extant\_assertion

Asserts that the keeper whose stake is being withdrawn actually has any stake pending withdrawal; i.e. that it is not attempted to finalise redemption of zero stake.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
redeemedCvp = pendingWithdrawalAmounts[keeperId_];
if (redeemedCvp == 0) {
  revert NoPendingWithdrawal();
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function finalizeRedeem(uint256 keeperId_, address to_) external returns (uint256 redeemedCvp)
```

{% endcode %}

### \_timeout\_not\_in\_excess\_of\_constant\_global\_cap\_assert

Asserts that the timeout parameter `pendingWithdrawalTimeoutSeconds` provided by the Agent instance owner is not in excess of a constant global cap on this value `MAX_PENDING_WITHDRAWAL_TIMEOUT_SECONDS`. This parameter is responsible for setting the minimal time delay between initiating and finalising redemption of staked CVP tokens by keepers.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (timeoutSeconds_ > MAX_PENDING_WITHDRAWAL_TIMEOUT_SECONDS) {
    revert TimeoutTooBig();
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _setAgentParams(
    uint256 minKeeperCvp_,
    uint256 timeoutSeconds_,
    uint256 feePpm_
  ) internal
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

```solidity
function setAgentParams(
    uint256 minKeeperCvp_,
    uint256 timeoutSeconds_,
    uint256 feePpm_
  ) external
```

</details>

### \_\_feeppm\_not\_in\_excess\_of\_constant\_global\_cap\_assert

Asserts that the timeout parameter `feePpm` provided by the Agent instance owner is not in excess of a constant global cap on this value `MAX_FEE_PPM`. This parameter governs the fee the Agent exacts from all&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (feePpm_ > MAX_FEE_PPM) {
    revert FeeTooBig();
}
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function _setAgentParams(
    uint256 minKeeperCvp_,
    uint256 timeoutSeconds_,
    uint256 feePpm_
  ) internal
```

{% endcode %}

<details>

<summary>Function invoking this internal routine</summary>

```solidity
function setAgentParams(
    uint256 minKeeperCvp_,
    uint256 timeoutSeconds_,
    uint256 feePpm_
  ) external
```

</details>

### \_calldata\_passed\_to\_resolver\_job\_assert

Asserts that if the job is of the `RESOLVER` type, the calldata passed to `execute_44g58pv` contains nonempty calldata after byte number 31 to be passed to the function being automated.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
assembly ("memory-safe") {
        let cdInCdSize := calldatasize()
        // calldata offset is 31
        let beforeCdSize := 31
        let ptr := mload(0x40)
        if lt(cdInCdSize, beforeCdSize) {
          // revert MissingInputCalldata()
          mstore(ptr, 0x47a0bafb00000000000000000000000000000000000000000000000000000000)
          revert(ptr, 4)
        }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

### \_selector\_check\_assert

Asserts that, provided the corresponding flag (`CFG_ASSERT_RESOLVER_SELECTOR`, which toggles checks of resolver selector coincidence) is specified, the resolver selector in the keeper-provided calldata matches the resolver selector contained in the `Job` binary representation.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
// CFG_ASSERT_RESOLVER_SELECTOR = 0x04
        if and(binJob, 0x04) {
          if iszero(eq(
            // actual
            shl(224, shr(224, calldataload(31))),
            // expected
            shl(224, shr(8, binJob))
          )) {
            // revert SelectorCheckFailed()
            mstore(ptr, 0x84fb827500000000000000000000000000000000000000000000000000000000)
            revert(ptr, 4)
          }
        }
```

{% endcode %}

#### Usage scope (functions in main contract)

{% code overflow="wrap" %}

```solidity
function execute_44g58pv() external
```

{% endcode %}

## RanDAO realisation-specific modifiers

All RanDAO realisation-specific modifiers are ad-hoc.

### \_enough\_stake\_to\_slash\_assertion

Asserts that a keeper has enough stake to be slashed. This should always be the case, since the fixed stake slash amount is capped at 50% of the minimal Agent-wide admissible stake, and the dynamic part must not exceed 50% of the actual keeper stake (imposed via a cap on bps).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 dynamicSlashAmount = eKeeper.cvpStake * uint256(rdConfig.slashingFeeBps) / 10_000;
      uint256 fixedSlashAmount = uint256(rdConfig.slashingFeeFixedCVP) * 1 ether;
      // NOTICE: totalSlashAmount can't be >= uint88
      uint88 totalSlashAmount = uint88(fixedSlashAmount + dynamicSlashAmount);
      if (totalSlashAmount > eKeeper.cvpStake) {
        // Actually this block should not be reached, so this is just in case
        revert InsufficientKeeperStakeToSlash(jobKey_, expectedKeeperId, eKeeper.cvpStake, totalSlashAmount);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _afterExecutionSucceeded(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal override
```

{% endcode %}

### \_interval\_job\_slashing\_timestamp\_reached\_assertion

Asserts that when a slasher attempts to execute an interval job (which necessarily leads to the assigned keeper being slashed), he does so when the grace period has elapsed. Resolver jobs have their own assertion.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 nextExecutionTimeoutAt;
      uint256 _lastExecutionAt = lastExecutionAt;
      if (_lastExecutionAt == 0) {
        _lastExecutionAt = jobCreatedAt[jobKey_];
      }
      unchecked {
        nextExecutionTimeoutAt = _lastExecutionAt + intervalSeconds + rdConfig.period1;
      }
      // if it is to early to slash this job
      if (block.timestamp < nextExecutionTimeoutAt) {
        revert OnlyNextKeeper(nextKeeperId, lastExecutionAt, intervalSeconds, rdConfig.period1, block.timestamp);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _beforeExecute(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal view override
```

{% endcode %}

### \_resolver\_job\_slashing\_timestamp\_reached\_assertion

Asserts that when a slasher attempts to execute a resolver job (which necessarily leads to the assigned keeper being slashed), he does so when the grace period has elapsed. Interval jobs have their own assertion.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 _jobSlashingPossibleAfter = jobSlashingPossibleAfter[jobKey_];
      if (_jobSlashingPossibleAfter > block.timestamp) {
        revert TooEarlyForSlashing(block.timestamp, jobSlashingPossibleAfter[jobKey_]);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _beforeExecute(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal view override
```

{% endcode %}

### \_resolver\_job\_cannot\_release\_before\_slashing\_init\_assertion

Asserts that a keeper of a resolver job shall not be released (i.e. unassigned from execution) while slashing is not initialised (unless by job owner, in which case release is unconditional).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 _jobSlashingPossibleAfter = jobSlashingPossibleAfter[jobKey_];
      if (_jobSlashingPossibleAfter != 0) {
          //...//
        }
      // if no slashing initiated
      } else {
        revert CantRelease();
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function releaseJob(bytes32 jobKey_) external
```

{% endcode %}

### \_keeper\_activation\_timeout\_elapsed\_assertion

Asserts that a keeper shall not be activated unless a specified Agent-wide time interval has passed since his activation was initialised. &#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 availableAt = keeperActivationCanBeFinalizedAt[keeperId_];
    if (availableAt > block.timestamp) {
      revert TooEarlyForActivationFinalization(block.timestamp, availableAt);
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function finalizeKeeperActivation(uint256 keeperId_) external
```

{% endcode %}

### \_lockup\_period\_expired\_assertion

Asserts that a keeper of a job shall not be released (i.e. unassigned from execution) until the lock-up period (defined as the sum of `period1` and `period2`, where `period1` corresponds to the grace period, `period2` corresponds to the slashing reservation period, also called admissibility period, and both are set by the Agent owner as global parameters) has elapsed since the execution was made possible (for interval jobs) or slashing was initialised (for resolver jobs; largely equivalent to execution being made possible if slashers are rational). Once again, does not apply to release by job owner, which is unconditional.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
//interval case
uint256 period2EndsAt = lastExecutionAt + rdConfig.period1 + rdConfig.period2;
      if (period2EndsAt > block.timestamp) {
        revert TooEarlyToRelease(jobKey_, period2EndsAt);
      } 
//resolver case
uint256 _jobSlashingPossibleAfter = jobSlashingPossibleAfter[jobKey_];
      if (_jobSlashingPossibleAfter != 0) {
        uint256 period2EndsAt = _jobSlashingPossibleAfter + rdConfig.period2;
        if (period2EndsAt > block.timestamp) {
          revert TooEarlyToRelease(jobKey_, period2EndsAt);
        }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function releaseJob(bytes32 jobKey_) external
```

{% endcode %}

### \_revert\_with\_false

Technical modifier made to obtain a function that always reverts to perform checks without introducing state changes (`checkCouldBeExecuted`). Corresponds to the case of the job not being executable at call.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
(bool ok, bytes memory result) = jobAddress_.call(jobCalldata_);
    if (ok) {
      //...//
    } else {
      revert JobCheckCanNotBeExecuted(result);
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function checkCouldBeExecuted(address jobAddress_, bytes memory jobCalldata_) external
```

{% endcode %}

### \_revert\_with\_true

Technical modifier made to obtain a function that always reverts to perform checks without introducing state changes (`checkCouldBeExecuted`). Corresponds to the case of the job being executable at call.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
(bool ok, bytes memory result) = jobAddress_.call(jobCalldata_);
    if (ok) {
      revert JobCheckCanBeExecuted();
    } else {
      //...//
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function checkCouldBeExecuted(address jobAddress_, bytes memory jobCalldata_) external
```

{% endcode %}

### \_slashing\_period\_elapsed\_assertion

Asserts that slashing will not be reinitialised until the admissibility period of the previous slashing instance thereof has expired. Has the meaning of giving the slasher who initiates slashing a period during which he is the sole actor capable of slashing the keeper, in the same vein as the keeper is given a grace period for execution, since re-initation does not necessarily assign the same slasher.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 _jobSlashingPossibleAfter = jobSlashingPossibleAfter[jobKey];
    // if is already initiated
    if (_jobSlashingPossibleAfter != 0 &&
      // but not overdue yet
      (_jobSlashingPossibleAfter + rdConfig.period2) > block.timestamp
      ) {
      revert TooEarlyToReinitiateSlashing();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

### \_resolver\_terminated\_successfully\_assertion

Asserts that when slashing is initiated, the resolver job for which it is done can actually be executed (in actuality, this check is done in two stage, and this is the first one, ensuring the resolver did not revert).

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
(bool ok, bytes memory result) = resolver.resolverAddress.call(resolver.resolverCalldata);
if (!ok) {
  revert JobCheckResolverError(result);
}
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

### \_resolver\_returned\_true\_assertion

Asserts that when slashing is initiated, the resolver job for which it is done can actually be executed (in actuality, this check is done in two stage, and this is the second one, ensuring th resolver returns `True`).

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
(bool ok, bytes memory result) = resolver.resolverAddress.call(resolver.resolverCalldata);
if (!ok) {
  //...//
}
(bool canExecute,) = abi.decode(result, (bool, bytes));
if (!canExecute) {
  revert JobCheckResolverReturnedFalse();
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

### \_no\_initiating\_for\_interval\_jobs

Asserts that slashing is not initated for interval jobs, since for them it has no meaning (their execution possibility timestamps are known in advance).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 intervalSeconds = (binJob << 32) >> 232;
      if (intervalSeconds != 0) {
        revert NonIntervalJob();
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

#### \_unexpected\_selector\_handler

Normally `checkCouldBeExecuted` reverts either with `JobCheckCanBeExecuted` or with `JobCheckCanNotBeExecuted`. However, in the unlikely case a third error is returned, differing in selector from both, this handler throws an exception.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
(bool ok, bytes memory result) = address(this).call(
        abi.encodeWithSelector(PPAgentV2Randao.checkCouldBeExecuted.selector, jobAddress_, jobCalldata_)
      );
 bytes4 selector = bytes4(result);
if (selector == PPAgentV2Randao.JobCheckCanNotBeExecuted.selector) {
   //...//
  }
} else if (selector != PPAgentV2Randao.JobCheckCanBeExecuted.selector) {
  revert InitiateSlashingUnexpectedError();
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

#### \_unexpected\_nonrevert\_safeguard

Normally `checkCouldBeExecuted` reverts either with `JobCheckCanBeExecuted` or with `JobCheckCanNotBeExecuted`. However, in the unlikely case it does not revert at all, this handler throws an exception.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
(bool ok, bytes memory result) = address(this).call(
        abi.encodeWithSelector(PPAgentV2Randao.checkCouldBeExecuted.selector, jobAddress_, jobCalldata_)
      );
if (ok) {
  revert UnexpectedCodeBlock();
}
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

#### \_keeper\_not\_inactive\_assertion

Ensures that an already inactive keeper is not deactivated.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (!keepers[keeperId_].isActive) {
      revert KeeperIsAlreadyInactive();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function disableKeeper(uint256 keeperId_) external
```

{% endcode %}

#### \_keeper\_not\_active\_assertion

Ensures that an already active keeper is not activated.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (keepers[keeperId_].isActive) {
      revert KeeperIsAlreadyActive();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateKeeperActivation(uint256 keeperId_) external
```

{% endcode %}

#### \_keeper\_no\_slasher\_assertion

Ensures that at slashing initiation the initiating slasher (who is then stored as the only slasher able to execute the job at keeper failure) is not the assigned keeper (i.e. no one can slash themselves).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (jobNextKeeperId[jobKey] == slasherKeeperId_) {
      revert KeeperCantSlash();
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

#### \_handle\_revert\_no\_slashing

Ensures that at revert of a resolver job the keeper is not released if slashing has not yet been initiated. This has the meaning of blocking a keeper's ability to be released from a job they do not wish to execute by calling it when it is not yet executable and obtaining release through a revert handler. &#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
 if (calldataSource_ == CalldataSourceType.RESOLVER &&
      jobReservedSlasherId[jobKey_] == 0 && jobSlashingPossibleAfter[jobKey_] == 0) {
      revert SlashingNotInitiatedExecutionReverted();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _afterExecutionReverted(
    bytes32 jobKey_,
    CalldataSourceType calldataSource_,
    uint256 keeperId_,
    bytes memory executionResponse_
  ) internal
```

{% endcode %}

#### \_slashing\_initiated\_assertion

Ensures that when a slasher calls a resolver job, slashing was initiated beforehand. Overlaps with `_is_reserved_slasher_assertion`, since the reserved slasher is a zero address until slashing is initiated. &#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
 if (calldataSource_ == CalldataSourceType.RESOLVER &&
      jobReservedSlasherId[jobKey_] == 0 && jobSlashingPossibleAfter[jobKey_] == 0) {
      revert SlashingNotInitiatedExecutionReverted();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _afterExecutionReverted(
    bytes32 jobKey_,
    CalldataSourceType calldataSource_,
    uint256 keeperId_,
    bytes memory executionResponse_
  ) internal
```

{% endcode %}

#### \_slashing\_initiated\_assertion

Ensures that when a slasher calls a resolver job, slashing was initiated beforehand. Overlaps with `_is_reserved_slasher_assertion`, since the reserved slasher is a zero address until slashing is initiated. &#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (intervalSeconds == 0 && nextKeeperId != actualKeeperId_) {
      uint256 _jobSlashingPossibleAfter = jobSlashingPossibleAfter[jobKey_];
      if (_jobSlashingPossibleAfter == 0) {
        revert SlashingNotInitiated();
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _beforeExecute(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal view
```

{% endcode %}

#### \_resolver\_job\_slashing\_timestamp\_reached\_assertion

Ensures that when a slasher calls a resolver job, he does so after slashing has been made possible (i.e. the grace period elapsed)

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (_jobSlashingPossibleAfter > block.timestamp) {
        revert TooEarlyForSlashing(block.timestamp, jobSlashingPossibleAfter[jobKey_]);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _beforeExecute(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal view
```

{% endcode %}

#### \_is\_reserved\_slasher\_assertion

Ensures that when a slasher calls a resolver job, he is the slasher earmarked for doing so (i.e. he is the one who initiated slashing in the first place).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 _jobReservedSlasherId = jobReservedSlasherId[jobKey_];
      if (_jobReservedSlasherId != actualKeeperId_) {
        revert OnlyReservedSlasher(_jobReservedSlasherId);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _beforeExecute(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal view
```

{% endcode %}

#### \_is\_current\_slasher\_assertion

Ensures that when a slasher calls an interval job or initiates resolver job slashing, he is the slasher earmarked for doing so at the current time (i.e. the `getSlasherIdByBlock` returns his ID). Distinct from the preceding modifier because there are no reserved slashers for interval jobs (no initiation process, either) and at slashing initialisation the reserved slasher is a null value.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 currentSlasherId = getCurrentSlasherId(jobKey_);
      if (actualKeeperId_ != currentSlasherId) {
        revert OnlyCurrentSlasher(currentSlasherId);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _beforeExecute(bytes32 jobKey_, uint256 actualKeeperId_, uint256 binJob_) internal view
```

{% endcode %}

#### \_keeper\_releasable\_assertion

Ensures that when an attempt is made to disable the keeper or initiate redemption of part of the stake thereof, the keeper can be released (i.e. has no jobs pending).&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 len = keeperLocksByJob[keeperId_].length();
    if (len > 0) {
      revert KeeperIsAssignedToJobs(len);
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _ensureCanReleaseKeeper(uint256 keeperId_) internal view
```

{% endcode %}

<details>

<summary>Internal function is invoked by</summary>

```solidity
function disableKeeper(uint256 keeperId_) external
```

```solidity
function _beforeInitiateRedeem(uint256 keeperId_) internal view
```

</details>

#### \_keeper\_active\_assertion

Ensures that when an attempt is made to initiate slashing, the slasher is an active keeper.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
Keeper memory keeper = keepers[slasherKeeperId_];
if (!keeper.isActive) {
        revert InactiveKeeper();
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function initiateSlashing(
    address jobAddress_,
    uint256 jobId_,
    uint256 slasherKeeperId_,
    bool useResolver_,
    bytes memory jobCalldata_
  ) external
```

{% endcode %}

#### \_fixed\_reward\_coeff\_finite

Ensures that when an attempt is made to change the inverse of the global stake scaling coefficient for the purposes of computing compensation (see [copy-of-task-reward-and-gas-compensation](https://docs.powerpool.finance/powerpool-and-poweragent-network/power-agent/old-pages/task-reward-and-gas-compensation/copy-of-task-reward-and-gas-compensation "mention")), it is nonzero.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (rdConfig_.stakeDivisor == 0) {
      revert InvalidStakeDivisor();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _setRdConfig(RandaoConfig memory rdConfig_) internal
```

{% endcode %}

#### \_slashing\_bps\_not\_too\_great\_assertion

Ensures that when an attempt is made to change the global dynamic slash coefficient in basis points of the current stake (see [slashing](https://docs.powerpool.finance/powerpool-and-poweragent-network/power-agent/old-pages/slashing "mention")), it is not in excess of 50%.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (rdConfig_.slashingFeeBps > 5000) {
      revert SlashingBpsGt5000Bps();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _setRdConfig(RandaoConfig memory rdConfig_) internal
```

{% endcode %}

#### \_slashing\_fee\_not\_too\_great\_assertion

Ensures that when an attempt is made to change the global fixed slashing fee (see [slashing](https://docs.powerpool.finance/powerpool-and-poweragent-network/power-agent/old-pages/slashing "mention")), it is not in excess of 50% of the Agent-wide minimal Keeper stake. Together with the preceding modifier ensure that a keeper is slashed for at most 100% of their stake.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (rdConfig_.slashingFeeFixedCVP > (minKeeperCvp / 2)) {
      revert InvalidSlashingFeeFixedCVP();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _setRdConfig(RandaoConfig memory rdConfig_) internal
```

{% endcode %}

#### \_admissibility\_period\_long\_enough\_assertion

Ensures that when an attempt is made to change the global parameter `period2`, which corresponds to the length of the time interval for which a job is not considered overdue (and e.g. cannot have slashing re-initiated; during that time the reserved/current keeper is the only person allowed to perform slashing), it is at least 15 seconds, so at least one block plus some reserve.  &#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (rdConfig_.period2 < 15 seconds) {
      revert InvalidPeriod2();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _setRdConfig(RandaoConfig memory rdConfig_) internal
```

{% endcode %}

#### \_grace\_period\_long\_enough\_assertion

Ensures that when an attempt is made to change the global parameter `period1`, which corresponds to the length of the grace period during which execution (and therefore slashing, if we assume Slashers are optimal actors) is possible, but cannot be done yet to give the keeper a chance to execute the job, it is at least 15 seconds, so at least one block plus some reserve.  &#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (rdConfig_.period1 < 15 seconds) {
      revert InvalidPeriod1();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _setRdConfig(RandaoConfig memory rdConfig_) internal
```

{% endcode %}

#### \_slashing\_period\_long\_enough\_assertion

Ensures that when an attempt is made to change the global parameter `slashingEpochBlocks`, which corresponds to the length of the slashing epoch, defined as the time interval during which the only sources of slasher variability are the job keys and possible shrinkage of the active keeper set, it is at least 3 blocks.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
if (rdConfig_.slashingEpochBlocks < 3) {
      revert SlashingEpochBlocksTooLow();
    }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function _setRdConfig(RandaoConfig memory rdConfig_) internal
```

{% endcode %}

#### \_job\_has\_no\_keeper\_assigned\_assertion

Ensures that when an attempt is made by a job owner to assign a keeper for a job, the job does not have a keeper assigned already.&#x20;

#### Code of the assertion

{% code overflow="wrap" %}

```solidity
uint256 assignedKeeperId = jobNextKeeperId[jobKey];
      if (assignedKeeperId != 0) {
        revert JobHasKeeperAssigned(assignedKeeperId);
      }
```

{% endcode %}

#### Usage scope (functions in RanDAO contract)

{% code overflow="wrap" %}

```solidity
function assignKeeper(bytes32[] calldata jobKeys_) external
```

{% endcode %}
