Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bonança

Bonança (pronounced boh-nahn-sah) is an open-source library for creating crypto defi bots on various blockchains. It provides functionalities for creating HD wallets, private key encryption, executing trades, lending and borrow crypto, and more.

Bonança is fully free and completely open source. You can find the source code on GitHub. The crypto is yours, and you are in full control of your funds at all times.

Features

  • Create and manage wallets using secure KeyVaults.
  • Connect to multiple blockchains (e.g., Solana, EVM-compatible chains).
  • Integrate with various exchanges and oracles for trading and price data.
  • Python wrapper

Disclaimer

This documentation has been largely written by AI, so it is likely there are some inaccuracies in the code examples. I occasionally look over the docs to fix them, but some might still be out there.

Getting Started

To get started with Bonança, follow the instructions in the Installation guide. Once installed, you can create a wallet by following the steps in the Create Account section. After setting up your wallet, you can manage your index fund using the instructions provided in the Manage Index Fund documentation.

About The Name

Bonança is a Portuguese word used to describe a period of prosperity and tranquility, that typically comes after a period of instability or hardship. In the context of this project, Bonança represents a tool that aims to bring financial stability and growth to cryptocurrency investors.

A big insipration for the name comes from a verse in a famous Brazilian funk song "Rap da Felicidade" by Cidinho and Doca:

"Sofri na tempestade, agora eu quero a bonança"

Which translates to "I suffered in the storm, now I want prosperity". I hope this CLI can help users find their own "bonança" in the volatile world of cryptocurrency investing.

Installation

cargo add bonanca

Wallets

This section documents the wallet and key management utilities provided by Bonanca. It covers creating and managing EVM and Solana wallets, using the keyvault, signing transactions, and helper functions for balance and token operations.

HD Wallets

Bonança can create a master key for a Hierarchical Deterministic (HD) wallet, which can generate multiple child keys for different blockchains. This means you can manage multiple wallets for multiple blockchains (e.g., Solana, EVM-compatible chains) using a single KeyVault file. If you are unfamiliar with HD wallets consider reading this post.

Creating a New HD Wallet

HD wallets are stored as KeyVault files in Bonança, which is explained in more depth here. You can create a KeyVault using Rust or Python.

Rust

use bonanca::keyvault::KeyVault;
use std::path::Path;

fn main() {
  // Create new KeyVault with english mneomonic
  let key_vault = KeyVault::new("English");
  let filename = Path::new("./keyvault.json");

  // Write json file
  key_vault.write(filename)
}

Python

from bonanca import KeyVault

# Create new KeyVault with english mneomonic
key_vault = KeyVault.new("English")

# Write json file
key_vault.write("./keyvault.json")

The available languages for the mneomonic are:

  • English
  • Simplified Chinese
  • Traditional Chinese,
  • French
  • Italian
  • Japanese
  • Korean
  • Spanish

Create a KeyVault from a Mneomonic

You can also create a KeyVault from an existing mneomonic phrase. This is useful if you already have a wallet and want to manage it using Bonança.

Rust

use bonanca::keyvault::KeyVault;

fn main() {
  // Your mneomonic (in any language listed above)
  let mneomonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";

  let key_vault = KeyVault::from_mneomonic(mneomonic);
  let filename = Path::new("./keyvault.json");

  // Write json file
  key_vault.write(filename)
}

Python

from bonanca import KeyVault

# Your mneomonic (in any language listed above)
mneomonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about

key_vault = KeyVault.from_mneomonic(mneomonic)

# Write json file
key_vault.write("./keyvault.json")

View vs Load

Bonança offers you the ability to interact with wallets in two modes; view and load. In view mode the wallet is only the public key, whereas, load has both public and private keys. This is useful for when you want to check token balances without having to expose your private key or type your password in.

Rust

In Rust view and load are both methods of the wallet struct.

use bonanca::wallets::{EvmWallet, SolWallet}
use std::path::Path;

fn main() {
    let filename = Path::new("./keyvault.json");
    let child = 0;

    let evm_wallet_view = EvmWallet::view(filename, "rpc_url", child)
    let sol_wallet_view = SolWallet::view(filename, "rpc_url", child)

    let evm_wallet_load = EvmWallet::load(filename, "rpc_url", child)
    let sol_wallet_load = SolWallet::load(filename, "rpc_url", child)
}

Python

In Python the dynamic style view and load isn't possible, so instead there are two different classes for each method.

import bonanca

wallet_view = bonanca.wallets.EvmWalletView("keyvault.json", "rpc_url", 0)

wallet_load = bonanca.wallets.EvmWallet("keyvault.json", "rpc_url", 0)

EVM Wallet

To interact with an EVM-compatible wallet using bonanca you can use the EvmWallet struct.

Parse and Format Decimals

You can use the parse_decimals and format_decimals methods to convert between the raw integer representation of token amounts and the human-readable decimal format.

Rust

// Format a float into a big int
let big_amount = wallet.format_native(2.5); // Native (ETH, POL, ...) only
let big_amount_token = wallet.format_token(14.2, "TOKEN_ADDRESS"); // Any token

// Parse a big int number into a float
let x0 = wallet.parse_native(big_amount); // Native (ETH, POL, ...) only
let x1 = wallet.parse_token(big_amount_token, "TOKEN_ADDRESS"); // Any token

Python

# Format a float into a big int
big_amount = wallet.format_native(2.5)# Native (ETH, POL, ...) only
big_amount_token = wallet.format_token(14.2, "TOKEN_ADDRESS")# Any token

# Parse a big int number into a float
x0 = wallet.parse_native(big_amount)# Native (ETH, POL, ...) only
x1 = wallet.parse_token(big_amount_token, "TOKEN_ADDRESS")# Any token

Balances

Bonança provides methods to check native and token balances in your wallet. You can use the balance method to retrieve the native balance and the token_balance method for tokens.

Rust

// Get native balance (as float)
let nat_bal = wallet.balance().await?;

// Get token balance (as float)
let tkn_bal = wallet.token_balance("TOKEN_ADDRESS").await?;

Python

sol_bal = wallet.balance()
spl_bal = wallet.token_balance("TOKEN_ADDRESS")

Token Approvals

To approve an address for spending your tokens you can use the approve_token_spending method.

Rust

// Approve 2.05 tokens to be spent by spender address
wallet.approve_token_spending("TOKEN_ADDRESS","SPENDER_ADDRESS", 2.05).await?;

Python

wallet.approve_token_spending("TOKEN_ADDRESS","SPENDER_ADDRESS", 2.05)

Transfers

For native transfers you can use the transfer method, and token_transfer for tokens. For native transfers, specify the recipient's public key and the amount as a decimal value. For token transfers, specify the recipient's token account, the token address, and the amount in decimal value.

Rust

// Transfer 2.5 native
let receipt = wallet.transfer(2.5, "TO_ADDRESS").await?;

// Transfer 2.5 token
let receipt2 = wallet.token_transfer("TOKEN_ADDRESS", 2.5, "TO_ADDRESS").await?;

Python

# Transfer 2.5 native
receipt = wallet.transfer(2.5, "TO_ADDRESS")

# Transfer 2.5 token
receipt2 = wallet.token_transfer("TOKEN_ADDRESS", 2.5, "TO_ADDRESS")

Solana Wallet

To interact with a Solana wallet using Bonança you can use the SolWallet struct. For all examples shown below its assumed a wallet has been initialized as wallet. In the examples where signing is not required a view wallet is sufficient.

Parse and Format Decimals

You can use the parse_decimals and format_decimals methods to convert between the raw integer representation of token amounts and the human-readable decimal format.

Rust

// Format a float into a big int
let big_amount = wallet.format_native(2.5); // Sol only
let big_amount_token = wallet.format_token(14.2, "TOKEN_MINT"); // Any SPL token

// Parse a big int number into a float
let x0 = wallet.parse_native(big_amount); // Sol only
let x1 = wallet.parse_token(big_amount_token, "TOKEN_MINT"); // Any SPL token
# Format a float into a big int
big_amount = wallet.format_native(2.5) # Sol only
big_amount_token = wallet.format_token(14.2, "TOKEN_MINT") # Any SPL token

# Parse a big int number into a float
x0 = wallet.parse_native(big_amount)# Sol only
x1 = wallet.parse_token(big_amount_token, "TOKEN_MINT")# Any SPL token

Balances

Bonança provides methods to check the balance of SOL and SPL tokens in your wallet. You can use the balance method to retrieve the balance of SOL and the token_balance method for SPL tokens.

Rust

// Get Sol balance (as float)
let sol_bal = wallet.balance().await?;

// Get SPL token balance (as float)
let spl_bal = wallet.token_balance("TOKEN_MINT").await?;

Python

sol_bal = wallet.balance()
spl_bal = wallet.token_balance("TOKEN_MINT")

Create Token Account

Before you can hold or transfer SPL tokens, you need to create a token account for the specific token mint. You can use the create_token_account method to create a new token account.

Rust

let ata_pubkey = wallet.create_token_account("TOKEN_MINT").await?;

Python

ata_pubkey = wallet.create_token_account("TOKEN_MINT")

Burn Token

To burn SPL tokens, you can use the burn_token method. This will permanently remove the specified amount of tokens from circulation. Note that unlike EVM chains in Solana you can't burn tokens by sending them to burn address.

Rust

let receipt = wallet.burn_token("TOKEN_MINT", 2.5).await?;

Python

receipt = wallet.burn_token("TOKEN_MINT", 2.5)

Close Token Account

To close a token account, you can use the close_token_account method. This can only be done when the token balance is zero (you must send or burn all tokens before calling this method). After closing the account the SOL deposit for the account will be returned to your wallet.

Rust

wallet.close_token_account("TOKEN_MINT").await?;

Python

wallet.close_token_account("TOKEN_MINT")

Transfers

To transfer SOL you can use the transfer method, and token_transfer for SPL tokens. For SOL transfers, specify the recipient's public key and the amount as a decimal value. For SPL token transfers, specify the recipient's token account, the token mint, and the amount in decimal value.

Rust

// Transfer 2.5 Sol
let receipt = wallet.transfer(2.5, "TO_ADDRESS").await?;

// Transfer 2.5 SPL token
let receipt2 = wallet.token_transfer("TOKEN_MINT", 2.5, "TO_ADDRESS").await?;

Python

# Transfer 2.5 Sol
receipt = wallet.transfer(2.5, "TO_ADDRESS")

# Transfer 2.5 SPL token
receipt2 = wallet.token_transfer("TOKEN_MINT", 2.5, "TO_ADDRESS")

DeFi

Overview of protocol integrations and adapters provided by Bonanca. This section links into EVM and Solana integrations (Aave, 0x, CoW, Morpho, Jupiter, Kamino, etc.) and shows how to query markets, perform swaps, and manage vaults from Rust and Python.

EVM DeFi Interfaces

Bonanca provides interfaces to interact with popular DeFi protocols on EVM-compatible blockchains. This section covers the main DeFi integrations available.

Aave V3 - Lending Protocol

Aave V3 is a decentralized lending protocol that allows users to supply assets as collateral, borrow tokens, and earn interest. The AaveV3 interface provides methods for managing lending positions.

Overview

  • Supply: Deposit tokens to earn interest
  • Borrow: Borrow tokens using your collateral
  • Repay: Pay back borrowed tokens
  • Withdraw: Withdraw supplied tokens
  • Account Data: Query user's collateral, debt, and health factor

Supported Operations

Rust

use bonanca::defi::AaveV3;
use bonanca::wallets::evm::EvmWallet;

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize wallet
    let wallet = EvmWallet::new(
        "private_key",
        "rpc_url",
        137  // Chain ID for Polygon
    )?;

    // Initialize Aave V3 for Polygon (chain_id=137)
    let aave = AaveV3::new(137);

    // Example 1: Supply USDC
    let usdc_address = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359";
    let receipt = aave.supply(&wallet, usdc_address, 100.0).await?;
    println!("Supply tx: {:?}", receipt.transaction_hash);

    // Example 2: Check user account data
    let user_data = aave.get_user_data(
        &wallet.pubkey.to_string(),
        &wallet.client
    ).await?;
    println!("Health Factor: {}", user_data.health_factor);
    println!("Total Collateral: {}", user_data.total_collateral);
    println!("Total Debt: {}", user_data.total_debt);
    println!("Available Borrows: {}", user_data.available_borrows);

    // Example 3: Borrow WETH
    let weth_address = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726";
    let borrow_receipt = aave.borrow(&wallet, weth_address, 0.5).await?;
    println!("Borrow tx: {:?}", borrow_receipt.transaction_hash);

    // Example 4: Repay borrowed tokens
    let repay_receipt = aave.repay(&wallet, weth_address, 0.3).await?;
    println!("Repay tx: {:?}", repay_receipt.transaction_hash);

    // Example 5: Withdraw collateral
    let withdraw_receipt = aave.withdraw(&wallet, usdc_address, 50.0).await?;
    println!("Withdraw tx: {:?}", withdraw_receipt.transaction_hash);

    Ok(())
}

Python

import bonanca

# Initialize wallet
wallet = bonanca.wallets.EvmWallet(
    "private_key",
    "https://polygon-rpc.com",
    137  # Chain ID for Polygon
)

# Initialize Aave V3
aave = bonanca.defi.AaveV3(137)

# Token addresses on Polygon
usdc = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
weth = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726"

# Supply tokens
supply_receipt = aave.supply(wallet, usdc, 100.0)
print(f"Supply tx: {supply_receipt['transaction_hash']}")

# Check account data
account_data = aave.get_user_data(wallet.pubkey, wallet)
print(f"Health Factor: {account_data['Health Factor']}")
print(f"Total Collateral: {account_data['Total Collateral']}")
print(f"Total Debt: {account_data['Total Debt']}")

# Borrow tokens
borrow_receipt = aave.borrow(wallet, weth, 0.5)
print(f"Borrow tx: {borrow_receipt['transaction_hash']}")

# Repay debt
repay_receipt = aave.repay(wallet, weth, 0.3)
print(f"Repay tx: {repay_receipt['transaction_hash']}")

# Withdraw collateral
withdraw_receipt = aave.withdraw(wallet, usdc, 50.0)
print(f"Withdraw tx: {withdraw_receipt['transaction_hash']}")

Chain IDs

Common Aave V3 deployments:

  • Ethereum: 1
  • Polygon: 137
  • Arbitrum: 42161
  • Optimism: 10
  • Base: 8453
  • Avalanche: 43114

Important Notes

  • Ensure sufficient collateral before borrowing
  • Monitor your health factor to avoid liquidation
  • The health factor formula considers collateral and debt ratios
  • Interest rates vary based on market utilization
  • Requires token approval before first interaction with Aave

CoW (Coincidence of Wants) - DEX Aggregator

CoW is an order-based DEX aggregator that uses batch auctions to execute trades. It supports both market orders and limit orders.

Overview

  • Market Orders: Execute immediately at best available price
  • Limit Orders: Execute only when price reaches your target
  • Order Queries: Check order status and history
  • EIP-712 Signing: Secure order signing

Supported Operations

Rust

use bonanca::defi::CoW;
use bonanca::wallets::evm::EvmWallet;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<()> {
    let wallet = EvmWallet::new(
        "private_key",
        "https://polygon-rpc.com",
        137
    )?;

    // Initialize CoW for Polygon
    let cow = CoW::new("polygon")?;

    let weth = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726";
    let usdc = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359";

    // Example 1: Execute market order (WETH → USDC)
    let market_quote = cow.get_market_quote(
        &wallet,
        weth,
        usdc,
        0.1  // 0.1 WETH
    ).await?;

    let order_uid = cow.post_market_order(
        &wallet,
        market_quote
    ).await?;
    println!("Market order placed: {}", order_uid);

    // Example 2: Check order status
    let order_info = cow.get_order_info(&order_uid).await?;
    println!("Status: {}", order_info.status);
    println!("Executed Buy Amount: {}", order_info.executed_buy_amount);
    println!("Executed Sell Amount: {}", order_info.executed_sell_amount);

    // Example 3: Get user order history
    let user_orders = cow.get_user_orders(
        &wallet.pubkey.to_string(),
        Some(10)  // Last 10 orders
    ).await?;
    println!("Recent orders: {} found", user_orders.len());

    // Example 4: Place limit order
    // Valid for 1 hour (60 minutes + 0 seconds)
    let limit_duration = Duration::new(3600, 0);
    let limit_uid = cow.limit_order(
        &wallet,
        weth,      // Selling WETH
        usdc,      // Buying USDC
        0.1,       // Sell amount
        200.0,     // Buy amount (minimum)
        limit_duration
    ).await?;
    println!("Limit order placed: {}", limit_uid);

    // Example 5: Place limit order by price
    let price_limit_uid = cow.limit_order_by_price(
        &wallet,
        weth,
        usdc,
        0.1,       // Amount of WETH to sell
        2000.0,    // Minimum price (USDC per WETH)
        limit_duration
    ).await?;
    println!("Price limit order placed: {}", price_limit_uid);

    Ok(())
}

Python

import bonanca

wallet = bonanca.wallets.EvmWallet(
    "private_key",
    "https://polygon-rpc.com",
    137
)

# Initialize CoW for Polygon
cow = bonanca.defi.CoW("polygon")

weth = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726"
usdc = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"

# Market order: Sell 0.1 WETH for USDC
order_uid = cow.market_order(wallet, weth, usdc, 0.1)
print(f"Order UID: {order_uid}")

# Get order details
order_info = cow.get_order_info(order_uid)
print(f"Status: {order_info['status']}")
print(f"Buy Amount: {order_info['executed_buy_amount']}")
print(f"Sell Amount: {order_info['executed_sell_amount']}")

# Get all orders for a user
user_orders = cow.get_user_orders(wallet.pubkey, 10)
print(f"Found {len(user_orders)} recent orders")

# Limit order: Sell 0.1 WETH for minimum 200 USDC, valid for 1 hour
limit_uid = cow.limit_order(
    wallet,
    weth,               # Sell token
    usdc,               # Buy token
    0.1,                # Sell amount
    200.0,              # Minimum buy amount
    (1, 0)              # Duration: 1 hour, 0 minutes
)
print(f"Limit order: {limit_uid}")

# Limit order by price
price_uid = cow.limit_order_by_price(
    wallet,
    weth,
    usdc,
    0.1,                # Amount to sell
    2000.0,             # Minimum price
    (1, 0)              # Duration
)
print(f"Price limit order: {price_uid}")

Supported Chains

  • Ethereum (mainnet)
  • Polygon
  • Arbitrum
  • Optimism
  • Base
  • Gnosis Chain (xDai)
  • Linea
  • Avalanche
  • BNB Chain

Important Notes

  • CoW Protocol uses batch auctions for better pricing
  • Limit orders expire after specified duration
  • Orders must be signed with EIP-712
  • Focus on MEV protection compared to traditional DEXs
  • No gas required for failed orders

Morpho - Lending Optimization

Morpho optimizes lending by matching users peer-to-peer while falling back to lending pools. The MorphoVaultV1 interface provides access to Morpho vaults.

Overview

  • Supply: Deposit into optimized vaults
  • Withdraw: Withdraw from vaults
  • Vault Data: Query available vaults for specific tokens
  • User Positions: Track user's vault positions

Supported Operations

Rust

use bonanca::defi::MorphoVaultV1;
use bonanca::wallets::evm::EvmWallet;

#[tokio::main]
async fn main() -> Result<()> {
    let wallet = EvmWallet::new(
        "private_key",
        "https://polygon-rpc.com",
        137
    )?;

    let morpho = MorphoVaultV1::new();

    // Example 1: Get user's vault positions
    let user_positions = morpho.get_user_data(
        &wallet.pubkey.to_string(),
        137  // Chain ID
    ).await?;
    println!("User positions: {:?}", user_positions);

    // Example 2: Find USDC vaults
    let usdc_vaults = morpho.get_token_vaults(
        "USDC",
        137
    ).await?;
    println!("Available USDC vaults: {}", usdc_vaults.len());
    for vault in &usdc_vaults {
        println!("Vault: {:?}", vault);
    }

    // Example 3: Supply to a vault
    // First, get a vault address from get_token_vaults()
    let vault_address = "0x..."; // Example vault address
    let deposit_receipt = morpho.supply(
        &wallet,
        vault_address,
        100.0  // Amount in decimal format
    ).await?;
    println!("Deposit tx: {:?}", deposit_receipt.transaction_hash);

    // Example 4: Withdraw from vault
    let withdraw_receipt = morpho.withdraw(
        &wallet,
        vault_address,
        50.0
    ).await?;
    println!("Withdraw tx: {:?}", withdraw_receipt.transaction_hash);

    Ok(())
}

Python

import bonanca

wallet = bonanca.wallets.EvmWallet(
    "private_key",
    "https://polygon-rpc.com",
    137
)

morpho = bonanca.defi.MorphoVaultV1()

# Get user's vault positions
user_data = morpho.get_user_data(wallet.pubkey, 137, wallet)
print(f"User positions: {user_data}")

# Find USDC vaults
usdc_vaults = morpho.get_token_vaults("USDC", 137, wallet)
print(f"Available vaults: {usdc_vaults}")

# Supply to a vault (replace with actual vault address)
vault_address = "0x..."
deposit_receipt = morpho.supply(wallet, vault_address, 100.0)
print(f"Deposit tx: {deposit_receipt['transaction_hash']}")

# Withdraw from vault
withdraw_receipt = morpho.withdraw(wallet, vault_address, 50.0)
print(f"Withdraw tx: {withdraw_receipt['transaction_hash']}")

Morpho Vaults

Morpho offers specialized vaults for different strategies:

  • USDC Vaults: Stable yield on USDC
  • WETH Vaults: Ethereum staking
  • Strategy Vaults: Custom yield strategies
  • Metamorpho Vaults: User-created vault bundles

Important Notes

  • Vault addresses vary by chain
  • Deposits are immediately invested
  • Withdrawals may take time depending on vault liquidity
  • Each vault has different risk/reward profiles
  • Query vault details for APY and TVL information

0x (ZeroX) - DEX Aggregator

0x is a decentralized exchange aggregator that sources liquidity from multiple DEXs to find the best prices for token swaps.

Overview

  • Swap Quotes: Get best available swap prices
  • Quick Swaps: Execute swaps in one transaction
  • Issue Checking: Verify swap feasibility
  • Multi-source Routing: Optimal liquidity from multiple DEXs

Supported Operations

Rust

use bonanca::defi::ZeroX;
use bonanca::wallets::evm::EvmWallet;

#[tokio::main]
async fn main() -> Result<()> {
    let wallet = EvmWallet::new(
        "private_key",
        "https://polygon-rpc.com",
        137
    )?;

    // Initialize 0x with API key (get from 0x.org)
    let zerox = ZeroX::new("your_api_key".to_string(), 137);

    let weth = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726";
    let usdc = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359";

    // Example 1: Check for swap issues
    let issues = zerox.check_swap(
        &wallet,
        weth,
        usdc,
        0.1  // 0.1 WETH
    ).await?;

    if issues.allowance.is_some() {
        println!("Token approval required");
    }
    if issues.balance.is_some() {
        println!("Insufficient balance");
    }

    // Example 2: Get swap quote
    let quote = zerox.get_swap_quote(
        &wallet,
        weth,
        usdc,
        0.1
    ).await?;

    println!("Buy Amount: {}", quote.buy_amount);
    println!("Min Buy Amount: {}", quote.min_buy_amount);
    println!("Liquidity Available: {}", quote.liquidity_available);
    println!("Allowance Target: {}", quote.allowance_target);

    // Example 3: Execute swap with quote
    let swap_receipt = zerox.swap(
        &wallet,
        quote
    ).await?;
    println!("Swap tx: {:?}", swap_receipt.transaction_hash);

    // Example 4: Quick swap (get quote and swap in one call)
    // This is more convenient for simpler scenarios
    let receipt = zerox.quick_swap(
        &wallet,
        weth,
        usdc,
        0.1
    ).await?;
    println!("Quick swap tx: {:?}", receipt.transaction_hash);

    Ok(())
}

Python

import bonanca

wallet = bonanca.wallets.EvmWallet(
    "private_key",
    "https://polygon-rpc.com",
    137
)

# Initialize 0x (replace with actual API key from 0x.org)
zerox = bonanca.defi.ZeroX("api_key", 137)

weth = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726"
usdc = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"

# Check for swap issues (allowance, balance)
issues = zerox.check_swap(wallet, weth, usdc, 0.1)
print(f"Issues: {issues}")

# Get detailed quote
quote = zerox.get_swap_quote(wallet, weth, usdc, 0.1)
print(f"Buy Amount: {quote.buy_amount}")
print(f"Min Buy Amount: {quote.min_buy_amount}")
print(f"Liquidity Available: {quote.liquidity_available}")

# Execute swap with quote
swap_receipt = zerox.swap(wallet, quote)
print(f"Swap tx: {swap_receipt['transaction_hash']}")

# Quick swap (recommended for simple swaps)
quick_receipt = zerox.quick_swap(wallet, weth, usdc, 0.1)
print(f"Quick swap tx: {quick_receipt['transaction_hash']}")

Supported Chains

  • Ethereum
  • Polygon
  • Arbitrum
  • Optimism
  • Base
  • Avalanche
  • BNB Chain
  • Linea
  • Scroll

Quote Information

The swap quote returns:

  • buy_amount: Exact amount of output tokens
  • min_buy_amount: Minimum considering slippage
  • sell_amount: Amount of input tokens
  • allowance_target: Address to approve for token spending
  • liquidity_available: Whether sufficient liquidity exists

Important Notes

  • Requires 0x API key (free tier available)
  • Always check issues before executing trades
  • Slippage is automatically handled
  • Gas estimates included in quotes
  • Quote validity is typically 1 minute
  • Quick swaps are simpler but less flexible than manual swap flow

General Best Practices

Security

  1. Private Key Management

    • Never hardcode private keys
    • Use environment variables or secure vaults
    • Rotate keys regularly
  2. Token Approval

    • Check allowances before transactions
    • Use minimal necessary amounts
    • Revoke approvals when done
  3. Position Management

    • Monitor health factors in lending protocols
    • Set alerts for liquidation risk
    • Rebalance positions regularly

Gas Optimization

  • Batch multiple operations when possible
  • Use limit orders for time-insensitive trades
  • Monitor gas prices before executing
  • Consider network congestion

Testing

  • Test on testnet before mainnet
  • Start with small amounts
  • Verify transactions before committing funds
  • Use price impact slippage limits

Transaction Confirmation

All operations return transaction receipts containing:

  • Transaction hash
  • Block number
  • Gas used
  • Transaction status

Always verify successful execution before relying on results.

Solana DeFi Interfaces

Bonanca provides interfaces to interact with popular DeFi protocols on Solana. This section covers the main DeFi integrations available.

Jupiter - DEX Aggregator

Jupiter is the leading decentralized exchange aggregator on Solana, sourcing liquidity from multiple DEXs to find the best prices for token swaps. It also offers a lending protocol called Jupiter Earn.

Overview

  • Token Swaps: Get best pricing across multiple Solana DEXs
  • Limit Orders: Place orders that execute at specified prices
  • Price Queries: Check token prices and value conversions
  • Lending/Earn: Deposit tokens to earn yield
  • Lendable Markets: Query available lending markets

Supported Operations

Rust

use bonanca::defi::Jupiter;
use bonanca::wallets::solana::SolWallet;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize wallet
    let wallet = SolWallet::new(
        "base58_private_key",
        "https://api.mainnet-beta.solana.com"
    )?;

    // Initialize Jupiter with API key
    let jupiter = Jupiter::new("your_api_key".to_string());

    // Token mint addresses
    let sol = "So11111111111111111111111111111111111111112";
    let usdc = "EPjFWdd5Au17FXxeB6VWyeXKSa3LvwV0LCH7f3uyxVEP";
    let orca = "orcaEKTdK7LKz57chYcUBK6GDZT5bNvmnucEZDfmWQe";

    // Example 1: Get token price in USD
    let sol_price = jupiter.get_token_price(token_mint, 1.0).await?;
    println!("1 SOL = ${}", sol_price);

    // Example 2: Get swap quote
    let quote = jupiter.get_swap_quote(
        &wallet,
        sol,      // Sell token (SOL)
        usdc,     // Buy token (USDC)
        1.0       // Amount in decimal format
    ).await?;

    println!("Input Amount: {}", quote.in_amount);
    println!("Output Amount: {}", quote.out_amount);
    println!("Price Impact: {}%", quote.price_impact_pct);
    println!("Slippage (bps): {}", quote.slippage_bps);

    // Example 3: Execute swap with quote
    let swap_receipt = jupiter.swap(&wallet, quote).await?;
    println!("Swap signature: {}", swap_receipt.hash);
    println!("Slot: {}", swap_receipt.slot);

    // Example 4: Quick swap (get quote and swap in one call)
    let receipt = jupiter.quick_swap(
        &wallet,
        sol,
        usdc,
        1.0
    ).await?;
    println!("Quick swap signature: {}", receipt.hash);

    // Example 5: Place limit order
    // Order is valid for 24 hours (86400 seconds)
    let limit_receipt = jupiter.limit_order(
        &wallet,
        sol,           // Sell token
        usdc,          // Buy token
        1.0,           // Amount to sell
        34.5,          // Minimum to receive
        Duration::from_secs(86400)
    ).await?;
    println!("Limit order signature: {}", limit_receipt.hash);

    // Example 6: Limit order by price
    // Sell 1 SOL if price reaches 35 USDC per SOL
    let price_limit_receipt = jupiter.limit_order_by_price(
        &wallet,
        sol,
        usdc,
        1.0,                  // Amount to sell
        35.0,                 // Price threshold
        Duration::from_secs(86400)
    ).await?;
    println!("Price limit order: {}", price_limit_receipt.hash);

    // Example 7: Get available lending markets
    let markets = jupiter.get_lendable_tokens().await?;
    for market in &markets {
        println!("Market: {} ({})", market.name, market.symbol);
        println!("  Supply Rate: {}", market.supply_rate);
        println!("  Total Assets: {}", market.total_assets);
        println!("  Total Supply: {}", market.total_supply);
    }

    // Example 8: Deposit into lending market
    let deposit_receipt = jupiter.deposit(
        &wallet,
        usdc,   // Token to deposit
        100.0   // Amount in decimal format
    ).await?;
    println!("Deposit signature: {}", deposit_receipt.hash);

    // Example 9: Withdraw from lending market
    let withdraw_receipt = jupiter.withdraw(
        &wallet,
        usdc,
        50.0
    ).await?;
    println!("Withdraw signature: {}", withdraw_receipt.hash);

    Ok(())
}

Python

import bonanca
import time

# Initialize wallet
wallet = bonanca.wallets.SolWallet(
    "base58_private_key",
    "https://api.mainnet-beta.solana.com"
)

# Initialize Jupiter
jupiter = bonanca.defi.Jupiter("your_api_key")

# Token mint addresses
sol = "So11111111111111111111111111111111111111112"
usdc = "EPjFWdd5Au17FXxeB6VWyeXKSa3LvwV0LCH7f3uyxVEP"
orca = "orcaEKTdK7LKz57chYcUBK6GDZT5bNvmnucEZDfmWQe"

# Get token price
sol_price = jupiter.get_token_price(wallet, sol, 1.0)
print(f"1 SOL = ${sol_price}")

# Get swap quote
quote = jupiter.get_swap_quote(wallet, sol, usdc, 1.0)
print(f"Input: {quote.in_amount}")
print(f"Output: {quote.out_amount}")
print(f"Price Impact: {quote.price_impact_pct}%")

# Execute swap
swap_receipt = jupiter.swap(wallet, quote)
print(f"Swap tx: {swap_receipt.hash}")

# Quick swap (simpler one-liner)
receipt = jupiter.quick_swap(wallet, sol, usdc, 1.0)
print(f"Quick swap tx: {receipt.hash}")

# Limit order (valid for 1 day = 86400 seconds)
limit_receipt = jupiter.limit_order(
    wallet,
    sol,              # Sell token
    usdc,             # Buy token
    1.0,              # Amount to sell
    34.5,             # Minimum to receive
    86400             # Lifetime in seconds
)
print(f"Limit order: {limit_receipt.hash}")

# Price-based limit order
price_receipt = jupiter.limit_order_by_price(
    wallet,
    sol,
    usdc,
    1.0,              # Amount to sell
    35.0,             # Price threshold
    86400
)
print(f"Price limit: {price_receipt.hash}")

# Get available lending markets
markets = jupiter.get_lendable_tokens(wallet)
for market in markets:
    print(f"Market: {market.name} ({market.symbol})")
    print(f"  APY: {market.supply_rate}")
    print(f"  TVL: {market.total_assets}")

# Deposit into lending protocol
deposit_receipt = jupiter.deposit(wallet, usdc, 100.0)
print(f"Deposit tx: {deposit_receipt.hash}")

# Withdraw from lending protocol
withdraw_receipt = jupiter.withdraw(wallet, usdc, 50.0)
print(f"Withdraw tx: {withdraw_receipt.hash}")

Quote Structure

The swap quote includes:

  • in_amount: Exact input amount needed
  • out_amount: Expected output amount
  • other_amount_threshold: Minimum output considering slippage
  • price_impact_pct: Price impact percentage
  • slippage_bps: Slippage in basis points
  • context_slot: Slot when quote was created
  • swap_mode: Type of swap (ExactIn, ExactOut)

Lending Markets

Jupiter Earn provides lending markets with:

  • supply_rate: Current APY for deposits
  • total_assets: Total assets in the market
  • total_supply: Total supply shares issued
  • decimals: Token decimal places
  • symbol: Token symbol

API Key

Get a free API key from Jupiter:

  • Free tier available for development
  • Rate limits apply
  • Required for production swaps

Kamino - Yield Optimization Vaults

Kamino is a vault protocol on Solana that optimizes yield strategies by allocating assets across multiple lending markets. Kamino vaults provide automated yield farming and lending strategies.

Overview

  • Vault Discovery: Find vaults by name, ID, or underlying token
  • Vault Metrics: APY, TVL, performance tracking
  • Position Management: Deposit and withdraw from vaults
  • User Positions: Track vault holdings across all vaults
  • Strategy Allocation: Vaults allocate across KLend reserves

Important Note

Kamino is currently available in Rust only. Python bindings are not yet available. The interface requires direct interaction with the Kamino smart contracts via Anchor.

Supported Operations (Rust Only)

use bonanca::defi::Kamino;
use bonanca::wallets::solana::SolWallet;

#[tokio::main]
async fn main() -> Result<()> {
    let wallet = SolWallet::new(
        "base58_private_key",
        "https://api.mainnet-beta.solana.com"
    )?;

    let kamino = Kamino::new();

    // Example 1: Get all available vaults
    let all_vaults = kamino.get_vaults().await?;
    println!("Total vaults: {}", all_vaults.len());
    for vault in &all_vaults {
        println!("Vault: {} ({})", vault.state.name, vault.address);
        println!("  Token: {}", vault.state.token_mint);
        println!("  APY: {}", vault.state.name);
    }

    // Example 2: Find vault by name
    let usdc_vault = kamino.get_vault_data_by_name("Kamino USDC")
        .await?;
    println!("USDC Vault Address: {}", usdc_vault.address);

    // Example 3: Find vault by ID
    let vault_id = "7i..."; // Vault address
    let vault_data = kamino.get_vault_data_by_id(vault_id).await?;
    println!("Vault Name: {}", vault_data.state.name);

    // Example 4: Get user's vault positions
    let positions = kamino.get_user_data(&wallet.pubkey.to_string()).await?;
    println!("User positions: {}", positions.len());
    for position in &positions {
        println!("Vault: {}", position.vault_address);
        println!("  Staked Shares: {}", position.staked_shares);
        println!("  Unstaked Shares: {}", position.unstaked_shares);
        println!("  Total Shares: {}", position.total_shares);
    }

    // Example 5: Find all USDC vaults
    let usdc_mint = "EPjFWdd5Au17FXxeB6VWyeXKSa3LvwV0LCH7f3uyxVEP";
    let usdc_vaults = kamino.get_token_vaults(usdc_mint).await?;
    println!("USDC vaults available: {}", usdc_vaults.len());

    // Example 6: Deposit into a vault
    let vault = kamino.get_vault_data_by_name("Kamino USDC").await?;
    kamino.supply(&wallet, &vault, 1000.0).await?;
    println!("Deposited 1000 USDC into vault");

    // Example 7: Withdraw from a vault
    kamino.withdraw(&wallet, &vault, 500.0).await?;
    println!("Withdrew 500 USDC from vault");

    // Example 8: Monitor vault performance
    println!("\nVault Details:");
    println!("  Name: {}", vault.state.name);
    println!("  Token Mint: {}", vault.state.token_mint);
    println!("  Shares Mint: {}", vault.state.shares_mint);
    println!("  Total Shares Issued: {}", vault.state.shares_issued);
    println!("  Performance Fee: {} bps", vault.state.performance_fee_bps);
    println!("  Management Fee: {} bps", vault.state.management_fee_bps);

    Ok(())
}

Vault Information

Each vault provides detailed information:

  • name: Human-readable vault name
  • token_mint: The token deposited in this vault
  • shares_mint: The receipt token for vault shares
  • address: Vault account address
  • token_available: Amount available for withdrawal
  • shares_issued: Total shares in circulation
  • performance_fee_bps: Fee on profits (basis points)
  • management_fee_bps: Annual management fee
  • vault_allocation_strategy: How tokens are allocated across reserves

Vault Allocation

Kamino vaults automatically allocate deposits across multiple lending reserves:

  • Optimizes yield across KLend markets
  • Rebalances automatically
  • Charges performance and management fees
  • Reinvests earned interest

User Positions

Track positions across all vaults:

  • staked_shares: Shares in staking/earning strategies
  • unstaked_shares: Shares not yet fully invested
  • total_shares: Total position size
  • One entry per vault per user

Fee Structure

  • Performance Fee: Percentage of earned yield (in basis points)
  • Management Fee: Annual fee charged (in basis points)
  • Example: 10% performance fee = 1000 bps, 1% management fee = 100 bps

Swap Best Practices

General Guidelines

  1. Slippage Management

    • Always check other_amount_threshold on quotes
    • Jupiter automatically handles slippage configuration
    • Adjust slippage for volatile markets
  2. Quote Validity

    • Quotes are typically valid for ~30 seconds
    • Refresh quotes before executing large swaps
    • Use quick_swap for time-sensitive trades
  3. Price Impact

    • Monitor price_impact_pct in quotes
    • Larger swaps have higher price impact
    • Consider breaking into smaller swaps if > 5% impact

Limit Order Strategy

  • Expiration: Set lifetime based on trading frequency

    • Short-term: 1-24 hours
    • Day trading: 1 hour
    • Long-term: 7+ days
  • Order Amounts

    • limit_order takes exact amounts
    • limit_order_by_price calculates amounts from price
  • Order Book

    • Limit orders wait for market to reach your price
    • No execution guarantee
    • Prices are checked continuously

Vault Management Best Practices

Deposit Strategy

  1. Find Appropriate Vault

    • Check vault APY and TVL
    • Verify vault allocation strategy
    • Review fee structure
  2. Monitor Positions

    • Track share value over time
    • Monitor APY changes
    • Watch fee deductions
  3. Withdrawal Timing

    • Withdraw when strategy is optimal
    • Consider gas costs
    • Account for any lock-up periods

Risk Management

  • Concentration Risk: Diversify across multiple vaults/tokens
  • Smart Contract Risk: Kamino/KLend are audited but not risk-free
  • Market Risk: Underlying tokens can be volatile
  • Strategy Risk: Allocations may not perform as expected

Common Patterns

Simple Swap

let receipt = jupiter.quick_swap(&wallet, sell_token, buy_token, 1.0).await?;

Quoted Swap

let quote = jupiter.get_swap_quote(&wallet, sell, buy, amount).await?;
// Check quote before proceeding
let receipt = jupiter.swap(&wallet, quote).await?;

Deposit to Earn

let markets = jupiter.get_lendable_tokens().await?;
// Find market with best APY
let receipt = jupiter.deposit(&wallet, chosen_market, amount).await?;

Vault Position Tracking

let kamino = Kamino::new();
let positions = kamino.get_user_data(&wallet_pubkey).await?;
for position in positions {
    let vault = kamino.get_vault_data_by_id(&position.vault_address).await?;
    println!("Position in {}: {}", vault.state.name, position.total_shares);
}

Token Addresses

Common Solana token addresses:

  • SOL: So11111111111111111111111111111111111111112
  • USDC: EPjFWdd5Au17FXxeB6VWyeXKSa3LvwV0LCH7f3uyxVEP
  • USDT: Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenEst
  • ORCA: orcaEKTdK7LKz57chYcUBK6GDZT5bNvmnucEZDfmWQe
  • JUP: JUPyiwrYJFskidvHPcMj5kLSnsxPJ3Bad7Or7SvxJvP
  • COPE: 8HGyAAB1yoM1ttS7pnK6DGPhcF1JSQhQTiNrgQpTsEq
  • RAY: 4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX4r

Troubleshooting

Swap Failures

  • Insufficient Balance: Ensure wallet has enough tokens
  • Slippage Exceeded: Quote may have expired, refresh and try again
  • Network Congestion: Retry after waiting or increase priority fee
  • Liquidity Issues: Requested pair may not have sufficient liquidity

Limit Order Issues

  • Order Not Filling: Price may not have reached your target
  • Expired Order: Lifetime has passed, create new order
  • Invalid Amounts: Ensure amounts are correctly formatted

Vault Operations

  • Deposit Fails: Verify token balance and vault capacity
  • Withdraw Fails: Ensure sufficient shares, check vault liquidity
  • Account Creation: First interaction with vault may require account setup

Security Considerations

  • Never share your private key
  • Use environment variables for sensitive data
  • Test on devnet before mainnet
  • Monitor transaction fees and balances
  • Verify token addresses before trading
  • Start with small amounts while testing

Examples

A curated collection of example projects and scripts demonstrating common Bonanca workflows. Browse the examples to learn how to run bots, manage index funds, use the scalper, and interact with on-chain protocols in both Rust and Python.

Index Fund Example

The Index Fund is a Rust-based portfolio management tool that maintains a diversified cryptocurrency index. It allows you to manage a basket of tokens with automatic rebalancing to maintain target weights.

You can see the example code here.

Features

  • Create and manage a diversified portfolio of cryptocurrencies
  • Automatic rebalancing to target weights
  • Multiple rebalancing strategies

Building the Project

cd examples/crates/index-fund
cargo build --release

Basic Usage

This example project build a CLI which includes help docs that cover basic usage.

index --help

Configuration

Create an index fund configuration file:

{
  "name": "Basic Index Fund",
  "chain": "EVM:Polygon",
  "chain_id": 137,
  "rpc_url": "https://1rpc.io/matic",
  "keyvault": "./keyvault.json",
  "child": 0,
  "max_offset": 0.01,

  "aggregator": {
    "name": "0x",
    "api_key": "API_KEY"
  },

  "oracle": {
    "name": "DefiLlama",
    "api_key": "API_KEY"
  },

  "auxiliary_assets": [
    {
      "name": "Dai Stablecoin",
      "symbol": "DAI",
      "address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063"
    }
  ],

  "sectors": [
    {
      "name": "Layer 1",
      "weight": 0.4,
      "assets": [
        {
          "name": "Bitcoin",
          "symbol": "WBTC",
          "address": "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6"
        },
        {
          "name": "Ethereum",
          "symbol": "WETH",
          "address": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619"
        }
      ]
    },
    {
      "name": "DeFi",
      "weight": 0.2,
      "assets": [
        {
          "name": "Uniswap",
          "symbol": "UNI",
          "address": "0xb33EaAd8d922B1083446DC23f610c2567fB5180f"
        },
        {
          "name": "Aave",
          "symbol": "AAVE",
          "address": "0xD6DF932A45C0f255f85145f286eA0b292B21C90B"
        }
      ]
    },
    {
      "name": "Infrastructure",
      "weight": 0.2,
      "assets": [
        {
          "name": "ChainLink",
          "symbol": "LINK",
          "address": "0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39"
        },
        {
          "name": "Graph Token",
          "symbol": "GRT",
          "address": "0x5fe2B58c013d7601147DcdD68C143A77499f5531"
        }
      ]
    },
    {
      "name": "Stablecoins",
      "weight": 0.2,
      "assets": [
        {
          "name": "Circle USD",
          "symbol": "USDC",
          "address": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
        },
        {
          "name": "Stasis EUR",
          "symbol": "EURS",
          "address": "0xE111178A87A3BFf0c8d18DECBa5798827539Ae99"
        }
      ]
    }
  ]
}

Grid Bot Example

The Grid Bot is a Rust-based automated trading bot that implements a grid trading strategy on EVM-compatible blockchains. Grid trading works by placing buy and sell orders at regular price intervals (grid levels) to capture profits from price fluctuations.

You can see the example code here.

Features

  • Automated grid trading on EVM chains
  • Configurable grid parameters (size, max orders, price delta)
  • Trading history and profit tracking
  • Real-time order management
  • Balance monitoring

Building the Project

cd examples/crates/grid-bot
cargo build --release

Basic Usage

This example project build a CLI which includes help docs that cover basic usage.

grid-bot --help

Configuration

Create a grid_bot.json configuration file with the following structure:

{
  "chain": "base",
  "rpc_url": "https://base.drpc.org",
  "keyvault": "./keyvault.json",
  "log_file": "./grid_bot_log.json",
  "child": 0,

  "trading_pair": {
    "token_a": {
      "name": "Circle USD",
      "symbol": "USDC",
      "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "decimals": 6
    },
    "token_b": {
      "name": "Ethereum",
      "symbol": "WETH",
      "address": "0x4200000000000000000000000000000000000006",
      "decimals": 18
    },
    "num_grids": 5,
    "upper_limit": 2300.0,
    "lower_limit": 1700.0,
    "buy_amount": 0.1,
    "sell_amount": 0.1
  }
}

Parameters

  • num_grids: Number of grid levels to place
  • upper_limit: The highest price at which to place sell orders
  • lower_limit: The lowest price at which to place buy orders
  • buy_amount: The amount of token_a to use for each buy level
  • sell_amount: The amount of token_b to sell at each sell level

Scalper Bot Example

The Scalper Bot is a Python-based trading bot. Scalping involves making many small trades to capture tiny price differences (spreads). This uses the CoW protocol for limit orders.

You can check out the code here.

Features

  • Automated scalping on EVM-compatible blockchains
  • Configurable trade parameters and limits
  • Detailed trade logging and performance tracking
  • Order history tracking (buy/sell averages)
  • Profit monitoring and reporting
  • Support for any EVM token pair

Configuration

Create a scalper.toml configuration file:

chain = "Polygon"
rpc_url = "https://polygon-rpc.com"
keyvault = "./keyvault.json"
child = 0
log_file = "./grid_bot_log.json"

[base]
name = "Wrapped Ether"
symbol = "WETH"
address = "0x7ceB23fD6bC0adD59E27f9EA9d0231e0f01cc726"
decimals = 18

[target]
name = "USDC Coin"
symbol = "USDC"
address = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
decimals = 6

[trade_settings]
size = 0.1
max_orders = 5
delta = 0.2
profit = 1.5
expiry = "0-30-300"

Configuration Parameters

Trade Settings

  • size: The size of each scalp trade (in base token units)
  • max_orders: Maximum number of concurrent orders
  • delta: Price difference between placed buy orders (percentage)
  • profit: Minimum profit target for sell orders (percentage)
  • expiry: Order expiration time format "DAYS-HOURS-MINUTES"

Output Files

  • log_file: JSON file containing:
    • Active orders
    • Current profit
    • Buy history (total bought, average buy price)
    • Sell history (total sold, average sell price)

KeyVault

Bonança stores the seed to your HD wallet in what is called a KeyVault, which can be serialized into a json file. This takes inspiration from keystore files, if you are unfamiliar with them consider reading this post.

When serialized, your HD wallet seed is encrypted using a password you define. An example key vault json file structure is as follows:

{
  "vault": {
    "cipher": "aes256-gcm",
    "cipher_params": { "nonce": "287189f34a1433d2de201d08" },
    "cipher_text": "7a34170003c0a7b3ccb75bac28757801a7d9b5e1ff062afa4af5f3c03e7d8982eb1f36ccce87436e42b44ffea6bcf39eba8c15d4e79ee0bf012811fca81ae1e112c0f8ae5d8e43ac8cad1ae961b11207",
    "kdf": "pbkdf2",
    "kdf_params": {
      "key_length": 32,
      "n": 600000,
      "salt": "M6lWvNAGuZBSp9fBGAUEqw"
    },
    "mac": "$argon2id$v=19$m=19456,t=2,p=1$M6lWvNAGuZBSp9fBGAUEqw$/U5VYPmg3+BQj0ttOyPnOUjH7bP23V9/tgvBpovna/8",
    "salt": "M6lWvNAGuZBSp9fBGAUEqw"
  },
  "chain_keys": {
    "Solana": ["AbwHhAquPXvDfxvWEh1b4mG969DQF9wJQSK5k8XKSKtG"],
    "EVM": ["0x50940F0C5779BE15F7ACB12E9b75128e1415BFec"]
  }
}

Breaking down the components:

  • cipher is the encryption algorithm used to encrypt your HD wallet seed
  • Within cipher_params you find nonce which is an initialization vector for the AES-256-GCM algorithm
  • cipher_text is your encrypted seed
  • kdf is the key derivation function used (PBKDF2)
  • kdf_params are the parameters used in the key derivation function
    • key_length is the length in bytes of the key
    • n is the number of cycles in the algorithm, where 600,000 is used to make encrypting/decrypting time consuming to prevent brute force attacks
    • salt is the password salt
  • mac is your hashed and salted password using Argon2 (its parameters are included in the mac string)
  • salt again the password salt
  • chain_keys these are your public keys for various blockchains

Changes to any of these fields can result in failure to decrypt the seed, and possibly permanent loss of all funds.

The only point of weakness within the KeyVault encryption is your choice of password. If a malicious actor were to get a hold of your json file, they could try to decrypt it by either guessing the password or the seed. Guessing the seed is extremely difficult and unlikely, whereas guessing a password is more doable. This means picking a good password is crucial.

KeyVault includes your public keys within the chain_keys field, which allows you to view your accounts without having to decrypt your KeyVault. There are positives and negatives to this approach, with the main benefit being that you can check wallet balances without supplying your password. The main drawback is that if a malicious actor were to get this file, they would know how valuable breaking the encryption is.

Contributing to Bonança

I welcome contributions from the community to help improve Bonança! Whether it's fixing bugs, adding new features, or improving documentation, your contributions are valuable to me. Here are some guidelines to help you get started:

Getting Started

  1. Fork the Repository: Start by forking the Bonança repository on GitHub to create your own copy of the project.
  2. Create a Branch: Create a new branch for your feature or bug fix. Use a descriptive name for your branch, such as add-new-bot or fix-index-calculation.
  3. Make Changes: Make your changes in the new branch. Ensure that your code follows the existing coding style and conventions used in the project.
  4. Test Your Changes: Write tests for your changes to ensure they work as expected and do not introduce new issues. Run existing tests to verify that everything is still functioning correctly.
  5. Commit Your Changes: Commit your changes with clear and concise commit messages that describe the purpose of the changes.
  6. Push to Your Fork: Push your changes to your forked repository on GitHub.
  7. Create a Pull Request: Open a pull request from your branch to the main Bonança repository. Provide a detailed description of the changes you made and any relevant information for reviewers.

Reporting Issues

If you encounter any bugs or have suggestions for new features, please open an issue on the GitHub Issues page. Provide as much detail as possible to help us understand and address the issue.

Support Bonança

If you find Bonança useful and would like to support its development, there are several ways you can contribute:

  1. Star the Repository: Show your appreciation by starring the Bonança GitHub repository. This helps increase the visibility of the project and encourages others to check it out.
  2. Report Issues: If you encounter any bugs or have suggestions for new features, please open an issue on the GitHub Issues page. Providing detailed information helps me address problems more effectively.
  3. Contribute Code: If you're a developer, consider contributing code to the project. You can fork the repository, make improvements or add new features, and submit a pull request.
  4. Spread the Word: Share Bonança with your friends, colleagues, and on social media. The more people who know about it, the more support and contributions the project can receive.

Thank you for being a part of the Bonança community!

Reporting Security Issues

If you discover a security vulnerability in Bonança, please report it to me privately so that we can address the issue before it becomes public knowledge. This helps protect all users of Bonança and ensures that vulnerabilities are fixed promptly.