✨📞💻
The original implementation was based on an older version of Orca's Whirlpool protocol. Since then, significant changes have been made:
-
Protocol Architecture Changes
- Whirlpool has moved to a new architecture with concentrated liquidity positions
- The old constant product pools are being phased out
- New CPI (Cross-Program Invocation) interfaces have been introduced
-
Integration Requirements
- Integration now requires using the latest Whirlpool CPI crate
- Reference: whirlpool-cpi
- Minimum requirements:
[dependencies] anchor-lang = ">=0.29.0" anchor-spl = ">=0.29.0" whirlpool-cpi = { git = "https://github.com/orca-so/whirlpool-cpi", branch = "anchor/0.29.0" }
Important note: On-chain arbitrage programs face several limitations and risks:
-
MEV Competition
- Searchers and validators can front-run transactions
- Transaction ordering can be manipulated
- Limited control over execution timing
-
Technical Constraints
- Compute unit limitations for complex calculations
- Transaction size limits for multi-hop trades
- Higher latency compared to off-chain solutions
-
Recommended Approach
- Use off-chain arbitrage detection
- Submit transactions through MEV-aware RPC providers
- Consider integrating with Jito-MEV for better execution
-
Alternative Architecture
graph TD A[Off-chain Monitor] --> B[Price Analysis] B --> C[Opportunity Detection] C --> D[Transaction Builder] D --> E[MEV-aware RPC] E --> F[Validator Network]
The original implementation should be considered as educational material rather than a production-ready solution. For real-world arbitrage:
- Use off-chain monitoring and calculations
- Integrate with MEV-aware infrastructure
- Consider validator relationships for better transaction placement
- Implement proper slippage and risk management
This arbitrage bot implements advanced strategies for detecting and executing profitable trading opportunities across multiple Solana DEXs including Raydium, Orca (Whirlpool), Meteora, and Jupiter, with optional integration for Jito-MEV.
graph TD
A[Price Monitor] --> B[Opportunity Detector]
B --> C{Strategy Selector}
C --> D[Two-Hop Strategy]
C --> E[Triangle Strategy]
C --> F[Multi-DEX Strategy]
D --> G[Execution Engine]
E --> G
F --> G
G --> H[Transaction Builder]
H --> I[MEV Bundle/Transaction]
- Real-time price monitoring across DEXs
- WebSocket connections for instant updates
- Price impact calculation
- Liquidity depth analysis
Example from Transaction Analysis:
Input: 0.196969275 Token A
↓ [Meteora DEX]
Intermediate: 146.90979292 Token B
↓ [Raydium DEX]
Output: 0.202451396 Token A
Profit: ~2.78%
Example Pattern:
Token A → Token B [Meteora]
Token B → Token C [Meteora]
Token C → Token A [Raydium]
Example from Whirlpool-Orca Route:
Input: 0.314737179 Token A
↓ [Orca]
Mid: 118.612731091 Token B
↓ [Whirlpool]
Output: 0.316606012 Token A
Profit: ~0.59%
-
Profitability Check
- Minimum profit threshold: 0.5%
- Gas cost estimation
- Slippage calculation
-
Route Optimization
- DEX selection based on:
- Liquidity depth
- Historical success rate
- Gas efficiency
- DEX selection based on:
-
Transaction Building
// Example structure const route = { steps: [ {dex: "Meteora", tokenIn: "A", tokenOut: "B"}, {dex: "Raydium", tokenIn: "B", tokenOut: "A"} ], expectedProfit: "2.78%", gasEstimate: 200000 };
- Dynamic slippage calculation
- Maximum slippage: 1%
- Route abandonment on excessive slippage
- Success rate tracking
- Gas price optimization
- Failed transaction analysis
- Dynamic position sizing based on:
- Available liquidity
- Historical volatility
- Success probability
- Minimum profit per trade: 0.5%
- Maximum gas cost: 0.002741081 SOL
- Transaction success rate: >95%
- Meteora: Primary DEX for initial swaps
- Raydium: Secondary DEX for route completion
- Orca Whirlpool: Specialized for concentrated liquidity
- Jupiter: Aggregation and backup routes
sequenceDiagram
participant Bot
participant DEX1
participant DEX2
participant Blockchain
Bot->>DEX1: Monitor Prices
Bot->>DEX2: Monitor Prices
Bot->>Bot: Detect Opportunity
Bot->>Blockchain: Build Transaction
Blockchain->>DEX1: Execute Swap 1
Blockchain->>DEX2: Execute Swap 2
DEX2->>Bot: Confirm Profit
- Retry mechanism for failed transactions
- Fallback routes on primary route failure
- Automatic circuit breaker on consecutive failures
const config = {
minProfitThreshold: 0.005, // 0.5%
maxSlippage: 0.01, // 1%
gasLimit: 900000,
dexPriority: ['meteora', 'raydium', 'orca-whirlpool', 'jupiter'],
monitoringInterval: 1000, // 1 second
retryAttempts: 3
};
- Always maintain sufficient balance for gas fees
- Implement proper error handling and logging
- Regular monitoring of DEX contract updates
- Maintain fallback routes for each strategy
- Regular performance analysis and strategy adjustment
// Program entrypoint and state management
#[program]
pub mod solana_arbitrage {
use super::*;
#[state]
pub struct ArbitrageState {
pub owner: Pubkey,
pub profit_threshold: u64,
pub active_routes: u64,
}
// Initialize the arbitrage program
#[access_control(Initialize::accounts(&ctx))]
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// Implementation
}
// Execute arbitrage route
pub fn execute_arbitrage(ctx: Context<ExecuteArbitrage>, route_data: RouteData) -> Result<()> {
// Implementation
}
}
// Account validation structures
#[derive(Accounts)]
pub struct ExecuteArbitrage<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(mut)]
pub user_token_account_a: Account<'info, TokenAccount>,
#[account(mut)]
pub user_token_account_b: Account<'info, TokenAccount>,
pub token_program: Program<'info, Token>,
// DEX program accounts
pub raydium_program: Program<'info, Raydium>,
pub orca_program: Program<'info, Orca>,
pub meteora_program: Program<'info, Meteora>,
}
// DEX integration modules
pub mod dex {
pub mod meteora {
use anchor_lang::prelude::*;
pub fn swap(
ctx: Context<MeteoraSwap>,
amount_in: u64,
minimum_amount_out: u64
) -> Result<()> {
// Implementation
}
}
pub mod raydium {
use anchor_lang::prelude::*;
pub fn swap(
ctx: Context<RaydiumSwap>,
amount_in: u64,
minimum_amount_out: u64
) -> Result<()> {
// Implementation
}
}
pub mod orca {
use anchor_lang::prelude::*;
pub fn whirlpool_swap(
ctx: Context<OrcaSwap>,
amount_in: u64,
sqrt_price_limit: u128
) -> Result<()> {
// Implementation
}
}
}
use anchor_client::solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
transaction::Transaction,
};
pub struct ArbitrageClient {
cluster: Cluster,
wallet: Keypair,
commitment: CommitmentConfig,
}
impl ArbitrageClient {
// Monitor price feeds across DEXs
pub async fn monitor_prices(&self) -> Result<Vec<PriceData>> {
// Implementation using websocket connections
}
// Calculate optimal arbitrage route
pub fn calculate_route(&self, prices: Vec<PriceData>) -> Option<RouteData> {
// Implementation
}
// Execute arbitrage transaction
pub async fn execute_route(&self, route: RouteData) -> Result<Signature> {
// Implementation
}
}
// Price monitoring implementation
#[derive(Debug)]
pub struct PriceMonitor {
websocket_clients: Vec<WebSocketClient>,
price_cache: Arc<RwLock<HashMap<String, PriceData>>>,
}
impl PriceMonitor {
pub async fn start_monitoring(&self) -> Result<()> {
// Implementation
}
pub fn get_latest_prices(&self) -> HashMap<String, PriceData> {
// Implementation
}
}
#[error_code]
pub enum ArbitrageError {
#[msg("Insufficient profit margin")]
InsufficientProfit,
#[msg("Slippage tolerance exceeded")]
SlippageExceeded,
#[msg("Invalid route configuration")]
InvalidRoute,
#[msg("Insufficient liquidity")]
InsufficientLiquidity,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
pub struct RouteData {
pub steps: Vec<SwapStep>,
pub min_profit_lamports: u64,
pub deadline: i64,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
pub struct SwapStep {
pub dex_program_id: Pubkey,
pub pool_id: Pubkey,
pub token_in: Pubkey,
pub token_out: Pubkey,
pub amount_in: u64,
pub minimum_amount_out: u64,
}
pub mod constants {
use solana_program::declare_id;
// Program IDs
declare_id!("ArbitrageProgram11111111111111111111111111111111");
// DEX Program IDs
pub const RAYDIUM_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8";
pub const ORCA_WHIRLPOOL_PROGRAM_ID: &str = "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc";
pub const METEORA_PROGRAM_ID: &str = "M2mx93ekt1fmXSVkTrUL9xVFHkmME8HTUi5Cyc5aF7K";
// Configuration Constants
pub const MIN_PROFIT_THRESHOLD: u64 = 5000; // 0.5% in bps
pub const MAX_SLIPPAGE: u64 = 10000; // 1% in bps
pub const MAX_COMPUTE_UNITS: u32 = 900_000;
pub const PRIORITY_FEES: u64 = 1_000; // lamports
}
# Build the program
cargo build-bpf
# Run tests
cargo test-bpf
# Deploy
solana program deploy target/deploy/solana_arbitrage.so
#[cfg(test)]
mod tests {
use super::*;
use solana_program_test::*;
#[tokio::test]
async fn test_arbitrage_execution() {
// Test implementation
}
#[tokio::test]
async fn test_slippage_protection() {
// Test implementation
}
#[tokio::test]
async fn test_profit_calculation() {
// Test implementation
}
}
-
Transaction Atomicity
// Ensure all swaps in the route are atomic #[invariant(check_atomic_execution)] pub fn execute_route(ctx: Context<ExecuteRoute>, route: RouteData) -> Result<()> { // Implementation with require! macro for validation }
-
Slippage Protection
// Implement slippage checks pub fn check_slippage( amount_expected: u64, amount_received: u64, max_slippage_bps: u64 ) -> Result<()> { // Implementation }
-
Deadline Validation
// Validate transaction deadline pub fn validate_deadline(deadline: i64) -> Result<()> { require!( Clock::get()?.unix_timestamp <= deadline, ArbitrageError::DeadlineExceeded ); Ok(()) }
npm install @project-serum/anchor @solana/web3.js @solana/spl-token chai
https://docs.raydium.io/raydium/protocol/developers/addresses
https://github.com/raydium-io/raydium-amm/blob/master/program/Cargo.toml
https://github.com/raydium-io/raydium-cpi-example
https://github.com/raydium-io/raydium-docs/tree/master/dev-resources
https://github.com/microgift/meteora-cpi