@intentsolutionsio/mempool-analyzer 1.0.0 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/agents/mempool-agent.md +41 -1
- package/package.json +1 -1
- package/skills/analyzing-mempool/ARD.md +7 -0
- package/skills/analyzing-mempool/PRD.md +2 -0
- package/skills/analyzing-mempool/SKILL.md +19 -5
- package/skills/analyzing-mempool/references/errors.md +30 -0
- package/skills/analyzing-mempool/references/examples.md +24 -0
- package/skills/analyzing-mempool/references/implementation.md +10 -3
- package/skills/analyzing-mempool/scripts/formatters.py +6 -7
- package/skills/analyzing-mempool/scripts/gas_analyzer.py +7 -15
- package/skills/analyzing-mempool/scripts/mempool_analyzer.py +30 -33
- package/skills/analyzing-mempool/scripts/mev_detector.py +44 -52
- package/skills/analyzing-mempool/scripts/rpc_client.py +21 -20
- package/skills/analyzing-mempool/scripts/tx_decoder.py +11 -14
- package/skills/skill-adapter/references/README.md +0 -1
- package/skills/skill-adapter/references/examples.md +6 -0
- package/skills/skill-adapter/scripts/validation.sh +0 -32
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Advanced mempool analysis for MEV opportunities, pending transaction monitoring,
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
22
22
|
The mempool agent automatically activates when you discuss:
|
|
23
|
+
|
|
23
24
|
- Mempool analysis and pending transactions
|
|
24
25
|
- MEV opportunities and extraction strategies
|
|
25
26
|
- Gas price optimization
|
|
@@ -77,6 +78,7 @@ Create a `.mempool-config.json` file:
|
|
|
77
78
|
## Risk Warnings
|
|
78
79
|
|
|
79
80
|
️ **Important Considerations**:
|
|
81
|
+
|
|
80
82
|
- MEV extraction is highly competitive with sophisticated bots
|
|
81
83
|
- Gas wars can eliminate profits quickly
|
|
82
84
|
- Smart contract interactions carry inherent risks
|
|
@@ -90,7 +92,7 @@ MIT License - See LICENSE file for details
|
|
|
90
92
|
## Support
|
|
91
93
|
|
|
92
94
|
- GitHub Issues: [Report bugs](https://github.com/jeremylongshore/claude-code-plugins/issues)
|
|
93
|
-
- Documentation:
|
|
95
|
+
- Documentation: Full docs
|
|
94
96
|
|
|
95
97
|
---
|
|
96
98
|
|
package/agents/mempool-agent.md
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mempool-agent
|
|
3
|
-
description:
|
|
3
|
+
description: Mempool analysis specialist for MEV detection and transaction monitoring
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Edit
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- WebFetch
|
|
12
|
+
- WebSearch
|
|
13
|
+
- Task
|
|
14
|
+
- TodoWrite
|
|
15
|
+
model: sonnet
|
|
16
|
+
color: yellow
|
|
17
|
+
version: 1.0.0
|
|
18
|
+
author: Jeremy Longshore <jeremy@intentsolutions.io>
|
|
19
|
+
tags:
|
|
20
|
+
- crypto
|
|
21
|
+
- mempool
|
|
22
|
+
disallowedTools: []
|
|
23
|
+
skills: []
|
|
24
|
+
background: false
|
|
25
|
+
# ── upgrade levers — uncomment + set when tuning this agent ──
|
|
26
|
+
# effort: high # reasoning depth: low/medium/high/xhigh/max (omit = inherit session)
|
|
27
|
+
# maxTurns: 50 # cap the agentic loop (omit = engine default)
|
|
28
|
+
# memory: project # persistent scope: user/project/local (omit = ephemeral)
|
|
29
|
+
# isolation: worktree # run in an isolated git worktree
|
|
30
|
+
# initialPrompt: "…" # seed the agent's first turn
|
|
31
|
+
# hooks / mcpServers / permissionMode → set at the PLUGIN level, not on a plugin agent
|
|
4
32
|
---
|
|
5
33
|
# Mempool Analysis Agent
|
|
6
34
|
|
|
@@ -9,6 +37,7 @@ You are a specialized agent for analyzing blockchain mempools, detecting MEV (Ma
|
|
|
9
37
|
## Your Capabilities
|
|
10
38
|
|
|
11
39
|
### Mempool Monitoring
|
|
40
|
+
|
|
12
41
|
- Real-time monitoring of pending transactions across Ethereum, BSC, Polygon, and Arbitrum
|
|
13
42
|
- Transaction classification (swaps, transfers, contract interactions)
|
|
14
43
|
- Priority fee analysis and gas price trends
|
|
@@ -16,6 +45,7 @@ You are a specialized agent for analyzing blockchain mempools, detecting MEV (Ma
|
|
|
16
45
|
- Mempool congestion metrics
|
|
17
46
|
|
|
18
47
|
### MEV Detection
|
|
48
|
+
|
|
19
49
|
- **Sandwich attacks**: Detect front-running and back-running opportunities
|
|
20
50
|
- **Arbitrage opportunities**: Multi-DEX price discrepancies in pending trades
|
|
21
51
|
- **Liquidation monitoring**: Track undercollateralized positions
|
|
@@ -23,6 +53,7 @@ You are a specialized agent for analyzing blockchain mempools, detecting MEV (Ma
|
|
|
23
53
|
- **Just-in-time (JIT) liquidity**: Uniswap v3 position optimization
|
|
24
54
|
|
|
25
55
|
### Transaction Analysis
|
|
56
|
+
|
|
26
57
|
- Decode transaction calldata and extract parameters
|
|
27
58
|
- Estimate profit/loss for detected MEV opportunities
|
|
28
59
|
- Calculate optimal gas prices for transaction inclusion
|
|
@@ -30,6 +61,7 @@ You are a specialized agent for analyzing blockchain mempools, detecting MEV (Ma
|
|
|
30
61
|
- Track transaction replacement (RBF) patterns
|
|
31
62
|
|
|
32
63
|
### Gas Optimization
|
|
64
|
+
|
|
33
65
|
- EIP-1559 base fee prediction
|
|
34
66
|
- Priority fee recommendation engine
|
|
35
67
|
- Gas auction analysis
|
|
@@ -39,6 +71,7 @@ You are a specialized agent for analyzing blockchain mempools, detecting MEV (Ma
|
|
|
39
71
|
## When to Activate
|
|
40
72
|
|
|
41
73
|
Activate this agent when users need to:
|
|
74
|
+
|
|
42
75
|
- Monitor the mempool for trading opportunities
|
|
43
76
|
- Detect MEV opportunities in real-time
|
|
44
77
|
- Analyze pending transactions for a specific address or contract
|
|
@@ -51,6 +84,7 @@ Activate this agent when users need to:
|
|
|
51
84
|
## Approach
|
|
52
85
|
|
|
53
86
|
### Analysis Methodology
|
|
87
|
+
|
|
54
88
|
1. **Data Collection**: Connect to mempool nodes via WebSocket or RPC endpoints
|
|
55
89
|
2. **Classification**: Categorize transactions by type and intent
|
|
56
90
|
3. **Pattern Recognition**: Identify MEV opportunities using heuristics and ML models
|
|
@@ -59,7 +93,9 @@ Activate this agent when users need to:
|
|
|
59
93
|
6. **Recommendation**: Provide actionable insights with risk/reward analysis
|
|
60
94
|
|
|
61
95
|
### Output Format
|
|
96
|
+
|
|
62
97
|
Present findings in structured format:
|
|
98
|
+
|
|
63
99
|
```
|
|
64
100
|
MEMPOOL ANALYSIS REPORT
|
|
65
101
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -101,6 +137,7 @@ Present findings in structured format:
|
|
|
101
137
|
## Risk Warnings
|
|
102
138
|
|
|
103
139
|
Always include appropriate risk warnings:
|
|
140
|
+
|
|
104
141
|
- **MEV extraction is highly competitive** - Sophisticated bots with direct block builder relationships dominate
|
|
105
142
|
- **Gas wars can eliminate profits** - Fast-moving opportunities attract aggressive bidding
|
|
106
143
|
- **Smart contract risk** - Interacting with unverified contracts is dangerous
|
|
@@ -110,6 +147,7 @@ Always include appropriate risk warnings:
|
|
|
110
147
|
## Data Sources
|
|
111
148
|
|
|
112
149
|
Primary data sources for mempool analysis:
|
|
150
|
+
|
|
113
151
|
- **Flashbots Protect RPC**: MEV-protected transaction submission
|
|
114
152
|
- **Blocknative Mempool Explorer**: Real-time mempool data and gas predictions
|
|
115
153
|
- **Eden Network**: Priority transaction ordering
|
|
@@ -128,6 +166,7 @@ Primary data sources for mempool analysis:
|
|
|
128
166
|
## Technical Requirements
|
|
129
167
|
|
|
130
168
|
To perform mempool analysis, ensure:
|
|
169
|
+
|
|
131
170
|
- Access to archive nodes or mempool-focused RPC providers
|
|
132
171
|
- WebSocket connections for real-time transaction streams
|
|
133
172
|
- Transaction simulation capabilities (eth_call, Tenderly)
|
|
@@ -138,6 +177,7 @@ To perform mempool analysis, ensure:
|
|
|
138
177
|
## Example Queries
|
|
139
178
|
|
|
140
179
|
You can answer questions like:
|
|
180
|
+
|
|
141
181
|
- "What MEV opportunities are currently in the mempool?"
|
|
142
182
|
- "Show me all pending large ETH transfers"
|
|
143
183
|
- "What's the optimal gas price to get included in the next block?"
|
package/package.json
CHANGED
|
@@ -54,11 +54,13 @@ skills/analyzing-mempool/
|
|
|
54
54
|
## API Integration
|
|
55
55
|
|
|
56
56
|
### Ethereum RPC
|
|
57
|
+
|
|
57
58
|
- **Endpoints**: `eth_pendingTransactions`, `eth_getTransactionByHash`, `eth_gasPrice`
|
|
58
59
|
- **Auth**: RPC URL with API key embedded
|
|
59
60
|
- **WebSocket**: `eth_subscribe` for real-time updates
|
|
60
61
|
|
|
61
62
|
### Transaction Decoding
|
|
63
|
+
|
|
62
64
|
- **Router ABIs**: Uniswap V2/V3, SushiSwap, 1inch
|
|
63
65
|
- **Method Detection**: Swap, addLiquidity, removeLiquidity, approve
|
|
64
66
|
- **Value Estimation**: Using pool reserves or price feeds
|
|
@@ -66,6 +68,7 @@ skills/analyzing-mempool/
|
|
|
66
68
|
## Component Design
|
|
67
69
|
|
|
68
70
|
### rpc_client.py
|
|
71
|
+
|
|
69
72
|
```python
|
|
70
73
|
class MempoolClient:
|
|
71
74
|
def connect(rpc_url) -> None
|
|
@@ -75,6 +78,7 @@ class MempoolClient:
|
|
|
75
78
|
```
|
|
76
79
|
|
|
77
80
|
### tx_decoder.py
|
|
81
|
+
|
|
78
82
|
```python
|
|
79
83
|
class TransactionDecoder:
|
|
80
84
|
def decode_input(tx) -> DecodedCall
|
|
@@ -83,6 +87,7 @@ class TransactionDecoder:
|
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
### gas_analyzer.py
|
|
90
|
+
|
|
86
91
|
```python
|
|
87
92
|
class GasAnalyzer:
|
|
88
93
|
def analyze_pending_gas() -> GasDistribution
|
|
@@ -91,6 +96,7 @@ class GasAnalyzer:
|
|
|
91
96
|
```
|
|
92
97
|
|
|
93
98
|
### mev_detector.py
|
|
99
|
+
|
|
94
100
|
```python
|
|
95
101
|
class MEVDetector:
|
|
96
102
|
def detect_sandwich_opportunity(pending_txs) -> List[Opportunity]
|
|
@@ -124,6 +130,7 @@ class MEVDetector:
|
|
|
124
130
|
## DEX Detection
|
|
125
131
|
|
|
126
132
|
Supported routers with ABI decoding:
|
|
133
|
+
|
|
127
134
|
- Uniswap V2 Router
|
|
128
135
|
- Uniswap V3 Router
|
|
129
136
|
- SushiSwap Router
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# PRD: Mempool Analyzer
|
|
2
2
|
|
|
3
3
|
## Summary
|
|
4
|
+
|
|
4
5
|
**One-liner**: Monitor blockchain mempools for pending transactions, gas analysis, and MEV opportunity detection
|
|
5
6
|
**Domain**: Cryptocurrency / Blockchain / Trading Infrastructure
|
|
6
7
|
**Users**: Traders, MEV Searchers, Protocol Developers, Researchers
|
|
@@ -8,6 +9,7 @@
|
|
|
8
9
|
## Problem Statement
|
|
9
10
|
|
|
10
11
|
Blockchain mempools contain pending transactions waiting to be included in blocks. Understanding mempool activity is critical for:
|
|
12
|
+
|
|
11
13
|
- Optimizing gas prices for transaction inclusion
|
|
12
14
|
- Detecting large pending trades before execution
|
|
13
15
|
- Identifying MEV (Maximal Extractable Value) opportunities
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: analyzing-mempool
|
|
3
|
-
description:
|
|
4
|
-
|
|
3
|
+
description: 'Monitor blockchain mempools for pending transactions, gas analysis,
|
|
4
|
+
and MEV opportunities.
|
|
5
|
+
|
|
5
6
|
Use when analyzing pending transactions, optimizing gas prices, or researching MEV.
|
|
6
|
-
Trigger with phrases like "check mempool", "scan pending txs", "find MEV", "gas price analysis", or "pending swaps".
|
|
7
7
|
|
|
8
|
+
Trigger with phrases like "check mempool", "scan pending txs", "find MEV", "gas
|
|
9
|
+
price analysis", or "pending swaps".
|
|
10
|
+
|
|
11
|
+
'
|
|
8
12
|
allowed-tools: Read, Write, Edit, Grep, Glob, Bash(python:*mempool*)
|
|
9
13
|
version: 1.0.0
|
|
10
14
|
author: Jeremy Longshore <jeremy@intentsolutions.io>
|
|
11
15
|
license: MIT
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
tags:
|
|
17
|
+
- crypto
|
|
18
|
+
- monitoring
|
|
19
|
+
- analyzing-mempool
|
|
20
|
+
compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
|
|
14
21
|
---
|
|
15
22
|
# Analyzing Mempool
|
|
16
23
|
|
|
@@ -46,6 +53,7 @@ cd ${CLAUDE_SKILL_DIR}/scripts
|
|
|
46
53
|
6. Watch specific contract: `python mempool_analyzer.py watch 0x7a250d...`
|
|
47
54
|
|
|
48
55
|
Alternatively, customize with flags:
|
|
56
|
+
|
|
49
57
|
```bash
|
|
50
58
|
python mempool_analyzer.py pending --limit 100 # Limit results
|
|
51
59
|
python mempool_analyzer.py --chain polygon gas # Use different chain
|
|
@@ -55,12 +63,14 @@ python mempool_analyzer.py --chain arbitrum pending # Or use Arbitrum
|
|
|
55
63
|
### Step 3: Interpret Results
|
|
56
64
|
|
|
57
65
|
**Gas Recommendations:**
|
|
66
|
+
|
|
58
67
|
- Slow (10th percentile): May take 10+ blocks
|
|
59
68
|
- Standard (50th percentile): 2-5 blocks
|
|
60
69
|
- Fast (75th percentile): 1-2 blocks
|
|
61
70
|
- Instant (90th percentile): Next block likely
|
|
62
71
|
|
|
63
72
|
**MEV Warnings:**
|
|
73
|
+
|
|
64
74
|
- MEV detection is for educational purposes
|
|
65
75
|
- Real MEV extraction requires specialized infrastructure
|
|
66
76
|
- Use this for research and understanding mempool dynamics
|
|
@@ -76,6 +86,7 @@ python mempool_analyzer.py --chain arbitrum pending # Or use Arbitrum
|
|
|
76
86
|
## Error Handling
|
|
77
87
|
|
|
78
88
|
See `${CLAUDE_SKILL_DIR}/references/errors.md` for:
|
|
89
|
+
|
|
79
90
|
- RPC connection issues and timeout recovery
|
|
80
91
|
- Mempool access limitations per chain
|
|
81
92
|
- Transaction decoding errors and fallbacks
|
|
@@ -84,17 +95,20 @@ See `${CLAUDE_SKILL_DIR}/references/errors.md` for:
|
|
|
84
95
|
## Examples
|
|
85
96
|
|
|
86
97
|
**Example 1: Check gas before sending transaction:**
|
|
98
|
+
|
|
87
99
|
```bash
|
|
88
100
|
python mempool_analyzer.py gas
|
|
89
101
|
# Use "Fast" for quick confirmation
|
|
90
102
|
```
|
|
91
103
|
|
|
92
104
|
**Example 2: Monitor for large pending swaps:**
|
|
105
|
+
|
|
93
106
|
```bash
|
|
94
107
|
python mempool_analyzer.py swaps --limit 200 # 200: max results to scan
|
|
95
108
|
```
|
|
96
109
|
|
|
97
110
|
**Example 3: Research MEV opportunities:**
|
|
111
|
+
|
|
98
112
|
```bash
|
|
99
113
|
python mempool_analyzer.py mev -v
|
|
100
114
|
```
|
|
@@ -3,31 +3,40 @@
|
|
|
3
3
|
## RPC Connection Errors
|
|
4
4
|
|
|
5
5
|
### Connection Refused
|
|
6
|
+
|
|
6
7
|
```
|
|
7
8
|
Error: Connection refused to RPC endpoint
|
|
8
9
|
```
|
|
10
|
+
|
|
9
11
|
**Cause**: RPC endpoint is down or unreachable
|
|
10
12
|
**Solution**:
|
|
13
|
+
|
|
11
14
|
- Check if RPC URL is correct
|
|
12
15
|
- Try alternative endpoint (Alchemy, Chainstack, Infura, or public RPC)
|
|
13
16
|
- Verify network connectivity
|
|
14
17
|
|
|
15
18
|
### Timeout
|
|
19
|
+
|
|
16
20
|
```
|
|
17
21
|
Error: Request timed out
|
|
18
22
|
```
|
|
23
|
+
|
|
19
24
|
**Cause**: RPC node is slow or overloaded
|
|
20
25
|
**Solution**:
|
|
26
|
+
|
|
21
27
|
- Increase timeout setting
|
|
22
28
|
- Switch to faster RPC provider
|
|
23
29
|
- Reduce request frequency
|
|
24
30
|
|
|
25
31
|
### Rate Limited
|
|
32
|
+
|
|
26
33
|
```
|
|
27
34
|
Error: Too many requests (429)
|
|
28
35
|
```
|
|
36
|
+
|
|
29
37
|
**Cause**: Exceeded RPC provider rate limits
|
|
30
38
|
**Solution**:
|
|
39
|
+
|
|
31
40
|
- Reduce polling frequency
|
|
32
41
|
- Upgrade RPC tier (paid Alchemy, Chainstack, or Infura plans)
|
|
33
42
|
- Use multiple RPC endpoints
|
|
@@ -35,21 +44,27 @@ Error: Too many requests (429)
|
|
|
35
44
|
## Mempool Access Errors
|
|
36
45
|
|
|
37
46
|
### txpool_content Not Available
|
|
47
|
+
|
|
38
48
|
```
|
|
39
49
|
Error: txpool_content not supported
|
|
40
50
|
```
|
|
51
|
+
|
|
41
52
|
**Cause**: Not all nodes support txpool methods
|
|
42
53
|
**Solution**:
|
|
54
|
+
|
|
43
55
|
- Use Geth node with txpool enabled
|
|
44
56
|
- Try eth_pendingTransactions instead
|
|
45
57
|
- Use mock data for demo purposes
|
|
46
58
|
|
|
47
59
|
### Empty Mempool
|
|
60
|
+
|
|
48
61
|
```
|
|
49
62
|
No pending transactions found
|
|
50
63
|
```
|
|
64
|
+
|
|
51
65
|
**Cause**: Mempool is empty or access limited
|
|
52
66
|
**Solution**:
|
|
67
|
+
|
|
53
68
|
- Normal during low activity periods
|
|
54
69
|
- Verify RPC supports mempool access
|
|
55
70
|
- Check if node is fully synced
|
|
@@ -57,32 +72,41 @@ No pending transactions found
|
|
|
57
72
|
## Transaction Decoding Errors
|
|
58
73
|
|
|
59
74
|
### Unknown Method Signature
|
|
75
|
+
|
|
60
76
|
```
|
|
61
77
|
Warning: Unknown method 0x12345678
|
|
62
78
|
```
|
|
79
|
+
|
|
63
80
|
**Cause**: Method signature not in known ABI list
|
|
64
81
|
**Solution**:
|
|
82
|
+
|
|
65
83
|
- Transaction will show as "Unknown" type
|
|
66
84
|
- Add ABI to decoder if needed
|
|
67
85
|
- Use Etherscan to look up contract ABI
|
|
68
86
|
|
|
69
87
|
### Invalid Input Data
|
|
88
|
+
|
|
70
89
|
```
|
|
71
90
|
Error: Cannot decode input data
|
|
72
91
|
```
|
|
92
|
+
|
|
73
93
|
**Cause**: Malformed or non-standard input
|
|
74
94
|
**Solution**:
|
|
95
|
+
|
|
75
96
|
- Skip transaction, continue analysis
|
|
76
97
|
- Raw data still available
|
|
77
98
|
|
|
78
99
|
## Gas Analysis Errors
|
|
79
100
|
|
|
80
101
|
### No Sample Data
|
|
102
|
+
|
|
81
103
|
```
|
|
82
104
|
Warning: Insufficient data for gas analysis
|
|
83
105
|
```
|
|
106
|
+
|
|
84
107
|
**Cause**: Too few pending transactions
|
|
85
108
|
**Solution**:
|
|
109
|
+
|
|
86
110
|
- Use default recommendations
|
|
87
111
|
- Wait for more mempool activity
|
|
88
112
|
- Reduce sample requirements
|
|
@@ -90,11 +114,14 @@ Warning: Insufficient data for gas analysis
|
|
|
90
114
|
## MEV Detection Errors
|
|
91
115
|
|
|
92
116
|
### Pool Data Unavailable
|
|
117
|
+
|
|
93
118
|
```
|
|
94
119
|
Warning: Cannot fetch pool reserves
|
|
95
120
|
```
|
|
121
|
+
|
|
96
122
|
**Cause**: DEX subgraph or pool query failed
|
|
97
123
|
**Solution**:
|
|
124
|
+
|
|
98
125
|
- MEV detection will have lower confidence
|
|
99
126
|
- Use estimated values
|
|
100
127
|
- Check subgraph health
|
|
@@ -102,16 +129,19 @@ Warning: Cannot fetch pool reserves
|
|
|
102
129
|
## Debugging
|
|
103
130
|
|
|
104
131
|
### Enable Verbose Mode
|
|
132
|
+
|
|
105
133
|
```bash
|
|
106
134
|
python mempool_analyzer.py -v pending
|
|
107
135
|
```
|
|
108
136
|
|
|
109
137
|
### Check Connection
|
|
138
|
+
|
|
110
139
|
```bash
|
|
111
140
|
python mempool_analyzer.py status
|
|
112
141
|
```
|
|
113
142
|
|
|
114
143
|
### Test RPC Endpoint
|
|
144
|
+
|
|
115
145
|
```bash
|
|
116
146
|
curl -X POST -H "Content-Type: application/json" \
|
|
117
147
|
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
|
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
## View Pending Transactions
|
|
4
4
|
|
|
5
5
|
### Basic View
|
|
6
|
+
|
|
6
7
|
```bash
|
|
7
8
|
python mempool_analyzer.py pending
|
|
8
9
|
```
|
|
9
10
|
|
|
10
11
|
### Limit Results
|
|
12
|
+
|
|
11
13
|
```bash
|
|
12
14
|
python mempool_analyzer.py pending --limit 20
|
|
13
15
|
```
|
|
14
16
|
|
|
15
17
|
### JSON Output
|
|
18
|
+
|
|
16
19
|
```bash
|
|
17
20
|
python mempool_analyzer.py pending --format json
|
|
18
21
|
```
|
|
@@ -20,11 +23,13 @@ python mempool_analyzer.py pending --format json
|
|
|
20
23
|
## Gas Price Analysis
|
|
21
24
|
|
|
22
25
|
### Current Gas Prices
|
|
26
|
+
|
|
23
27
|
```bash
|
|
24
28
|
python mempool_analyzer.py gas
|
|
25
29
|
```
|
|
26
30
|
|
|
27
31
|
### Gas Recommendations
|
|
32
|
+
|
|
28
33
|
```bash
|
|
29
34
|
python mempool_analyzer.py gas
|
|
30
35
|
# Output shows:
|
|
@@ -34,6 +39,7 @@ python mempool_analyzer.py gas
|
|
|
34
39
|
```
|
|
35
40
|
|
|
36
41
|
### JSON for Programmatic Use
|
|
42
|
+
|
|
37
43
|
```bash
|
|
38
44
|
python mempool_analyzer.py gas --format json
|
|
39
45
|
```
|
|
@@ -41,11 +47,13 @@ python mempool_analyzer.py gas --format json
|
|
|
41
47
|
## Pending DEX Swaps
|
|
42
48
|
|
|
43
49
|
### View All Pending Swaps
|
|
50
|
+
|
|
44
51
|
```bash
|
|
45
52
|
python mempool_analyzer.py swaps
|
|
46
53
|
```
|
|
47
54
|
|
|
48
55
|
### Analyze More Transactions
|
|
56
|
+
|
|
49
57
|
```bash
|
|
50
58
|
python mempool_analyzer.py swaps --limit 200
|
|
51
59
|
```
|
|
@@ -53,16 +61,19 @@ python mempool_analyzer.py swaps --limit 200
|
|
|
53
61
|
## MEV Opportunity Scanning
|
|
54
62
|
|
|
55
63
|
### Scan for Opportunities
|
|
64
|
+
|
|
56
65
|
```bash
|
|
57
66
|
python mempool_analyzer.py mev
|
|
58
67
|
```
|
|
59
68
|
|
|
60
69
|
### Detailed Analysis
|
|
70
|
+
|
|
61
71
|
```bash
|
|
62
72
|
python mempool_analyzer.py mev --limit 300 -v
|
|
63
73
|
```
|
|
64
74
|
|
|
65
75
|
### JSON Output
|
|
76
|
+
|
|
66
77
|
```bash
|
|
67
78
|
python mempool_analyzer.py mev --format json
|
|
68
79
|
```
|
|
@@ -70,6 +81,7 @@ python mempool_analyzer.py mev --format json
|
|
|
70
81
|
## Mempool Summary
|
|
71
82
|
|
|
72
83
|
### Quick Overview
|
|
84
|
+
|
|
73
85
|
```bash
|
|
74
86
|
python mempool_analyzer.py summary
|
|
75
87
|
```
|
|
@@ -77,11 +89,13 @@ python mempool_analyzer.py summary
|
|
|
77
89
|
## Watch Specific Contract
|
|
78
90
|
|
|
79
91
|
### Monitor Uniswap Router
|
|
92
|
+
|
|
80
93
|
```bash
|
|
81
94
|
python mempool_analyzer.py watch 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
|
|
82
95
|
```
|
|
83
96
|
|
|
84
97
|
### Monitor Any Contract
|
|
98
|
+
|
|
85
99
|
```bash
|
|
86
100
|
python mempool_analyzer.py watch 0xYOUR_CONTRACT_ADDRESS --limit 200
|
|
87
101
|
```
|
|
@@ -89,6 +103,7 @@ python mempool_analyzer.py watch 0xYOUR_CONTRACT_ADDRESS --limit 200
|
|
|
89
103
|
## Connection Status
|
|
90
104
|
|
|
91
105
|
### Check RPC Connection
|
|
106
|
+
|
|
92
107
|
```bash
|
|
93
108
|
python mempool_analyzer.py status
|
|
94
109
|
```
|
|
@@ -96,17 +111,20 @@ python mempool_analyzer.py status
|
|
|
96
111
|
## Different Chains
|
|
97
112
|
|
|
98
113
|
### Polygon
|
|
114
|
+
|
|
99
115
|
```bash
|
|
100
116
|
python mempool_analyzer.py --chain polygon pending
|
|
101
117
|
python mempool_analyzer.py --chain polygon gas
|
|
102
118
|
```
|
|
103
119
|
|
|
104
120
|
### Arbitrum
|
|
121
|
+
|
|
105
122
|
```bash
|
|
106
123
|
python mempool_analyzer.py --chain arbitrum summary
|
|
107
124
|
```
|
|
108
125
|
|
|
109
126
|
### Custom RPC URL
|
|
127
|
+
|
|
110
128
|
```bash
|
|
111
129
|
python mempool_analyzer.py --rpc-url https://your-rpc.example.com pending
|
|
112
130
|
```
|
|
@@ -114,6 +132,7 @@ python mempool_analyzer.py --rpc-url https://your-rpc.example.com pending
|
|
|
114
132
|
## Common Workflows
|
|
115
133
|
|
|
116
134
|
### Pre-Transaction Gas Check
|
|
135
|
+
|
|
117
136
|
```bash
|
|
118
137
|
# Before sending a transaction, check optimal gas
|
|
119
138
|
python mempool_analyzer.py gas
|
|
@@ -124,6 +143,7 @@ python mempool_analyzer.py gas
|
|
|
124
143
|
```
|
|
125
144
|
|
|
126
145
|
### Monitor for Front-Running Risk
|
|
146
|
+
|
|
127
147
|
```bash
|
|
128
148
|
# Check if there are pending swaps that might affect your trade
|
|
129
149
|
python mempool_analyzer.py swaps
|
|
@@ -132,6 +152,7 @@ python mempool_analyzer.py swaps
|
|
|
132
152
|
```
|
|
133
153
|
|
|
134
154
|
### MEV Opportunity Research
|
|
155
|
+
|
|
135
156
|
```bash
|
|
136
157
|
# Educational: See what MEV opportunities exist
|
|
137
158
|
python mempool_analyzer.py mev -v
|
|
@@ -169,18 +190,21 @@ print(f"Pending swaps: {len(swaps)}")
|
|
|
169
190
|
## Integration with jq
|
|
170
191
|
|
|
171
192
|
### Filter High Gas Transactions
|
|
193
|
+
|
|
172
194
|
```bash
|
|
173
195
|
python mempool_analyzer.py pending --format json | \
|
|
174
196
|
jq '[.[] | select(.gas_price > 50000000000)]'
|
|
175
197
|
```
|
|
176
198
|
|
|
177
199
|
### Count by Transaction Type
|
|
200
|
+
|
|
178
201
|
```bash
|
|
179
202
|
python mempool_analyzer.py swaps --format json | \
|
|
180
203
|
jq 'group_by(.dex) | map({dex: .[0].dex, count: length})'
|
|
181
204
|
```
|
|
182
205
|
|
|
183
206
|
### Export Gas Data
|
|
207
|
+
|
|
184
208
|
```bash
|
|
185
209
|
python mempool_analyzer.py gas --format json > gas_snapshot.json
|
|
186
210
|
```
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
The gas analysis command calculates percentile-based recommendations from pending transactions:
|
|
6
6
|
|
|
7
7
|
**Gas Recommendations:**
|
|
8
|
+
|
|
8
9
|
- Slow (10th percentile): May take 10+ blocks
|
|
9
10
|
- Standard (50th percentile): 2-5 blocks
|
|
10
11
|
- Fast (75th percentile): 1-2 blocks
|
|
@@ -13,11 +14,13 @@ The gas analysis command calculates percentile-based recommendations from pendin
|
|
|
13
14
|
## MEV Detection Details
|
|
14
15
|
|
|
15
16
|
MEV detection scans for common patterns:
|
|
17
|
+
|
|
16
18
|
- **Sandwich attacks**: Detects front-run + back-run pairs targeting the same swap
|
|
17
19
|
- **Arbitrage**: Identifies circular token paths (A→B→A) across DEXs
|
|
18
20
|
- **Liquidation**: Finds health-factor monitoring and repay+seize patterns
|
|
19
21
|
|
|
20
22
|
**Important:** MEV detection is for educational purposes only. Real MEV extraction requires:
|
|
23
|
+
|
|
21
24
|
- Specialized block-builder infrastructure (Flashbots, MEV-Boost)
|
|
22
25
|
- Sub-millisecond execution timing
|
|
23
26
|
- Significant capital for gas auctions
|
|
@@ -25,6 +28,7 @@ MEV detection scans for common patterns:
|
|
|
25
28
|
## DEX Swap Detection
|
|
26
29
|
|
|
27
30
|
The `swaps` command identifies pending DEX transactions by matching method selectors:
|
|
31
|
+
|
|
28
32
|
- Uniswap V2/V3: `swapExactTokensForTokens`, `exactInputSingle`
|
|
29
33
|
- SushiSwap: Same interface as Uniswap V2
|
|
30
34
|
- 1inch: `swap`, `unoswap` aggregation methods
|
|
@@ -32,6 +36,7 @@ The `swaps` command identifies pending DEX transactions by matching method selec
|
|
|
32
36
|
## Multi-Chain Support
|
|
33
37
|
|
|
34
38
|
Supported chains and their mempool characteristics:
|
|
39
|
+
|
|
35
40
|
| Chain | Mempool Access | Block Time | Notes |
|
|
36
41
|
|-------|---------------|------------|-------|
|
|
37
42
|
| Ethereum | Full | ~12s | Richest MEV environment |
|
|
@@ -43,6 +48,7 @@ Supported chains and their mempool characteristics:
|
|
|
43
48
|
## Contract Watching
|
|
44
49
|
|
|
45
50
|
The `watch` command monitors pending transactions to a specific contract address:
|
|
51
|
+
|
|
46
52
|
1. Filters mempool by `to` address
|
|
47
53
|
2. Decodes known method selectors
|
|
48
54
|
3. Estimates gas cost in USD
|
|
@@ -51,11 +57,12 @@ The `watch` command monitors pending transactions to a specific contract address
|
|
|
51
57
|
## Configuration
|
|
52
58
|
|
|
53
59
|
Edit `${CLAUDE_SKILL_DIR}/config/settings.yaml`:
|
|
60
|
+
|
|
54
61
|
```yaml
|
|
55
62
|
rpc_endpoints:
|
|
56
|
-
ethereum: "
|
|
57
|
-
polygon: "
|
|
58
|
-
arbitrum: "
|
|
63
|
+
ethereum: "eth"
|
|
64
|
+
polygon: "polygon"
|
|
65
|
+
arbitrum: "arbitrum"
|
|
59
66
|
|
|
60
67
|
defaults:
|
|
61
68
|
chain: ethereum
|
|
@@ -81,6 +81,7 @@ def format_pending_tx_table(
|
|
|
81
81
|
# Create decoder only if not provided
|
|
82
82
|
if decoder is None:
|
|
83
83
|
from tx_decoder import TransactionDecoder
|
|
84
|
+
|
|
84
85
|
decoder = TransactionDecoder()
|
|
85
86
|
|
|
86
87
|
for tx in transactions[:50]:
|
|
@@ -101,7 +102,9 @@ def format_pending_tx_table(
|
|
|
101
102
|
decoded = decoder.decode_input(tx.input_data, tx.to_address)
|
|
102
103
|
tx_type = decoded.method_type[:10]
|
|
103
104
|
|
|
104
|
-
lines.append(
|
|
105
|
+
lines.append(
|
|
106
|
+
f"{tx_hash:<18} {from_addr:<14} {to_addr:<14} {value_str:<12} {gas_price_str:<12} {gas_str:<10} {tx_type:<12}"
|
|
107
|
+
)
|
|
105
108
|
|
|
106
109
|
lines.append("-" * 100)
|
|
107
110
|
lines.append(f"Showing {min(len(transactions), 50)} of {len(transactions)} pending transactions")
|
|
@@ -149,12 +152,7 @@ def format_pending_swaps_table(swaps: List[Any]) -> str:
|
|
|
149
152
|
return "\n".join(lines)
|
|
150
153
|
|
|
151
154
|
|
|
152
|
-
def format_mempool_summary(
|
|
153
|
-
pending_count: int,
|
|
154
|
-
gas_info: Any,
|
|
155
|
-
swap_count: int,
|
|
156
|
-
opportunities: int
|
|
157
|
-
) -> str:
|
|
155
|
+
def format_mempool_summary(pending_count: int, gas_info: Any, swap_count: int, opportunities: int) -> str:
|
|
158
156
|
"""Format mempool summary.
|
|
159
157
|
|
|
160
158
|
Args:
|
|
@@ -220,6 +218,7 @@ def format_stream_alert(
|
|
|
220
218
|
# Create decoder only if not provided
|
|
221
219
|
if decoder is None:
|
|
222
220
|
from tx_decoder import TransactionDecoder
|
|
221
|
+
|
|
223
222
|
decoder = TransactionDecoder()
|
|
224
223
|
decoded = decoder.decode_input(tx.input_data, tx.to_address)
|
|
225
224
|
|
|
@@ -9,7 +9,7 @@ Version: 1.0.0
|
|
|
9
9
|
License: MIT
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
from typing import
|
|
12
|
+
from typing import Any, List
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
import statistics
|
|
15
15
|
|
|
@@ -17,6 +17,7 @@ import statistics
|
|
|
17
17
|
@dataclass
|
|
18
18
|
class GasRecommendation:
|
|
19
19
|
"""Gas price recommendation."""
|
|
20
|
+
|
|
20
21
|
priority: str # slow, standard, fast, instant
|
|
21
22
|
max_fee: int # in wei
|
|
22
23
|
priority_fee: int # in wei
|
|
@@ -27,6 +28,7 @@ class GasRecommendation:
|
|
|
27
28
|
@dataclass
|
|
28
29
|
class GasDistribution:
|
|
29
30
|
"""Gas price distribution analysis."""
|
|
31
|
+
|
|
30
32
|
min_gwei: float
|
|
31
33
|
max_gwei: float
|
|
32
34
|
mean_gwei: float
|
|
@@ -46,11 +48,7 @@ class GasAnalyzer:
|
|
|
46
48
|
"""Initialize gas analyzer."""
|
|
47
49
|
self.verbose = verbose
|
|
48
50
|
|
|
49
|
-
def analyze_pending_gas(
|
|
50
|
-
self,
|
|
51
|
-
pending_txs: List[Any],
|
|
52
|
-
base_fee: int = None
|
|
53
|
-
) -> GasDistribution:
|
|
51
|
+
def analyze_pending_gas(self, pending_txs: List[Any], base_fee: int = None) -> GasDistribution:
|
|
54
52
|
"""Analyze gas price distribution in pending transactions.
|
|
55
53
|
|
|
56
54
|
Args:
|
|
@@ -110,10 +108,7 @@ class GasAnalyzer:
|
|
|
110
108
|
)
|
|
111
109
|
|
|
112
110
|
def recommend_gas(
|
|
113
|
-
self,
|
|
114
|
-
distribution: GasDistribution = None,
|
|
115
|
-
base_fee: int = None,
|
|
116
|
-
priority: str = "standard"
|
|
111
|
+
self, distribution: GasDistribution = None, base_fee: int = None, priority: str = "standard"
|
|
117
112
|
) -> GasRecommendation:
|
|
118
113
|
"""Get gas price recommendation.
|
|
119
114
|
|
|
@@ -176,11 +171,7 @@ class GasAnalyzer:
|
|
|
176
171
|
confidence=confidence.get(priority, 0.5),
|
|
177
172
|
)
|
|
178
173
|
|
|
179
|
-
def estimate_inclusion_time(
|
|
180
|
-
self,
|
|
181
|
-
gas_price: int,
|
|
182
|
-
distribution: GasDistribution
|
|
183
|
-
) -> str:
|
|
174
|
+
def estimate_inclusion_time(self, gas_price: int, distribution: GasDistribution) -> str:
|
|
184
175
|
"""Estimate time to transaction inclusion.
|
|
185
176
|
|
|
186
177
|
Args:
|
|
@@ -278,6 +269,7 @@ def main():
|
|
|
278
269
|
self.gas_price = gas_price
|
|
279
270
|
|
|
280
271
|
import random
|
|
272
|
+
|
|
281
273
|
base = 30 * 10**9
|
|
282
274
|
mock_txs = [MockTx(base + random.randint(-10, 30) * 10**9) for _ in range(100)]
|
|
283
275
|
|
|
@@ -138,11 +138,7 @@ def cmd_summary(args):
|
|
|
138
138
|
swaps = detector.detect_pending_swaps(pending, eth_price=args.eth_price)
|
|
139
139
|
results = detector.detect_all_opportunities(pending, eth_price=args.eth_price)
|
|
140
140
|
|
|
141
|
-
total_opportunities = (
|
|
142
|
-
len(results["sandwich"]) +
|
|
143
|
-
len(results["arbitrage"]) +
|
|
144
|
-
len(results["liquidation"])
|
|
145
|
-
)
|
|
141
|
+
total_opportunities = len(results["sandwich"]) + len(results["arbitrage"]) + len(results["liquidation"])
|
|
146
142
|
|
|
147
143
|
if args.format == "json":
|
|
148
144
|
summary = {
|
|
@@ -153,12 +149,14 @@ def cmd_summary(args):
|
|
|
153
149
|
}
|
|
154
150
|
print(format_json(summary))
|
|
155
151
|
else:
|
|
156
|
-
print(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
print(
|
|
153
|
+
format_mempool_summary(
|
|
154
|
+
pending_count=len(pending),
|
|
155
|
+
gas_info=gas_info,
|
|
156
|
+
swap_count=len(swaps),
|
|
157
|
+
opportunities=total_opportunities,
|
|
158
|
+
)
|
|
159
|
+
)
|
|
162
160
|
|
|
163
161
|
|
|
164
162
|
def cmd_watch(args):
|
|
@@ -177,10 +175,7 @@ def cmd_watch(args):
|
|
|
177
175
|
|
|
178
176
|
pending = client.get_pending_transactions(limit=args.limit, allow_mock=args.demo)
|
|
179
177
|
|
|
180
|
-
matching = [
|
|
181
|
-
tx for tx in pending
|
|
182
|
-
if tx.to_address and tx.to_address.lower() == contract
|
|
183
|
-
]
|
|
178
|
+
matching = [tx for tx in pending if tx.to_address and tx.to_address.lower() == contract]
|
|
184
179
|
|
|
185
180
|
if not matching:
|
|
186
181
|
print("No pending transactions found for this contract.")
|
|
@@ -240,40 +235,42 @@ Examples:
|
|
|
240
235
|
%(prog)s watch 0x7a250d... Watch contract for pending txs
|
|
241
236
|
%(prog)s status Check connection status
|
|
242
237
|
%(prog)s --demo pending Use mock data for testing
|
|
243
|
-
"""
|
|
238
|
+
""",
|
|
244
239
|
)
|
|
245
240
|
|
|
246
241
|
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
|
|
247
|
-
parser.add_argument("--format", choices=["table", "json"], default="table",
|
|
248
|
-
help="Output format")
|
|
242
|
+
parser.add_argument("--format", choices=["table", "json"], default="table", help="Output format")
|
|
249
243
|
parser.add_argument("--rpc-url", help="Custom RPC URL")
|
|
250
|
-
parser.add_argument(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
244
|
+
parser.add_argument(
|
|
245
|
+
"--chain",
|
|
246
|
+
default="ethereum",
|
|
247
|
+
choices=["ethereum", "polygon", "arbitrum", "optimism", "base"],
|
|
248
|
+
help="Blockchain network",
|
|
249
|
+
)
|
|
250
|
+
parser.add_argument(
|
|
251
|
+
"--eth-price",
|
|
252
|
+
type=float,
|
|
253
|
+
default=DEFAULT_ETH_PRICE,
|
|
254
|
+
help=f"ETH price for USD conversion (default: {DEFAULT_ETH_PRICE})",
|
|
255
|
+
)
|
|
256
|
+
parser.add_argument("--demo", action="store_true", help="Use mock data when RPC fails (for testing/demo)")
|
|
257
257
|
|
|
258
258
|
subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
|
259
259
|
|
|
260
260
|
# pending command
|
|
261
261
|
pending_parser = subparsers.add_parser("pending", help="View pending transactions")
|
|
262
|
-
pending_parser.add_argument("--limit", type=int, default=50,
|
|
263
|
-
help="Max transactions to show")
|
|
262
|
+
pending_parser.add_argument("--limit", type=int, default=50, help="Max transactions to show")
|
|
264
263
|
|
|
265
264
|
# gas command
|
|
266
265
|
subparsers.add_parser("gas", help="Analyze gas prices")
|
|
267
266
|
|
|
268
267
|
# swaps command
|
|
269
268
|
swaps_parser = subparsers.add_parser("swaps", help="Show pending DEX swaps")
|
|
270
|
-
swaps_parser.add_argument("--limit", type=int, default=100,
|
|
271
|
-
help="Max transactions to analyze")
|
|
269
|
+
swaps_parser.add_argument("--limit", type=int, default=100, help="Max transactions to analyze")
|
|
272
270
|
|
|
273
271
|
# mev command
|
|
274
272
|
mev_parser = subparsers.add_parser("mev", help="Scan for MEV opportunities")
|
|
275
|
-
mev_parser.add_argument("--limit", type=int, default=200,
|
|
276
|
-
help="Max transactions to analyze")
|
|
273
|
+
mev_parser.add_argument("--limit", type=int, default=200, help="Max transactions to analyze")
|
|
277
274
|
|
|
278
275
|
# summary command
|
|
279
276
|
subparsers.add_parser("summary", help="Mempool summary")
|
|
@@ -281,8 +278,7 @@ Examples:
|
|
|
281
278
|
# watch command
|
|
282
279
|
watch_parser = subparsers.add_parser("watch", help="Watch contract for pending txs")
|
|
283
280
|
watch_parser.add_argument("contract", help="Contract address to watch")
|
|
284
|
-
watch_parser.add_argument("--limit", type=int, default=100,
|
|
285
|
-
help="Max transactions to check")
|
|
281
|
+
watch_parser.add_argument("--limit", type=int, default=100, help="Max transactions to check")
|
|
286
282
|
|
|
287
283
|
# status command
|
|
288
284
|
subparsers.add_parser("status", help="Check connection status")
|
|
@@ -312,6 +308,7 @@ Examples:
|
|
|
312
308
|
print(f"Error: {e}")
|
|
313
309
|
if args.verbose:
|
|
314
310
|
import traceback
|
|
311
|
+
|
|
315
312
|
traceback.print_exc()
|
|
316
313
|
sys.exit(1)
|
|
317
314
|
|
|
@@ -15,6 +15,7 @@ from dataclasses import dataclass
|
|
|
15
15
|
|
|
16
16
|
try:
|
|
17
17
|
import yaml
|
|
18
|
+
|
|
18
19
|
HAS_YAML = True
|
|
19
20
|
except ImportError:
|
|
20
21
|
HAS_YAML = False
|
|
@@ -25,6 +26,7 @@ from tx_decoder import TransactionDecoder
|
|
|
25
26
|
@dataclass
|
|
26
27
|
class MEVOpportunity:
|
|
27
28
|
"""Detected MEV opportunity."""
|
|
29
|
+
|
|
28
30
|
opportunity_type: str # sandwich, arbitrage, liquidation, backrun
|
|
29
31
|
target_tx: str # Target transaction hash
|
|
30
32
|
estimated_profit_usd: float
|
|
@@ -37,6 +39,7 @@ class MEVOpportunity:
|
|
|
37
39
|
@dataclass
|
|
38
40
|
class PendingSwap:
|
|
39
41
|
"""Detected pending swap transaction."""
|
|
42
|
+
|
|
40
43
|
tx_hash: str
|
|
41
44
|
dex: str
|
|
42
45
|
amount_in: Optional[int]
|
|
@@ -105,10 +108,12 @@ class MEVDetector:
|
|
|
105
108
|
|
|
106
109
|
# Default locations
|
|
107
110
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
108
|
-
search_paths.extend(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
search_paths.extend(
|
|
112
|
+
[
|
|
113
|
+
os.path.join(script_dir, "..", "config", "settings.yaml"),
|
|
114
|
+
os.path.expanduser("~/.mempool_analyzer.yaml"),
|
|
115
|
+
]
|
|
116
|
+
)
|
|
112
117
|
|
|
113
118
|
for path in search_paths:
|
|
114
119
|
if os.path.exists(path):
|
|
@@ -121,11 +126,7 @@ class MEVDetector:
|
|
|
121
126
|
|
|
122
127
|
return None
|
|
123
128
|
|
|
124
|
-
def detect_pending_swaps(
|
|
125
|
-
self,
|
|
126
|
-
pending_txs: List[Any],
|
|
127
|
-
eth_price: float = 3000.0
|
|
128
|
-
) -> List[PendingSwap]:
|
|
129
|
+
def detect_pending_swaps(self, pending_txs: List[Any], eth_price: float = 3000.0) -> List[PendingSwap]:
|
|
129
130
|
"""Identify pending swap transactions.
|
|
130
131
|
|
|
131
132
|
Args:
|
|
@@ -157,21 +158,21 @@ class MEVDetector:
|
|
|
157
158
|
# Try to identify as swap
|
|
158
159
|
swap_info = self.decoder.identify_dex_swap(input_data, to_address)
|
|
159
160
|
if swap_info:
|
|
160
|
-
swaps.append(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
161
|
+
swaps.append(
|
|
162
|
+
PendingSwap(
|
|
163
|
+
tx_hash=tx_hash,
|
|
164
|
+
dex=swap_info.dex,
|
|
165
|
+
amount_in=swap_info.amount_in,
|
|
166
|
+
amount_out_min=swap_info.amount_out_min,
|
|
167
|
+
gas_price=gas_price,
|
|
168
|
+
from_address=from_address,
|
|
169
|
+
)
|
|
170
|
+
)
|
|
168
171
|
|
|
169
172
|
return swaps
|
|
170
173
|
|
|
171
174
|
def detect_sandwich_opportunities(
|
|
172
|
-
self,
|
|
173
|
-
pending_swaps: List[PendingSwap],
|
|
174
|
-
eth_price: float = 3000.0
|
|
175
|
+
self, pending_swaps: List[PendingSwap], eth_price: float = 3000.0
|
|
175
176
|
) -> List[MEVOpportunity]:
|
|
176
177
|
"""Detect potential sandwich attack opportunities.
|
|
177
178
|
|
|
@@ -206,27 +207,27 @@ class MEVDetector:
|
|
|
206
207
|
if estimated_profit < self.min_profit_usd:
|
|
207
208
|
continue
|
|
208
209
|
|
|
209
|
-
opportunities.append(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
210
|
+
opportunities.append(
|
|
211
|
+
MEVOpportunity(
|
|
212
|
+
opportunity_type="sandwich",
|
|
213
|
+
target_tx=swap.tx_hash,
|
|
214
|
+
estimated_profit_usd=estimated_profit,
|
|
215
|
+
required_capital_usd=value_usd * 0.5, # Need capital to front-run
|
|
216
|
+
risk_level="high", # Sandwiches are risky
|
|
217
|
+
confidence=0.3, # Low confidence without pool analysis
|
|
218
|
+
details={
|
|
219
|
+
"dex": swap.dex,
|
|
220
|
+
"swap_value_usd": value_usd,
|
|
221
|
+
"target_slippage": estimated_slippage,
|
|
222
|
+
"gas_price_gwei": swap.gas_price / 10**9,
|
|
223
|
+
},
|
|
224
|
+
)
|
|
225
|
+
)
|
|
223
226
|
|
|
224
227
|
return opportunities
|
|
225
228
|
|
|
226
229
|
def detect_arbitrage_opportunities(
|
|
227
|
-
self,
|
|
228
|
-
pending_swaps: List[PendingSwap],
|
|
229
|
-
pool_prices: Dict[str, float] = None
|
|
230
|
+
self, pending_swaps: List[PendingSwap], pool_prices: Dict[str, float] = None
|
|
230
231
|
) -> List[MEVOpportunity]:
|
|
231
232
|
"""Detect arbitrage opportunities from pending swaps.
|
|
232
233
|
|
|
@@ -258,10 +259,7 @@ class MEVDetector:
|
|
|
258
259
|
|
|
259
260
|
return opportunities
|
|
260
261
|
|
|
261
|
-
def detect_liquidation_opportunities(
|
|
262
|
-
self,
|
|
263
|
-
pending_txs: List[Any]
|
|
264
|
-
) -> List[MEVOpportunity]:
|
|
262
|
+
def detect_liquidation_opportunities(self, pending_txs: List[Any]) -> List[MEVOpportunity]:
|
|
265
263
|
"""Detect pending liquidation opportunities.
|
|
266
264
|
|
|
267
265
|
Args:
|
|
@@ -285,9 +283,7 @@ class MEVDetector:
|
|
|
285
283
|
return opportunities
|
|
286
284
|
|
|
287
285
|
def detect_all_opportunities(
|
|
288
|
-
self,
|
|
289
|
-
pending_txs: List[Any],
|
|
290
|
-
eth_price: float = 3000.0
|
|
286
|
+
self, pending_txs: List[Any], eth_price: float = 3000.0
|
|
291
287
|
) -> Dict[str, List[MEVOpportunity]]:
|
|
292
288
|
"""Run all MEV detection algorithms.
|
|
293
289
|
|
|
@@ -310,10 +306,7 @@ class MEVDetector:
|
|
|
310
306
|
|
|
311
307
|
return results
|
|
312
308
|
|
|
313
|
-
def format_opportunities(
|
|
314
|
-
self,
|
|
315
|
-
opportunities: List[MEVOpportunity]
|
|
316
|
-
) -> str:
|
|
309
|
+
def format_opportunities(self, opportunities: List[MEVOpportunity]) -> str:
|
|
317
310
|
"""Format opportunities for display.
|
|
318
311
|
|
|
319
312
|
Args:
|
|
@@ -360,6 +353,7 @@ def main():
|
|
|
360
353
|
class MockTx:
|
|
361
354
|
def __init__(self, value, gas_price):
|
|
362
355
|
import random
|
|
356
|
+
|
|
363
357
|
self.hash = f"0x{''.join(random.choices('0123456789abcdef', k=64))}"
|
|
364
358
|
self.from_address = f"0x{''.join(random.choices('0123456789abcdef', k=40))}"
|
|
365
359
|
self.to_address = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
|
|
@@ -368,10 +362,8 @@ def main():
|
|
|
368
362
|
self.input_data = "0x38ed1739" + "0" * 256
|
|
369
363
|
|
|
370
364
|
import random
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
for _ in range(20)
|
|
374
|
-
]
|
|
365
|
+
|
|
366
|
+
mock_txs = [MockTx(random.randint(1, 100) * 10**18, (30 + random.randint(0, 20)) * 10**9) for _ in range(20)]
|
|
375
367
|
|
|
376
368
|
# Detect
|
|
377
369
|
print("=== Scanning for Pending Swaps ===")
|
|
@@ -33,6 +33,7 @@ DEFAULT_RPC_URLS = {
|
|
|
33
33
|
@dataclass
|
|
34
34
|
class PendingTransaction:
|
|
35
35
|
"""Represents a pending transaction in the mempool."""
|
|
36
|
+
|
|
36
37
|
hash: str
|
|
37
38
|
from_address: str
|
|
38
39
|
to_address: Optional[str]
|
|
@@ -49,6 +50,7 @@ class PendingTransaction:
|
|
|
49
50
|
@dataclass
|
|
50
51
|
class GasInfo:
|
|
51
52
|
"""Current gas price information."""
|
|
53
|
+
|
|
52
54
|
base_fee: int
|
|
53
55
|
priority_fee: int
|
|
54
56
|
gas_price: int # legacy
|
|
@@ -58,12 +60,7 @@ class GasInfo:
|
|
|
58
60
|
class RPCClient:
|
|
59
61
|
"""Ethereum JSON-RPC client for mempool access."""
|
|
60
62
|
|
|
61
|
-
def __init__(
|
|
62
|
-
self,
|
|
63
|
-
rpc_url: str = None,
|
|
64
|
-
chain: str = "ethereum",
|
|
65
|
-
verbose: bool = False
|
|
66
|
-
):
|
|
63
|
+
def __init__(self, rpc_url: str = None, chain: str = "ethereum", verbose: bool = False):
|
|
67
64
|
"""Initialize RPC client.
|
|
68
65
|
|
|
69
66
|
Args:
|
|
@@ -184,7 +181,9 @@ class RPCClient:
|
|
|
184
181
|
gas=int(tx.get("gas", "0x0"), 16),
|
|
185
182
|
gas_price=int(tx.get("gasPrice", "0x0"), 16),
|
|
186
183
|
max_fee_per_gas=int(tx.get("maxFeePerGas", "0x0"), 16) if tx.get("maxFeePerGas") else None,
|
|
187
|
-
max_priority_fee_per_gas=int(tx.get("maxPriorityFeePerGas", "0x0"), 16)
|
|
184
|
+
max_priority_fee_per_gas=int(tx.get("maxPriorityFeePerGas", "0x0"), 16)
|
|
185
|
+
if tx.get("maxPriorityFeePerGas")
|
|
186
|
+
else None,
|
|
188
187
|
nonce=int(tx.get("nonce", "0x0"), 16),
|
|
189
188
|
input_data=tx.get("input", "0x"),
|
|
190
189
|
block_number=int(tx.get("blockNumber", "0x0"), 16) if tx.get("blockNumber") else None,
|
|
@@ -209,19 +208,21 @@ class RPCClient:
|
|
|
209
208
|
|
|
210
209
|
for i in range(min(limit, 20)):
|
|
211
210
|
gas_price = base_gas_price + random.randint(-5, 20) * 10**9
|
|
212
|
-
mock_txs.append(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
211
|
+
mock_txs.append(
|
|
212
|
+
PendingTransaction(
|
|
213
|
+
hash=f"0x{''.join(random.choices('0123456789abcdef', k=64))}",
|
|
214
|
+
from_address=f"0x{''.join(random.choices('0123456789abcdef', k=40))}",
|
|
215
|
+
to_address=random.choice(routers),
|
|
216
|
+
value=random.randint(0, 10) * 10**18,
|
|
217
|
+
gas=random.randint(100000, 500000),
|
|
218
|
+
gas_price=gas_price,
|
|
219
|
+
max_fee_per_gas=gas_price + 5 * 10**9,
|
|
220
|
+
max_priority_fee_per_gas=2 * 10**9,
|
|
221
|
+
nonce=random.randint(1, 1000),
|
|
222
|
+
input_data=swap_input + "0" * 128,
|
|
223
|
+
block_number=None,
|
|
224
|
+
)
|
|
225
|
+
)
|
|
225
226
|
|
|
226
227
|
return mock_txs
|
|
227
228
|
|
|
@@ -26,7 +26,6 @@ METHOD_SIGNATURES = {
|
|
|
26
26
|
"0xf305d719": {"name": "addLiquidityETH", "type": "liquidity"},
|
|
27
27
|
"0xbaa2abde": {"name": "removeLiquidity", "type": "liquidity"},
|
|
28
28
|
"0x02751cec": {"name": "removeLiquidityETH", "type": "liquidity"},
|
|
29
|
-
|
|
30
29
|
# Uniswap V3 Router
|
|
31
30
|
"0x414bf389": {"name": "exactInputSingle", "type": "swap"},
|
|
32
31
|
"0xc04b8d59": {"name": "exactInput", "type": "swap"},
|
|
@@ -34,12 +33,10 @@ METHOD_SIGNATURES = {
|
|
|
34
33
|
"0xf28c0498": {"name": "exactOutput", "type": "swap"},
|
|
35
34
|
"0x5ae401dc": {"name": "multicall", "type": "multicall"},
|
|
36
35
|
"0xac9650d8": {"name": "multicall", "type": "multicall"},
|
|
37
|
-
|
|
38
36
|
# ERC20
|
|
39
37
|
"0xa9059cbb": {"name": "transfer", "type": "transfer"},
|
|
40
38
|
"0x23b872dd": {"name": "transferFrom", "type": "transfer"},
|
|
41
39
|
"0x095ea7b3": {"name": "approve", "type": "approval"},
|
|
42
|
-
|
|
43
40
|
# Common
|
|
44
41
|
"0x": {"name": "ETH Transfer", "type": "transfer"},
|
|
45
42
|
}
|
|
@@ -54,7 +51,6 @@ KNOWN_CONTRACTS = {
|
|
|
54
51
|
"0x1111111254fb6c44bac0bed2854e76f90643097d": "1inch Router",
|
|
55
52
|
"0xdef1c0ded9bec7f1a1670819833240f027b25eff": "0x Exchange Proxy",
|
|
56
53
|
"0x881d40237659c251811cec9c364ef91dc08d300c": "Metamask Swap Router",
|
|
57
|
-
|
|
58
54
|
# Tokens
|
|
59
55
|
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": "WETH",
|
|
60
56
|
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": "USDC",
|
|
@@ -66,6 +62,7 @@ KNOWN_CONTRACTS = {
|
|
|
66
62
|
@dataclass
|
|
67
63
|
class DecodedCall:
|
|
68
64
|
"""Decoded function call."""
|
|
65
|
+
|
|
69
66
|
method_name: str
|
|
70
67
|
method_type: str # swap, transfer, approval, liquidity, multicall, unknown
|
|
71
68
|
contract_name: Optional[str]
|
|
@@ -76,6 +73,7 @@ class DecodedCall:
|
|
|
76
73
|
@dataclass
|
|
77
74
|
class SwapInfo:
|
|
78
75
|
"""Detected swap information."""
|
|
76
|
+
|
|
79
77
|
dex: str
|
|
80
78
|
method: str
|
|
81
79
|
token_in: Optional[str]
|
|
@@ -114,10 +112,13 @@ class TransactionDecoder:
|
|
|
114
112
|
# Get method signature (first 4 bytes)
|
|
115
113
|
signature = input_data[:10].lower()
|
|
116
114
|
|
|
117
|
-
method_info = METHOD_SIGNATURES.get(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
method_info = METHOD_SIGNATURES.get(
|
|
116
|
+
signature,
|
|
117
|
+
{
|
|
118
|
+
"name": "Unknown",
|
|
119
|
+
"type": "unknown",
|
|
120
|
+
},
|
|
121
|
+
)
|
|
121
122
|
|
|
122
123
|
contract_name = self._get_contract_name(to_address) if to_address else None
|
|
123
124
|
|
|
@@ -148,7 +149,7 @@ class TransactionDecoder:
|
|
|
148
149
|
params = {}
|
|
149
150
|
|
|
150
151
|
# Parse 32-byte chunks
|
|
151
|
-
chunks = [data[i:i+64] for i in range(0, len(data), 64)]
|
|
152
|
+
chunks = [data[i : i + 64] for i in range(0, len(data), 64)]
|
|
152
153
|
|
|
153
154
|
# For swaps, try to extract amounts
|
|
154
155
|
if signature in ["0x38ed1739", "0x8803dbee"]:
|
|
@@ -219,11 +220,7 @@ class TransactionDecoder:
|
|
|
219
220
|
decoded = self.decode_input(input_data, to_address)
|
|
220
221
|
return decoded.method_type
|
|
221
222
|
|
|
222
|
-
def estimate_attached_eth_usd_value(
|
|
223
|
-
self,
|
|
224
|
-
tx: Dict,
|
|
225
|
-
eth_price: float = 3000.0
|
|
226
|
-
) -> float:
|
|
223
|
+
def estimate_attached_eth_usd_value(self, tx: Dict, eth_price: float = 3000.0) -> float:
|
|
227
224
|
"""Estimate USD value of ETH attached to transaction (msg.value).
|
|
228
225
|
|
|
229
226
|
Note: This only calculates the USD value of ETH sent with the transaction.
|
|
@@ -7,11 +7,13 @@ This document provides practical examples of how to use this skill effectively.
|
|
|
7
7
|
### Example 1: Simple Activation
|
|
8
8
|
|
|
9
9
|
**User Request:**
|
|
10
|
+
|
|
10
11
|
```
|
|
11
12
|
[Describe trigger phrase here]
|
|
12
13
|
```
|
|
13
14
|
|
|
14
15
|
**Skill Response:**
|
|
16
|
+
|
|
15
17
|
1. Analyzes the request
|
|
16
18
|
2. Performs the required action
|
|
17
19
|
3. Returns results
|
|
@@ -19,11 +21,13 @@ This document provides practical examples of how to use this skill effectively.
|
|
|
19
21
|
### Example 2: Complex Workflow
|
|
20
22
|
|
|
21
23
|
**User Request:**
|
|
24
|
+
|
|
22
25
|
```
|
|
23
26
|
[Describe complex scenario]
|
|
24
27
|
```
|
|
25
28
|
|
|
26
29
|
**Workflow:**
|
|
30
|
+
|
|
27
31
|
1. Step 1: Initial analysis
|
|
28
32
|
2. Step 2: Data processing
|
|
29
33
|
3. Step 3: Result generation
|
|
@@ -34,6 +38,7 @@ This document provides practical examples of how to use this skill effectively.
|
|
|
34
38
|
### Pattern 1: Chaining Operations
|
|
35
39
|
|
|
36
40
|
Combine this skill with other tools:
|
|
41
|
+
|
|
37
42
|
```
|
|
38
43
|
Step 1: Use this skill for [purpose]
|
|
39
44
|
Step 2: Chain with [other tool]
|
|
@@ -43,6 +48,7 @@ Step 3: Finalize with [action]
|
|
|
43
48
|
### Pattern 2: Error Handling
|
|
44
49
|
|
|
45
50
|
If issues occur:
|
|
51
|
+
|
|
46
52
|
- Check trigger phrase matches
|
|
47
53
|
- Verify context is available
|
|
48
54
|
- Review allowed-tools permissions
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Skill validation helper
|
|
3
|
-
# Validates skill activation and functionality
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
echo "🔍 Validating skill..."
|
|
8
|
-
|
|
9
|
-
# Check if SKILL.md exists
|
|
10
|
-
if [ ! -f "../SKILL.md" ]; then
|
|
11
|
-
echo "❌ Error: SKILL.md not found"
|
|
12
|
-
exit 1
|
|
13
|
-
fi
|
|
14
|
-
|
|
15
|
-
# Validate frontmatter
|
|
16
|
-
if ! grep -q "^---$" "../SKILL.md"; then
|
|
17
|
-
echo "❌ Error: No frontmatter found"
|
|
18
|
-
exit 1
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
# Check required fields
|
|
22
|
-
if ! grep -q "^name:" "../SKILL.md"; then
|
|
23
|
-
echo "❌ Error: Missing 'name' field"
|
|
24
|
-
exit 1
|
|
25
|
-
fi
|
|
26
|
-
|
|
27
|
-
if ! grep -q "^description:" "../SKILL.md"; then
|
|
28
|
-
echo "❌ Error: Missing 'description' field"
|
|
29
|
-
exit 1
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
echo "✅ Skill validation passed"
|