Executors
Executors are modules that are called during the execution phase of a UserOperation. They extend the execution logic of the account and thus allow for a more diverse set of actions that the account can natively perform.
A module can be broken down into three different domains:
- Config: Handles configurations on the module, such as installation and uninstallation
- Business logic: Handles the core logic of the module, depending on the module type
- Metadata: Additional data that is used to identify and correctly use a module
This page only covers domain 2 in the specific case of an Executor Module. For more information on domains 1 and 3, read through the Module page.
Building an executor
To build a compliant executor you need to ensure that it:
- Inherits from the
ERC7579ExecutorBase
contract. - Implements the required functions of the interface.
An example of a compliant executor (without actual logic) looks like this:
contract ExecutorExample is ERC7579ExecutorBase {
/*//////////////////////////////////////////////////////////////////////////
CONFIG
//////////////////////////////////////////////////////////////////////////*/
...
/*//////////////////////////////////////////////////////////////////////////
MODULE LOGIC
//////////////////////////////////////////////////////////////////////////*/
/**
* ERC-7579 does not define any specific interface for executors, so the
* executor can implement any logic that is required for the specific usecase.
*/
/*
* Execute the given data
* @dev This is an example function that can be used to execute arbitrary data
* @dev This function is not part of the ERC-7579 standard
* @param data The data to execute
*/
function execute(bytes calldata data) external {
IERC7579Account(msg.sender).executeFromExecutor(ModeLib.encodeSimpleSingle(), data);
}
/*//////////////////////////////////////////////////////////////////////////
METADATA
//////////////////////////////////////////////////////////////////////////*/
...
}
Execution function
As mentioned in the example contract above, ERC-7579 does not specify an interface for executors beyond the general Module interface. This means that executors can implement any kind of function in their business logic.
In the example above, the function execute
simply forwards its calldata and executes it on the account. Note that executors can only call the executeFromExecutor
function of the account and not the execute
function. Unlike the example above, the executor can also execute a batch of executions on the account. To pass the execution mode, the executor can use the ModeLib
and to correctly format the calldata, you can use the ExecutionLib
.
ModeLib
The ModeLib
is a library that provides a set of functions to encode and decode execution modes. The ModeLib
is used to encode the execution mode and pass it to the account. You can import the ModeLib
from the erc7579
package:
import { ModeLib } from "erc7579/lib/ModeLib.sol";
The ModeLib
provides the following functions:
encodeSimpleSingle()
: Encodes a simple single execution modeencodeSimpleBatch()
: Encodes a simple batch execution modeencode(CallType callType, ExecType execType, ModeSelector mode, ModePayload payload)
: Encodes a custom execution mode (uses theCallType
,ExecType
,ModeSelector
, andModePayload
custom types from theModeLib
)decode(ModeCode mode)
: Decodes the execution mode intoCallType
,ExecType
,ModeSelector
, andModePayload
custom types
ExecutionLib
The ExecutionLib
is a library that provides a set of functions to encode and decode execution data. The ExecutionLib
is used to encode the execution data and pass it to the account. You can import the ExecutionLib
from the erc7579
package:
import { ExecutionLib } from "erc7579/lib/ExecutionLib.sol";
The ExecutionLib
provides the following functions:
encodeSingle(address target, uint256 value, bytes calldata callData)
: Encodes a single executionencodeBatch(Execution[] calldata executions)
: Encodes a batch of executions, which uses theExecution
interface which can be imported frommodulekit/Accounts
decodeSingle(bytes calldata callData)
: Decodes the execution data intoaddress target
,uint256 value
, andbytes calldata callData
decodeBatch(bytes calldata callData)
: Decodes the execution data intoExecution[]