Skip to main content

Functionality

Test it yourself

If the bot will be running on our hardware, then you will be able to test it yourself. You can find it under @breeze_integration_bot handle or under this link.

Code Location

GitHub Repo

Find out the github repository with the full code

Explanation

Overview

The Breeze Protocol integration enables:
  • Simplified User Experience: No manual fund account initialization required
  • Real-time Balance Tracking: Live updates from the Breeze API
  • Multi-Asset Support: USDC, USDT, USDS, JupSOL, JLP, mSOL, JitoSOL, and SOL
  • Strategy-Based Yield: Use strategy ID with per-asset APY tracking
  • Seamless Transactions: Direct deposit and withdrawal flow
The Breeze API handles user fund account creation automatically, eliminating the need for manual initialization flows. The new strategy-based approach allows depositing multiple assets into a single strategy with individual APY tracking per asset.

Architecture

API Configuration

Environment Variables

const BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN || process.env.BOT_TOKEN!;
const SOLANA_RPC_URL = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
const BREEZE_API_KEY = process.env.BREEZE_API_KEY!;
const STRATEGY_ID = process.env.STRATEGY_ID!;

Base URL

https://api.breeze.baby/
Ensure your API key is kept secure and never exposed in client-side code.

Core API Endpoints

1. Strategy Info

Fetches strategy details including APY per asset.
GET /strategy-info/{strategy_id}
Response:
{
  "strategy_id": "43620ba3-354c-456b-aa3c-5bf7fa46a6d4",
  "strategy_name": "try-breeze-all-assets",
  "assets": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "..."],
  "apy": 4.10,
  "apy_per_asset": {
    "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v": 5.25,
    "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB": 4.80,
    "jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v": 7.20
  }
}

2. Breeze Balances

Fetches user’s positions within a strategy.
GET /breeze-balances/{user_pubkey}?strategy_id={strategy_id}
Response:
{
  "data": [
    {
      "strategy_name": "try-breeze-all-assets",
      "strategy_id": "43620ba3-354c-456b-aa3c-5bf7fa46a6d4",
      "fund_id": "fund_123",
      "token_address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "token_symbol": "USDC",
      "token_name": "USD Coin",
      "decimals": 6,
      "total_position_value": 1000000000,
      "total_deposited_value": 950000000,
      "yield_earned": 50000000,
      "apy": 5.25,
      "last_updated": "2024-01-20T14:45:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 10,
    "total": 1,
    "total_pages": 1,
    "has_more": false
  }
}

3. Deposit Transaction

Creates a deposit transaction using strategy ID and base asset (mint).
POST /deposit/tx
Request Body:
{
  "params": {
    "strategy_id": "43620ba3-354c-456b-aa3c-5bf7fa46a6d4",
    "base_asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": 1000000,
    "all": false,
    "user_key": "user_public_key",
    "payer_key": "user_public_key"
  }
}
Response (Success):
// Returns serialized transaction as string
"base64_encoded_transaction_string"
Response (Error):
{
  "message": "Error description"
}

4. Withdraw Transaction

Creates a withdrawal transaction using strategy ID and base asset.
POST /withdraw/tx
Request Body:
{
  "params": {
    "strategy_id": "43620ba3-354c-456b-aa3c-5bf7fa46a6d4",
    "base_asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": 1000000,
    "all": false,
    "user_key": "user_public_key",
    "payer_key": "user_public_key"
  }
}

Implementation Guide

Asset Configuration

// Asset configuration interface
interface AssetConfig {
    symbol: string;
    mint: string;
    decimals: number;
}

// Available assets for the strategy
const AVAILABLE_ASSETS: AssetConfig[] = [
    { symbol: 'USDC', mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', decimals: 6 },
    { symbol: 'USDT', mint: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', decimals: 6 },
    { symbol: 'USDS', mint: 'USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA', decimals: 6 },
    { symbol: 'JupSOL', mint: 'jupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v', decimals: 9 },
    { symbol: 'JLP', mint: '27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4', decimals: 6 },
    { symbol: 'mSOL', mint: 'mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So', decimals: 9 },
    { symbol: 'JitoSOL', mint: 'J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn', decimals: 9 },
    { symbol: 'SOL', mint: 'So11111111111111111111111111111111111111112', decimals: 9 },
];

// Create lookup maps for quick access
const TOKEN_DECIMALS: Record<string, number> = {};
const TOKEN_MINTS: Record<string, string> = {};
const MINT_TO_SYMBOL: Record<string, string> = {};
for (const asset of AVAILABLE_ASSETS) {
    TOKEN_DECIMALS[asset.symbol] = asset.decimals;
    TOKEN_MINTS[asset.symbol] = asset.mint;
    MINT_TO_SYMBOL[asset.mint] = asset.symbol;
}

API Response Interfaces

// API response types
type BreezeApiResponseUpdated =
    | string // serialized transaction
    | { message: string }; // error

// Breeze Balances API response
interface BreezeBalance {
    strategy_name: string;
    strategy_id: string;
    fund_id: string;
    token_address: string;
    token_symbol: string;
    token_name: string;
    decimals: number;
    total_position_value: number;  // in token units
    total_deposited_value: number; // in token units
    yield_earned: number;          // in token units
    apy: number;
    last_updated: string;
}

interface BreezeBalancesResponse {
    data: BreezeBalance[];
    meta: {
        page: number;
        per_page: number;
        total: number;
        total_pages: number;
        has_more: boolean;
    };
}

// Strategy Info API response
interface StrategyInfo {
    strategy_id: string;
    strategy_name: string;
    assets: string[];
    apy: number;
    apy_per_asset: Record<string, number>; // mint -> APY
}

// User data with selected asset
interface UserData {
    keypair?: Keypair;
    publicKey?: string;
    currentMenu?: string;
    selectedAsset?: AssetConfig;
    pendingTransaction?: {
        serializedTx: string;
        type: 'deposit' | 'withdraw';
        amount?: number;
        asset?: string;
    };
}

Core Integration Class

class BreezeBot {
    private bot: TelegramBot;
    private connection: Connection;
    private users: Map<number, UserData> = new Map();

    constructor() {
        this.bot = new TelegramBot(BOT_TOKEN, { polling: true });
        this.connection = new Connection(SOLANA_RPC_URL);
        this.setupHandlers();
    }

    // Fetch strategy info with APY per asset
    private async getStrategyInfo(): Promise<StrategyInfo | null> {
        try {
            const response = await fetch(`https://api.breeze.baby/strategy-info/${STRATEGY_ID}`, {
                method: 'GET',
                headers: {
                    "Content-Type": "application/json",
                    "x-api-key": BREEZE_API_KEY
                }
            });

            if (!response.ok) {
                console.error('Error fetching strategy info: HTTP', response.status);
                return null;
            }

            return await response.json() as StrategyInfo;
        } catch (error) {
            console.error('Error fetching strategy info:', error);
            return null;
        }
    }

    // Fetch breeze balances with strategy_id
    private async getBreezeBalances(userPublicKey: string): Promise<BreezeBalancesResponse | null> {
        try {
            const response = await fetch(
                `https://api.breeze.baby/breeze-balances/${userPublicKey}?strategy_id=${STRATEGY_ID}`,
                {
                    method: 'GET',
                    headers: {
                        "Content-Type": "application/json",
                        "x-api-key": BREEZE_API_KEY
                    }
                }
            );

            if (!response.ok) {
                console.error('Error fetching breeze balances: HTTP', response.status);
                return null;
            }

            return await response.json() as BreezeBalancesResponse;
        } catch (error) {
            console.error('Error fetching breeze balances:', error);
            return null;
        }
    }

    // Precise BigInt token amount conversion
    private convertToTokenAmount(humanAmount: number, tokenSymbol: string): bigint {
        const decimals = TOKEN_DECIMALS[tokenSymbol] || 6;
        const amountStr = humanAmount.toFixed(decimals);
        const [integerPart, decimalPart = ''] = amountStr.split('.');
        const paddedDecimal = decimalPart.padEnd(decimals, '0').slice(0, decimals);
        const fullAmountStr = integerPart + paddedDecimal;
        return BigInt(fullAmountStr);
    }

    private convertFromTokenAmount(tokenAmount: bigint, tokenSymbol: string): number {
        const decimals = TOKEN_DECIMALS[tokenSymbol] || 6;
        const divisor = BigInt(10 ** decimals);
        const integerPart = Number(tokenAmount / divisor);
        const remainder = tokenAmount % divisor;
        const decimalPart = Number(remainder) / Number(divisor);
        return integerPart + decimalPart;
    }

    // Get total portfolio value across all assets
    private async getUserCurrentValue(userPublicKey: string): Promise<number> {
        try {
            const balanceData = await this.getBreezeBalances(userPublicKey);
            if (!balanceData) return 0;

            let totalPortfolioValue = 0;
            for (const balance of balanceData.data) {
                // Convert from token units to human-readable
                const humanValue = this.convertFromTokenAmount(
                    BigInt(Math.floor(balance.total_position_value)),
                    balance.token_symbol
                );
                totalPortfolioValue += humanValue;
            }
            return totalPortfolioValue;
        } catch (error) {
            console.error('Error fetching user current value:', error);
            return 0;
        }
    }

    // Get user's balance for a specific asset in Breeze
    private async getUserAssetBalance(userPublicKey: string, mint: string): Promise<number> {
        try {
            const balanceData = await this.getBreezeBalances(userPublicKey);
            if (!balanceData) return 0;

            for (const balance of balanceData.data) {
                if (balance.token_address === mint) {
                    return this.convertFromTokenAmount(
                        BigInt(Math.floor(balance.total_position_value)),
                        balance.token_symbol
                    );
                }
            }
            return 0;
        } catch (error) {
            console.error('Error fetching asset balance:', error);
            return 0;
        }
    }
}

Deposit Flow with Multi-Asset Support

private async showDepositInterface(chatId: number) {
    const strategyInfo = await this.getStrategyInfo();
    const userData = this.users.get(chatId)!;
    const balances = await this.getBalances(userData.publicKey!);

    let message = '📥 **Deposit to Breeze** 📥\n\n' +
        'Select the asset you want to deposit:\n\n';

    // Build keyboard with all available assets and their APY
    const keyboard: TelegramBot.InlineKeyboardButton[][] = [];

    for (const asset of AVAILABLE_ASSETS) {
        const apy = strategyInfo?.apy_per_asset?.[asset.mint] || 0;
        const assetKey = asset.symbol.toLowerCase();
        const balance = balances[assetKey]?.human || 0;

        const buttonText = `${asset.symbol} - ${apy.toFixed(2)}% APY (${balance.toFixed(2)} available)`;
        keyboard.push([{ text: buttonText, callback_data: `deposit_asset_${asset.symbol}` }]);
    }

    keyboard.push([{ text: '🔙 Back', callback_data: 'earn_yield' }]);

    await this.bot.sendMessage(chatId, message, {
        parse_mode: 'Markdown',
        reply_markup: { inline_keyboard: keyboard }
    });
}

// Process deposit with strategy_id + base_asset
private async processDeposit(chatId: number, percentage?: number, customAmount?: number) {
    const userData = this.users.get(chatId)!;
    const selectedAsset = userData.selectedAsset;

    if (!selectedAsset) {
        await this.bot.sendMessage(chatId, '❌ No asset selected. Please select an asset first.');
        return;
    }

    const balances = await this.getBalances(userData.publicKey!);
    const assetKey = selectedAsset.symbol.toLowerCase();
    const assetBalance = balances[assetKey] || { raw: BigInt(0), human: 0 };

    let tokenAmount: bigint;
    let humanAmount: number;
    let isAll = false;

    if (percentage === 100) {
        tokenAmount = assetBalance.raw;
        humanAmount = assetBalance.human;
        isAll = true;
    } else if (percentage === 50) {
        tokenAmount = assetBalance.raw / BigInt(2);
        humanAmount = this.convertFromTokenAmount(tokenAmount, selectedAsset.symbol);
    } else if (customAmount) {
        humanAmount = customAmount;
        tokenAmount = this.convertToTokenAmount(customAmount, selectedAsset.symbol);
    } else {
        return;
    }

    if (tokenAmount <= 0) {
        await this.bot.sendMessage(chatId, `❌ Insufficient ${selectedAsset.symbol} balance!`);
        return;
    }

    try {
        // Use strategy_id + base_asset instead of fund_id
        const requestBody = {
            "params": {
                "strategy_id": STRATEGY_ID,
                "base_asset": selectedAsset.mint,
                "amount": Number(tokenAmount),
                "all": isAll,
                "user_key": userData.publicKey,
                "payer_key": userData.publicKey
            }
        };

        const response = await fetch('https://api.breeze.baby/deposit/tx', {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
                "x-api-key": BREEZE_API_KEY
            },
            body: JSON.stringify(requestBody)
        });

        const data = await response.json() as BreezeApiResponseUpdated;

        if (typeof data === 'object' && 'message' in data) {
            await this.bot.sendMessage(chatId, `❌ Error: ${data.message}`);
            return;
        }

        userData.pendingTransaction = {
            serializedTx: data,
            type: 'deposit',
            amount: humanAmount,
            asset: selectedAsset.symbol
        };

        await this.showTransactionConfirmation(chatId, 'deposit', humanAmount, selectedAsset.symbol);
    } catch (error) {
        console.error('Deposit error:', error);
        await this.bot.sendMessage(chatId, '❌ Failed to create deposit transaction.');
    }
}

Withdraw Flow with Multi-Asset Support

private async showWithdrawInterface(chatId: number) {
    const userData = this.users.get(chatId)!;
    const breezeBalances = await this.getBreezeBalances(userData.publicKey!);
    const strategyInfo = await this.getStrategyInfo();

    let message = '📤 **Withdraw from Breeze** 📤\n\n' +
        'Select the asset you want to withdraw:\n\n';

    const keyboard: TelegramBot.InlineKeyboardButton[][] = [];

    if (breezeBalances && breezeBalances.data.length > 0) {
        for (const balance of breezeBalances.data) {
            if (balance.total_position_value > 0) {
                // Convert from token units to human-readable
                const positionValue = this.convertFromTokenAmount(
                    BigInt(Math.floor(balance.total_position_value)),
                    balance.token_symbol
                );
                const apy = strategyInfo?.apy_per_asset?.[balance.token_address] || balance.apy || 0;
                const buttonText = `${balance.token_symbol} - $${positionValue.toFixed(2)} (${apy.toFixed(2)}% APY)`;
                keyboard.push([{ text: buttonText, callback_data: `withdraw_asset_${balance.token_symbol}` }]);
            }
        }
    }

    if (keyboard.length === 0) {
        message += 'No positions found to withdraw.';
    }

    keyboard.push([{ text: '🔙 Back', callback_data: 'earn_yield' }]);

    await this.bot.sendMessage(chatId, message, {
        parse_mode: 'Markdown',
        reply_markup: { inline_keyboard: keyboard }
    });
}

// Process withdraw with strategy_id + base_asset
private async processWithdraw(chatId: number, percentage?: number, customAmount?: number) {
    const userData = this.users.get(chatId)!;
    const selectedAsset = userData.selectedAsset;

    if (!selectedAsset) {
        await this.bot.sendMessage(chatId, '❌ No asset selected.');
        return;
    }

    const assetBreezeBalance = await this.getUserAssetBalance(userData.publicKey!, selectedAsset.mint);

    let humanAmount: number;
    let isAll = false;

    if (percentage === 100) {
        humanAmount = assetBreezeBalance;
        isAll = true;
    } else if (percentage === 50) {
        humanAmount = assetBreezeBalance * 0.5;
    } else if (customAmount) {
        humanAmount = customAmount;
    } else {
        return;
    }

    if (humanAmount <= 0) {
        await this.bot.sendMessage(chatId, `❌ No ${selectedAsset.symbol} funds available to withdraw!`);
        return;
    }

    const tokenAmount = this.convertToTokenAmount(humanAmount, selectedAsset.symbol);

    try {
        const requestBody = {
            "params": {
                "strategy_id": STRATEGY_ID,
                "base_asset": selectedAsset.mint,
                "amount": Number(tokenAmount),
                "all": isAll,
                "user_key": userData.publicKey,
                "payer_key": userData.publicKey
            }
        };

        const response = await fetch('https://api.breeze.baby/withdraw/tx', {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
                "x-api-key": BREEZE_API_KEY
            },
            body: JSON.stringify(requestBody)
        });

        const data = await response.json() as BreezeApiResponseUpdated;

        if (typeof data === 'object' && 'message' in data) {
            await this.bot.sendMessage(chatId, `❌ Error: ${data.message}`);
            return;
        }

        userData.pendingTransaction = {
            serializedTx: data,
            type: 'withdraw',
            amount: humanAmount,
            asset: selectedAsset.symbol
        };

        await this.showTransactionConfirmation(chatId, 'withdraw', humanAmount, selectedAsset.symbol);
    } catch (error) {
        console.error('Withdraw error:', error);
        await this.bot.sendMessage(chatId, '❌ Failed to create withdrawal transaction.');
    }
}

Enhanced Features

Earn Yield Interface with Strategy Info

private async showEarnYieldInterface(chatId: number) {
    const userData = this.users.get(chatId)!;
    const publicKey = userData.publicKey!;
    const breezeBalance = await this.getUserCurrentValue(publicKey);
    const strategyInfo = await this.getStrategyInfo();

    let message = '🌊 **Earn Yield with Breeze** 🌊\n\n';
    message += `📊 **Strategy:** ${strategyInfo?.strategy_name || 'Unknown'}\n`;
    message += `📈 **Average APY:** ${(strategyInfo?.apy || 0).toFixed(2)}%\n`;
    message += `🌊 **Your Position:** $${breezeBalance.toFixed(2)}\n\n`;

    message += '**APY by Asset:**\n';
    if (strategyInfo?.apy_per_asset) {
        for (const asset of AVAILABLE_ASSETS) {
            const apy = strategyInfo.apy_per_asset[asset.mint] || 0;
            if (apy > 0) {
                message += `• ${asset.symbol}: ${apy.toFixed(2)}%\n`;
            }
        }
    }

    message += '\n💡 Select an asset to earn passive yield!';

    const keyboard = {
        inline_keyboard: [
            [
                { text: '📥 Deposit', callback_data: 'deposit' },
                { text: '📤 Withdraw', callback_data: 'withdraw' }
            ],
            [{ text: '🔙 Back to Main', callback_data: 'back_to_main' }]
        ]
    };

    await this.bot.sendMessage(chatId, message, {
        parse_mode: 'Markdown',
        reply_markup: keyboard
    });
}

Detailed Balances View

private async showDetailedBalances(chatId: number) {
    const userData = this.users.get(chatId)!;
    const publicKey = userData.publicKey!;
    const breezeBalances = await this.getBreezeBalances(publicKey);
    const strategyInfo = await this.getStrategyInfo();

    let totalPortfolioValue = 0;
    let totalYieldEarned = 0;

    if (breezeBalances) {
        for (const balance of breezeBalances.data) {
            const positionValue = this.convertFromTokenAmount(
                BigInt(Math.floor(balance.total_position_value)),
                balance.token_symbol
            );
            const yieldEarned = this.convertFromTokenAmount(
                BigInt(Math.floor(balance.yield_earned)),
                balance.token_symbol
            );
            totalPortfolioValue += positionValue;
            totalYieldEarned += yieldEarned;
        }
    }

    let message = '💳 **Detailed Breeze Balances** 💳\n\n';
    message += `📊 **Strategy:** ${strategyInfo?.strategy_name || 'Unknown'}\n`;
    message += `💰 **Total Portfolio Value:** $${totalPortfolioValue.toFixed(2)}\n`;
    message += `🎯 **Total Yield Earned:** $${totalYieldEarned.toFixed(2)}\n\n`;

    if (!breezeBalances || breezeBalances.data.length === 0) {
        message += 'No positions found in Breeze.';
    } else {
        message += '**Positions by Asset:**\n\n';
        for (const balance of breezeBalances.data) {
            if (balance.total_position_value > 0) {
                const positionValue = this.convertFromTokenAmount(
                    BigInt(Math.floor(balance.total_position_value)),
                    balance.token_symbol
                );
                const depositedValue = this.convertFromTokenAmount(
                    BigInt(Math.floor(balance.total_deposited_value)),
                    balance.token_symbol
                );
                const yieldEarned = this.convertFromTokenAmount(
                    BigInt(Math.floor(balance.yield_earned)),
                    balance.token_symbol
                );
                const apy = strategyInfo?.apy_per_asset?.[balance.token_address] || balance.apy || 0;

                message += `**${balance.token_symbol}**\n`;
                message += `• Position Value: $${positionValue.toFixed(2)}\n`;
                message += `• Deposited: $${depositedValue.toFixed(2)}\n`;
                message += `• Yield Earned: $${yieldEarned.toFixed(2)}\n`;
                message += `• APY: ${apy.toFixed(2)}%\n\n`;
            }
        }
    }

    await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
}

Transaction Management

Transaction Signing and Submission

private async confirmTransaction(chatId: number) {
    const userData = this.users.get(chatId)!;
    const pendingTx = userData.pendingTransaction;

    if (!pendingTx || !pendingTx.serializedTx) {
        await this.bot.sendMessage(chatId, '❌ No pending transaction found.');
        return;
    }

    try {
        const transaction = VersionedTransaction.deserialize(
            Buffer.from(pendingTx.serializedTx, 'base64')
        );
        transaction.sign([userData.keypair!]);

        const signature = await this.connection.sendTransaction(transaction);

        await this.bot.sendMessage(chatId, '⏳ Transaction sent! Waiting for confirmation...');

        const confirmation = await this.connection.confirmTransaction(signature, 'confirmed');

        if (confirmation.value.err) {
            await this.bot.sendMessage(chatId, '❌ Transaction failed!');
            return;
        }

        const action = pendingTx.type === 'deposit' ? 'deposited to' : 'withdrawn from';
        await this.bot.sendMessage(chatId,
            `🎉 **Successfully ${action} Breeze!**\n\n` +
            `💰 Amount: ${pendingTx.amount?.toFixed(2)} ${pendingTx.asset}\n` +
            `🔗 Transaction: \`${signature}\``,
            { parse_mode: 'Markdown' }
        );

        userData.pendingTransaction = undefined;
    } catch (error) {
        console.error('Transaction error:', error);
        await this.bot.sendMessage(chatId, '❌ Failed to process transaction.');
    }
}

Environment Setup

Required Environment Variables

# Telegram Bot Configuration
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here

# Solana Configuration
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com

# Breeze API Configuration
BREEZE_API_KEY=your_breeze_api_key_here
STRATEGY_ID=your_strategy_id_here

Build and Run

# Install dependencies
npm install

# Build the project
npm run build

# Start the bot
npm start

# Or for development with hot reload
npm run dev

Supported Assets

AssetMint AddressDecimals
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v6
USDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB6
USDSUSDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA6
JupSOLjupSoLaHXQiZZTSfEWMTRRgpnyFm8f6sZdosWBjx93v9
JLP27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD46
mSOLmSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So9
JitoSOLJ1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn9
SOLSo111111111111111111111111111111111111111129

Key Features

Strategy-Based Yield Farming

  • Multi-Asset Support: Deposit 8 different assets into a single strategy
  • Per-Asset APY: Real-time APY tracking for each supported asset
  • Strategy Info: Fetch strategy details including name and average APY

Wallet Management

  • Keypair Generation: Create new Solana keypairs securely
  • Private Key Import: Import existing wallets using base58 encoded private keys
  • Balance Tracking: Real-time SOL and SPL token balance monitoring

Enhanced User Experience

  • Asset Selection UI: Choose which asset to deposit/withdraw with APY displayed
  • Real-time Data: All data fetched live from Breeze APIs
  • Detailed Analytics: View positions by asset with yield earned
  • Transaction Feedback: Real-time updates during transaction processing

Troubleshooting

  • Verify API key is correct and active
  • Check network connectivity to Breeze API
  • Ensure STRATEGY_ID is valid
  • Review API rate limits and quotas
  • Check user has sufficient SOL for transaction fees
  • Verify token account exists and has sufficient balance
  • Ensure transaction isn’t expired
  • Check Solana network status
  • API returns values in token units (raw amounts)
  • Ensure proper decimal conversion using convertFromTokenAmount
  • Check for pending transactions
  • Verify strategy_id parameter in API calls
  • Verify asset mint address is correct
  • Check strategy supports the asset
  • Ensure strategy-info API returns apy_per_asset for the mint