Skip to main content

Agents

Agents operate within the simulator and are permitted to take actions in an environment. It is important to understand that each agent can act independently and not every agent needs to take actions in at every step.

The agent field allows you to specify agents within the simulator and map them to an address for each environment. Agents also require a source (read more here), which defines how the agent functions.

Each agent should specify the following itemsadvanced in the configuration:

  • address (required)
  • agentType (required)
  • environments (required)
  • metrics (optional)
  • settings (optional)
  • source (optional)
  • strategy (optional)

address is the primary identifier for the agent throughout the simulation. This MUST be unique across all agents. It should be a wallet address.

agentType specifies the type of agent you want to create. Currently, we support mev and regular. mev agents have distinct behaviors, which you can read more about here.

environments indicates in which environments the agent is allowed to act. You can also specify an address specific to each environment. Additionally, you can specify a wallet to set the initial token holdings of the agent in that environment. See the example below for implementation details.

metrics provides more information on metrics here.

settings is a simple key-value list that helps modularize agents. This can include any value, which will be passed into the agent class.

source is the location of the Python file that implements the AgentInterface. Read more about sources here.

strategy specifies the source of the strategy you want the agent to use. See below for more details on this relationship.

Strategy

Agents have a close relationship with strategies, which are used to define the agent's behavior. The specific implementation of how to handle the behavior defined in a strategy should be within the agent itself.

State

Agents are executed using multithreading, which means variables assigned to self are not retained between function executions. To enable agents to maintain a state, you can use the AgentHelperInterface to add_variable, set_variable, and get_variable.

Any value stored in this manner is accessible throughout the simulator when the agent's actions are performed.

Agent Type

Regular (Base Agent)

To simplify development, we provide a "Base Agent." If no source is specified, this will be used automatically.

The base agent simply said just calls the strategy that is defined by the agent and performs the actions that have been configured there.

If you don't have a need for adding any special actions to the agent and just want it to do what the Strategy specifies you can remove the source field of the agent in the configuration. The simulator will see that you left it out and pick the Base Agent Class as the source option automatically.

You can still use all the other features of the agent like metrics for example to record metrics from the agent.

The following is an example of a configuration this type of agent.

agents:
- address: '0x52F065344b1298C5fc8b01217A2EfC3ef7Dd3AF6'
agentType: regular
environments:
- address: '0x52F065344b1298C5fc8b01217A2EfC3ef7Dd3AF6'
alias: ethereum1
wallet:
tokens:
- amount: 4338109590
token: bnWBTC
- amount: 2847843290371928722
token: ETH
- amount: 2847843290371928722
token: DAI
metrics:
- alias: amazing_agent_metric
source: file://metrics/amazing_agent_metric/
settings:
deposit: 1002
pool1:
fee: 5000
token0: WETH
token1: USDT
source: file://agent/defi/
strategy: file://strategy/trend-following/

MEV

MEV agents are a special type of agent that are only asked to perform a step after all other agents have completed theirs.

The purpose of this is to allow MEV agents to search for MEV opportunities and capitalize on them by ordering transactions for the block that will be mined. They primarily do this by using priority fees to arrange the transactions within the block.

Each agent has access to a function within the EnvironmentHelper called get_tx_pool, which allows the agent to retrieve information about the transaction pool for that block. This information can then be used to identify MEV opportunities.

Class implementation

One of the required items for the agent is a Python file that implements the AgentInterface. If you haven't done this before please read this before continuing.

You can find an example of an agent that has implemented the AgentInterface in the configuration template under agent/defi/main.py (use simcli generate to get the template in a local directory).

✅ What to add to the Agent implementation:

  • Performing actions on behalf of agents

❌ What not to add:

  • Logging metrics inside the environment (use environment metrics)

Methods to implement

__init__(self, strategy: StrategyInterface | None, agent_helper: AgentHelperInterface, metric_helper: MetricHelperInterface)
agent_initialization(self, simulation_state: SimulationStateHelperInterface)
agent_pre_step(self, simulation_state: SimulationStateHelperInterface)
agent_step(self, environment_helper: EnvironmentHelperInterface, simulation_state: SimulationStateHelperInterface)
agent_post_step(self, simulation_state: SimulationStateHelperInterface)
agent_teardown(self, simulation_state: SimulationStateHelperInterface)

Library file

The library file for the agent class supports a few extra parameters besides the standard ones, see a full example of a library file for an agent below:

name: "Liquidator"
version: "1.0.0"
type: "agent"
author: "Almanak AG"
description: ""
license: "MIT"

supported_chains:
- engine: 'evm'
chainId: '1'
dependencies:
protocols:
- "library://almanak/protocols/aave-v3:1.0.0"
- engine: 'evm'
chainId: '2'
dependencies:
protocols:
- "library://almanak/protocols/aave-v3:1.0.0"
settings:
uniswap_v3_usdc_pool: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"

As you can see the main part that we add is the supported_chains, which is simply an array of objects that you can use to configure dependencies and only allow the agent to work on certain chains because it has unique features to them.

  • engine is the Chain Engine as configured for the environment.
  • chainId is the chain id as configured for the environment.
  • dependencies allow you to set certain dependencies on an environment level, these have to be library items.
  • settings are like any other settings but can overwrite them on an environment level. Useful for contract addresses that are different per chain