@intentsolutionsio/mempool-analyzer 1.0.0

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.
Files changed (28) hide show
  1. package/.claude-plugin/plugin.json +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +97 -0
  4. package/agents/mempool-agent.md +158 -0
  5. package/package.json +43 -0
  6. package/skills/analyzing-mempool/ARD.md +146 -0
  7. package/skills/analyzing-mempool/PRD.md +71 -0
  8. package/skills/analyzing-mempool/SKILL.md +110 -0
  9. package/skills/analyzing-mempool/config/settings.yaml +43 -0
  10. package/skills/analyzing-mempool/references/errors.md +122 -0
  11. package/skills/analyzing-mempool/references/examples.md +189 -0
  12. package/skills/analyzing-mempool/references/implementation.md +67 -0
  13. package/skills/analyzing-mempool/scripts/formatters.py +244 -0
  14. package/skills/analyzing-mempool/scripts/gas_analyzer.py +299 -0
  15. package/skills/analyzing-mempool/scripts/mempool_analyzer.py +320 -0
  16. package/skills/analyzing-mempool/scripts/mev_detector.py +387 -0
  17. package/skills/analyzing-mempool/scripts/rpc_client.py +311 -0
  18. package/skills/analyzing-mempool/scripts/tx_decoder.py +273 -0
  19. package/skills/skill-adapter/assets/README.md +6 -0
  20. package/skills/skill-adapter/assets/config-template.json +32 -0
  21. package/skills/skill-adapter/assets/skill-schema.json +28 -0
  22. package/skills/skill-adapter/assets/test-data.json +27 -0
  23. package/skills/skill-adapter/references/README.md +4 -0
  24. package/skills/skill-adapter/references/best-practices.md +69 -0
  25. package/skills/skill-adapter/references/examples.md +73 -0
  26. package/skills/skill-adapter/scripts/README.md +8 -0
  27. package/skills/skill-adapter/scripts/helper-template.sh +42 -0
  28. package/skills/skill-adapter/scripts/validation.sh +32 -0
@@ -0,0 +1,43 @@
1
+ # Mempool Analyzer Configuration
2
+ # Copy to ~/.mempool_analyzer.yaml and customize
3
+
4
+ # RPC Configuration
5
+ rpc:
6
+ ethereum: "https://eth.llamarpc.com"
7
+ polygon: "https://polygon-rpc.com"
8
+ arbitrum: "https://arb1.arbitrum.io/rpc"
9
+ optimism: "https://mainnet.optimism.io"
10
+ base: "https://mainnet.base.org"
11
+
12
+ # Default Settings
13
+ defaults:
14
+ chain: "ethereum"
15
+ limit: 100
16
+ eth_price: 3000.0
17
+
18
+ # Gas Analysis
19
+ gas:
20
+ cache_ttl: 10 # seconds
21
+ percentiles: [10, 25, 50, 75, 90]
22
+
23
+ # MEV Detection
24
+ mev:
25
+ min_swap_value_usd: 10000 # $10k minimum
26
+ min_profit_usd: 100 # $100 minimum profit
27
+ detection_types:
28
+ - sandwich
29
+ - arbitrage
30
+ - liquidation
31
+
32
+ # Known DEX Routers
33
+ routers:
34
+ uniswap_v2: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
35
+ uniswap_v3: "0xE592427A0AEce92De3Edee1F18E0157C05861564"
36
+ sushiswap: "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F"
37
+ oneinch: "0x1111111254fb6c44bac0bed2854e76f90643097d"
38
+
39
+ # Output Settings
40
+ output:
41
+ format: "table"
42
+ max_display: 50
43
+ show_raw_data: false
@@ -0,0 +1,122 @@
1
+ # Error Handling Guide
2
+
3
+ ## RPC Connection Errors
4
+
5
+ ### Connection Refused
6
+ ```
7
+ Error: Connection refused to RPC endpoint
8
+ ```
9
+ **Cause**: RPC endpoint is down or unreachable
10
+ **Solution**:
11
+ - Check if RPC URL is correct
12
+ - Try alternative endpoint (Alchemy, Chainstack, Infura, or public RPC)
13
+ - Verify network connectivity
14
+
15
+ ### Timeout
16
+ ```
17
+ Error: Request timed out
18
+ ```
19
+ **Cause**: RPC node is slow or overloaded
20
+ **Solution**:
21
+ - Increase timeout setting
22
+ - Switch to faster RPC provider
23
+ - Reduce request frequency
24
+
25
+ ### Rate Limited
26
+ ```
27
+ Error: Too many requests (429)
28
+ ```
29
+ **Cause**: Exceeded RPC provider rate limits
30
+ **Solution**:
31
+ - Reduce polling frequency
32
+ - Upgrade RPC tier (paid Alchemy, Chainstack, or Infura plans)
33
+ - Use multiple RPC endpoints
34
+
35
+ ## Mempool Access Errors
36
+
37
+ ### txpool_content Not Available
38
+ ```
39
+ Error: txpool_content not supported
40
+ ```
41
+ **Cause**: Not all nodes support txpool methods
42
+ **Solution**:
43
+ - Use Geth node with txpool enabled
44
+ - Try eth_pendingTransactions instead
45
+ - Use mock data for demo purposes
46
+
47
+ ### Empty Mempool
48
+ ```
49
+ No pending transactions found
50
+ ```
51
+ **Cause**: Mempool is empty or access limited
52
+ **Solution**:
53
+ - Normal during low activity periods
54
+ - Verify RPC supports mempool access
55
+ - Check if node is fully synced
56
+
57
+ ## Transaction Decoding Errors
58
+
59
+ ### Unknown Method Signature
60
+ ```
61
+ Warning: Unknown method 0x12345678
62
+ ```
63
+ **Cause**: Method signature not in known ABI list
64
+ **Solution**:
65
+ - Transaction will show as "Unknown" type
66
+ - Add ABI to decoder if needed
67
+ - Use Etherscan to look up contract ABI
68
+
69
+ ### Invalid Input Data
70
+ ```
71
+ Error: Cannot decode input data
72
+ ```
73
+ **Cause**: Malformed or non-standard input
74
+ **Solution**:
75
+ - Skip transaction, continue analysis
76
+ - Raw data still available
77
+
78
+ ## Gas Analysis Errors
79
+
80
+ ### No Sample Data
81
+ ```
82
+ Warning: Insufficient data for gas analysis
83
+ ```
84
+ **Cause**: Too few pending transactions
85
+ **Solution**:
86
+ - Use default recommendations
87
+ - Wait for more mempool activity
88
+ - Reduce sample requirements
89
+
90
+ ## MEV Detection Errors
91
+
92
+ ### Pool Data Unavailable
93
+ ```
94
+ Warning: Cannot fetch pool reserves
95
+ ```
96
+ **Cause**: DEX subgraph or pool query failed
97
+ **Solution**:
98
+ - MEV detection will have lower confidence
99
+ - Use estimated values
100
+ - Check subgraph health
101
+
102
+ ## Debugging
103
+
104
+ ### Enable Verbose Mode
105
+ ```bash
106
+ python mempool_analyzer.py -v pending
107
+ ```
108
+
109
+ ### Check Connection
110
+ ```bash
111
+ python mempool_analyzer.py status
112
+ ```
113
+
114
+ ### Test RPC Endpoint
115
+ ```bash
116
+ curl -X POST -H "Content-Type: application/json" \
117
+ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
118
+ YOUR_RPC_URL
119
+ ```
120
+
121
+ ---
122
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,189 @@
1
+ # Usage Examples
2
+
3
+ ## View Pending Transactions
4
+
5
+ ### Basic View
6
+ ```bash
7
+ python mempool_analyzer.py pending
8
+ ```
9
+
10
+ ### Limit Results
11
+ ```bash
12
+ python mempool_analyzer.py pending --limit 20
13
+ ```
14
+
15
+ ### JSON Output
16
+ ```bash
17
+ python mempool_analyzer.py pending --format json
18
+ ```
19
+
20
+ ## Gas Price Analysis
21
+
22
+ ### Current Gas Prices
23
+ ```bash
24
+ python mempool_analyzer.py gas
25
+ ```
26
+
27
+ ### Gas Recommendations
28
+ ```bash
29
+ python mempool_analyzer.py gas
30
+ # Output shows:
31
+ # - Current base fee
32
+ # - Gas price distribution (10th, 25th, 50th, 75th, 90th percentile)
33
+ # - Recommendations for slow, standard, fast, instant
34
+ ```
35
+
36
+ ### JSON for Programmatic Use
37
+ ```bash
38
+ python mempool_analyzer.py gas --format json
39
+ ```
40
+
41
+ ## Pending DEX Swaps
42
+
43
+ ### View All Pending Swaps
44
+ ```bash
45
+ python mempool_analyzer.py swaps
46
+ ```
47
+
48
+ ### Analyze More Transactions
49
+ ```bash
50
+ python mempool_analyzer.py swaps --limit 200
51
+ ```
52
+
53
+ ## MEV Opportunity Scanning
54
+
55
+ ### Scan for Opportunities
56
+ ```bash
57
+ python mempool_analyzer.py mev
58
+ ```
59
+
60
+ ### Detailed Analysis
61
+ ```bash
62
+ python mempool_analyzer.py mev --limit 300 -v
63
+ ```
64
+
65
+ ### JSON Output
66
+ ```bash
67
+ python mempool_analyzer.py mev --format json
68
+ ```
69
+
70
+ ## Mempool Summary
71
+
72
+ ### Quick Overview
73
+ ```bash
74
+ python mempool_analyzer.py summary
75
+ ```
76
+
77
+ ## Watch Specific Contract
78
+
79
+ ### Monitor Uniswap Router
80
+ ```bash
81
+ python mempool_analyzer.py watch 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
82
+ ```
83
+
84
+ ### Monitor Any Contract
85
+ ```bash
86
+ python mempool_analyzer.py watch 0xYOUR_CONTRACT_ADDRESS --limit 200
87
+ ```
88
+
89
+ ## Connection Status
90
+
91
+ ### Check RPC Connection
92
+ ```bash
93
+ python mempool_analyzer.py status
94
+ ```
95
+
96
+ ## Different Chains
97
+
98
+ ### Polygon
99
+ ```bash
100
+ python mempool_analyzer.py --chain polygon pending
101
+ python mempool_analyzer.py --chain polygon gas
102
+ ```
103
+
104
+ ### Arbitrum
105
+ ```bash
106
+ python mempool_analyzer.py --chain arbitrum summary
107
+ ```
108
+
109
+ ### Custom RPC URL
110
+ ```bash
111
+ python mempool_analyzer.py --rpc-url https://your-rpc.example.com pending
112
+ ```
113
+
114
+ ## Common Workflows
115
+
116
+ ### Pre-Transaction Gas Check
117
+ ```bash
118
+ # Before sending a transaction, check optimal gas
119
+ python mempool_analyzer.py gas
120
+
121
+ # Use "Fast" recommendation for quick confirmation
122
+ # Use "Standard" for normal priority
123
+ # Use "Slow" if not time-sensitive
124
+ ```
125
+
126
+ ### Monitor for Front-Running Risk
127
+ ```bash
128
+ # Check if there are pending swaps that might affect your trade
129
+ python mempool_analyzer.py swaps
130
+
131
+ # High-value pending swaps = potential slippage
132
+ ```
133
+
134
+ ### MEV Opportunity Research
135
+ ```bash
136
+ # Educational: See what MEV opportunities exist
137
+ python mempool_analyzer.py mev -v
138
+
139
+ # Note: This is for research/education only
140
+ # Real MEV extraction requires specialized infrastructure
141
+ ```
142
+
143
+ ## Programmatic Usage
144
+
145
+ ```python
146
+ from rpc_client import RPCClient
147
+ from gas_analyzer import GasAnalyzer
148
+ from mev_detector import MEVDetector
149
+
150
+ # Initialize
151
+ client = RPCClient()
152
+ gas_analyzer = GasAnalyzer()
153
+ mev_detector = MEVDetector()
154
+
155
+ # Get pending transactions
156
+ pending = client.get_pending_transactions(limit=100)
157
+
158
+ # Analyze gas
159
+ gas_info = client.get_gas_price()
160
+ distribution = gas_analyzer.analyze_pending_gas(pending)
161
+
162
+ print(f"Median gas: {distribution.median_gwei:.1f} gwei")
163
+
164
+ # Detect swaps
165
+ swaps = mev_detector.detect_pending_swaps(pending)
166
+ print(f"Pending swaps: {len(swaps)}")
167
+ ```
168
+
169
+ ## Integration with jq
170
+
171
+ ### Filter High Gas Transactions
172
+ ```bash
173
+ python mempool_analyzer.py pending --format json | \
174
+ jq '[.[] | select(.gas_price > 50000000000)]'
175
+ ```
176
+
177
+ ### Count by Transaction Type
178
+ ```bash
179
+ python mempool_analyzer.py swaps --format json | \
180
+ jq 'group_by(.dex) | map({dex: .[0].dex, count: length})'
181
+ ```
182
+
183
+ ### Export Gas Data
184
+ ```bash
185
+ python mempool_analyzer.py gas --format json > gas_snapshot.json
186
+ ```
187
+
188
+ ---
189
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,67 @@
1
+ # Implementation Details
2
+
3
+ ## Gas Price Distribution Analysis
4
+
5
+ The gas analysis command calculates percentile-based recommendations from pending transactions:
6
+
7
+ **Gas Recommendations:**
8
+ - Slow (10th percentile): May take 10+ blocks
9
+ - Standard (50th percentile): 2-5 blocks
10
+ - Fast (75th percentile): 1-2 blocks
11
+ - Instant (90th percentile): Next block likely
12
+
13
+ ## MEV Detection Details
14
+
15
+ MEV detection scans for common patterns:
16
+ - **Sandwich attacks**: Detects front-run + back-run pairs targeting the same swap
17
+ - **Arbitrage**: Identifies circular token paths (A→B→A) across DEXs
18
+ - **Liquidation**: Finds health-factor monitoring and repay+seize patterns
19
+
20
+ **Important:** MEV detection is for educational purposes only. Real MEV extraction requires:
21
+ - Specialized block-builder infrastructure (Flashbots, MEV-Boost)
22
+ - Sub-millisecond execution timing
23
+ - Significant capital for gas auctions
24
+
25
+ ## DEX Swap Detection
26
+
27
+ The `swaps` command identifies pending DEX transactions by matching method selectors:
28
+ - Uniswap V2/V3: `swapExactTokensForTokens`, `exactInputSingle`
29
+ - SushiSwap: Same interface as Uniswap V2
30
+ - 1inch: `swap`, `unoswap` aggregation methods
31
+
32
+ ## Multi-Chain Support
33
+
34
+ Supported chains and their mempool characteristics:
35
+ | Chain | Mempool Access | Block Time | Notes |
36
+ |-------|---------------|------------|-------|
37
+ | Ethereum | Full | ~12s | Richest MEV environment |
38
+ | Polygon | Full | ~2s | Lower gas, faster blocks |
39
+ | Arbitrum | Limited | ~0.25s | Sequencer-based, less MEV |
40
+ | Optimism | Limited | ~2s | Sequencer-based |
41
+ | Base | Limited | ~2s | Coinbase sequencer |
42
+
43
+ ## Contract Watching
44
+
45
+ The `watch` command monitors pending transactions to a specific contract address:
46
+ 1. Filters mempool by `to` address
47
+ 2. Decodes known method selectors
48
+ 3. Estimates gas cost in USD
49
+ 4. Identifies transaction type (swap, approve, transfer, etc.)
50
+
51
+ ## Configuration
52
+
53
+ Edit `${CLAUDE_SKILL_DIR}/config/settings.yaml`:
54
+ ```yaml
55
+ rpc_endpoints:
56
+ ethereum: "https://rpc.ankr.com/eth"
57
+ polygon: "https://rpc.ankr.com/polygon"
58
+ arbitrum: "https://rpc.ankr.com/arbitrum"
59
+
60
+ defaults:
61
+ chain: ethereum
62
+ limit: 50
63
+ output_format: table
64
+ ```
65
+
66
+ ---
67
+ *[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Mempool Analyzer Formatters
4
+
5
+ Format mempool data for various outputs.
6
+
7
+ Author: Jeremy Longshore <jeremy@intentsolutions.io>
8
+ Version: 1.0.0
9
+ License: MIT
10
+ """
11
+
12
+ import json
13
+ from datetime import datetime
14
+ from typing import Any, List, Optional, TYPE_CHECKING
15
+
16
+ if TYPE_CHECKING:
17
+ from tx_decoder import TransactionDecoder
18
+
19
+
20
+ def format_gwei(wei: int) -> str:
21
+ """Format wei as gwei."""
22
+ gwei = wei / 10**9
23
+ return f"{gwei:.1f} gwei"
24
+
25
+
26
+ def format_eth(wei: int) -> str:
27
+ """Format wei as ETH."""
28
+ eth = wei / 10**18
29
+ if eth >= 1:
30
+ return f"{eth:.4f} ETH"
31
+ else:
32
+ return f"{eth:.6f} ETH"
33
+
34
+
35
+ def format_usd(value: float) -> str:
36
+ """Format USD value."""
37
+ if value >= 1e6:
38
+ return f"${value / 1e6:.2f}M"
39
+ elif value >= 1e3:
40
+ return f"${value / 1e3:.1f}K"
41
+ else:
42
+ return f"${value:,.2f}"
43
+
44
+
45
+ def format_address(address: str, length: int = 12) -> str:
46
+ """Truncate address for display."""
47
+ if not address:
48
+ return "N/A"
49
+ if len(address) <= length:
50
+ return address
51
+ half = (length - 3) // 2
52
+ return f"{address[:half]}...{address[-half:]}"
53
+
54
+
55
+ def format_pending_tx_table(
56
+ transactions: List[Any],
57
+ eth_price: float = 3000.0,
58
+ decoder: Optional["TransactionDecoder"] = None,
59
+ ) -> str:
60
+ """Format pending transactions as table.
61
+
62
+ Args:
63
+ transactions: List of PendingTransaction objects
64
+ eth_price: Current ETH price for USD conversion
65
+ decoder: Optional TransactionDecoder instance (created if not provided)
66
+
67
+ Returns:
68
+ Formatted table string
69
+ """
70
+ if not transactions:
71
+ return "No pending transactions."
72
+
73
+ lines = [
74
+ "",
75
+ "PENDING TRANSACTIONS",
76
+ "=" * 100,
77
+ f"{'Hash':<18} {'From':<14} {'To':<14} {'Value':<12} {'Gas Price':<12} {'Gas':<10} {'Type':<12}",
78
+ "-" * 100,
79
+ ]
80
+
81
+ # Create decoder only if not provided
82
+ if decoder is None:
83
+ from tx_decoder import TransactionDecoder
84
+ decoder = TransactionDecoder()
85
+
86
+ for tx in transactions[:50]:
87
+ tx_hash = format_address(tx.hash, 16)
88
+ from_addr = format_address(tx.from_address, 12)
89
+ to_addr = format_address(tx.to_address or "Contract", 12)
90
+
91
+ # Value
92
+ if tx.value > 0:
93
+ value_str = format_eth(tx.value)
94
+ else:
95
+ value_str = "0"
96
+
97
+ gas_price_str = format_gwei(tx.gas_price)
98
+ gas_str = f"{tx.gas:,}"
99
+
100
+ # Decode type
101
+ decoded = decoder.decode_input(tx.input_data, tx.to_address)
102
+ tx_type = decoded.method_type[:10]
103
+
104
+ lines.append(f"{tx_hash:<18} {from_addr:<14} {to_addr:<14} {value_str:<12} {gas_price_str:<12} {gas_str:<10} {tx_type:<12}")
105
+
106
+ lines.append("-" * 100)
107
+ lines.append(f"Showing {min(len(transactions), 50)} of {len(transactions)} pending transactions")
108
+
109
+ return "\n".join(lines)
110
+
111
+
112
+ def format_pending_swaps_table(swaps: List[Any]) -> str:
113
+ """Format pending swaps as table.
114
+
115
+ Args:
116
+ swaps: List of PendingSwap objects
117
+
118
+ Returns:
119
+ Formatted table string
120
+ """
121
+ if not swaps:
122
+ return "No pending swaps detected."
123
+
124
+ lines = [
125
+ "",
126
+ "PENDING DEX SWAPS",
127
+ "=" * 90,
128
+ f"{'Hash':<18} {'DEX':<20} {'Amount In':<16} {'Gas Price':<12} {'From':<14}",
129
+ "-" * 90,
130
+ ]
131
+
132
+ for swap in swaps[:30]:
133
+ tx_hash = format_address(swap.tx_hash, 16)
134
+ dex = swap.dex[:18] if swap.dex else "Unknown"
135
+
136
+ if swap.amount_in:
137
+ amount = format_eth(swap.amount_in)
138
+ else:
139
+ amount = "Unknown"
140
+
141
+ gas_price = format_gwei(swap.gas_price)
142
+ from_addr = format_address(swap.from_address, 12)
143
+
144
+ lines.append(f"{tx_hash:<18} {dex:<20} {amount:<16} {gas_price:<12} {from_addr:<14}")
145
+
146
+ lines.append("-" * 90)
147
+ lines.append(f"Total: {len(swaps)} pending swaps")
148
+
149
+ return "\n".join(lines)
150
+
151
+
152
+ def format_mempool_summary(
153
+ pending_count: int,
154
+ gas_info: Any,
155
+ swap_count: int,
156
+ opportunities: int
157
+ ) -> str:
158
+ """Format mempool summary.
159
+
160
+ Args:
161
+ pending_count: Number of pending transactions
162
+ gas_info: GasInfo object
163
+ swap_count: Number of pending swaps
164
+ opportunities: Number of MEV opportunities
165
+
166
+ Returns:
167
+ Formatted summary string
168
+ """
169
+ lines = [
170
+ "",
171
+ "MEMPOOL SUMMARY",
172
+ "=" * 50,
173
+ f"Pending Transactions: {pending_count:,}",
174
+ f"Pending Swaps: {swap_count}",
175
+ f"MEV Opportunities: {opportunities}",
176
+ "",
177
+ "Gas Prices:",
178
+ f" Base Fee: {format_gwei(gas_info.base_fee)}",
179
+ f" Priority Fee: {format_gwei(gas_info.priority_fee)}",
180
+ f" Gas Price: {format_gwei(gas_info.gas_price)}",
181
+ "=" * 50,
182
+ ]
183
+
184
+ return "\n".join(lines)
185
+
186
+
187
+ def format_json(data: Any) -> str:
188
+ """Format data as JSON."""
189
+ if hasattr(data, "__iter__") and not isinstance(data, (str, dict)):
190
+ serialized = []
191
+ for item in data:
192
+ if hasattr(item, "__dict__"):
193
+ serialized.append(vars(item))
194
+ else:
195
+ serialized.append(item)
196
+ return json.dumps(serialized, indent=2, default=str)
197
+ elif hasattr(data, "__dict__"):
198
+ return json.dumps(vars(data), indent=2, default=str)
199
+ else:
200
+ return json.dumps(data, indent=2, default=str)
201
+
202
+
203
+ def format_stream_alert(
204
+ tx: Any,
205
+ decoder: Optional["TransactionDecoder"] = None,
206
+ ) -> str:
207
+ """Format single transaction for stream output.
208
+
209
+ Args:
210
+ tx: Transaction object
211
+ decoder: Optional TransactionDecoder instance (created if not provided)
212
+
213
+ Returns:
214
+ Single-line alert string
215
+ """
216
+ timestamp = datetime.now().strftime("%H:%M:%S")
217
+ tx_hash = format_address(tx.hash, 12)
218
+ gas_price = tx.gas_price / 10**9
219
+
220
+ # Create decoder only if not provided
221
+ if decoder is None:
222
+ from tx_decoder import TransactionDecoder
223
+ decoder = TransactionDecoder()
224
+ decoded = decoder.decode_input(tx.input_data, tx.to_address)
225
+
226
+ if tx.value > 0:
227
+ value = format_eth(tx.value)
228
+ return f"[{timestamp}] {tx_hash} | {gas_price:.1f} gwei | {value} | {decoded.method_type}"
229
+ else:
230
+ return f"[{timestamp}] {tx_hash} | {gas_price:.1f} gwei | {decoded.method_name}"
231
+
232
+
233
+ def main():
234
+ """CLI entry point for testing."""
235
+ # Test formatting functions
236
+ print("=== Format Tests ===")
237
+ print(f"Gwei: {format_gwei(30 * 10**9)}")
238
+ print(f"ETH: {format_eth(1.5 * 10**18)}")
239
+ print(f"USD: {format_usd(1234567)}")
240
+ print(f"Address: {format_address('0x1234567890abcdef1234567890abcdef12345678')}")
241
+
242
+
243
+ if __name__ == "__main__":
244
+ main()