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