Skip to main content
Version: 2.0.0

Agents

Agents live inside the simulator and are allowed to take actions in an environment. That concept is important to understand, the design thinking here was that each agent can take agents on multiple blockchains simultaneously or independently. Not every agent has to take actions on every environment or at any step for that matter.

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

Each agent should specify the following items in the configuration.

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

address is the primary key by which the agent is mentioned at all stages of the simulation. This NEEDS to be unique across agents.

agentType specifies what type of agent you want this agent to be. Currently we only support mev and NOT mev types. Specifically mev agents have different behavior, read more about it here.

environments makes it known to the simulator in which environments this agent should be allowed to take actions. You can also specify an address for specifically this environment. On top of that, you can specify a wallet to update the initial token holdings of the agent in that specific environment. See the example below for how to implement that.

metrics more about metrics can be read here.

settings is a simple "key value" list that can help modularize agents. They can take anything as a 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 allows you to specify the source of the strategy that you want to use for the agent. See below for more details on this relationship.

Strategy

Agents have a tight relationship with strategies. Strategies can be used to define the behavior of an agent. Specific implementations on how to deal with the behavior defined in a strategy should be implemented inside the agent itself. (for more info what the exact differentiating factors are reach out to the product team)

State

Agents are executed using multithreading, due to this we don't store any variables that were assigned to self in between executions of functions. To still allow for agents to have a state you can use the AgentHelperInterface to add_variable, set_variable and get_variable.

Any value that is stored in this variable is available throughout the simulator when executions are being performed for this agent.

MEV agents

Read more about why agent types exist and what an "MEV agent" is here.

Base Agent

To allow for easy development we have a "Base Agent". If you don't specify a source this will automatically be used. Go here to read more about what it is and how it works.

Example

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/

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 first 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 Blockchain Labs"
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