🎯 Initial commit: Uniswap Auto CLP trading system
Core Components: - uniswap_manager.py: V3 concentrated liquidity position manager - clp_hedger.py: Hyperliquid perpetuals hedging bot - requirements.txt: Python dependencies - .gitignore: Security exclusions for sensitive data - doc/: Project documentation - tools/: Utility scripts and Git agent Features: - Automated liquidity provision on Uniswap V3 (WETH/USDC) - Delta-neutral hedging using Hyperliquid perpetuals - Position lifecycle management (open/close/rebalance) - Automated backup and version control system Security: - Private keys and tokens excluded from version control - Environment variables properly handled - Automated security validation for backups Git Agent: - Hourly automated backups to separate branches - Keep last 100 backups (~4 days coverage) - Detailed change tracking and parameter monitoring - Push to Gitea server automatically - Manual main branch control preserved - No performance tracking for privacy - No notifications for simplicity Files Added: - git_agent.py: Main automation script - agent_config.json: Configuration with Gitea settings - git_utils.py: Git operations wrapper - backup_manager.py: Backup branch management - change_detector.py: File change analysis - cleanup_manager.py: 100-backup rotation - commit_formatter.py: Detailed commit messages - README_GIT_AGENT.md: Complete usage documentation
This commit is contained in:
108
doc/LOW_LATENCY_OPTIMIZATION_PLAN.md
Normal file
108
doc/LOW_LATENCY_OPTIMIZATION_PLAN.md
Normal file
@ -0,0 +1,108 @@
|
||||
# Low Latency Optimization Plan: Memory Sharing Integration
|
||||
|
||||
## Overview
|
||||
Currently, the system consists of two separate processes (`uniswap_manager_refactored.py` and `clp_hedger.py`) communicating via a file (`hedge_status.json`). This introduces inevitable latency due to:
|
||||
1. **Polling Intervals:** The hedger must "sleep" and "wake up" to check the file.
|
||||
2. **File I/O:** Reading/writing to disk is thousands of times slower than memory operations.
|
||||
3. **Synchronization:** Potential race conditions if both try to access the file simultaneously.
|
||||
|
||||
## Goal
|
||||
Eliminate file reliance to achieve **sub-millisecond** reaction times between "Uniswap Position Out of Range" detection and "Hedge Close" execution.
|
||||
|
||||
## Proposed Architecture: Unified Multi-Threaded Bot
|
||||
|
||||
Instead of two independent scripts, we will merge them into a single Python application running two concurrent threads that share a common data object in memory.
|
||||
|
||||
### Key Components
|
||||
|
||||
1. **`SharedState` Class (The Brain)**
|
||||
* A thread-safe data structure (using `threading.Lock`) that holds the current position status, price, and range.
|
||||
* **Events:** Uses `threading.Event` (e.g., `close_signal`) to allow the Manager to *instantly* wake up the Hedger without waiting for a sleep cycle to finish.
|
||||
|
||||
2. **`UniswapManager` Thread**
|
||||
* **Role:** Monitors on-chain data (RPC).
|
||||
* **Action:** When it detects "Out of Range", it updates `SharedState` and sets `close_signal.set()`.
|
||||
|
||||
3. **`ClpHedger` Thread**
|
||||
* **Role:** Manages the Hyperliquid hedge.
|
||||
* **Action:** Instead of `time.sleep(1)`, it waits on `close_signal.wait(timeout=1)`.
|
||||
* **Reaction:** If `close_signal` is triggered, it executes the close logic **immediately** (0 latency).
|
||||
|
||||
4. **`main_bot.py` (The Entry Point)**
|
||||
* Initializes `SharedState`.
|
||||
* Starts `UniswapManager` and `ClpHedger` as threads.
|
||||
* Handles centralized logging and clean shutdown.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Step 1: Create `SharedState`
|
||||
Define a class that replaces the JSON file structure.
|
||||
```python
|
||||
class SharedState:
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
self.close_event = threading.Event()
|
||||
self.position_data = {} # Stores the dict formerly in JSON
|
||||
|
||||
def update_position(self, data):
|
||||
with self.lock:
|
||||
self.position_data.update(data)
|
||||
|
||||
def get_position(self):
|
||||
with self.lock:
|
||||
return self.position_data.copy()
|
||||
|
||||
def trigger_emergency_close(self):
|
||||
self.close_event.set()
|
||||
```
|
||||
|
||||
### Step 2: Refactor `uniswap_manager_refactored.py`
|
||||
* Convert the script into a class `UniswapManager`.
|
||||
* Replace all `load_status_data()` and `save_status_data()` calls with `self.shared_state.update_position(...)`.
|
||||
* When "Out of Range" is detected:
|
||||
```python
|
||||
# Old
|
||||
update_position_status(token_id, "CLOSING")
|
||||
|
||||
# New
|
||||
self.shared_state.update_position({'status': 'CLOSING'})
|
||||
self.shared_state.trigger_emergency_close() # Wakes up Hedger instantly
|
||||
```
|
||||
|
||||
### Step 3: Refactor `clp_hedger.py`
|
||||
* Convert the script into a class `ClpHedger`.
|
||||
* Replace file reading logic with `self.shared_state.get_position()`.
|
||||
* Update the main loop to handle the event:
|
||||
```python
|
||||
# Old
|
||||
time.sleep(CHECK_INTERVAL)
|
||||
|
||||
# New
|
||||
# Wait for 1 second OR immediate signal
|
||||
if self.shared_state.close_event.wait(timeout=1.0):
|
||||
self.close_all_positions()
|
||||
self.shared_state.close_event.clear()
|
||||
```
|
||||
|
||||
### Step 4: Create `main_bot.py`
|
||||
```python
|
||||
if __name__ == "__main__":
|
||||
state = SharedState()
|
||||
|
||||
manager = UniswapManager(state)
|
||||
hedger = ClpHedger(state)
|
||||
|
||||
t1 = threading.Thread(target=manager.run)
|
||||
t2 = threading.Thread(target=hedger.run)
|
||||
|
||||
t1.start()
|
||||
t2.start()
|
||||
|
||||
t1.join()
|
||||
t2.join()
|
||||
```
|
||||
|
||||
## Benefits
|
||||
1. **Zero Latency:** The moment the Manager sets the event, the Hedger reacts. No polling delay.
|
||||
2. **Reliability:** No file corruption risks (like the JSON error experienced earlier).
|
||||
3. **Efficiency:** Reduces disk I/O, extending SD card/drive life and reducing CPU usage.
|
||||
139
doc/PYTHON_BLOCKCHAIN_REVIEW_GUIDELINES.md
Normal file
139
doc/PYTHON_BLOCKCHAIN_REVIEW_GUIDELINES.md
Normal file
@ -0,0 +1,139 @@
|
||||
# Python Blockchain Development & Review Guidelines
|
||||
|
||||
## Overview
|
||||
This document outlines the standards for writing, reviewing, and deploying Python scripts that interact with EVM-based blockchains (Ethereum, Arbitrum, etc.). These guidelines prioritize **capital preservation**, **transaction robustness**, and **system stability**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Transaction Handling & Lifecycle
|
||||
*High-reliability transaction management is the core of a production bot. Never "fire and forget."*
|
||||
|
||||
### 1.1. Timeout & Receipt Management
|
||||
- **Requirement:** Never send a transaction without immediately waiting for its receipt or tracking its hash.
|
||||
- **Why:** The RPC might accept the tx, but it could be dropped from the mempool or stuck indefinitely.
|
||||
- **Code Standard:**
|
||||
```python
|
||||
# BAD
|
||||
w3.eth.send_raw_transaction(signed_txn.rawTransaction)
|
||||
|
||||
# GOOD
|
||||
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
|
||||
try:
|
||||
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
|
||||
except TimeExhausted:
|
||||
# Handle stuck transaction (bump gas or cancel)
|
||||
handle_stuck_transaction(tx_hash)
|
||||
```
|
||||
|
||||
### 1.2. Verification of Success
|
||||
- **Requirement:** Explicitly check `receipt.status == 1`.
|
||||
- **Why:** A transaction can be mined (success=True) but execution can revert (status=0).
|
||||
- **Code Standard:**
|
||||
```python
|
||||
if receipt.status != 1:
|
||||
raise TransactionRevertedError(f"Tx {tx_hash.hex()} reverted on-chain")
|
||||
```
|
||||
|
||||
### 1.3. Gas Management & Stuck Transactions
|
||||
- **Requirement:** Do not hardcode gas prices. Use dynamic estimation.
|
||||
- **Mechanism:**
|
||||
- For EIP-1559 chains (Arbitrum/Base/Mainnet), use `maxFeePerGas` and `maxPriorityFeePerGas`.
|
||||
- Implement a "Gas Bumping" mechanism: If a tx is not mined in $X$ seconds, resubmit with 10-20% higher gas using the **same nonce**.
|
||||
|
||||
### 1.4. Nonce Management
|
||||
- **Requirement:** In high-frequency loops, track the nonce locally.
|
||||
- **Why:** `w3.eth.get_transaction_count(addr, 'pending')` is often slow or eventually consistent on some RPCs, leading to "Nonce too low" or "Replacement transaction underpriced" errors.
|
||||
|
||||
---
|
||||
|
||||
## 2. Financial Logic & Precision
|
||||
|
||||
### 2.1. No Floating Point Math for Token Amounts
|
||||
- **Requirement:** NEVER use standard python `float` for calculating token amounts or prices involved in protocol interactions.
|
||||
- **Standard:** Use `decimal.Decimal` or integer math (Wei).
|
||||
- **Why:** `0.1 + 0.2 != 0.3` in floating point. This causes dust errors and "Insufficient Balance" reverts.
|
||||
```python
|
||||
# BAD
|
||||
amount = balance * 0.5
|
||||
|
||||
# GOOD
|
||||
amount = int(Decimal(balance) * Decimal("0.5"))
|
||||
```
|
||||
|
||||
### 2.2. Slippage Protection
|
||||
- **Requirement:** Never use `0` for `amountOutMinimum` or `sqrtPriceLimitX96` in production.
|
||||
- **Standard:** Calculate expected output and apply a config-defined slippage (e.g., 0.1%).
|
||||
- **Why:** Front-running and sandwich attacks will drain value from `amountOutMin: 0` trades.
|
||||
|
||||
### 2.3. Approval Handling
|
||||
- **Requirement:** Check allowance before approving.
|
||||
- **Standard:**
|
||||
- Verify `allowance >= amount`.
|
||||
- If `allowance == 0`, approve.
|
||||
- **Note:** Some tokens (USDT) require approving `0` before approving a new amount if an allowance already exists.
|
||||
|
||||
---
|
||||
|
||||
## 3. Security & Safety
|
||||
|
||||
### 3.1. Secrets Management
|
||||
- **Requirement:** No private keys or mnemonics in source code.
|
||||
- **Standard:** Use `.env` files (loaded via `python-dotenv`) or proper secrets managers.
|
||||
- **Review Check:** `grep -r "0x..." .` to ensure no keys were accidentally committed.
|
||||
|
||||
### 3.2. Address Validation
|
||||
- **Requirement:** All addresses must be checksummed before use.
|
||||
- **Standard:**
|
||||
```python
|
||||
# Input
|
||||
target_address = "0xc364..."
|
||||
|
||||
# Validation
|
||||
if not Web3.is_address(target_address):
|
||||
raise ValueError("Invalid address")
|
||||
checksum_address = Web3.to_checksum_address(target_address)
|
||||
```
|
||||
|
||||
### 3.3. Simulation (Dry Run)
|
||||
- **Requirement:** For complex logic (like batch swaps), use `contract.functions.method().call()` before `.build_transaction()`.
|
||||
- **Why:** If the `.call()` fails (reverts), the transaction will definitely fail. Save gas by catching logic errors off-chain.
|
||||
|
||||
---
|
||||
|
||||
## 4. Coding Style & Observability
|
||||
|
||||
### 4.1. Logging
|
||||
- **Requirement:** No `print()` statements. Use `logging` module.
|
||||
- **Standard:**
|
||||
- `INFO`: High-level state changes (e.g., "Position Opened").
|
||||
- `DEBUG`: API responses, specific calc steps.
|
||||
- `ERROR`: Stack traces and critical failures.
|
||||
- **Traceability:** Log the Transaction Hash **immediately** upon sending, not after waiting. If the script crashes while waiting, you need the hash to check the chain manually.
|
||||
|
||||
### 4.2. Idempotency & State Recovery
|
||||
- **Requirement:** Scripts must be restartable without double-spending.
|
||||
- **Standard:** Before submitting a "Open Position" transaction, read the chain (or `hedge_status.json`) to ensure a position isn't already open.
|
||||
|
||||
### 4.3. Type Hinting
|
||||
- **Requirement:** Use Python type hints for clarity.
|
||||
- **Standard:**
|
||||
```python
|
||||
def execute_swap(
|
||||
token_in: str,
|
||||
amount: int,
|
||||
slippage_pct: float = 0.5
|
||||
) -> str: # Returns tx_hash
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Review Checklist (Copy-Paste for PRs)
|
||||
|
||||
- [ ] **Secrets:** No private keys in code?
|
||||
- [ ] **Math:** Is `Decimal` or Integer math used for all financial calcs?
|
||||
- [ ] **Slippage:** Is `amountOutMinimum` > 0?
|
||||
- [ ] **Timeouts:** Does `wait_for_transaction_receipt` have a timeout?
|
||||
- [ ] **Status Check:** Is `receipt.status` checked for success/revert?
|
||||
- [ ] **Gas:** Are gas limits and prices dynamic/reasonable?
|
||||
- [ ] **Addresses:** Are all addresses Checksummed?
|
||||
- [ ] **Restartability:** What happens if the script dies halfway through?
|
||||
71
doc/UNISWAP_MANAGER_WORKFLOW.md
Normal file
71
doc/UNISWAP_MANAGER_WORKFLOW.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Uniswap Manager Workflow Documentation
|
||||
|
||||
This document describes the operational logic of the `uniswap_manager_refactored.py` script, specifically focusing on how it handles position lifecycle events.
|
||||
|
||||
## 1. Out of Range Workflow (Position Closing)
|
||||
|
||||
When the script detects that an active Concentrated Liquidity Position (CLP) has moved out of its defined tick range, the following sequence occurs:
|
||||
|
||||
1. **Detection (Monitoring Loop):**
|
||||
* The `main` loop runs every `MONITOR_INTERVAL_SECONDS` (default: 60s).
|
||||
* It retrieves the active position's `tickLower` and `tickUpper` from on-chain data.
|
||||
* It fetches the current pool `tick`.
|
||||
* It determines if the position is out of range (`current_tick < tickLower` or `current_tick >= tickUpper`).
|
||||
|
||||
2. **Logging:**
|
||||
* A warning is logged to both console and file: `🛑 Closing Position {token_id} (Out of Range)`.
|
||||
|
||||
3. **Status Update -> "CLOSING":**
|
||||
* The `hedge_status.json` file is updated to mark the position status as `"CLOSING"`.
|
||||
* **Purpose:** This signals external Hedger bots (watching this file) to halt hedging operations or close their hedges immediately.
|
||||
|
||||
4. **Liquidity Removal:**
|
||||
* The script executes a `decreaseLiquidity` transaction on the `NonfungiblePositionManager` contract.
|
||||
* It removes 100% of the liquidity, converting the position back into the underlying tokens (WETH and USDC) in the wallet.
|
||||
|
||||
5. **Fee Collection:**
|
||||
* Immediately following liquidity removal, a `collect` transaction is sent to claim all accrued trading fees.
|
||||
|
||||
6. **Status Update -> "CLOSED":**
|
||||
* Upon successful confirmation of the transactions, `hedge_status.json` is updated to status `"CLOSED"`.
|
||||
* A `timestamp_close` is recorded.
|
||||
|
||||
7. **Rebalancing (Optional/Configuration Dependent):**
|
||||
* The script checks the `REBALANCE_ON_CLOSE_BELOW_RANGE` flag.
|
||||
* **Scenario:** If the price fell **BELOW** the range, the position is 100% WETH.
|
||||
* **Action:** If implemented, the script may perform a swap (e.g., selling 50% of the WETH for USDC) to rebalance the portfolio before opening a new position.
|
||||
* *Current State:* The logic identifies this condition but requires the specific swap logic implementation (currently a `pass` placeholder in the refactored script).
|
||||
|
||||
8. **Cycle Reset:**
|
||||
* The script returns to the monitoring loop.
|
||||
* In the next cycle, detecting no "OPEN" position, it will evaluate `OPEN_POSITION_ENABLED` to potentially calculate and mint a **new** position centered on the current market price.
|
||||
|
||||
## 2. New Position Creation (Opening)
|
||||
|
||||
When no active position exists and `OPEN_POSITION_ENABLED` is `True`:
|
||||
|
||||
1. **Market Analysis:**
|
||||
* Fetches current pool price and tick.
|
||||
* Calculates a new range (default: +/- 2.5%) centered on the current tick.
|
||||
|
||||
2. **Investment Calculation:**
|
||||
* Uses `TARGET_INVESTMENT_VALUE_USDC` (default: $200).
|
||||
* If set to `"MAX"`, it calculates the maximum affordable position based on wallet balances minus a safety buffer.
|
||||
* Calculates the precise amount of Token0 and Token1 required for the target value at the current price and range.
|
||||
|
||||
3. **Preparation (Swap & Approve):**
|
||||
* Checks wallet balances.
|
||||
* **Auto-Wrap:** Wraps ETH to WETH if necessary.
|
||||
* **Auto-Swap:** Swaps surplus tokens (e.g., excess USDC for WETH) to match the required ratio for the new position.
|
||||
* **Approvals:** Checks and sends `approve` transactions for the Position Manager if allowances are insufficient.
|
||||
|
||||
4. **Minting:**
|
||||
* Sends the `mint` transaction to create the new NFT position.
|
||||
* Applies a slippage tolerance (default: 0.5%) to `amountMin` parameters.
|
||||
|
||||
5. **Status Recording:**
|
||||
* On success, updates `hedge_status.json` with the new position details (Token ID, Range, Entry Price, Initial Amounts).
|
||||
* Sets status to `"OPEN"`.
|
||||
|
||||
---
|
||||
*Last Updated: December 19, 2025*
|
||||
Reference in New Issue
Block a user