# Ethereum Execution Service

## Introduction

Ethereum Execution Service (EES) is a permissionless protocol for decentralized and reliable time-based execution of smart contracts. The protocol allows anyone to build applications on top of it freely and allows their users to create on-chain jobs, executing the application logic on a timely basis. Each job carries a fee paid by the user which goes to incentivize external executors for performing on-chain transactions at the right time. We believe that applications should be built on infrastructure that is as sound as the underlying blockchain. From this comes the importance of a protocol which:

* Does not rely on a single party for execution.
* Does not require high computational power or running a blockchain node to participate in executing jobs.
* Does not make use of off-chain coordination.

The EES aims to achieve this with the goal of increasing web3 adoption by allowing builders to make applications that weren't possible before.

## Automated Consumer Applications

EES is made to facilitate automation of user-facing applications. In contrast to existing automation services, typically focusing on internal automation, users of applications built on EES can pay execution fees in *any* ERC-20 token and do not require locking up any tokens. Users have complete control over their jobs and can utilize different pre-made fee modules to customize how fees are calculated. Furthermore, third parties can sponsor execution fees, allowing users to create and maintain jobs without needing sufficient tokens themselves. This could for example be done by applications to provide an even better UX for their users. EES allows applications such as 1-click subscription payments, dollar cost average (DCA) in DeFi and much much more. Since all jobs are stored on-chain, these take part of the EVM's composability and can be used in other external contracts.

## Reliable Execution

EES uses a new mechanism for incentivizing the activity of executing jobs consisting of continuously alternating rounds of open competition between executors and a designated exclusivity similar to PoS. The mechanism relies on zero trust between executors and the whole model is on-chain. The more users of EES, the more executors are incentivized leading to a more reliable platform. [This blog post](https://medium.com/@victorbrevig_95582/arcade-alternating-round-based-competitive-and-designated-decentralized-execution-c3d4246976d3) goes into more detail on this topic.

Additionally, it is cheap to run an executor. Since EES is purely time-based, executors can compute and keep track of the next execution time off-chain. This removes the need for continuous blind checking reducing the number of RPC calls by orders of magnitude such that running a node is not required.

## Why now?

The recent EIP-4844 upgrade significantly reduced transaction costs on Ethereum L2s, creating an opportunity for automated consumer applications to thrive. For example, it is now cheaper to process a <$10 subscription payment via EES than a traditional payment processor. Lower transaction cost also means that we can build more complex and reliable infrastructure on-chain instead of relying on off-chain coordination.


# Concepts

This section will introduce the core concepts of EES. Reading this section should give you an extended knowledge of the workings of the protocol.


# Jobs and registry

A job is an on-chain specification of the details of the execution. The `JobRegistry` contract stores them as `Job` structs inside a public array `jobs`:

```solidity
struct Job {
    address owner;
    bool active;
    bool ignoreAppRevert;
    bool sponsorFallbackToOwner;
    bool sponsorCanUpdateFeeModule;
    bytes1 executionModule;
    bytes1 feeModule;
    uint24 executionWindow;
    uint24 zeroFeeWindow;
    address sponsor;
    uint48 executionCounter;
    uint48 maxExecutions;
    IApplication application;
    uint96 creationTime;
}

Job[] public jobs;
```

Let's break down the content of the `Job` struct:

* `address owner` is the creator of the job and has the ability to deactivate the job.
* `bool active` is a flag telling whether the job can still be executed. An active job is still stored on-chain until expiry or `maxExecutions` is reached, whereafter it can be deleted.
* `bool ignoreAppRevert` is a flag telling whether the job should continue if the application reverts during execution. If this is true, the job will not expire upon reversion of the application `onExecute` call.
* `bool sponsorFallbackToOwner` is a flag telling whether the protocol should try to transfer execution fees from the owner in the case the transfer from the sponsor reverts. In this case, if the transfer from the owner succeeds, then the owner will be set as the sponsor going forward. If this is enabled, the owner should have token permissions to the `JobRegistry` contract.
* `bool sponsorCanUpdateFeeModule` is a flag telling whether the sponsor of the job is allowed to update the fee module. Updating can either be changing the parameters of the existing fee module or migrate to another fee module with new parameters. If this is set to false, only the owner can update the fee module.
* `bytes1 executionModule` is the identifier of the execution module tied to the job. This controls timing of the execution and expiry of the job.
* `bytes1 feeModule` is the identifier of the execution module tied to the job. This is responsible for calculating the execution fee and token for the job.
* `uint24 executionWindow` is the number of seconds in which the job can be executed after it is due. If the job is not executed within this window, the job will expire according to the execution module.
* `uint24 zeroFeeWindow` is the number of seconds in which the job pays zero execution fee. This means that there will be no incentive to execute this job for this duration. It is an option for applications running their own execution logic and using EES as a fallback mechanism in case of execution misses or censorship. It will always be smaller than `executionWindow`.
* `address sponsor` is the payer of the execution fees. As we will see later, any third-party can generate a signature approving the job specification and agreeing to pay the execution fees. If no sponsor is given upon creation, the sponsor field will default to the owner.
* `uint48 executionCounter` is the current number of *successful* executions for this job. Successful means that the application did not revert upon execution.
* `uint48 maxExecutions` is the maximum number of executions possible on this job before it will expire when `executionCounter` reaches this number.
* `IApplication application` is the application contract implementing the `IApplication` interface. This contains logic on *what* is executed.
* `uint96 creationTime` stores the unix timestamp in seconds (block.timestamp) of when the job was created.

{% hint style="danger" %}
**Careful**: Having both `sponsorFallbackToOwner` and `sponsorCanUpdateFeeModule` true at the same time is dangerous for the owner as the sponsor can update the fee module setting an exceedingly large fee and then withdraw their sponsorship, falling back to the owner.
{% endhint %}

{% hint style="info" %}
**Note:** A job that is expired cannot be executed. Deleting a job simply means deleting the struct and calling `onDeleteJob` on its execution module, fee module and application.
{% endhint %}

When a job is canceled, its index in the `jobs` array is freed up and can be taken by another newly created job. This effectively makes the slots in the `jobs` array reusable and helps maintaing the size of the array and this minimizing the memory footprint on the chain. Because it is cheaper gas wise to cancel an expired job than extending the array, there is incentivement to do so.

{% hint style="warning" %}
**Careful:** If you are storing indices off-chain, be sure to check that the jobs are still the ones you expect and that they have not been canceled and replaced. Listening for events can help updating these automatically.&#x20;
{% endhint %}


# Executors and coordination

Automation in EES comes from incentivicing external parties to perform on-chain transactions at the right time in exchange for a fee. These parties are called *executors* and are typically automated programs scanning for jobs which are profitable to execute. Participation as an executor is permissionless, but requires registering via the `Coordinator` contract by staking an amount of tokens.  The `Coordinator` contract keeps track of all executors but more importantly coordinates who can execute jobs at what time as well as regulating incentivization.

## ARCADE

EES uses a new coordination mechanism named ARCADE (**A**lternating **R**ound-based **C**ompetitive **A**nd **D**esignated Decentralized **E**xecution). As the name suggests, ARCADE alternates between phases of open competition and designation.&#x20;

### Open competition

During open competition, *any* executor can execute any job which is executable in that period.  However, executing during open competition costs a flat tax which covers both *executor tax* and *protocol tax*. Thus, for the job to be profitable to execute, the associated fee must be sufficient to cover both the tax and gas fee for performing the on-chain transaction.

### Designated round

During a designated round, one of the executors are randomly selected to have the exclusive ability to execute jobs for the whole duration of that period. However, the designated executor is slashed some of their stake if they fail to check-in via the `executeBatch` of the `Coordinator` contract at some point during the round. If they check-in, they are rewarded with the accumulated executor tax from the last open competition. Furthermore, designated executors do not have to pay executor tax, only protocol tax.

### Properties

The ARCADE mechanism has a set of properties making it suitable for a smart ocntract automation system:

* Anyone can participate given they have the resources to stake.&#x20;
* Coordination happens exclusively on-chain - there are no dependencies on external mechanisms. Executors can run their own software completely independant of other executors.
* Single honest actor - even if one or more bad actors try to stall the system by not executing any jobs during designated rounds, a single honest actor can always take the reward and execute those jobs during open competition. This makes the system censorship resistant.
* &#x20;Fair incentivization - while open competition can lead to low profit margin, the executor tax ensures stable profit for designated executors, incentivizing non competitive executors to participate and execute as many jobs as they can during their designated round.
* Harsh punishment - Being offline incurs slashing of the executor's stake and eventually deactivates them. This makes the current number of staked executors a good proxy for measuring honest participants.

Read more about the properties and design choices of ARCADE in [this post](https://medium.com/@victorbrevig_95582/arcade-alternating-round-based-competitive-and-designated-decentralized-execution-c3d4246976d3).

## Implementation in EES

The ARCADE model is implemented in the EES `Coordinator` contract. However, picking an executor for each round requires a state change which cannot be completely time-based automated since this would be self referencing the problem. Thus in EES, alternation rounds of designation and open competition are packed together in *epochs.* Each epoch contains a fixed number of rounds and has to be initiated. Anyone, even non-executors, can initiate a new epoch if the last one has passed by calling the `initiateEpoch` function on the `Coordinator` contract. There is open competition in-between epochs.

<figure><img src="https://2488988847-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FotYFhyxmfp3Clnu5Ko5Q%2Fuploads%2FflT9tWZbx91X2gJ1JKeF%2Fees_epoch_diagram.png?alt=media&amp;token=862bcddd-c0ec-4ce5-a7a0-1d1e132b5dda" alt=""><figcaption><p>Diagram of a single epoch. The time durations are non-indicative of the actual values in the implementation. Rounds are short for designated rounds and OC is short for open competition.</p></figcaption></figure>

Once a new epoch has been initiated, there is a time with open competition before the first round starts. During this time, the executors selected for this epoch are found. The designated executors are derived pseudo-randomly from a seed stored on-chain. Upon initiation of a new epoch, the seed is pseudo-randomly reset based on the epoch. The first part of an epoch is the *commit phase*. Here, each executor can choose to commit to a secret on-chain. Then, in the second part of the epoch, the *reveal phase*, each executor must reveal their secret on-chain which is used to shuffle the seed. At the end of the reveal phase, the current seed is the one used to derive the designated executors. Becasue each committing executor cannot know the secret of the other executors' commitment, it is impossible to construct a commitment which favors oneself. If an executor commits without revealing, they can be slashed. Read more about the commit/reveal scheme and its security properties [here](/coordination/designation).&#x20;

After the reveal phase, the rounds begin, alternating between designated execution and open competition as speficied in the pure ARCADE model. If an executor is inactive during their designated round, they can be slashed by another executor during the *slashing phase* at the end of the epoch. It is also during this phase executors who committed without revealing gets slashed. Read more about this phase [here](/coordination/slashing).

{% hint style="info" %}
**Note:** Initiating a new epoch requires an on-chain transaction and therefore has a gas cost associated with the call. No-one initiating a new epoch is equivalent of having endless open competition. Executors who are out competed in open competition are incentivized to initiate epochs since it enforces random designation and gives them a chance to profit. Furthermore, at some point the pool of executor tax will grow so large that it is worth paying the gas fee for a chance to get it.
{% endhint %}

{% hint style="info" %}
**Note:** An epoch can be initiated immediately after the previous one ends. That is right after the slashing period.
{% endhint %}

{% hint style="info" %}
**Note:** Multiple rounds are packed together in epochs to reduce the time and gas cost associated with the initiating, committing, reveaing and slashing.
{% endhint %}

{% hint style="warning" %}
**Careful:** The system parameters such as rounds per epoch and time per round can vary from deployment to deployment. Please check details about the specific deployment [here](/deployments).
{% endhint %}


# Applications

Applications are smart contracts with logic to be executed by the `JobManager` contract. An application contract must implement the `IApplication` interface:

```solidity
interface IApplication {
    function onExecuteJob(uint256 _index, address _owner) external;
    function onCreatedJob(uint256 _index, bytes1 _executionModule, address _owner, bytes calldata _inputs) external;
    function onDeletedJob(uint256 _index, address _owner) external;
}
```

The functions `onExecuteJob`, `onCreatedJob` and `onDeletedJob` are callback functions which the `JobManager` contract will call upon execution, creation  and deletion of a job respectively.

Applications can be implemented by anyone and can contain any logic such as calling external contracts. This makes it possible to execute any logic through EES jobs.&#x20;


# Execution modules

Execution modules are smart contracts containing the *logic* of the execution i.e. when conditions are met for the job to be executed. When a job is created through the `JobRegistry` contract, it commits to a single execution module. Execution modules are very abstract giving most flexibility for future execution logic. However, every execution module must implement the `IExecutionModule` interface:

```solidity
interface IExecutionModule {
    function onExecuteJob(uint256 _index, uint32 _executionWindow) external returns (uint256);
    function onCreateJob(uint256 _index, bytes calldata _inputs, uint32 _executionWindow) external;
    function onDeleteJob(uint256 _index) external;
    function jobIsExpired(uint256 _index, uint32 _executionWindow) external view returns (bool);
    function jobIsInExecutionMode(uint256 _index, uint32 _executionWindow) external view returns (bool);
    function getEncodedData(uint256 _index) external view returns (bytes memory);
}
```

The `onExecuteJob` callback function is called by the `JobRegistry` upon execution. It returns the UNIX time in seconds when the job can be executed from.   The `onCreateJob` callback function is called upon creation of a job and is passed arbitrary input data in form of the argument `_input`. It can be used to initialise auxiliary data structures within the module. Similarly, the `onDeleteJob` callback function is called by the `JobRegistry` contract upon deletion of a job. The `jobIsExpired` function returns a bool whether a job is expired and can be canceled. `jobIsInExecutionMode` returns whether the job is in execution mode. Lastly, the `getEncodedData` function returns all data stored in the execution module contract for a job index as an encoded bytes array.

{% hint style="warning" %}
**Warning:** `onExecuteJob` might revert which will in turn revert the original call to `execute` in `JobRegistry`. The execution module solely decides if the right conditions are met for the job to be executed.
{% endhint %}

In contrast to applications, execution modules are created and tested by the EES before being supported by the `JobRegistry` contract. The reason for gatekeeping the addition of execution modules is to avoid fragmentation as every executor has to implement logic to support new execution modules. However, the modular structure allows for progressively adding new and flexible logic to the protocol.

{% hint style="info" %}
**Note:** Existing execution modules are completely *immutable*. The data stored in these can only be created or deleted with job creation or deletion but cannot be modified. A job cannot change execution module during its lifetime.
{% endhint %}

Applications can choose to implement logic to restrict creation of jobs with specific execution modules. An example could be a subscription payment application which chooses to only support recurring jobs. It is recommended that the set of supported modules is extensible, thus having the ability to support new modules in the future.&#x20;


# Fee modules

Fee modules are smart contracts with the purpose of calculating the execution fee for a given job. Similarly to execution modules, a job commits to a fee module upon creation. However, data for a job within a fee module can be updated and a job can even migrate to use another fee module with time. Fee modules must implement the `IFeeModule` interface:

```solidity
interface IFeeModule {
    function onExecuteJob(uint256 _index, address _caller, uint32 _executionWindow, uint256 _executionTime, uint256 _variableGasConsumption) external returns (uint256, address);
    function onCreateJob(uint256 _index, bytes calldata _inputs) external;
    function onDeleteJob(uint256 _index) external;
    function onUpdateData(uint256 _index, bytes calldata _inputs) external;
    function getEncodedData(uint256 _index) external view returns (bytes memory);
}

```

The `onExecuteJob` callback function is called by the `JobRegistry` upon execution. It returns the execution fee and execution fee token.   The `onCreateJob` callback function is called upon creation of a job and is passed arbitrary input data in form of the argument `_input`. It can be used to initialise auxiliary data structures within the module. Similarly, the `onDeleteJob` callback function is called by the `JobRegistry` contract upon deletion of a job. The `jobIsExpired` function returns a bool whether a job is expired and can be canceled. `jobIsInExecutionMode` returns whether the job is in execution mode. Lastly, the `getEncodedData` function returns all data stored in the fee module contract for a job index as an encoded bytes array.

Similarly to execution modules, fee modules are created and tested by the EES before being supported by the `JobRegistry` contract. The modularity of fee computation allows implementation of new fee mechanisms which might be relevant in the future.

{% hint style="info" %}
**Note:** The execution fee returned by the `onExecuteJob` function is the amount withdrawn from the sponsor of the job upon execution.
{% endhint %}

{% hint style="warning" %}
**Warning:** Updating or migrating to another fee module is not permitted while a job is in execution mode.
{% endhint %}


# Execution fees

Fees are necessary to incentivise executors to execute jobs. We can largely view the fee as doing three things:

1. Compensating the executor paying gas fee to perform the on-chain transaction.
2. Incentivizing the executor beyond gas fee compensation, making it profitable to execute a job. Being an executor typically requires some kind of hardware and time invested and it should be worth the trouble economically.
3. Funding protocol development. Part of the fee goes to the protocol treasury, funding building of tools, integrations and protocol R\&D.

The total fee is calculated by the [fee module](/concepts/fee-modules) of the job and can be paid in any ERC-20 token. Getting the fee right is important as the job might not get executed if it is too low and the user risks overpaying if it is set too high. Fee modules contain mechanisms assisting in this.&#x20;

{% hint style="info" %}
**Note:** The execution fee is *always* paid by the sponsor. If no sponsor was set duing creation of a job, then the creator (`msg.sender`) will be set as sponsor.
{% endhint %}

{% hint style="warning" %}
**Warning:** Even though the fee can be paid in any ERC-20 token, it is the executors who decide if the job is worth executing. They might do that by looking at the current price of the fee token. To ensure reliable execution it is adviced to choose an established token with multiple price feeds.
{% endhint %}


# Sponsored jobs

Jobs can be *sponsored*, meaning that someone else than the owner pays the execution fee. By default, if a job is created without a sponsor, the owner is set as the sponsor, thus as the payer of execution fees. To sponsor a job, an EIP-712 signature over a specific `JobSpecification` has to be provided ias an argument to the `createJob` function in the `JobRegistry` contract:

```solidity
struct JobSpecification {
    uint256 nonce;
    uint256 deadline;
    IApplication application;
    uint32 executionWindow;
    bytes1 executionModule;
    bytes1 feeModule;
    bytes executionModuleInput;
    bytes feeModuleInput;
    bytes applicationInput;
}
```

The `createJob` function verifies the signature against the provided values, ensuring the sponsor that only a job with the agreed upon specification can be sponsored. Note that the parameter `applicationInput` is part of the signed struct. This is the same input data which is provided to the executable upon creation, which means that the sponsor is also guaranteed that even inputs to the application is a agreed upon.

The sponsor or owner of a job can at any time revoke the sponsorship, hereby setting the owner as the sponsor. Changing the fee module data in by calling `updateFeeModuleData` or migrating to a new fee module calling `migrateFeeModule` will automatically revoke the sponsorship, but a new sponsor can be set given a new signature signing a `FeeModuleInput` struct:

```solidity
struct FeeModuleInput {
    uint256 nonce;
    uint256 deadline;
    uint256 index;
    bytes1 feeModule;
    bytes feeModuleInput;
}
```

{% hint style="info" %}
**Note:** Signing a EIP-712 signature is a completely off-chain operation and will not incur gas cost.
{% endhint %}

{% hint style="info" %}
**Note:** Signatures of `JobSpecification` and `FeeModuleInput` share the same nonces, so make sure to always use unused nonces.
{% endhint %}


# Coordination

This section aims to go more in-depth with the details of the `Coordinator` contract introduced in the [concepts](/concepts/executors-and-coordination) section which is highly recommended to read first.


# Staking

To participate in EES, an executor must stake ERC-20 tokens via the `stake` function. Depending on the deployed chain, the token and amount may vary. Staking is needed such that behaviour against the rules can be punished financially with [slashing](/coordination/slashing) of funds. Staked executors are rewarded by having the chance to be designated during epochs and get further rewards from executing.

### Module registration

Staking means registering for execution and fee modules that the the executor wants to be able to execute with. That is, an executor can only execute a job if the executor has registered for both the execution and fee module. Since registering for a module means committing to executing jobs with that module, there are higher stakes for registering more modules. More specifically, the amount of tokens required to stake is proportional to the number of modules registered or.

While the `stake` function requires registration of at least two modules, the executor might at a later point register further modules via the `registerModules` function or deregister modules via the `deregisterModules` function.

### Unstaking

An executor can unstake via the `unstake` function, thus withdrawing their token balance back to the caller. This will completely withdraw their participation within the protocol and cannot be slashed going forward.

### Active vs inactive executors

Upon staking an executor is set to active and is actively in the pool of executors who can be designated during epochs. If the executor's internal balance falls below the staking balance threshold, the executor will be deactivated and can no longer be designated in epochs. This can happen due to slashing or paying execution tax. While being inactive, the executors balance still persists and they can execute jobs outside designated rounds as usual.&#x20;

The minimum staking amount it proportional to the number of modules registered and is enough to make sure that the executor has enough balance to be slashed. An inactive executor might topup their balance via the `topup` function to bring their balance back above the minimum.

### Time restrictions

Staking can not happen during the alternating rounds of designation and open competition and during the slashing phase of an epoch. This is a technicality to preserve internal data structures after the [designation seed](/coordination/designation) is set. Furthermore, there is a lock period after any registration of modules which resets upon new registrations. During this time, the executor is committed and cannot unstake.


# Designation

The process of designating executors for the rounds in an epoch happens in the beginning of that epoch. The objective is to generate a pseudo-random seed used as source of randomness when selecting the executors.

Immediately after an epoch is initiated there is a *commit* phase. Here, executors can publish a commitment which is a keccak256 hash of an ERC-191 signature of a keccak256 hash of the current epoch and chain ID. The commitment is stored in the `Coordinator` contract inside the `commitmentMap`. After the commit phase follows the *reveal phase*. Here, executors who published a commitment must reveal the signature i.e. the secret of the commitment. Failing to reveal makes the executor subject to [slashing](/coordination/slashing).

When a new epoch is initiated, the seed is updated to the keccak256 hash of the current `block.timestamp`, `block.number` and the seed of the previous epoch. When the `reveal` function of the `Coordinator` contract is called, the seed is updated to the keccak256 hash of the signature (commit secret) and previous seed value. Because committing executors do not know the secret of other committors before the reveal (it is derrived from their private key) and becasue the commitment must be of a valid signature, there is no way to try and tailor the secret to influence the seed. Executors are incentivized to commit to ensure a fair and unpredictable selection process. However, an executor might choose *not* to reveal their secret. They might do this if they know everyone else have revealed and the current seed favor themself. This is why committing without revealing makes the executor subject to [slashing](/coordination/slashing).

The final seed is locked after the reveal phase. The designated executor for each round can be calculated by taking the keccak256 hash of the seed and the round number and modulo the hash with the `numberOfActiveExecutors`. The resulting number is the index in the `activeExecutors` array where the address of the designated executor resides.


# Slashing

Anyone can slash during the slashing window of an epoch. The caller will receive half of the slashed amount. If the caller is a staked executor, the reward will to go their internal balance within the `Coordinator` contract, otherwise the caller is rewarded by a ERC-20 transfer. The other half of the slashed amount goes to the protocol. In EES there are two situations where an active executor can be slashed:

1. Designation inactivity - if an executor is designated for a round in which they do not call the `executeBatch` function.
2. Committing without revealing - if an executor calls `commit` during an epoch without doing the followup `reveal` call during the same epoch.

Each of these comes with a different slashing amount stored on-chain as `inactiveSlashingAmountPerModule` and `commitSlashingAmountPerModule`. The actual slashed amount is either of these multiplied by the number of modules the executor has registered for. For specific deployment values please refer to [Deployments](/deployments).


# Execution modules

This section will go in depth with each execution module currently supported by EES.

Here is an overview of the supported modules and their index:

<table><thead><tr><th>Execution module</th><th>Index</th><th data-hidden></th></tr></thead><tbody><tr><td>RegularTimeInterval</td><td><code>0x00</code></td><td></td></tr></tbody></table>


# RegularTimeInterval

The `RegularTimeInterval` execution module enables recurring execution of jobs in a fixed time interval. The input bytes to the `onCreateJob` function should follow the structure:

```solidity
uint32 cooldown;
uint40 initialExecutionTime;
```

&#x20;`cooldown` specifies the number of seconds between when the job can be executed. The `initialExecutionTime` value is the UNIX time in seconds when the job can be executed from the first time. If `initialExecutionTime <= block.timestamp`, `block.timestamp` becomes the initial time of execution and the job will be executed immediately.

The contract stores information about each job in a public mapping from job indices to Params structs:

```solidity
struct Params {
    uint40 lastExecution;
    uint32 cooldown;
}
```

The `lastExecution` field is the UNIX time in seconds of when the last execution opened. Initially it will be set to `initialExecutionTime - cooldown`, unless `initialExecutionTime <= block.timestamp`, then it is set to `block.timestamp`. The `lastExecution` value is updated every time the job is executed and there are always `cooldown` seconds between each value of `lastExecution`.

{% hint style="warning" %}
**Warning:** The `onCreateJob` function will revert if  `cooldown < _executionWindow.`
{% endhint %}

{% hint style="warning" %}
**`Warning:`** `lastExecution` is not *necessarily* the last timestamp the job was executed. To get an exact timestamp of when the job is executed, you can listen for the `JobExecuted` event emitted by the `JobRegistry` contract.
{% endhint %}


# Fee modules

This section will go in depth with each fee module currently supported by EES.

Here is an overview of the supported modules and their index:

<table><thead><tr><th>Execution module</th><th>Index</th><th data-hidden></th></tr></thead><tbody><tr><td>LinearAuction</td><td><code>0x00</code></td><td></td></tr><tr><td>PeggedLinearAuction</td><td><code>0x01</code></td><td></td></tr></tbody></table>


# LinearAuction

The `LinearAuction` fee module creates a reverse dutch auction upon time of execution of a job. The input bytes to the `onCreateJob` function should follow the structure:

```solidity
address executionFeeToken;
uint256 minExecutionFee;
uint256 maxExecutionFee;
```

The `executionFeeToken` field is the token which execution fee will be paid in. During the auction period, the execution fee will grow linearly every second from `minExecutionFee` to `maxExecutionFee`.

<figure><img src="https://2488988847-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FotYFhyxmfp3Clnu5Ko5Q%2Fuploads%2FEDHKZSiyhDgpFQe90KHB%2FlinearAuctionChart.png?alt=media&amp;token=7b430256-3465-48ee-9951-d4dab7699c08" alt="" width="563"><figcaption><p>Abstract graph of the fee function.</p></figcaption></figure>

More precisely, the execution fee can be calculated as follows, where *t* is the number of seconds the job is within the execution window:

$$
fee(t) = \frac{(maxFee  - minFee) }{executionWindow - 1} \cdot (t - executionTime) + minFee
$$

Here $$fee(t)$$ is the execution fee and  $$t$$ is the UNIX time in seconds of the execution (measured as `block.timestamp` in the contract). This is not to be confused with $$executionTime$$ which is the time from which the job can be executed.


# PeggedLinearAuction

The `PeggedLinearAuction` fee module builds upon the same core ideas of [`LinearAuction`](/fee-modules/linearauction) but utilizes [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) and [EIP-3198](https://eips.ethereum.org/EIPS/eip-3198) to peg the execution fee to the current base fee. This fee module calculates the total gas cost of the execution, multiplies it with `block.basefee`  and uses a price oracle to convert the amount in ETH to the amount of the user specified execution fee token. During the execution window, `PeggedLinearAuction` performs a reverse dutch auction similarly to `LinearAuction` but over the percentage overhead from the calculated base fee in execution fee tokens. The overhead is represented in basis points (bps), such that 10000 bps corresponds to 100%.

<figure><img src="https://2488988847-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FotYFhyxmfp3Clnu5Ko5Q%2Fuploads%2FEtatSFSB0wdkS7gemDAL%2FpeggedLinearAuctionChart.png?alt=media&amp;token=c8702e1c-8375-4e55-b3ff-d048e69df788" alt="" width="563"><figcaption><p>Abstract chart of execution fee function.</p></figcaption></figure>

The overhead basis points as a function of time within execution mode is calculated as follows:

$$
overhead(t) = \frac{(maxBps  - minBps) }{executionWindow - 1} \cdot (t - executionTime) + minBps
$$

The fee function is then:

$$
fee(t) = \frac{overhead(t)}{10000} \cdot baseFee\_{feeToken}
$$

The input bytes to the `onCreateJob` function should follow the structure:

```solidity
address executionFeeToken;
uint48 minOverheadBps;
uint48 maxOverheadBps;
IPriceOracle priceOracle;
bytes memory oracleData;
```

`priceOracle` is a contract implementing `IPriceOracle` which will provide price data of the token. `oracleData` is arbitrary data which can be used by the price oracle.

{% hint style="info" %}
**Note:** Price oracles have the purpose of finding the price of the execution fee token in terms of ETH.
{% endhint %}

{% hint style="warning" %}
**Warning:** `PeggedLinearAuction`is only deployed on EVM chains supporting EIP-1559 and EIP-3198.
{% endhint %}


# Deployments

Coming soon.


# Guides

This section contains guides and examples of how to utilise the EES protocol in practise.&#x20;


# Create an application

In this section we will go through how to create an application on EES using a simple example of a contract for automated ERC-20 transfers. Along the way we will explore best practises and design patterns. However, we will not focus on gas optimization.

First, a reminder of the interface we have to implement:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IApplication {
    function onExecuteJob(uint256 _index, address _owner, uint48 _executionNumber) external;
    function onCreateJob(uint256 _index, address _owner, bool _ignoreAppRevert, uint24 _executionWindow, bytes1 _executionModule, bytes calldata _executionModuleInput, bytes calldata _applicationInput) external;
    function onDeleteJob(uint256 _index, address _owner) external;
}
```

The application we wish to create in this example fulfils the following specification:

* `onExecute`: transfers a specified amount of an ERC-20 token from the job owner to a recipient. Specifications are stored within the contract.
* `onCreateJob`: store state data for job index with given specification.
* `onDeleteJob`: deletes stored state data for job index.
* The `IApplication` callback functions should only be callable by the `JobRegistry` contract. This is important because the user gives our contract token permissions, so we want to make sure transfers only happen accordingly to the time restrictions defined in EES.

### Storage layout and constructor

The data we need to store for each job are the recipient of the transfer, the amount and the ERC-20 token to be transferred. Note that the owner of the job is given in all the callback functions, removing the necessity to store it. We will also use [solmate](https://github.com/transmissions11/solmate)'s `SafeTransferLib` library for safe ERC-20 token transfers.

```solidity
using SafeTransferLib for ERC20;
struct TransferData {
    address recipient;
    uint256 amount;
    address token;
}
```

In our contract, we are going to store a couple of things:

1. The `JobRegistry` contract so we can verify the caller.
2. A mapping from job index to a `TransferData` to keep track of the transfer specification for each job.

```solidity
// JobRegistry contract
JobRegistry public immutable jobRegistry;
// job index to data object
mapping(uint256 => TransferData) public transferDataMapping;
```

We will also create a modifier, restricting the caller of the implemented callback functions to the address of `JobRegistry`.

```solidity
modifier onlyJobRegistry() {
    require(msg.sender == address(jobRegistry), "NotJobRegistry");
    _;
} 
```

In the constructor we set the `jobRegistry` variable:

```solidity
constructor(JobRegistry _jobRegistry) {
    jobRegistry = _jobRegistry;
}
```

### Job creation

Now we can start implementing the first callback function, `onCreateJob`:

```solidity
function onCreateJob(uint256 _index, address /* _owner */, bool /* _ignoreAppRevert */, uint24 /* _executionWindow */, bytes1 /* _executionModule */, bytes calldata /* _executionModuleInput */, bytes calldata _applicationInput)
    external
    override
    onlyJobRegistry
{
    (address recipient, uint256 amount, address token) = abi.decode(_inputs, (address, uint256, address));
    TransferData memory transferData = TransferData({recipient: recipient, amount: amount, token: token});
    transferDataMapping[_index] = transferData;
}
```

The first line checks if the given execution module is supported and reverts if not. Then, we unpack the encoded `_applicationInput` bytes to the `recipient`, `amount` and `token` values which are stored in a new `TransferData` object. Finally, we add the `transferData` object in the `transferDataMapping` at `_index`. Notice that we only use the `_index` and `_applicationInput` arguments for this example. Let's quickly go over a few examples where these might be relevant:\
`_owner` could be relevant if wanted to do something specific to the creator of the job or simply emit an event that a recurring payment has been created from `_owner` to the recipient.

`_ignoreAppRevert` could be checked if we want to make sure that the recurring payment is canceled if it doesn't go through, e.g. by lack of funds.

`_executionWindow` could be relevant in this case if we want to make sure that payments fall within a certain time frame after they're due.

`_executionModule` can be used to restrict which execution modules we allow for this application, for example regular time intervals.

`_executionModuleInput` can be used to get information about the job's input to the execution module. For example if we only allow payments in a 30 day interval, we could enforce this by checking the `cooldown` parameter of the decoded `_executionModuleInput` in the case of RegularTimeInterval.

### Job deletion

Now, let us implement the `onDeleteJob` callback function:

```solidity
function onDeleteJob(uint256 _index, address /* _owner */) 
    external 
    override 
    onlyJobRegistry 
{
    delete transferDataMapping[_index];
}
```

This function doesn't do anything fancy, we simply delete the `TransferData` object corresponding to the index of the deleted job from `transferDataMapping`.&#x20;

### Job execution

Finally, let us implement the core logic that is executed upon the call to the `onExecuteJob` callback function:

```solidity
function onExecuteJob(uint256 _index, address _owner, uint48 /* _executionNumber */)
    external 
    override 
    onlyJobRegistry 
{
    TransferData memory transferData = transferDataMapping[_index];
    ERC20(transferData.token).safeTransferFrom(_owner, transferData.recipient, transferData.amount);
}
```

In here, we are simply doing an ERC-20 token transfer from the owner of the job to the recipient with the specified amount and token saved in `transferData`. We are not using the `_executionNumber` argument for anything in this example as we wish to perform the same ERC-20 transfer no matter how many times the job has been executed.

### The full contract

Putting it all together, we get the contract:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;

import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {IApplication} from "ees/interfaces/IApplication.sol";
import {JobRegistry} from "ees/core/JobRegistry.sol";

contract AutomatedTransfer is IApplication, Owned {
    using SafeTransferLib for ERC20;
    struct TransferData {
        address recipient;
        uint256 amount;
        address token;
    }

    JobRegistry public immutable jobRegistry;
    mapping(uint256 => TransferData) public transferDataMapping;

    modifier onlyJobRegistry() {
        require(msg.sender == address(jobRegistry), "NotJobRegistry");
        _;
    }

    constructor(JobRegistry _jobRegistry) Owned(msg.sender) {
        jobRegistry = _jobRegistry;
    }

    function onCreateJob(uint256 _index, address /* _owner */, bool /* _ignoreAppRevert */, uint24 /* _executionWindow */, bytes1 /* _executionModule */, bytes calldata /* _executionModuleInput */, bytes calldata _applicationInput)
        external
        override
        onlyJobRegistry
    {
        (address recipient, uint256 amount, address token) = abi.decode(_inputs, (address, uint256, address));
        TransferData memory transferData = TransferData({recipient: recipient, amount: amount, token: token});
        transferDataMapping[_index] = transferData;
    }

    function onDeleteJob(uint256 _index, address /* _owner */) 
        external 
        override 
        onlyJobRegistry
    {
        delete transferDataMapping[_index];
    }

    function onExecuteJob(uint256 _index, address _owner, uint48 /* _executionNumber */)
        external 
        override 
        onlyJobRegistry
    {
        TransferData memory transferData = transferDataMapping[_index];
        ERC20(transferData.token).safeTransferFrom(_owner, transferData.recipient, transferData.amount);
    }
}
```

Now we have successfully created an application for automated transfer of ERC-20 tokens checking all the specifications we wanted. By supporting any execution module and fee module, users can make both single scheduled and recurring jobs performing ERC-20 transfers using their own preferred fee structure. The EES protocol will take care of the rest and make sure the jobs get executed. Because we keep the set of supported execution modules modifiable, we can progressively support new execution modules with time.

{% hint style="danger" %}
**Careful:** This contract is not tested and should not be used in production. Always perform extensive testing and auditing on smart contracts containing critical logic.
{% endhint %}


# Sponsor jobs

In this guide we will take you through an example of sponsoring a job using ees-sdk, viem and Typescript. Going forward it is assumed that ees-sdk is installed and setup like shown [here](/sdk).&#x20;

As a real example, we will in this guide show how to sponsor a [Socialsub](https://www.socialsub.xyz/) job for a recurring payment using execution module [0x00 RegularTimeInterval](/execution-modules/regulartimeinterval) and fee module [0x01 LinearAuction](/fee-modules/linearauction) on [Base Sepolia](https://sepolia.basescan.org). The Socialsub application is depoyed at address `0xe1efEA15fe277A360bd9bE3e8860Ce5c508Ca938`.&#x20;

The execution module input values we wish to sponsor has the following values:

| Solidity type | Name                   | Value     |
| ------------- | ---------------------- | --------- |
| `uint32`      | `cooldown`             | `2592000` |
| `uint40`      | `initialExecutionTime` | `0`       |

Similarly, the fee module input values we wish to sponsor:

| Solidity Type | Name                | Value                                        |
| ------------- | ------------------- | -------------------------------------------- |
| `address`     | `executionFeeToken` | `0x7139F4601480d20d43Fa77780B67D295805aD31a` |
| `uint256`     | `minExecutionFee`   | `0`                                          |
| `uint256`     | `maxExecutionFee`   | `10000`                                      |

Finally, the application input values for the job we wish to sponsor has the values:

| Solidity type | Name        | Value                                        |
| ------------- | ----------- | -------------------------------------------- |
| `address`     | `recipient` | `0x303cAE9641B868722194Bd9517eaC5ca2ad6e71a` |
| `uint256`     | `amount`    | `1000000`                                    |
| `address`     | `token`     | `0x7139F4601480d20d43Fa77780B67D295805aD31a` |
| `uint96`      | `tierId`    | `0`                                          |

First, we are going to import some functions and types from ees-sdk and viem:

```typescript
import { JobSpecification } from 'ees-sdk';
import { encodeAbiParameters } from 'viem';
```

To create a sponsor signature for the said specification, we are going to use the [`signJobSpecificationSponsor`](/sdk/sponsor-job) function which takes an object of type `JobSpecification`. Before creating the object, we have to specify a nonce and a deadline. If `reusableNonce` in the `JobSpecification` is true, then the signature can be reused to create multiple with this specification until the nonce is invalidated on-chain. Otherwise, the nonce will be consumed and the signature can only be used once. In the latter case, we should use a new nonce for each signature. The deadline specifies when the signature expires. In this example we will just use nonce 0 and the maximum uint256 value as deadline (no deadline in practice).

```typescript
const jobSpecification: JobSpecification = {
    nonce: 0n,
    deadline: BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
    application: "0x7d337f7452fb892D7DAdfb4f7c02249DDAc41d4E",
    executionWindow: 1800, // 30 minutes
    zeroFeeWindow: 0,
    maxExecutions: 0,
    reusableNonce: false,
    sponsorFallbackToOwner: false,
    sponsorCanUpdateFeeModule: false,
    ignoreAppRevert: false,
    executionModule: "0x00",
    feeModule: "0x01",
    executionModuleInput: encodeAbiParameters(
      [
          {name: 'cooldown', type: 'uint32'},
          { name: 'initialExecutionTime', type: 'uint40' }
      ],
      [2592000, 0]
    ),
    feeModuleInput: encodeAbiParameters(
       [
          { name: 'executionFeeToken', type: 'address' },
          { name: 'minExecutionFee', type: 'uint256' },
          { name: 'maxExecutionFee', type: 'uint256' }
      ],
      ["0x7139F4601480d20d43Fa77780B67D295805aD31a", 0n, 10000n]
    ),
    applicationInput: encodeAbiParameters(
      [
          { name: 'recipient', type: 'address' },
          { name: 'amount', type: 'uint256' },
          { name: 'token', type: 'address' },
          { name: 'tierId', type: 'uint96' }
      ],
      ["0x303cAE9641B868722194Bd9517eaC5ca2ad6e71a", 1000000n, "0x7139F4601480d20d43Fa77780B67D295805aD31a", 0n]
    )
  }
```

Now we can utilize the `signJobSpecificationSponsor` function from ees-sdk:

```typescript
const signature: `0x${string}` = await eesSdk.signJobSpecificationSponsor(jobSpecification);
```

And voila, now we have successfully generated an EIP-712 signature which can be used as input to creating a job through the `JobManager` contract.

{% hint style="info" %}
**Tip:** In practice you can uniformly sample a random number between `0` and `2^256 - 1` for the nonce. Because the sample space is so large, the probability of generating two signatures with the same nonce is vanishingly small.
{% endhint %}

{% hint style="warning" %}
**Warning:** Be careful handling ERC-20 token amounts. The signed amounts are using full integer precision according to the number of decimals of the token. In this example, the `maxExecutionFee` of `10000` correspond to `0.01` in decimal form since the fee token uses 6 decimals in this example. Viem's `parseUnits` and `formatUnits` functions can be utilized to convert between the two formats.
{% endhint %}

{% hint style="danger" %}
**Careful**: Be sure to only sign job specifications with `reusableNonce=true` if you intend an unlimited number of users to be able to create jobs with this specification using you as sponsor.
{% endhint %}


# Build an executor bot

This page will go over some concepts which are important when building an EES executor bot, whether it be for profit or to ensure processing of jobs related to your own application. A comprehensive guide is in the works.

## Execution module specific logic

Execution modules determine crucial information such as:

* when the job can be executed
* who can execute the job
* how much the execution fee will be
* the execution fee token

All of these are necessary to avoid failed or unprofitable transactions. Since each execution module contains its own rules, it is important to implement custom logic to each of those you wish to support.

## Off-chain computation

All information necessary to determine if a job is profitable and can be executed is stored inside the job's execution module. Execution module data is stored as `Param` structs inside the `params` mapping. To avoid unnecessary RPC calls it can be advantageous to query the state once and update it locally by listening for events.

## Listen for events

Events emitted from the `JobRegistry` contract will tell when a job is created, executed or deleted. It is also beneficial to listen for execution module specific events such as if the fee function has changed.

## Parallelisation

Since all jobs are stored in the public `jobs` array, execution can easy be parallelised. The array can simply be split into even sections that each executor bot takes care of.

## Executing in batches

The `executeBatch` function of the `Coordinator` contract enables you to execute multiple jobs in a single transaction. The transaction will not revert even if one or more single job executions revert. This protects you from having your whole batch reverted because someone executed a single job from that batch faster than you. It also helps you save gas fees and makes transaction nonce management easier.

## Correct for execution tax

An executor *always* has to pay execution tax per execution. It is therefore crucial to implement into your calculations to know when a job is profitable to execute or not. The specific amount is stored on-chain and should be queried in intervals or listen for events to see if this changes.

## Strict gas price monitoring

Strict gas price monitoring is crucial to implementing a profitable executor bot. The profit you can make on executing a specific job is primarily depending on the current gas price together with how large the received execution fee is. Having live gas monitoring will give you an edge over other executor bots.

## Stay online

As an active executor, you will be designated for rounds once in a while. It is important to stay online and look out for when this happens, since failing to check-in via the `executeBatch` function on the `Coordinator` contract will result in slashing.


# EES DAO

The EES protocol is meant to be community-owned and community governed through a DAO. All protocol earnings will go to the DAO and be split between protocol R\&D, funding projects building on EES and rewarding the community members of the DAO. R\&D mostly consists of designing and implementing new modules and building periphery infrastructure and tools around the protocol.

More information and plans for the DAO will come later.


# SDK

### Overview <a href="#overview" id="overview"></a>

The EES SDK is a Node library to interact with the EES protocol in a typescript/javascript environment. It is built with [viem](https://viem.sh/) and contains functionality that makes it easy to query data from and interact with the EES contracts among other features. The implementation can be found [here](https://github.com/victorbrevig/sub2-sdk).

Interactions requiring querying on-chain data require the user to supply a viem public client. Some functionality like executing a job or generating a sponsor signature requires the user to additionally supply a viem wallet client.

### Installation and setup <a href="#installation-and-setup" id="installation-and-setup"></a>

The SDK can be installed through npm.

```
npm i --save ees-sdk
```

After installation, the SDK contains a class called EESSDK which can be initialized as follows:

{% tabs %}
{% tab title="index.ts" %}

```typescript
import { EESSDK } from 'ees-sdk';
import { publicClient, walletClient } from "./config";

const eesSDK = new EESSDK(publicClient, walletClient);
```

{% endtab %}

{% tab title="config.ts" %}

```typescript
import { createPublicClient, createWalletClient, http, PublicClient, WalletClient } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';

export const publicClient: PublicClient = createPublicClient({
  chain: baseSepolia,
  transport: http('YOUR_RPC_URL')
}) as PublicClient;

export const walletClient: WalletClient = createWalletClient({
  account: privateKeyToAccount('YOUR_PRIVATE_KEY'),
  chain: baseSepolia,
  transport: http('YOUR_RPC_URL')
});
```

{% endtab %}
{% endtabs %}

Now you are ready to start interacting with EES!

{% hint style="danger" %}
**Warning:** Make sure to replace `YOUR_PRIVATE_KEY` and `YOUR_RPC_URL` with your own private key and RPC url. Remember to never store these in plain text in your project.&#x20;
{% endhint %}

{% hint style="info" %}
**Note:** The EES protocol is currently only deployed on the Base Sepolia network.
{% endhint %}


# Types

The Typescript type definitions used in ees-sdk are shown here:

```typescript
export interface Job {
  index: bigint;
  owner: `0x${string}`,
  sponsor: `0x${string}`,
  active: boolean,
  ignoreAppRevert: boolean,
  inactiveGracePeriod: number,
  application: `0x${string}`,
  executionWindow: number,
  executionCounter: number,
  maxExecutions: number,
  executionModuleCode: `0x${string}`,
  feeModuleCode: `0x${string}`,
  executionModule: RegularTimeInterval,
  feeModule: LinearAuction,
  nextExecution: bigint
}

export interface JobSpecification {
  nonce: bigint,
  deadline: bigint,
  application: `0x${string}`,
  executionWindow: number,
  maxExecutions: number,
  inactiveGracePeriod: number,
  ignoreAppRevert: boolean,
  executionModule: `0x${string}`,
  feeModule: `0x${string}`,
  executionModuleInput: `0x${string}`,
  feeModuleInput: `0x${string}`,
  applicationInput: `0x${string}`
}

export interface FeeModuleInput {
  nonce: bigint,
  deadline: bigint,
  index: bigint,
  feeModule: `0x${string}`,
  feeModuleInput: `0x${string}`
}

export interface EpochInfo {
  epoch: bigint,
  epochPeriod: [bigint, bigint],
  seed: `0x${string}`,
  numberOfActiveExecutors: number,
  commitPhasePeriod: [bigint, bigint],
  revealPhasePeriod: [bigint, bigint],
  roundPeriods: [bigint, bigint][],
  roundBufferPeriods: [bigint, bigint][],
  slashingPhasePeriod: [bigint, bigint],
  selectedExecutors: `0x${string}`[]
}

export interface ExecutorInfo {
  balance: bigint;
  active: boolean;
  initialized: boolean;
  arrayIndex: number;
  lastCheckinRound: number;
  lastCheckinEpoch: bigint;
  stakingTimestamp: bigint;
}

export interface CommitData {
  executor: `0x${string}`,
  commitment: `0x${string}`,
  epoch: bigint,
  revealed: boolean
}

export interface RegularTimeInterval {
  lastExecution: number,
  cooldown: number
}

export interface LinearAuction {
  executionFeeToken: `0x${string}`,
  minExecutionFee: bigint,
  maxExecutionFee: bigint
}

export interface ProtocolConfig {
  jobRegistry: `0x${string}`,
  executionManager: `0x${string}`,
  querier: `0x${string}`,
  batchSlasher: `0x${string}`,
  executionGasOverhead: bigint,
  executionModulesLength: bigint,
  feeModulesLength: bigint,
  stakingToken: `0x${string}`,
  stakingAmount: bigint,
  minimumStakingPeriod: bigint,
  stakingBalanceThreshold: bigint,
  inactiveSlashingAmount: bigint,
  commitSlashingAmount: bigint,
  roundsPerEpoch: number,
  executorTax: bigint,
  protocolTax: bigint,
  roundDuration: number,
  roundBuffer: number,
  slashingDuration: number,
  commitPhaseDuration: number,
  revealPhaseDuration: number,
  selectionPhaseDuration: number,
  totalRoundDuration: number,
  epochDuration: number
}
```


# Query jobs

Here is an example of how to query jobs given their respective index using ees-sdk. As mentioned [here](/concepts/jobs-and-registry), jobs are stored in one public array called `jobs` and are uniquely identified by their index in the array. Assuming ees-sdk is installed and initialised like shown [here](/sdk), we can query jobs as follows:

```typescript
import { Job } from 'ees-sdk';

const jobs: Job[] = await eesSDK.getJobs(indices);
```

Here, `indices` has type `bigint[]`.The `getJobs` function returns a promise with a `Job[]` array. The the `Job` object contains information stored in the `JobManager` contract as well as the stored information in the associated execution module and can be found [here](/sdk/types).

{% hint style="info" %}
**Note:** Application data associated with the job index can be completely arbitrary. Thus it is necessary to look how each applciation is structured.
{% endhint %}


# Execute batch

The ees-sdk allows you to execute a batch using the `BatchExecutor` contract.

```typescript
const transactionReceipt: TransactionReceipt = await eesSDK.executeBatch(indices, feeRecipient);
```

Here `indices` is of type `bigint[]` and specifies the indices of jobs to execute. The `feeRecipient` is of type `0x${string}` and is the address that the execution fee will be sent to for all jobs in the batch. The returned value of viem's type `TransactionReceipt` gives information about the transaction.

The transaction sent by `executeBatch` will not revert if any of the individual jobs revert during execution. This means that the execution of the other jobs will still go through.

{% hint style="warning" %}
**Warning:** This action will perform an on-chain transaction and requires that the eesSDK object was initialised with a wallet client.
{% endhint %}


# Create job

The ees-sdk makes it easy to create jobs.

```typescript
const transactionReceipt: `0x${string}` = await eesSDK.createJob(jobSpecification, sponsor, sponsorSignature, hasSponsorship, index);
```

Here `jobSpecification` has type [`JobSpecification`](/sdk/types). The `sponsor` field has type `` `0x{string}` `` and is the sponsor address of the job. The `sponsorSignature` has type `` `0x{string}` `` and is an EIP-712 signature of `jobSpecification` signed by the `sponsor`. Next, `hasSponsorship` has type boolean and is a flag that indicates whether the job should be created with a sponsorship. Finally, `index` is the index in the jobs array in which the job should be created. The function returns `transactionReceipt` of viem's type `TransactionReceipt` containing information about the transaction.

{% hint style="warning" %}
**Warning:** If `index < jobs.length`, the job will *reuse* an existing index in the array. This can only be done if the job at that index is cancelled, i.e. if the `owner` field is set to the zero address. Otherwise if `index >= jobs.length`, this operation will extend the `jobs` array. Reusing an index is cheaper gas wise but will revert if the index is not free.
{% endhint %}

{% hint style="info" %}
**Note:** If `hasSponsorship` is set to true, the `sponsor` and `sponsorSignature` will not be considered and arbitrary values can be given. The same is true for the `nonce` and `deadline` fields of the `jobSpecification` object.
{% endhint %}

{% hint style="warning" %}
**Warning:** This action will perform an on-chain transaction and requires that the eesSDK object was initialised with a wallet client.
{% endhint %}


# Delete job

The ees-sdk makes it easy to delete a job given it's index.

```typescript
const transactionReceipt: TransactionReceipt = await eesSDK.deleteJob(index);
```

Here `index` is of type `bigint` and specifies the index of job to delete. The returned value of viem's type `TransactionReceipt` gives information about the transaction.

{% hint style="warning" %}
**Warning:** Deletion of a job is restricted to the owner unless the job is expired which is determined by it's execution module.
{% endhint %}

{% hint style="warning" %}
**Warning:** This action will perform an on-chain transaction and requires that the eesSDK object was initialised with a wallet client.
{% endhint %}


# Sponsor job

The ees-sdk makes it easy to generate an EIP-712 signature required to sponsor a job. As mentioned [here](/concepts/sponsored-jobs), sponsoring a subscription means that all execution fees associated with execution of the job are paid by you.

```typescript
const signature: `0x${string}` = await eesSDK.generateSponsorSignature(jobSpecification);
```

Here `jobSpecification` has type [`JobSpecification`](/sdk/types). The returned value is an EIP-712 signature which can be used as input to creating a job.

{% hint style="info" %}
**Note:** A signature can only be redeemed by a single job. Providing an already redeemed signature when creating a job will cause the transaction to revert.
{% endhint %}

{% hint style="info" %}
**Note:** This action does not perform an on-chan transaction but still requires that `eesSDK` was initialised with a wallet client.
{% endhint %}


# Revoke sponsorship

You can revoke your sponsorship of a job with the ees-sdk.

```typescript
const transactionReceipt: TransactionReceipt = await eesSDK.revokeSponsorship(index);
```

Here `index` is of type `bigint` and specifies the index of job to revoke sponsorship for. The returned value of viem's type `TransactionReceipt` gives information about the transaction.

{% hint style="warning" %}
**Warning:** This action can only be performed if the caller is the sponsor of the job at the given index.
{% endhint %}

{% hint style="warning" %}
**Warning:** This action will perform an on-chain transaction and requires that the eesSDK object was initialised with a wallet client.
{% endhint %}


# Listen for created jobs

The ees-sdk provides the ability to listen for created jobs&#x20;


# EES Subgraph

Coming soon.


# Technical reference

The technical reference covers the technicalities of interacting with the EES protocol.


# API

This goes over all the ways to interact with the EES core and periphery contracts.


# Core


# JobRegistry

This page covers technical information on the JobRegistry contract.

## Events

### JobCreated

```solidity
event JobCreated(uint256 indexed index, address indexed owner, address indexed application, bool initialExecution)
```

Emitted when a job is created via [createJob](#createjob).

### JobDeleted

<pre class="language-solidity"><code class="lang-solidity"><strong>event JobDeleted(uint256 indexed index, address indexed owner, address indexed application, bool applicationRevertedOnDelete)
</strong></code></pre>

Emitted when a job is deleted via [deleteJob](#deletejob).

### JobDeactivated

```solidity
event JobDeactivated(uint256 indexed index, address indexed owner, address indexed application);
```

Emitted when a job is deactivated via [deactivateJob](#deactivatejob).

### JobExecuted

```solidity
event JobExecuted(uint256 indexed index, address indexed owner, address indexed application, bool success, uint48 executionNumber, uint256 executionFee, address executionFeeToken, bool inZeroFeeWindow);
```

Emitted when a job is executed via [execute](#execute).

### FeeModuleUpdate

```solidity
event FeeModuleUpdate(uint256 indexed index, address indexed owner, address indexed sponsor, bytes1 feeModule);
```

Emitted when the fee module data is updated or a migration to a new fee module for a job via [updateFeeModule](#updatefeemodule).

### SponsorshipRevoked

```solidity
event SponsorshipRevoked(uint256 indexed index, address indexed owner, address indexed newSponsor, address oldSponsor);
```

Emitted when the sponsor of a job revokes the sponsorship via [revokeSponsorship](#revokesponsorship).

## State-changing functions

### createJob

```solidity
function createJob(JobSpecification calldata _specification, address _sponsor, bytes calldata _sponsorSignature, bytes calldata _ownerSignature, uint256 _index) external returns (uint256 index);
```

Creates a new job according to the `_specification`. This call will make external `onCreateJob` calls to the specified execution module, fee module and application. Both `_sponsorSignature` and `_ownerSignature` are EIP-712 signatures of the `_specification`. The function supports ERC-1271 and ERC-6492 verification of signatures.

#### Arguments

| Name                | Type                        | Description                                                                                                                                       |
| ------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_specification`    | `JobSpecification calldata` | Specification of the job containing, execution module, fee module, application and initialization data to these, as well as general job settings. |
| `_sponsor`          | `address`                   | Address of the sponsor. The zero address means no sponsor set.                                                                                    |
| `_sponsorSignature` | `bytes calldata`            | An EIP-712 signature of the `_specification`, signed by `_sponsor`.                                                                               |
| `_ownerSignature`   | `bytes calldata`            | An EIP-712 signature of `_specification`, signed by `_specification.owner`.                                                                       |
| `_index`            | `uint256`                   | Index in the `jobs` array where the job is intended to be created.                                                                                |

#### Notes

* If `_index` is greater or equal to the current length of the `jobs` array, then the job will be created at the last index expanding the `jobs` array. Otherwise it will try to reuse the existing slot at `_index` succeeding if the current job at that index is expired or has been deleted. Otherwise, it falls back to expanding the array.&#x20;
* If the caller is the `owner` of the `_specification` then the `_ownerSignature` is not considered.
* If the `_sponsor` is the zero address, then the `_sponsorSignature` is not considered.
* The sponsor will be set as the payer of execution fees and should thus have approved fee tokens to the `JobRegistry` contract.
* The job may execute immediately as decided by the execution module and `_specification.executionModuleInput`. In this case the application will be executed and the execution counter is incremented. If the application call reverts, then the `createJob` call also reverts.
* Having both `_specification.sponsorFallbackToOwner` and `_specification.sponsorCanUpdateFeeModule` true at the same time should be prevented as the sponsor can update the fee module setting an exceedingly large fee and then withdraw their sponsorship, falling back to the owner.

Emits [JobCreated](#jobcreated) and possibly [JobExecuted](#jobexecuted).

### execute

```solidity
function execute(uint256 _index, address _feeRecipient) external returns (uint256 executionFee, address executionFeeToken, uint8 executionModule, uint8 feeModule, bool inZeroFeeWindow)
```

Executes a job, making external `onExecuteJob` calls to the execution module, fee module and application associated with the job. It also handles transferring of execution fees.

#### Arguments

| Name            | Type      | Description                                              |
| --------------- | --------- | -------------------------------------------------------- |
| `_index`        | `uint256` | The index of the job to be executed in the `jobs` array. |
| `_feeRecipient` | `address` | Address that execution fees are transferred to.          |

#### Return data

| Name                | Type      | Description                                                         |
| ------------------- | --------- | ------------------------------------------------------------------- |
| `executionFee`      | `uint256` | Number of `executionFeeToken` that are transferred to `_recipient`. |
| `executionFeeToken` | `address` | Address of the ERC-20 token the execution fee is transferred in.    |
| `executionModule`   | `uint8`   | Identifier of the executed job's execution module.                  |
| `feeModule`         | `uint8`   | Identifier of the executed job's fee module.                        |
| `inZeroFeeWindow`   | `bool`    | A flag telling if the job is in zero fee window.                    |

#### Notes

* Can only be called by [`coordinator`](/technical-reference/api/core/coordinator).&#x20;
* If the `sponsorFallbackToOwner` field of the job is true, it will try to transfer the fee from the owner if transferring from the sponsor fails. If the owner transfer succeeds, the owner is set as sponsor.
* May deactivate the job if application reverted and the `ignoreAppRevert` property of the job is false or if `maxExecutions` of the job is reached.
* Only increments the job's `executionCounter` upon successful execution of application (even when `ignoreAppRevert` is true).

Emits [JobExecuted](#jobexecuted).

### deleteJob

```solidity
function deleteJob(uint256 _index) external;
```

Deletes the job from the `jobs` array and externally calls `onDeleteJob` on the associated execution module, fee module and application.

#### Arguments

| Name     | Type      | Description                                         |
| -------- | --------- | --------------------------------------------------- |
| `_index` | `uint256` | Index in the `jobs` array of the job to be deleted. |

#### Notes

* Can only be called by the owner of the job.
* Will not revert of application's `onDeleteJob` call reverts.

Emits [JobDeleted](#jobdeleted).

### deactivateJob

```solidity
function deactivateJob(uint256 _index) external;
```

Deactivates a job, preventing it from being executed, but keeps the job in storage.

#### Arguments

| Name     | Type      | Description                                             |
| -------- | --------- | ------------------------------------------------------- |
| `_index` | `uint256` | Index in the `jobs` array of the job to be deactivated. |

#### Notes

* Can only be called by the owner of the job.
* Sets `activate` field of the job to false.
* Does *not* perform any external calls to modules or application.

Emits [JobDeactivated](#jobdeactivated).

### revokeSponsorship

```solidity
function revokeSponsorship(uint256 _index) external;
```

Revokes sponsorship of a job, alternating the `sponsor` field of the job.

#### Arguments

| Name     | Type      | Description                                                     |
| -------- | --------- | --------------------------------------------------------------- |
| `_index` | `uint256` | Index in the `jobs` array of the job to revoke sponsorship for. |

#### Notes

* Can only be called by the owner *or* the sponsor of the job.
* If called by the owner, the owner is set as the new sponsor.
* If called by the sponsor, the owner is set as sponsor if the `sponsorFallbackToOwner` of the job is set to true, otherwise it sets the zero address as sponsor. Note that in this case, if the job owner does not find a new sponsor or chose to sponsor themselves before the next execution window is over, then the job will expire.

Emits [SponsorshipRevoked](#sponsorshiprevoked).

### updateFeeModule

```solidity
function updateFeeModule(FeeModuleInput calldata _feeModuleInput, address _sponsor, bytes calldata _sponsorSignature) external;
```

Updates current fee module data or migrates to a different fee module. This function supports EIP-1271 and EIP-6492.

#### Arguments

|                     |                           |                                                                                    |
| ------------------- | ------------------------- | ---------------------------------------------------------------------------------- |
| `_feeModuleInput`   | `FeeModuleInput calldata` | Contains information about the new fee module as well as input data to the module. |
| `_sponsor`          | `address`                 | Address of the new sponsor of the job.                                             |
| `_sponsorSignature` | `bytes calldata`          | EIP-712 signature of the `_feeModuleInput`.                                        |

#### Notes

* Can only be called by the owner of the job, unless the `sponsorCanUpdateFeeModule` field of the job is true, then the sponsor can also call this function.
* Cannot be called while the job is in execution window.
* If the fee module code is the same as the current one, the fee module data is updated calling `onUpdateData` on the existing fee module.
* If the fee module code differs from the current one, a migration to the new fee module happens. Here, `onDeleteJob` is called on the old fee module and `onCreateJob` is called on the new fee module.

Emits [FeeModuleUpdate](#feemoduleupdate).

## Read-only functions

### getJobsArrayLength

```solidity
function getJobsArrayLength() external view returns (uint256 length)
```

Returns the length of the `jobs` array.

#### Return data

| Name     | Type      | Description                 |
| -------- | --------- | --------------------------- |
| `length` | `uint256` | Length of the `jobs` array. |


# Coordinator

This page covers technical information on the Coordinator contract.

## Events

### BatchExecution

```solidity
event BatchExecution(uint8 jobRegistryIndex, uint256 standardTax, uint256 zeroFeeTax, bool inRound)
```

Emitted upon batch execution of jobs via executeBatch.

### EpochInitiated

```solidity
event EpochInitiated(uint192 epoch, uint256 previousEpochPoolDistributed, uint256 protocolCut)
```

Emitted upon initiation of an epoch via initiateEpoch.

### CheckIn

```solidity
event CheckIn(address indexed executor, uint192 indexed epoch, uint8 round)
```

Emitted upon an executor checking in via executeBatch.

### Commitment

```solidity
event Commitment(address indexed executor, uint192 indexed epoch)
```

Emitted upon an executor committing to an epoch via commit.

### Reveal

```solidity
event Reveal(address indexed executor, uint192 indexed epoch, bytes32 newSeed)
```

Emitted upon an executor revealing their commitment for an epoch via reveal.

### InactiveExecutorSlashed

```solidity
event SlashInactiveExecutor(address indexed executor, address indexed slasher, uint192 indexed epoch, uint8 round, uint256 amount)
```

Emitted upon slashing of an executor who did not check in upon designation of a round in an epoch. Is emitted in slashInactiveExecutor.

### CommitterSlashed

```solidity
event SlashCommitter(address indexed executor, address indexed slasher, uint192 indexed epoch, uint256 amount)
```

### ExecutorActivated

```solidity
event ExecutorActivated(address indexed executor)
```

Emitted when an executor is activated. Is emitted in stake and may be emitted in topup.

### ExecutorDeactivated

```solidity
event ExecutorDeactivated(address indexed executor)
```

Emitted when an executor is deactivated. Is emitted in unstake and may be emitted from executeBatch,, slashCommitter and slashInactiveExecutor.

### ModulesRegistered

```solidity
event ModulesRegistered(address indexed executor, uint256 indexed modulesBitset)
```

Emitted upon executor registration of modules via stake and registerModules.

### ModulesDeregistered

```solidity
event ModulesDeregistered(address indexed executor, uint256 indexed modulesBitset)
```

Emitted upon executor deregistration of modules via unstake and deregisterModules.

## State-changing functions

### executeBatch

```solidity
function executeBatch(uint256[] calldata _indices, uint256[] calldata _gasLimits, address _feeRecipient, uint8 _jobRegistryIndex) external returns (uint256 standardTax, uint256 zeroFeeTax, uint96 successfulExecutions)
```

Executes a batch of jobs within a given job registry, transferring execution fees to the `_feeRecipient` and pays execution tax from the callers account. During designated rounds, only the designated executor for that round can execute jobs with both execution module and fee module supported by that executor. Furthermore, designated executors will check in on this call, preventing potential slashing. Lastly, the number of executions where standard execution tax applies is counted and stored for pool reward distribution during initateEpoch.

#### Arguments

| Name                | Type                 | Description                                                                                                                                |
| ------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `_indices`          | `uint256[] calldata` | Indices within the job registry of the jobs to be executed.                                                                                |
| `_gasLimits`        | `uint256[] calldata` | Gas limits for each `execute` calls within the job registry. Each gas limit correspond to the index in `_indices` at the same array index. |
| `_feeRecipient`     | `address`            | Address which the execution fees are transferred to.                                                                                       |
| `_jobRegistryIndex` | `uint8`              | Identifier for the job registry contract to execute jobs within.                                                                           |

#### Return data

| Name                   | Type      | Description                                                        |
| ---------------------- | --------- | ------------------------------------------------------------------ |
| `standardTax`          | `uint256` | Accumulated tax paid for executing jobs not in zero fee window.    |
| `zeroFeeTax`           | `uint256` | Accumulated tax paid for jobs in zero fee window.                  |
| `successfulExecutions` | `uint96`  | Total number of job executions where the execution did not revert. |

#### Notes

* If the caller is an initialized executor, the tax is withdrawn from the internal staking balance, otherwise it is transferred via a ERC-20 transferFrom call. In the latter case, the caller should have given the Coordinator token permissions to cover the execution tax (both standard and zero fee tax).
* If the caller is an active executor, the executor will be deactivated if their balance after paying execution taxes goes below the `stakingBalanceThresholdPerModule` times the number of registered modules.
* The total tax taken consists of `executionTax * a + zeroFeeExecutionTax * b` where `a` is the number of successful executions of jobs not in zero fee window and `b` is the number of successful jobs in zero fee window.

Emits [BatchExecution](#batchexecution) and potentially [CheckIn](#checkin) and [ExecutorDeactivated](#executordeactivated).

### stake

```solidity
function stake(uint256 _modulesBitset) external returns (uint256 stakingAmount)
```

Staking tokens to register for modules and thereby activating the caller as an executor.

#### Arguments

| Name             | Type      | Description                                                                                                                                                     |
| ---------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_modulesBitset` | `uint256` | A bitset containing 1's a the positions corresponding to the module numbers to register for. For example `000...0101 = 5` means registering for module 0 and 2. |

#### Return data

| Name            | Type      | Description                                          |
| --------------- | --------- | ---------------------------------------------------- |
| `stakingAmount` | `uint256` | Total number of tokens  transferred from the caller. |

#### Notes

* Cannot be called during alternating open competition and designated rounds and during slashing window phase of an epoch.
* Requires registration of at least two modules. If caller does not register for at least one execution module and one fee module then they will not be able to execute any jobs during designated rounds.
* Cannot be called if the caller is already an initialized executor.
* The exact amount staked (`stakingAmount`) is `stakingAmountPerModule` times the number modules to register. The staking token is `stakingToken`.
* Caller has to approve at least the staking amount of tokens to the Coordinator contract.

Emits [ExecutorActivated](#executoractivated) and [ModulesRegistered](#modulesregistered).

### unstake

```solidity
function unstake() external
```

Unstakes the caller, deregistering modules, deactivating the executor if it is active and transferring internal executor balance to the caller. After unstaking all executor data is deleted and the caller executor be slashed going further.

#### Notes

* Cannot be called during reveal phase, alternating open competition and designated rounds and during slashing window.
* Can only be called when the minimum registration period is over. That is, at least `minimumRegistrationPeriod` seconds has to have passed since the last registration of a module via [stake](#stake) or registerModules.

Emits [ModulesDeregistered](#modulesderegistered) and potentially [ExecutorDeactivated](#executordeactivated).

### topup

```solidity
function topup(uint256 _amount) external
```

Tops up the internal balance of the caller with the `_amount` if they are an initialized executor and activates the executor if they were previously inactive.

#### Arguments

| Name      | Type      | Description                                 |
| --------- | --------- | ------------------------------------------- |
| `_amount` | `uint256` | The amount of tokens to top up the balance. |

#### Notes

* Cannot be called during alternating open competition and designated rounds and during slashing window phase of an epoch.
* Can only be called if the caller is an initialized executor.
* Topup amount has to be enough such that the final is balance is at least `stakingAmountPerModule` times the number of registered modules.

Potentially emits [ExecutorActivated](#executoractivated).

### slashInactiveExecutor

```solidity
function slashInactiveExecutor(address _executor, uint8 _round, address _recipient) external
```

Slashes an executor that did not check in for a designated round during the current epoch, sending half of the slashing rewards to the executor.

#### Arguments

| Name         | Type      | Description                                              |
| ------------ | --------- | -------------------------------------------------------- |
| `_executor`  | `address` | The address of the executor to slash.                    |
| `_round`     | `uint8`   | The round number to slash the executor for.              |
| `_recipient` | `address` | The recipient to transfer the slashing reward tokens to. |

#### Notes

* Can only be called during the slashing window of an epoch.
* Can only slash an executor who was designated for `_round` during the current epoch but did not check in during this round.
* The exact slashing amount is `inactiveSlashingAmountPerModule` times the number of registered modules by the executor. Half of this amount is transferred to the `_recipient` and half goes to the protocol.
* If `_recipient` is an initialized executor, the executor's internal balance is increased, otherwise an ERC-20 transfer will happen.
* The slashed executor will be deactivated if their balance after slashing goes below the `stakingBalanceThresholdPerModule` times the number of registered modules.

Emits [InactiveExecutorSlashed](#inactiveexecutorslashed) and potentially [ExecutorDeactivated](#executordeactivated).

### slashCommitter

```solidity
function slashCommitter(address _executor, address _recipient) external
```

Slashes an executor that did committed without revealing during the current epoch, sending half of the slashing rewards to the executor.

#### Arguments

| Name         | Type      | Description                                              |
| ------------ | --------- | -------------------------------------------------------- |
| `_executor`  | `address` | The address of the executor to slash.                    |
| `_recipient` | `address` | The recipient to transfer the slashing reward tokens to. |

#### Notes

* Can only be called during the slashing window of an epoch.
* Can only slash an executor who committed via the commit function without calling reveal during the current epoch.
* The exact slashing amount is `commitSlashingAmountPerModule` times the number of registered modules by the executor. Half of this amount is transferred to the `_recipient` and half goes to the protocol.
* If `_recipient` is an initialized executor, the executor's internal balance is increased, otherwise an ERC-20 transfer will happen.
* The slashed executor will be deactivated if their balance after slashing goes below the `stakingBalanceThresholdPerModule` times the number of registered modules.

Emits [CommitterSlashed](#committerslashed) and potentially [ExecutorDeactivated](#executordeactivated).

### initiateEpoch

```solidity
function initiateEpoch() external
```

Initiates a new epoch, distributing pool rewards to previous epoch's designated executors. It also sets the seed of the new epoch.

#### Notes

* Can only be called after the previous epoch has finished.
* Takes protocol cut of `epochPoolBalance` before it is distributed.
* Distributes the remaining of `epochPoolBalance` to designated executors of the previous epoch (the current epoch before initiating a new one) as follows:\
  The executor is rewarded by `maxRewardPerExecution` times the number of execution during their designated rounds (not counting zero fee executions). However this amount is capped by the executors proportional share of the remaining pool balance, i.e. if the executor is designated 2 out of 5 rounds, then their reward is capped by 2/5ths of the remaining pool balance.

Emits [EpochInitiated](#epochinitiated).

### commit

```solidity
function commit(bytes32 _commitment) external
```

Commits to an ERC-191 signature of the current epoch number and chain ID to participate in seed shuffling. It stores the commitment on-chain.

#### Arguments

| Name          | Type      | Description                                                                                                     |
| ------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
| `_commitment` | `bytes32` | A keccak256 hash of an ERC-191 signature of the current epoch number and chain ID packed, signed by the caller. |

#### Notes

* Can only be called during the commitment phase of an epoch.
* Can only be called by an active executor.
* If the executor commits and does not [reveal](#reveal-1) during the same epoch, they are subject to slashing via [slashInactiveExecutor](#slashinactiveexecutor).

Specifically, `_commitment` is:

```
keccak256(encodePacked("\x19EthereumSignedMessage:\32", keccak256(encodePacked(epochNumber, chainID))))
```

Where `epochNumber` is the current epoch number and `chainID` is the ID of the chain of the Coordinator contract. The `_commitment` is this hash signed by the executors private key.

Emits [Commitment](#commitment).

### reveal

```solidity
function reveal(bytes calldata _signature) external
```

Reveals the ERC-191 signature that was committed to via [commit](#commit), and uses the signature to shuffle the epoch seed.&#x20;

#### Arguments

| Name         | Type    | Definition                                                                                                   |
| ------------ | ------- | ------------------------------------------------------------------------------------------------------------ |
| `_signature` | `bytes` | The ERC-191 signature of the epoch number and chain ID committed to in the same epoch via [commit](#commit). |

#### Notes

* Can only be called in the reveal phase of the epoch.
* Can only be called by an active executor who has called [commit](#commit) during the same epoch.
* Shuffles the seed of the current epoch by keccak256 hashing the current seed together with the `_signature`.

Emits [Reveal](#reveal).

### registerModules

```solidity
function registerModules(uint256 _modulesBitset) external returns (uint256 stakingAmount) 
```

Registers modules and stakes tokens proportional to the number of modules registered.

#### Arguments

| Name             | Type      | Description                                                                                                                                                     |
| ---------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_modulesBitset` | `uint256` | A bitset containing 1's a the positions corresponding to the module numbers to register for. For example `000...0101 = 5` means registering for module 0 and 2. |

#### Return data

| Name            | Type      | Description                                          |
| --------------- | --------- | ---------------------------------------------------- |
| `stakingAmount` | `uint256` | Total number of tokens  transferred from the caller. |

#### Notes

* Can only be called by an initialized executor.
* The exact amount staked (`stakingAmount`) is `stakingAmountPerModule` times the number modules to register. The staking token is `stakingToken`.
* Caller has to approve at least the staking amount of tokens to the Coordinator contract.
* An inactive executor calling this function cannot become active because the minimum number of stake required to be active also increases proportionally with registered modules.

Emits [ModulesRegistered](#modulesregistered).

### deregisterModules

```solidity
function deregisterModules(uint256 _modulesBitset) external
```

Deregisters modules given.

#### Arguments

| Name             | Type      | Description                                                                                                                                                 |
| ---------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_modulesBitset` | `uint256` | A bitset containing 1's a the positions corresponding to the module numbers to deregister. For example `000...0101 = 5` means deregistering module 0 and 2. |

#### Notes

* Can only be called by an initialized executor that has already registered for the modules in `_modulesBitset`.
* The executor has to have registered at least two modules after the deregistration.
* Can only be called after `minimumRegistrationPeriod` seconds after the last module registration either via [stake](#stake) or [registerModules](#registermodules).
* This call does not transfer funds. However, the minimum staking threshold has lowered.

Emits [ModulesDeregistered](#modulesderegistered).

### withdrawStakingBalance

```solidity
function withdrawStakingBalance(uint256 _amount) external
```

Withdraws executor internal staking balance to the caller, doing an ERC-20 transfer of the staking token.

#### Arguments

| Name      | Type      | Description                                                 |
| --------- | --------- | ----------------------------------------------------------- |
| `_amount` | `uint256` | The amount to withdraw from the executor's staking balance. |

#### Notes

* Can only be called by an initialized executor.
* The internal executor balance after withdrawing has to be at least `stakingAmountPerModule` times the number of registered modules. If the executor wants to withdraw their whole balance,  [unstake](#unstake) should be used instead.

### withdrawProtocolBalance

```solidity
function withdrawProtocolBalance() external returns (uint256 amount)
```

Withdraws protocol's internal balance to the contract owner. This balance stems from execution tax an epoch pool balance cuts.&#x20;

#### Return data

| Name     | Type      | Description                              |
| -------- | --------- | ---------------------------------------- |
| `amount` | `uint256` | The amount of tokens that was withdrawn. |

#### Notes

* Can only be called by the `owner` address of the Coordinator contract.
* This will not affect executors' internal balance.


# Periphery


# Querier


