commit ba80b273e4de13f040ee18e2c0e737e64deb3b08 Author: Krypto Kajun Date: Fri Sep 12 01:16:30 2025 -0500 Initial commit: Set up MEV bot project structure diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba97e2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Binaries +bin/ + +# Configuration files that might contain sensitive information +config/local.yaml +config/secrets.yaml + +# Go workspace +go.work + +# Test coverage files +coverage.txt +coverage.html + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Log files +*.log + +# Database files +*.db \ No newline at end of file diff --git a/@prompts/README.md b/@prompts/README.md new file mode 100644 index 0000000..7a50164 --- /dev/null +++ b/@prompts/README.md @@ -0,0 +1,16 @@ +# MEV Bot Development Prompts + +This directory contains prompts that can be used with AI coding assistants to help with the development of the MEV bot. + +## Purpose + +These prompts are designed to help developers: +1. Understand complex Uniswap V3 pricing mathematics +2. Implement efficient market scanning algorithms +3. Optimize arbitrage detection logic +4. Handle Ethereum transaction monitoring +5. Implement gas optimization strategies + +## Usage + +When working on specific parts of the MEV bot, you can use these prompts with your AI coding assistant to get targeted help and suggestions. \ No newline at end of file diff --git a/@prompts/arbitrum-monitoring.md b/@prompts/arbitrum-monitoring.md new file mode 100644 index 0000000..d7ab9b1 --- /dev/null +++ b/@prompts/arbitrum-monitoring.md @@ -0,0 +1,24 @@ +You are an expert in Ethereum and Arbitrum blockchain development. I'm building an MEV bot in Go that needs to monitor the Arbitrum sequencer for potential swap transactions. + +I need help with: + +1. Setting up a connection to an Arbitrum node (both RPC and WebSocket) +2. Efficiently monitoring new blocks as they are added to the chain +3. Monitoring the mempool for pending transactions +4. Identifying transactions that interact with Uniswap-like contracts +5. Decoding transaction data to extract swap parameters +6. Handling network errors and reconnections gracefully + +Please provide production-ready Go code that: +- Uses the go-ethereum library +- Implements efficient polling or event-driven monitoring +- Handles errors gracefully +- Follows Go best practices +- Is optimized for performance +- Includes comprehensive comments + +The code should: +- Connect to the Arbitrum mainnet RPC endpoint (https://arb1.arbitrum.io/rpc) +- Monitor for transactions to common DEX contract addresses +- Extract function signatures and parameters from transaction data +- Decode swap function calls to get token addresses and amounts \ No newline at end of file diff --git a/@prompts/error-handling.md b/@prompts/error-handling.md new file mode 100644 index 0000000..cbd5516 --- /dev/null +++ b/@prompts/error-handling.md @@ -0,0 +1,27 @@ +You are an expert in Go error handling and logging best practices. I'm building an MEV bot in Go that needs robust error handling and comprehensive logging for production deployment. + +I need help with: + +1. Implementing structured logging throughout the application +2. Creating meaningful error messages for debugging +3. Implementing retry mechanisms for transient failures +4. Handling fatal errors gracefully +5. Implementing circuit breakers for external services +6. Creating health checks and metrics + +Please provide production-ready Go code that: +- Uses a structured logging library (like zap or logrus) +- Implements comprehensive error wrapping and context +- Includes retry mechanisms with exponential backoff +- Handles fatal errors gracefully with proper cleanup +- Follows Go best practices for error handling +- Is optimized for performance +- Includes comprehensive comments + +The code should: +- Log at appropriate levels (debug, info, warn, error) +- Include contextual information in log messages +- Implement circuit breakers for RPC connections +- Handle timeouts appropriately +- Provide health check endpoints +- Export metrics for monitoring \ No newline at end of file diff --git a/@prompts/gas-optimization.md b/@prompts/gas-optimization.md new file mode 100644 index 0000000..10a6027 --- /dev/null +++ b/@prompts/gas-optimization.md @@ -0,0 +1,26 @@ +You are an expert in Ethereum gas optimization and MEV strategies. I'm building an MEV bot in Go that needs to optimize transaction submission for maximum profitability. + +I need help with: + +1. Estimating optimal gas prices for arbitrage transactions +2. Implementing transaction bundling strategies +3. Working with flashbots or similar MEV protection services +4. Optimizing transaction ordering within bundles +5. Handling frontrunning and backrunning strategies +6. Managing gas refunds and stipends + +Please provide production-ready Go code that: +- Integrates with flashbots or similar MEV protection services +- Calculates optimal gas prices based on network conditions +- Implements transaction bundling for atomic execution +- Handles errors and edge cases properly +- Follows Go best practices +- Is optimized for performance +- Includes comprehensive comments + +The code should: +- Connect to flashbots relay or similar service +- Calculate optimal gas prices based on base fee and priority fees +- Bundle transactions for atomic execution +- Handle failed transactions gracefully +- Implement retry logic with exponential backoff \ No newline at end of file diff --git a/@prompts/market-scanning.md b/@prompts/market-scanning.md new file mode 100644 index 0000000..25c9f0f --- /dev/null +++ b/@prompts/market-scanning.md @@ -0,0 +1,26 @@ +You are an expert in MEV (Maximal Extractable Value) and DeFi arbitrage strategies. I'm building an MEV bot in Go that needs to scan markets for arbitrage opportunities. + +I need help with: + +1. Implementing efficient market scanning algorithms +2. Calculating price impact of large swaps +3. Detecting triangular arbitrage opportunities +4. Estimating gas costs for arbitrage transactions +5. Determining profitability after gas costs +6. Implementing risk management strategies + +Please provide production-ready Go code that: +- Implements efficient data structures for market data +- Calculates arbitrage opportunities across multiple pools +- Estimates gas costs accurately +- Handles edge cases properly +- Follows Go best practices +- Is optimized for performance +- Includes comprehensive comments + +The code should: +- Work with Uniswap V3 pool data +- Calculate price impact using liquidity and swap amounts +- Identify profitable arbitrage paths +- Estimate transaction costs +- Filter opportunities based on minimum profit thresholds \ No newline at end of file diff --git a/@prompts/testing.md b/@prompts/testing.md new file mode 100644 index 0000000..9471683 --- /dev/null +++ b/@prompts/testing.md @@ -0,0 +1,27 @@ +You are an expert in Go testing and test-driven development. I'm building an MEV bot in Go that needs comprehensive test coverage to ensure reliability. + +I need help with: + +1. Creating unit tests for Uniswap V3 pricing calculations +2. Implementing integration tests for Arbitrum monitoring +3. Creating mock contracts and transactions for testing +4. Testing market scanning algorithms with real-world data +5. Implementing property-based testing for mathematical functions +6. Creating benchmarks for performance-critical code + +Please provide production-ready Go test code that: +- Uses the standard testing package and testify for assertions +- Implements table-driven tests for pricing functions +- Creates realistic mock data for testing +- Includes benchmarks for performance-critical functions +- Follows Go testing best practices +- Provides comprehensive coverage +- Includes comprehensive comments + +The test code should: +- Test edge cases and boundary conditions +- Validate mathematical accuracy of pricing functions +- Simulate network errors and timeouts +- Test various swap scenarios +- Benchmark performance of critical algorithms +- Provide meaningful test output \ No newline at end of file diff --git a/@prompts/uniswap-pricing.md b/@prompts/uniswap-pricing.md new file mode 100644 index 0000000..168c130 --- /dev/null +++ b/@prompts/uniswap-pricing.md @@ -0,0 +1,23 @@ +You are an expert in Uniswap V3 mathematics and smart contract development. I'm building an MEV bot in Go that needs to calculate price movements using Uniswap V3 pricing functions. + +I need help with implementing these specific functions: + +1. sqrtPriceX96 to tick conversion +2. tick to sqrtPriceX96 conversion +3. price to tick conversion +4. tick to price conversion +5. Calculating price impact of a swap given liquidity and amount + +Please provide production-ready Go code that: +- Uses the math/big package for precision +- Handles edge cases properly +- Is optimized for performance +- Follows Go best practices +- Includes comprehensive comments explaining the mathematics + +The code should work with: +- sqrtPriceX96 values (uint160 in Solidity, but we'll use big.Int in Go) +- tick values (int24 in Solidity, but we'll use int in Go) +- liquidity values (uint128 in Solidity, but we'll use big.Int in Go) + +Please also explain the mathematical relationships between these values according to the Uniswap V3 whitepaper. \ No newline at end of file diff --git a/QWEN.md b/QWEN.md new file mode 100644 index 0000000..d027118 --- /dev/null +++ b/QWEN.md @@ -0,0 +1,25 @@ +# MEV Bot Project - Qwen Code Context + +This file contains context information for Qwen Code about the MEV Bot project. + +## Project Overview +This is an MEV (Maximal Extractable Value) bot written in Go 1.24+ that monitors the Arbitrum sequencer for potential swap opportunities. When a potential swap is detected, the bot scans the market to determine if the swap is large enough to move the price using off-chain methods. + +## Project Structure +- `cmd/` - Main applications +- `internal/` - Private application and library code +- `pkg/` - Library code that can be used by external projects +- `config/` - Configuration files +- `@prompts/` - AI prompts for development assistance +- `docs/` - Documentation +- `scripts/` - Scripts for building, testing, and deployment + +## Technologies +- Go 1.24+ +- Arbitrum sequencer monitoring +- Uniswap V3 pricing functions (price to tick, sqrtPriceX96 to tick, etc.) + +## Development Notes +- Focus on off-chain price movement calculations +- Refer to official Uniswap V3 documentation for pricing functions +- Implement market scanning functionality for potential arbitrage opportunities \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6173bf8 --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# MEV Bot + +An MEV (Maximal Extractable Value) bot written in Go that monitors the Arbitrum sequencer for potential swap opportunities and identifies profitable arbitrage opportunities. + +## Overview + +This bot monitors the Arbitrum sequencer for attempted swaps and analyzes them to determine if they are large enough to create price movements that can be exploited for arbitrage. It uses off-chain methods to calculate price movements using Uniswap V3 pricing functions. + +## Features + +- Real-time monitoring of Arbitrum sequencer +- Detection of potential swap transactions +- Market scanning for price movement analysis +- Uniswap V3 pricing calculations (price to tick, sqrtPriceX96 to tick, etc.) +- Arbitrage opportunity identification + +## Prerequisites + +- Go 1.24 or higher +- Access to Arbitrum node + +## Installation + +```bash +go mod tidy +``` + +## Usage + +```bash +go run cmd/mev-bot/main.go +``` + +## Configuration + +Configuration files can be found in the `config/` directory. + +## Project Structure + +``` +. +├── cmd/ # Main applications +├── config/ # Configuration files +├── internal/ # Private application and library code +├── pkg/ # Library code that can be used by external projects +├── @prompts/ # AI prompts for development assistance +├── docs/ # Documentation +├── scripts/ # Scripts for building, testing, and deployment +├── go.mod # Go module definition +├── go.sum # Go module checksums +├── README.md # This file +└── QWEN.md # Qwen Code context file +``` + +## Development + +### Prompts Directory + +The `@prompts/` directory contains prompts that can be used with AI coding assistants for various development tasks. + +### Contributing + +1. Fork the repository +2. Create a feature branch +3. Commit your changes +4. Push to the branch +5. Create a Pull Request + +## License + +MIT \ No newline at end of file diff --git a/cmd/mev-bot/main.go b/cmd/mev-bot/main.go new file mode 100644 index 0000000..ac21972 --- /dev/null +++ b/cmd/mev-bot/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "log" + "os" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Name: "mev-bot", + Usage: "An MEV bot that monitors Arbitrum sequencer for swap opportunities", + Commands: []*cli.Command{ + { + Name: "start", + Usage: "Start the MEV bot", + Action: func(c *cli.Context) error { + fmt.Println("Starting MEV bot...") + // TODO: Implement bot start logic + return nil + }, + }, + { + Name: "scan", + Usage: "Scan for potential arbitrage opportunities", + Action: func(c *cli.Context) error { + fmt.Println("Scanning for arbitrage opportunities...") + // TODO: Implement scanning logic + return nil + }, + }, + }, + } + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} \ No newline at end of file diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..b649871 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,47 @@ +# MEV Bot Configuration + +# Arbitrum node configuration +arbitrum: + # RPC endpoint for Arbitrum node + rpc_endpoint: "https://arb1.arbitrum.io/rpc" + # WebSocket endpoint for Arbitrum node (optional) + ws_endpoint: "" + # Chain ID for Arbitrum (42161 for mainnet) + chain_id: 42161 + +# Bot configuration +bot: + # Enable or disable the bot + enabled: true + # Polling interval in seconds + polling_interval: 1 + # Minimum profit threshold in USD + min_profit_threshold: 10.0 + # Gas price multiplier (for faster transactions) + gas_price_multiplier: 1.2 + +# Uniswap configuration +uniswap: + # Factory contract address + factory_address: "0x1F98431c8aD98523631AE4a59f267346ea31F984" + # Position manager contract address + position_manager_address: "0xC36442b4a4522E871399CD717aBDD847Ab11FE88" + # Supported fee tiers + fee_tiers: + - 500 # 0.05% + - 3000 # 0.3% + - 10000 # 1% + +# Logging configuration +log: + # Log level (debug, info, warn, error) + level: "info" + # Log format (json, text) + format: "text" + # Log file path (empty for stdout) + file: "" + +# Database configuration +database: + # Database file path + file: "mev-bot.db" \ No newline at end of file diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..f1b0335 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,58 @@ +# MEV Bot Architecture + +This document describes the high-level architecture of the MEV bot. + +## Components + +### 1. Arbitrum Monitor +Responsible for monitoring the Arbitrum sequencer for new blocks and transactions. + +Key responsibilities: +- Connect to Arbitrum RPC endpoint +- Monitor new blocks as they are added +- Identify potential swap transactions +- Extract transaction details + +### 2. Market Scanner +Analyzes potential swap transactions to determine if they create arbitrage opportunities. + +Key responsibilities: +- Calculate price impact of swaps +- Scan for arbitrage opportunities across pools +- Estimate profitability after gas costs +- Filter opportunities based on configured thresholds + +### 3. Uniswap Pricing +Handles all Uniswap V3 pricing calculations. + +Key responsibilities: +- Convert between sqrtPriceX96 and ticks +- Calculate price impact of swaps +- Work with liquidity values +- Implement Uniswap V3 mathematical formulas + +### 4. Transaction Executor +Responsible for executing profitable arbitrage transactions. + +Key responsibilities: +- Construct arbitrage transactions +- Optimize gas usage +- Submit transactions to flashbots or similar services +- Handle transaction confirmation and errors + +## Data Flow + +1. Arbitrum Monitor detects new blocks and transactions +2. Potential swap transactions are sent to Market Scanner +3. Market Scanner analyzes swaps and identifies opportunities +4. Profitable opportunities are sent to Transaction Executor +5. Transaction Executor constructs and submits arbitrage transactions + +## Configuration + +The bot is configured through config/config.yaml which allows customization of: +- Arbitrum RPC endpoints +- Polling intervals +- Profit thresholds +- Gas price multipliers +- Logging settings \ No newline at end of file diff --git a/docs/monitoring.md b/docs/monitoring.md new file mode 100644 index 0000000..072fdce --- /dev/null +++ b/docs/monitoring.md @@ -0,0 +1,40 @@ +# Monitoring System Documentation + +This document explains how the MEV bot monitors the Arbitrum sequencer for potential swap transactions. + +## Overview + +The monitoring system connects to an Arbitrum RPC endpoint and continuously monitors for new blocks and transactions. It identifies potential swap transactions and forwards them to the market scanner for analysis. + +## Components + +### ArbitrumMonitor +The main monitoring component that handles: +- Connecting to the Arbitrum RPC endpoint +- Polling for new blocks +- Processing transactions in new blocks +- Identifying potential swap transactions + +### Transaction Processing +Each transaction is analyzed to determine if it's a potential swap: +1. Check if the transaction is calling a known DEX contract +2. Decode the transaction data to extract swap parameters +3. Extract token addresses and amounts +4. Calculate potential price impact + +## Configuration + +The monitoring system is configured through config/config.yaml: +- `arbitrum.rpc_endpoint`: The RPC endpoint to connect to +- `bot.polling_interval`: How often to check for new blocks +- `arbitrum.chain_id`: The chain ID to ensure we're on the correct network + +## Implementation Details + +The monitor uses the go-ethereum library to interact with the Arbitrum network. It implements efficient polling to minimize RPC calls while ensuring timely detection of new blocks. + +Key features: +- Graceful error handling and reconnection +- Configurable polling intervals +- Transaction sender identification +- Support for both RPC and WebSocket endpoints \ No newline at end of file diff --git a/docs/uniswap-pricing.md b/docs/uniswap-pricing.md new file mode 100644 index 0000000..017494d --- /dev/null +++ b/docs/uniswap-pricing.md @@ -0,0 +1,57 @@ +# Uniswap V3 Pricing Documentation + +This document explains the Uniswap V3 pricing model and how it's implemented in the MEV bot. + +## Core Concepts + +### Ticks +In Uniswap V3, prices are represented as ticks. A tick is defined as: + +``` +tick = log√1.0001(√P) +``` + +Where P is the price of token1 in terms of token0. + +Ticks are integers that range from -887272 to 887272. + +### sqrtPriceX96 +Prices are stored internally as sqrtPriceX96, which is: + +``` +sqrtPriceX96 = √P * 2^96 +``` + +This allows for precise fixed-point arithmetic without floating-point operations. + +### Liquidity +Liquidity in a pool is represented as a uint128 value that determines the depth of the pool at a given price. + +## Mathematical Relationships + +### Converting between representations + +1. Tick to sqrtPriceX96: + ``` + sqrtPriceX96 = 1.0001^(tick/2) * 2^96 + ``` + +2. sqrtPriceX96 to Tick: + ``` + tick = log_1.0001(sqrtPriceX96 / 2^96)^2 + ``` + +3. Price to Tick: + ``` + tick = log_1.0001(price) + ``` + +## Implementation Details + +Our Go implementation uses the math/big package for precision and handles the fixed-point arithmetic required for Uniswap V3 calculations. + +Key functions: +- `SqrtPriceX96ToPrice`: Converts sqrtPriceX96 to a floating-point price +- `PriceToSqrtPriceX96`: Converts a floating-point price to sqrtPriceX96 +- `TickToSqrtPriceX96`: Converts a tick to sqrtPriceX96 +- `SqrtPriceX96ToTick`: Converts sqrtPriceX96 to a tick \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..40af861 --- /dev/null +++ b/go.mod @@ -0,0 +1,39 @@ +module github.com/your-username/mev-beta + +go 1.24 + +require ( + github.com/ethereum/go-ethereum v1.14.12 + github.com/urfave/cli/v2 v2.27.4 +) + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20200512141541-2758323733fd // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/hashicorp/go-bexpr v0.1.11 // indirect + github.com/holiman/uint256 v1.2.4 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/tools v0.25.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +// Replace with your actual fork or repository when available +replace github.com/your-username/mev-beta => ./ \ No newline at end of file diff --git a/pkg/monitor/monitor.go b/pkg/monitor/monitor.go new file mode 100644 index 0000000..e7a75d3 --- /dev/null +++ b/pkg/monitor/monitor.go @@ -0,0 +1,154 @@ +package monitor + +import ( + "context" + "fmt" + "log" + "math/big" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" +) + +// ArbitrumMonitor monitors the Arbitrum sequencer for transactions +type ArbitrumMonitor struct { + client *ethclient.Client + rpcEndpoint string + pollInterval time.Duration + running bool +} + +// NewArbitrumMonitor creates a new Arbitrum monitor +func NewArbitrumMonitor(rpcEndpoint string, pollInterval time.Duration) (*ArbitrumMonitor, error) { + client, err := ethclient.Dial(rpcEndpoint) + if err != nil { + return nil, fmt.Errorf("failed to connect to Arbitrum node: %v", err) + } + + return &ArbitrumMonitor{ + client: client, + rpcEndpoint: rpcEndpoint, + pollInterval: pollInterval, + running: false, + }, nil +} + +// Start begins monitoring the Arbitrum sequencer +func (m *ArbitrumMonitor) Start(ctx context.Context) error { + log.Println("Starting Arbitrum sequencer monitoring...") + m.running = true + + // Get the latest block to start from + header, err := m.client.HeaderByNumber(ctx, nil) + if err != nil { + return fmt.Errorf("failed to get latest block header: %v", err) + } + + lastBlock := header.Number.Uint64() + log.Printf("Starting from block: %d", lastBlock) + + for m.running { + select { + case <-ctx.Done(): + m.running = false + return nil + case <-time.After(m.pollInterval): + // Get the latest block + header, err := m.client.HeaderByNumber(ctx, nil) + if err != nil { + log.Printf("Failed to get latest block header: %v", err) + continue + } + + currentBlock := header.Number.Uint64() + + // Process blocks from lastBlock+1 to currentBlock + for blockNum := lastBlock + 1; blockNum <= currentBlock; blockNum++ { + if err := m.processBlock(ctx, blockNum); err != nil { + log.Printf("Failed to process block %d: %v", blockNum, err) + } + } + + lastBlock = currentBlock + } + } + + return nil +} + +// Stop stops the monitor +func (m *ArbitrumMonitor) Stop() { + m.running = false +} + +// processBlock processes a single block for potential swap transactions +func (m *ArbitrumMonitor) processBlock(ctx context.Context, blockNumber uint64) error { + log.Printf("Processing block %d", blockNumber) + + // Get block by number + block, err := m.client.BlockByNumber(ctx, big.NewInt(int64(blockNumber))) + if err != nil { + return fmt.Errorf("failed to get block %d: %v", blockNumber, err) + } + + // Process each transaction in the block + for _, tx := range block.Transactions() { + if err := m.processTransaction(ctx, tx); err != nil { + log.Printf("Failed to process transaction %s: %v", tx.Hash().Hex(), err) + } + } + + return nil +} + +// processTransaction analyzes a transaction for potential swap opportunities +func (m *ArbitrumMonitor) processTransaction(ctx context.Context, tx *types.Transaction) error { + // Check if this is a potential swap transaction + // This is a simplified check - in practice, you would check for + // specific function signatures of Uniswap-like contracts + + // For now, we'll just log all transactions + from, err := m.client.TransactionSender(ctx, tx, common.Hash{}, 0) + if err != nil { + // This can happen for pending transactions + from = common.HexToAddress("0x0") + } + + log.Printf("Transaction: %s, From: %s, To: %s, Value: %s ETH", + tx.Hash().Hex(), + from.Hex(), + func() string { + if tx.To() != nil { + return tx.To().Hex() + } + return "contract creation" + }(), + new(big.Float).Quo(new(big.Float).SetInt(tx.Value()), big.NewFloat(1e18)).String(), + ) + + // TODO: Add logic to detect swap transactions and analyze them + // This would involve: + // 1. Checking if the transaction is calling a Uniswap-like contract + // 2. Decoding the swap function call + // 3. Extracting the token addresses and amounts + // 4. Calculating potential price impact + + return nil +} + +// GetPendingTransactions retrieves pending transactions from the mempool +func (m *ArbitrumMonitor) GetPendingTransactions(ctx context.Context) ([]*types.Transaction, error) { + // This is a simplified implementation + // In practice, you might need to use a different approach to access pending transactions + + // Query for pending transactions + txs := make([]*types.Transaction, 0) + + // Note: ethclient doesn't directly expose pending transactions + // You might need to use a different approach or a custom RPC call + + return txs, nil +} \ No newline at end of file diff --git a/pkg/scanner/scanner.go b/pkg/scanner/scanner.go new file mode 100644 index 0000000..ccb421d --- /dev/null +++ b/pkg/scanner/scanner.go @@ -0,0 +1,122 @@ +package scanner + +import ( + "math/big" + + "github.com/holiman/uint256" +) + +// MarketScanner scans markets for price movement opportunities +type MarketScanner struct { + // Configuration fields would go here +} + +// NewMarketScanner creates a new market scanner +func NewMarketScanner() *MarketScanner { + return &MarketScanner{} +} + +// PriceMovement represents a potential price movement +type PriceMovement struct { + Token0 string // Token address + Token1 string // Token address + Pool string // Pool address + AmountIn *big.Int // Amount of token being swapped in + AmountOut *big.Int // Amount of token being swapped out + PriceImpact float64 // Calculated price impact + TickBefore int // Tick before the swap + TickAfter int // Tick after the swap +} + +// SwapDetails contains details about a detected swap +type SwapDetails struct { + PoolAddress string + Token0 string + Token1 string + Amount0In *big.Int + Amount0Out *big.Int + Amount1In *big.Int + Amount1Out *big.Int + SqrtPriceX96 *uint256.Int + Liquidity *uint256.Int + Tick int +} + +// AnalyzeSwap analyzes a swap to determine if it's large enough to move the price +func (s *MarketScanner) AnalyzeSwap(swap SwapDetails) (*PriceMovement, error) { + // This is a simplified implementation + // In practice, you would need to: + // 1. Calculate the price before the swap + // 2. Calculate the price after the swap + // 3. Determine the price impact + + priceMovement := &PriceMovement{ + Token0: swap.Token0, + Token1: swap.Token1, + Pool: swap.PoolAddress, + AmountIn: new(big.Int).Add(swap.Amount0In, swap.Amount1In), + AmountOut: new(big.Int).Add(swap.Amount0Out, swap.Amount1Out), + TickBefore: swap.Tick, + // TickAfter would be calculated based on the swap size and liquidity + } + + // Calculate price impact (simplified) + // In practice, this would involve more complex calculations + if priceMovement.AmountIn.Cmp(big.NewInt(0)) > 0 { + impact := new(big.Float).Quo( + new(big.Float).SetInt(priceMovement.AmountOut), + new(big.Float).SetInt(priceMovement.AmountIn), + ) + priceImpact, _ := impact.Float64() + priceMovement.PriceImpact = priceImpact + } + + return priceMovement, nil +} + +// IsSignificantMovement determines if a price movement is significant enough to exploit +func (s *MarketScanner) IsSignificantMovement(movement *PriceMovement, threshold float64) bool { + // Check if the price impact is above our threshold + return movement.PriceImpact > threshold +} + +// CalculateTickAfterSwap calculates the tick after a swap occurs +func (s *MarketScanner) CalculateTickAfterSwap( + currentTick int, + liquidity *uint256.Int, + amountIn *big.Int, + zeroForOne bool, // true if swapping token0 for token1 +) int { + // This is a simplified implementation + // In practice, you would need to use the Uniswap V3 math formulas + + // The actual calculation would involve: + // 1. Converting amounts to sqrt prices + // 2. Using the liquidity to determine the price movement + // 3. Calculating the new tick based on the price movement + + // For now, we'll return a placeholder + return currentTick +} + +// FindArbitrageOpportunities looks for arbitrage opportunities based on price movements +func (s *MarketScanner) FindArbitrageOpportunities(movements []*PriceMovement) []ArbitrageOpportunity { + opportunities := make([]ArbitrageOpportunity, 0) + + // This would contain logic to: + // 1. Compare prices across different pools + // 2. Calculate potential profit after gas costs + // 3. Identify triangular arbitrage opportunities + // 4. Check if the opportunity is profitable + + return opportunities +} + +// ArbitrageOpportunity represents a potential arbitrage opportunity +type ArbitrageOpportunity struct { + Path []string // Token path for the arbitrage + Pools []string // Pools involved in the arbitrage + Profit *big.Int // Estimated profit in wei + GasEstimate *big.Int // Estimated gas cost + ROI float64 // Return on investment percentage +} \ No newline at end of file diff --git a/pkg/uniswap/pricing.go b/pkg/uniswap/pricing.go new file mode 100644 index 0000000..d1458f6 --- /dev/null +++ b/pkg/uniswap/pricing.go @@ -0,0 +1,130 @@ +package uniswap + +import ( + "math/big" + + "github.com/holiman/uint256" +) + +const ( + // Q96 represents 2^96 used in Uniswap V3 sqrtPriceX96 calculations + Q96 = 79228162514264337593543950336 // 2^96 + + // Tick spacing for different fee tiers + LowTickSpacing = 10 + MediumTickSpacing = 60 + HighTickSpacing = 200 +) + +// SqrtPriceX96ToPrice converts sqrtPriceX96 to a price +// Price is represented as token1/token0 +func SqrtPriceX96ToPrice(sqrtPriceX96 *big.Int) *big.Float { + // price = (sqrtPriceX96 / 2^96)^2 + // price = sqrtPriceX96^2 / 2^192 + + // Convert to big.Float for precision + sqrtPrice := new(big.Float).SetInt(sqrtPriceX96) + + // Calculate sqrtPrice^2 + price := new(big.Float).Mul(sqrtPrice, sqrtPrice) + + // Divide by 2^192 (which is (2^96)^2) + q192 := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(192), nil)) + price.Quo(price, q192) + + return price +} + +// PriceToSqrtPriceX96 converts a price to sqrtPriceX96 +func PriceToSqrtPriceX96(price *big.Float) *big.Int { + // sqrtPriceX96 = sqrt(price) * 2^96 + + // Calculate sqrt(price) + sqrtPrice := new(big.Float).Sqrt(price) + + // Multiply by 2^96 + q96 := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(96), nil)) + sqrtPrice.Mul(sqrtPrice, q96) + + // Convert to big.Int + sqrtPriceX96 := new(big.Int) + sqrtPrice.Int(sqrtPriceX96) + + return sqrtPriceX96 +} + +// TickToSqrtPriceX96 converts a tick to sqrtPriceX96 +func TickToSqrtPriceX96(tick int) *big.Int { + // sqrtPriceX96 = 1.0001^(tick/2) * 2^96 + + // Calculate 1.0001^(tick/2) + base := new(big.Float).SetFloat64(1.0001) + tickF := new(big.Float).SetFloat64(float64(tick) / 2.0) + power := new(big.Float).Pow(base, tickF) + + // Multiply by 2^96 + q96 := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(2), big.NewInt(96), nil)) + sqrtPrice := new(big.Float).Mul(power, q96) + + // Convert to big.Int + sqrtPriceX96 := new(big.Int) + sqrtPrice.Int(sqrtPriceX96) + + return sqrtPriceX96 +} + +// SqrtPriceX96ToTick converts sqrtPriceX96 to a tick +func SqrtPriceX96ToTick(sqrtPriceX96 *big.Int) int { + // tick = log_1.0001(sqrtPriceX96 / 2^96)^2 + // tick = log_1.0001(price) + // tick = 2 * log_1.0001(sqrtPriceX96 / 2^96) + + if sqrtPriceX96.Cmp(big.NewInt(0)) <= 0 { + return 0 // Invalid input + } + + // Convert to big.Float + sqrtPrice := new(big.Float).SetInt(sqrtPriceX96) + q96 := new(big.Float).SetInt(new(big.Int).SetInt64(Q96)) + + // Calculate sqrtPriceX96 / 2^96 + ratio := new(big.Float).Quo(sqrtPrice, q96) + + // Calculate (sqrtPriceX96 / 2^96)^2 to get price + price := new(big.Float).Mul(ratio, ratio) + + // Calculate log_1.0001(price) + // log_1.0001(x) = ln(x) / ln(1.0001) + lnPrice := new(big.Float).Log(price) + lnBase := new(big.Float).Log(new(big.Float).SetFloat64(1.0001)) + logRatio := new(big.Float).Quo(lnPrice, lnBase) + + // Convert to int + tick, _ := logRatio.Int64() + + return int(tick) +} + +// GetTickAtSqrtPrice calculates the tick for a given sqrtPriceX96 using uint256 +func GetTickAtSqrtPrice(sqrtPriceX96 *uint256.Int) int { + // This is a simplified implementation + // In practice, you would use a more precise logarithmic calculation + + // Convert to big.Int for calculation + sqrtPriceBig := sqrtPriceX96.ToBig() + return SqrtPriceX96ToTick(sqrtPriceBig) +} + +// GetNextTick calculates the next initialized tick +func GetNextTick(currentTick int, tickSpacing int) int { + // Round down to nearest tick spacing + tick := ((currentTick / tickSpacing) + 1) * tickSpacing + return tick +} + +// GetPreviousTick calculates the previous initialized tick +func GetPreviousTick(currentTick int, tickSpacing int) int { + // Round down to nearest tick spacing + tick := (currentTick / tickSpacing) * tickSpacing + return tick +} \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..f0b531d --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# build.sh - Build the MEV bot + +echo "Building MEV bot..." + +# Create bin directory if it doesn't exist +mkdir -p bin + +# Build the application +go build -o bin/mev-bot cmd/mev-bot/main.go + +if [ $? -eq 0 ]; then + echo "Build successful! Binary created at bin/mev-bot" +else + echo "Build failed!" + exit 1 +fi \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..b78211d --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# run.sh - Run the MEV bot + +echo "Running MEV bot..." + +# Build the application first +./scripts/build.sh + +if [ $? -eq 0 ]; then + # Run the application + ./bin/mev-bot start +else + echo "Failed to build the application!" + exit 1 +fi \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..9434e6b --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# test.sh - Run tests for the MEV bot + +echo "Running tests..." + +# Run all tests +go test -v ./... + +if [ $? -eq 0 ]; then + echo "All tests passed!" +else + echo "Some tests failed!" + exit 1 +fi \ No newline at end of file