Protocols
The main goal of the protocol class is allowing anyone to implement protocols through a standardized format for a handful of categories:
- Dex
- Lending
- Custom
Each Protocol can implement one or multiple of these (AAVE for example can be both a Lending and Dex because it offers products in both categories).
The protocols are standardized so that they can easily be reused by others. Ideally through the library system.
Implementations
Dex is a Decentralized Exchange. More info about implementing a DEX class can be found below.
Lending is a lending protocol that allows borrowing and supplying tokens on chain. More info about implementing a Lending class can be found below.
Custom can be anything you want it to be and doesn't have to follow a standardized format. This is available in case you want to expose functions that don't fit the standardized format. Please note that when these functions are implemented by an agent or environment it won't be easily exchanged with a different Protocol because the standardization has been let go. More information about implementing a Custom class can be found below.
Contracts
The may to talk to on-chain contracts is through protocols (although you can make contracts available directly in an environment too). More information about contracts can be found here.
Class implementation
Each of the 3 options currently available (Dex, Lending or Custom) have to be a
separate file. dex.py
, lending.py
or custom.py
which have to implement the
respective protocol type.
Library file
The library file for the protocol supports a few extra parameters besides the standard ones, see a full example of a library file for an agent below:
name: "Aave V3"
version: "1.0.0"
type: "protocol"
author: "Almanak AG"
description: "Uniswap V3 protocol"
license: "MIT"
supported_chains:
- engine: 'evm'
chainId: '1'
dependencies:
contracts:
- abi: "file://abi/aave_pool.json"
address: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
alias: "aave_pool"
- engine: 'evm'
chainId: '2'
dependencies:
contracts:
- abi: "file://abi/aave_pool.json"
address: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"
alias: "aave_pool"
settings:
uniswap_v3_usdc_pool: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
Please note that only 1 almanak-library.yaml
file is required per protocol,
each protocol can implement 1 or all 3 types of protocol.
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 or contracts which have to be local files that are available in the same or subdirectory of thealmanak-library.yaml
.settings
are like any other settings but can overwrite them on an environment level. Useful for contract addresses that are different per chain
DEX protocol
DEX protocols need to follow a standardized interface and have to implement these functions. The main goal for this is to make it easy to swap in and out different protocols for agents or environments without having to change code.
To create a dex protocol, make a dex.py
file in the directory of your protocol
and create a class that implements the DexInterface
. From there you only need
to implement the required function using the standardized format.
Functions
__init__(self, contracts: List[ContractInterface], tokens: List[TokenInterface], settings: dict, metric_helper: MetricHelperInterface)
initialize(self, agent_addresses: List[str])
swap(self,
from_address: str,
token0: str,
token1: str,
amount: int
)
swap_output(self,
from_address: str,
token0: str,
token1: str,
amount: int
)
quote_input(self,
token0: str,
)
open_position(self,
from_address: str,
pool: str,
amount: int
)
add_liquidity(self,
from_address: str,
pool: str,
amount: int
)
remove_liquidity(self,
from_address: str,
pool: str,
amount: int
)
Lending Protocol
Lending protocols need to follow a standardized interface and have to implement these functions. The main goal for this is to make it easy to swap in and out different protocols for agents or environments without having to change code.
To create a dex protocol, make a lending.py
file in the directory of your protocol
and create a class that implements the LendingInterface
. From there you only need
to implement the required function using the standardized format.
Functions
__init__(self, contracts: List[ContractInterface], tokens: List[TokenInterface], settings: dict, metric_helper: MetricHelperInterface)
initialize(self, agent_addresses: List[str])
supply(self,
from_address: str,
asset: str,
amount: int,
**kwargs
)
borrow(self,
from_address: str,
asset: str,
amount: int,
rate: int,
**kwargs
)
withdraw(self,
from_address: str,
asset: str,
amount: int,
**kwargs
)
repay(self,
from_address: str,
asset: str,
amount: int,
**kwargs
)
liquidate(self,
from_address: str,
user: str,
debt: str,
collateral: str,
amount: int,
receive_collateral: bool,
**kwargs
)
fetch_positions(self,
from_address: str,
**kwargs
)
Custom Protocol
Custom protocols allows you to add any functions that the standardized formatting of the other available options don't allow. Any functions that can be useful for this protocol can be implemented.
To create a custom protocol, make a custom.py
file in the directory of your
protocol and create a class that implements the CustomProtocolInterface
. From
there you only need to implement the __init__
and initialize
function using
the standardized format.
Functions
__init__(self, contracts: List[ContractInterface], tokens: List[TokenInterface], settings: dict, metric_helper: MetricHelperInterface)
initialize(self, agent_addresses: List[str])