Build an AAVE AI Agent to Lend and Borrow Crypto

The AAVE Agent allows users to lend and borrow cryptocurrencies from the AAVE pool. AAVE is a Decentralized Finance (DeFi) protocol that enables peer-to-peer lending and borrowing without intermediaries. This agent provides the necessary functionality to interact with the AAVE protocol, offering liquidity for lenders and collateralized loans for borrowers.

This tutorial will guide you through setting up, configuring, and running an AAVE Agent using the lend_borrow_agent repository.

Step-By-Step Tutorial for Building an AAVE Agent with SwarmZero.ai

Here is a detailed guide to build, run and test the AAVE Agent:

Cloning the Repository

To begin, we need to clone the lend_borrow_agent repository to our local machine. This will give you access to the code and resources needed to run and customize the AAVE Agent.

Step 1: Open your terminal or command prompt. Ensure you have Git installed on your system.

Step 2: Run the following commands:

git clone https://github.com/hivenetwork-ai/example-agents/ 
cd lend_borrow_agent

These commands will download the repository and navigate into its directory, setting up the base environment to start working on the agent.

Setting Up the Environment

Now that you have the repository cloned, the next step is to set up the environment to run the agent. This involves creating a virtual environment, installing dependencies, and configuring environment variables.

Step 1: Create a virtual environment:

python -m venv venv

Step 2: Activate the virtual environment

  • Command Prompt:

    venv\Scripts\activate.bat
  • PowerShell:

    venv\Scripts\Activate.ps1
  • On Unix/Mac:

    source venv/bin/activate

Installing Dependencies

With the virtual environment activated, install the required dependencies:

pip install -r requirements.txt

Run the command below to install the optional dependencies:

pip install git+https://github.com/hivenetwork-ai/hive-agent-py.git@main#egg=hive-agent[web3]

Setting Up Environment Variables

Step 1: Create a new file called .env in the root directory:

touch .env

Step 2: Copy the contents of .env.example into your new .env file.

Step 3: Add your API keys to the .env file:

OPENAI_API_KEY=your_openai_api_key
RPC_URL=your_infura_rpc_url
PRIVATE_KEY=your_private_key
AAVE_LENDING_POOL_ADDRESS=your_aave_lending_pool_address
  • RPC_URL: The RPC URL is the endpoint for your connection to the Ethereum network. You can obtain this by creating an Infura account and setting up a project, which will provide you with a URL to connect to the Ethereum blockchain.

  • PRIVATE_KEY: The Private Key is a secure and confidential key associated with your cryptocurrency wallet. It grants access to your wallet and allows you to sign transactions.

  • AAVE_LENDING_POOL_ADDRESS: This is the specific smart contract address for the Aave Lending Pool on the Ethereum network. The Lending Pool is where users can deposit and borrow cryptocurrencies on the Aave platform.

These steps will ensure your environment is properly configured to run the AAVE Agent.

Understanding the Code Structure

Before running the agent, it's important to understand the structure of the lend_borrow_agent repository:

  • .env.example: This file provides an example of the environment variables required for the project. You should copy this file to create your .env file and add the necessary API keys.

  • main.py: This is the main script that runs the agent. It includes functions for lending and borrowing cryptocurrencies using the AAVE protocol.

  • hive_config.toml: Contains configuration settings for the agent.

  • aave_lending_pool_abi.json: Stores the ABI (Application Binary Interface) for the AAVE Lending Pool, required for interacting with the smart contracts.

  • requirements.txt: Lists all the dependencies required to run the agent. These are the libraries and tools the agent relies on.

  • requirements-dev.txt: Lists the development dependencies needed for testing and development purposes. This file is useful for setting up a development environment.

Building the AAVE Agent

Here are the steps to build the AAVE agent:

1. Import Necessary Libraries

Start by importing all the required libraries. These libraries will handle environment variables, logging, JSON processing, Web3 interactions, and the HiveAgent functionality.

import os
import logging
from typing import Union
import json

from web3 import Web3
from hive_agent import HiveAgent
from dotenv import load_dotenv
  • os: Used to interact with the operating system, particularly for handling file paths.

  • logging: Used for logging messages and errors, which is crucial for debugging and monitoring.

  • typing: Provides support for type hints, making the code easier to understand and maintain.

  • json: Handles JSON data, which is used to load the ABI (Application Binary Interface) for the AAVE smart contracts.

  • Web3: A Python library that allows interaction with the Ethereum blockchain.

  • HiveAgent: A custom library for creating and running agents.

  • dotenv: Loads environment variables from a .env file.

2. Set Up Logging

Logging is set up to track the execution of the program. This will help in debugging and understanding the flow of the application.

logging.basicConfig(level=logging.INFO, force=True)
logger = logging.getLogger(__name__)
  • level=logging.INFO: Sets the logging level to INFO, meaning all messages at this level and higher (WARNING, ERROR, CRITICAL) will be logged.

  • force=True: Forces the configuration of the root logger, overriding any prior configurations.

3. Load Environment Variables

Environment variables are loaded from the .env file to keep sensitive information like API keys and private keys secure.

load_dotenv()

rpc_url = os.getenv("RPC_URL")
private_key = os.getenv("PRIVATE_KEY")
aave_lending_pool_address = os.getenv("AAVE_LENDING_POOL_ADDRESS")
  • load_dotenv(): Loads environment variables from a .env file into the environment.

  • os.getenv(): Retrieves the value of the specified environment variable.

4. Initialize Web3 Connection

Web3 is initialized to establish a connection with the Ethereum blockchain using the RPC URL.

web3 = Web3(Web3.HTTPProvider(rpc_url))

if not web3.is_connected():
    logger.error("Unable to connect to Ethereum network")
  • Web3.HTTPProvider(rpc_url): Specifies the RPC URL to connect to the Ethereum network.

  • web3.is_connected(): Checks if the connection to the Ethereum network is successful.

5. Load AAVE Lending Pool ABI

The ABI (Application Binary Interface) is required to interact with the AAVE smart contracts. This is loaded from a JSON file.

with open('./aave_lending_pool_abi.json', 'r') as abi_file:
    aave_lending_pool_abi = json.load(abi_file)
  • json.load(abi_file): Loads the ABI from the specified JSON file, allowing interaction with the smart contracts.

6. Define Functions for Lending and Borrowing

Now, define the functions that will handle the lending and borrowing operations.

Lending Function

The lend_crypto function allows users to lend cryptocurrency to the AAVE lending pool.

def lend_crypto(amount: float, asset_address: str) -> Union[str, None]:
    """
    Lend cryptocurrency to the AAVE lending pool.

    Parameters:
    amount (float): The amount of cryptocurrency to lend.
    asset_address (str): The address of the asset to lend.

    Returns:
    Union[str, None]: The transaction hash if successful, None otherwise.
    """
    if not web3.is_connected():
        logging.error("Unable to connect to Ethereum")
        return None

    try:
        lending_pool = web3.eth.contract(address=aave_lending_pool_address, abi=aave_lending_pool_abi)
        account = web3.eth.account.from_key(private_key)
        nonce = web3.eth.get_transaction_count(account.address) + 1  # increment nonce by 1 to avoid nonce collision
        logging.info(f"Lending from this address: {account.address}")

        amount_in_wei = web3.to_wei(amount, 'ether')

        tx = lending_pool.functions.deposit(
            asset_address,
            amount_in_wei,
            account.address,
            0
        ).build_transaction({
            'chainId': 11155111,  # Replace with the appropriate chain ID
            'gas': 700000,
            'gasPrice': web3.eth.gas_price * 2, 
            'nonce': nonce,
        })

        logging.info(f"Transaction before estimation: {tx}")

        tx['gas'] = web3.eth.estimate_gas(tx)
        logging.info(f"Estimated gas: {tx['gas']}")

        signed_tx = web3.eth.account.sign_transaction(tx, private_key)
        tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
        logging.info(f"Lending Transaction Hash: {tx_hash.hex()}")
        return web3.to_hex(tx_hash)
    except Exception as e:
        logging.error(f"An error occurred during lending: {e}")
        return None
  • amount_in_wei: Converts the amount to Wei, which is the smallest denomination of Ether.

  • lending_pool.functions.deposit(): Calls the deposit function on the AAVE Lending Pool contract.

  • build_transaction(): Prepares the transaction for sending.

  • estimate_gas(): Estimates the gas required for the transaction.

  • sign_transaction(): Signs the transaction with the user's private key.

  • send_raw_transaction(): Sends the signed transaction to the Ethereum network.

Borrowing Function

The borrow_crypto function allows users to borrow cryptocurrency from the AAVE lending pool.

def borrow_crypto(amount: float, asset_address: str, interest_rate_mode: int) -> Union[str, None]:
    """
    Borrow cryptocurrency from the AAVE lending pool.

    Parameters:
    amount (float): The amount of cryptocurrency to borrow.
    asset_address (str): The address of the asset to borrow.
    interest_rate_mode (int): The interest rate mode (1 for stable, 2 for variable).

    Returns:
    Union[str, None]: The transaction hash if successful, None otherwise.
    """
    if not web3.is_connected():
        logging.error("Unable to connect to Ethereum")
        return None

    try:
        lending_pool = web3.eth.contract(address=aave_lending_pool_address, abi=aave_lending_pool_abi)
        account = web3.eth.account.from_key(private_key)
        nonce = web3.eth.get_transaction_count(account.address)
        logging.info(f"Borrowing from this address: {account.address}")

        amount_in_wei = web3.to_wei(amount, 'ether')

        # Convert addresses to checksum format
        checksum_asset_address = web3.to_checksum_address(asset_address)
        checksum_account_address = web3.to_checksum_address(account.address)

        tx = lending_pool.functions.borrow(
            checksum_asset_address,
            amount_in_wei,
            interest_rate_mode,
            0,
            checksum_account_address
        ).build_transaction({
            'chainId': 11155111,  # Replace with the appropriate chain ID
            'gas': 700000,
            'gasPrice': web3.eth.gas_price * 2,
            'nonce': nonce,
        })
        logging.info(f"Transaction before estimation: {tx}")

        tx['gas'] = web3.eth.estimate_gas(tx)
        logging.info(f"Estimated gas: {tx['gas']}")

        signed_tx = web3.eth.account.sign_transaction(tx, private_key)
        tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
        logging.info(f"Borrowing Transaction Hash: {tx_hash.hex()}")
        return web3.to_hex(tx_hash)
    
    except Exception as e:
        logging.error(f"An error occurred: {e}")
        return None
  • interest_rate_mode: Specifies the interest rate mode (1 for stable, 2 for variable).

  • lending_pool.functions.borrow(): Calls the borrow function on the AAVE Lending Pool contract.

7. Run the AAVE Agent

Finally, the HiveAgent is created and run, incorporating the lending and borrowing functions defined earlier.

if __name__ == "__main__":
    my_agent = HiveAgent(
        name="AAVE_agent",
        functions=[lend_crypto, borrow_crypto],
        config_path='./hive_config.toml'
    )

    my_agent.run()
  • HiveAgent: The HiveAgent is instantiated with the name "AAVE_agent", the functions lend_crypto and borrow_crypto, and the path to the configuration file hive_config.toml.

  • my_agent.run(): Starts the agent, enabling it to process requests and interact with the AAVE protocol.

Running the Agent

With the environment set up and a basic understanding of the code structure, you are now ready to run the agent and see it in action.

Ensure your virtual environment is activated. You can test your agent by calling its Chat API endpoint to see the result.

Here’s an example using curl:

Step 1: Run the API server:

(venv) python main.py

Step 2: Open the Swagger Docs

http://localhost:8000/docs

Step 3: Choose the POST /api/vi/chat and test it:

curl --location 'localhost:8000/api/v1/chat' \
--header 'Content-Type: application/json' \
--data '{
    "user_id": "user123",
    "session_id": "session123",
    "chat_data": {
        "messages": [
            { "role": "user", "content": "Borrow 5 ETH from the AAVE lending pool, with a variable interest rate" }
        ]
    }
}'

This will send a request to the API and provide you with a response, allowing you to verify the agent’s functionality.

Output

As the next steps, you can proceed with testing if required.

Wrap Up

Congratulations! You've successfully set up, configured, and customized your AAVE Agent using SwarmZero.ai.

Last updated