Environments
Environments are the heart of a simulation. Each simulation has at least 1 environment, which simply said is a single chain instance. For now only Ethereum is supported, but plans for other EVM based chains are in the works.
Agents can retrieve information from an environment and perform actions in it. Each step in the simulator the agent is allowed to take actions on one or multiple chains depending on how the timing of the chains are configured (for now this isn't a concern since only Ethereum mainnet is supported).
An Environment has many components to it and has to be configured using both the configuration file and a Python class implementation.
Configuration
Each environment needs to have the following components as part of its configuration:
alias
(required)block
(required)chainId
(required)contracts
(optional)dependencies
(optional)engine
(required)metrics
(optional)settings
(optional)source
(required)tokens
(optional)blockchain
(optional, if not present Ethereum is assumed)network
(optional, if not present regnet is assumed)
alias is a simple name to reference the environment by. This is used a primary key and will be used in other areas of the simulation to refer to this specific environment. TIP: Pick a name that is human readable.
block is the starting block from which the specific chain that has been
specified using engine
and chainID
will be forked from the mainnet. If
running a simulation with multiple environments you should make sure this aligns
with the other environment blocks.
chainId helps specify which chain we want to use for this environment. The source of truth is this list from sourcify for EVM chains.
contracts more about contracts can be read here.
dependencies more about dependencies can be read here.
engine helps with identifying which chain the environment is running. For
now only evm
is supported, but in the future items like cosmos
or solana
could be added for example.
metrics more about metrics can be read here.
settings is a simple "key value" list that can help modularize environments. They can take anything as a value which will be passed into the environment class.
source is the location of the Python file that implements the
EnvironmentInterface
. Read more about sources here.
tokens more about tokens can be read here.
blockchain is the name of the blockchain you wish to simulate with. We currently
support ethereum
, arbitrum
and avalanche
, but we may add more L2 in the future.
network is the name of the blockchain network. Currently, we support mainnet and
testnet. The goal is to be able to simulated in several networks. The only testnet
we support is Sepolia
for Ethereum.
An example of a configuration looks like this:
- alias: ethereum1
block: 16100000
chainId: '1'
contracts:
- abi: '[{"inputs": [], "stateMutability": "nonpayable", "type": "constructor"},
{"inputs": [{"internalType": "uint256", "name": "_value", "type": "uint256"}],
"name": "increment", "outputs": [], "stateMutability": "nonpayable", "type":
"function"}, {"inputs": [], "name": "number", "outputs": [{"internalType": "uint256",
"name": "", "type": "uint256"}], "stateMutability": "view", "type": "function"},
{"inputs": [], "name": "reset", "outputs": [], "stateMutability": "nonpayable",
"type": "function"}]'
alias: incrementer
installable:
bytecode: 608060405234801561001057600080fd5b50600080819055506101db806100276000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637cf5dab0146100465780638381f58a14610062578063d826f88f14610080575b600080fd5b610060600480360381019061005b91906100eb565b61008a565b005b61006a6100a1565b6040516100779190610127565b60405180910390f35b6100886100a7565b005b806000546100989190610171565b60008190555050565b60005481565b60008081905550565b600080fd5b6000819050919050565b6100c8816100b5565b81146100d357600080fd5b50565b6000813590506100e5816100bf565b92915050565b600060208284031215610101576101006100b0565b5b600061010f848285016100d6565b91505092915050565b610121816100b5565b82525050565b600060208201905061013c6000830184610118565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061017c826100b5565b9150610187836100b5565b925082820190508082111561019f5761019e610142565b5b9291505056fea264697066735822122072e7fdd0a3a63d596b9da980049bd6c53b405daff56912d3871ff9e9f4007e7664736f6c63430008120033
dependencies:
- settings:
uniswap_v3_usdc_pool: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
source: file://protocols/uniswap-v3/
- source: file://protocols/aave-v3/
engine: evm
metrics:
- alias: amazing_environment_metric
source: file://metrics/amazing_env_metric/
settings:
autoApprove: false
autoImpersonate: true
enableEvmLogging: true
source: file://environments/environment1/
tokens:
- address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
name: USDC
- address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
name: WETH
Class implementation
One of the required items for the environment is a Python file that implements
the EnvironmentInterface
. If you haven't done this before please read
this first before continuing.
You can find an example of an environment that has implemented the
EnvironmentInterface
in the configuration template under
environments/environment1/main.py
(use simcli generate
to get the template
in a local directory).
✅ What to add to the Environment implementation:
- Doing initial state changes before the simulation to the environment (both on-chain and off-chain).
- Changing certain on chain paramaters after or before every step.
- Calculating a value to store in the environment state (off chain), that can be used in next steps.
- Calculating final state values that can be used for metrics.
❌ What not to add:
- Performing actions on behalf of agents
- Logging metrics inside the environment (use environment metrics)
Methods to implement
__init__(self, environment_helper: EnvironmentHelperInterface, metric_helper: MetricHelperInterface)
environment_initialization(self)
environment_pre_step(self)
environment_post_step(self)
environment_teardown(self)
Library file
The library file for the environment class supports a few extra parameters besides the standard ones, see a full example of a library file for an agent below:
name: "Super amazing environment"
version: "1.0.0"
type: "environment"
author: "Almanak Blockchain Labs"
description: ""
license: "MIT"
supported_chains:
- engine: 'evm'
chainId: '1' # Ethereum Mainnet
dependencies:
protocols:
- "library://almanak/protocols/aave-v3:1.0.0"
- engine: 'evm'
chainId: '17000' # Ethereum Holesky
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