docs: expand AVE Claw Hackathon research with code examples and guides

- Added 3 runnable Python scripts for Data REST, Data WebSocket, and Trading APIs
- Expanded research with 7 new sections:
  - Extended API documentation with full request/response examples
  - Working code examples with CLI commands
  - Security guide (API keys, HMAC signing, private key protection)
  - Testing strategies (dry-run, paper trading, testnets)
  - Troubleshooting guide with error codes
  - Competitive analysis vs DexScreener, Moralis, CoinGecko
  - Quick reference appendix

Research doc grew from 242 to 906 lines
This commit is contained in:
shokollm
2026-04-05 20:52:58 +00:00
parent eabbcd911c
commit 90283d7403
5 changed files with 2217 additions and 38 deletions

View File

@@ -89,7 +89,7 @@ The AVE Claw Hackathon is a developer competition focused on building trading bo
|----------|-------------|------| |----------|-------------|------|
| `GET /v2/tokens` | Search tokens by keyword | 5 CU | | `GET /v2/tokens` | Search tokens by keyword | 5 CU |
| `GET /v2/tokens/{token-id}` | Token details + top 5 pairs | 5 CU | | `GET /v2/tokens/{token-id}` | Token details + top 5 pairs | 5 CU |
| `GET /v2/tokens/price` | Batch token prices (up to 200) | 100 CU | | `POST /v2/tokens/price` | Batch token prices (up to 200) | 100 CU |
| `GET /v2/tokens/trending` | Trending tokens | 5 CU | | `GET /v2/tokens/trending` | Trending tokens | 5 CU |
| `GET /v2/tokens/top100/{token-id}` | Top 100 token holders | 10 CU | | `GET /v2/tokens/top100/{token-id}` | Top 100 token holders | 10 CU |
| `GET /v2/contracts/{token-id}` | Token risk info | 10 CU | | `GET /v2/contracts/{token-id}` | Token risk info | 10 CU |
@@ -98,8 +98,13 @@ The AVE Claw Hackathon is a developer competition focused on building trading bo
| `GET /v2/address/tx` | Wallet transaction history | 100 CU | | `GET /v2/address/tx` | Wallet transaction history | 100 CU |
| `GET /v2/address/pnl` | Wallet PnL data | 5 CU | | `GET /v2/address/pnl` | Wallet PnL data | 5 CU |
| `GET /v2/address/walletinfo` | Wallet info (all tokens) | 5 CU | | `GET /v2/address/walletinfo` | Wallet info (all tokens) | 5 CU |
| `GET /v2/address/walletinfo/tokens` | All tokens in wallet | 10 CU |
| `GET /v2/address/smart_wallet/list` | Smart wallet list (copy trading) | 5 CU |
| `GET /v2/klines/token/{token-id}` | Kline data by token | 10 CU | | `GET /v2/klines/token/{token-id}` | Kline data by token | 10 CU |
| `GET /v2/klines/pair/{pair-id}` | Kline data by pair | 10 CU | | `GET /v2/klines/pair/{pair-id}` | Kline data by pair | 10 CU |
| `GET /v2/pairs/{pair-id}` | Pair details | 5 CU |
| `GET /v2/tokens/platform` | Tokens by launch platform | 10 CU |
| `GET /v2/tokens/main` | Main tokens on chain | 5 CU |
### WebSocket API (`wss://wss.ave-api.xyz`) ### WebSocket API (`wss://wss.ave-api.xyz`)
@@ -130,47 +135,15 @@ The AVE Claw Hackathon is a developer competition focused on building trading bo
| GitHub (Skills) | https://github.com/AveCloud/ave-cloud-skill | | GitHub (Skills) | https://github.com/AveCloud/ave-cloud-skill |
| Telegram Support | https://t.me/ave_ai_cloud | | Telegram Support | https://t.me/ave_ai_cloud |
### Python Skill Scripts (GitHub) ### Python Skill Scripts
The `ave-cloud-skill` repo provides Python scripts: The `docs/scripts/` directory contains runnable Python scripts:
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
| `ave_data_rest.py` | Token search, prices, klines, holders, risk | | `ave_data_rest.py` | Token search, prices, klines, holders, risk |
| `ave_data_wss.py` | Real-time WebSocket streams | | `ave_data_wss.py` | Real-time WebSocket streams |
| `ave_trade_rest.py` | Chain & proxy wallet trading | | `ave_trade_rest.py` | Chain & proxy wallet trading |
| `ave_trade_wss.py` | Proxy wallet WebSocket updates |
### Quick Start Example
```bash
# Build Docker image
docker build -f scripts/Dockerfile.txt -t ave-cloud .
# Token search
docker run --rm \
-e AVE_API_KEY=your_api_key \
-e API_PLAN=free \
--entrypoint python3 \
ave-cloud scripts/ave_data_rest.py search --keyword PEPE
# Live price watch
docker run --rm -it \
-e AVE_API_KEY=your_api_key \
-e API_PLAN=pro \
--entrypoint python3 \
ave-cloud scripts/ave_data_wss.py wss-repl
# Dry-run trade preview
docker run --rm \
-e AVE_API_KEY=your_api_key \
-e API_PLAN=free \
--entrypoint python3 \
ave-cloud scripts/ave_trade_rest.py quote \
--chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy
```
### Token Links Format ### Token Links Format
View tokens on AVE Pro: `https://pro.ave.ai/token/<token_address>-<chain>` View tokens on AVE Pro: `https://pro.ave.ai/token/<token_address>-<chain>`
@@ -178,7 +151,7 @@ Example: `https://pro.ave.ai/token/0x1234...abcd-bsc`
--- ---
## Decision Guidance for Participants ## 6. Decision Guidance for Participants
**What to Build:** **What to Build:**
@@ -195,7 +168,632 @@ Example: `https://pro.ave.ai/token/0x1234...abcd-bsc`
--- ---
## 6. AVE Cloud Agent Skills - User Insights ## 7. Extended API Documentation
### 7.1 Token ID Format
All token references use the format `<token_address>-<chain>`:
```
PEPE-bsc
0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc
6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN-solana
```
**Chain names:** `bsc`, `solana`, `eth`, `base`
### 7.2 Complete Request/Response Examples
#### Token Search
**Request:**
```bash
curl "https://prod.ave-api.com/v2/tokens?keyword=PEPE&chain=bsc&limit=10" \
-H "X-API-KEY: your_api_key"
```
**Response:**
```json
{
"status": 200,
"msg": "success",
"data": [
{
"name": "Pepe",
"symbol": "PEPE",
"chain": "bsc",
"current_price_usd": "0.00001234",
"market_cap": "1234567890",
"tx_volume_u_24h": "50000000",
"main_pair_tvl": "1000000",
"logo_url": "https://..."
}
]
}
```
#### Batch Token Price
**Request:**
```bash
curl -X POST "https://prod.ave-api.com/v2/tokens/price" \
-H "X-API-KEY: your_api_key" \
-H "Content-Type: application/json" \
-d '{"token_ids": ["PEPE-bsc", "TRUMP-bsc", "0x55d398326f99059fF775485246999027B3197955-bsc"]}'
```
**Response:**
```json
{
"status": 200,
"msg": "success",
"data": {
"PEPE-bsc": {
"price": "0.00001234",
"price_24h_change": "5.67",
"updated_at": 1756888200
},
"TRUMP-bsc": {
"price": "4.56",
"price_24h_change": "-2.34",
"updated_at": 1756888200
}
}
}
```
#### Wallet PnL
**Request:**
```bash
curl "https://prod.ave-api.com/v2/address/pnl?wallet_address=0xd9c500dff816a1da21a48a732d3498bf09dc9aeb&chain=bsc&token_address=0x55d398326f99059fF775485246999027B3197955" \
-H "X-API-KEY: your_api_key"
```
**Response:**
```json
{
"status": 200,
"msg": "success",
"data": {
"wallet_address": "0xd9c500dff816a1da21a48a732d3498bf09dc9aeb",
"token_address": "0x55d398326f99059fF775485246999027B3197955",
"total_profit": "123.45",
"total_profit_rate": "0.15",
"buy_amount": "10000",
"sell_amount": "10123.45",
"avg_buy_price": "1.0",
"avg_sell_price": "1.0123"
}
}
```
### 7.3 Error Codes
#### HTTP Status Codes
| Code | Meaning | Cause |
|------|---------|-------|
| 200 | Success | Request completed |
| 400 | Bad Request | Invalid parameters, malformed JSON |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | API key expired, plan limits reached |
| 429 | Rate Limited | TPS exceeded |
| 500 | Server Error | Internal error, try again later |
#### Business Error Codes
| Code | Meaning |
|------|---------|
| 200 | Success |
| 1001 | General failure |
| 1011 | System error |
| 1021 | Signature verification failed |
| 1022 | API frozen, contact support |
| 1023 | Request expired (timestamp out of range) |
| 2001 | Request parameter error |
| 3001 | Transaction send failed |
| 3011 | Transaction record not found |
| 3021 | Order cancellation failed |
| 3101 | User does not exist |
| 3102 | User assets don't belong to this organization |
| 3103 | User asset account disabled |
| 3104 | No proxy wallet permission, upgrade plan required |
### 7.4 CU (Compute Unit) Cost Optimization
Each API call costs CU. Strategies to minimize usage:
| Strategy | Example |
|----------|---------|
| Use `/v2/tokens/price` batch (100 CU) vs individual calls | Batch up to 200 tokens in one call |
| Cache trending/risk data | Risk info changes slowly, cache for 5-10 min |
| Use filters | Add `tvl_min`, `tx_24h_volume_min` to price queries |
| Prefer search over detailed token | `/v2/tokens` (5 CU) vs `/v2/tokens/{id}` (5 CU) |
### 7.5 Pagination
Endpoints that return lists support pagination:
| Parameter | For |
|-----------|-----|
| `page_size` | Results per page (max varies) |
| `current_page` | Page number (0-indexed) |
| `last_id` | Cursor for next page (from previous response) |
Example pagination flow:
```python
# Get first page
result = get_trending_tokens(chain="bsc", page=0, page_size=50)
next_page = result["next_page"] # Use this for next request
# For wallet PnL with cursor
result = get_wallet_pnl(wallet, chain, token)
if result.get("has_more"):
next_result = get_wallet_pnl(wallet, chain, token, last_id=result["last_id"])
```
---
## 8. Working Code Examples
### 8.1 Setup
```bash
cd /home/shoko/repositories/randebu
pip install -r docs/scripts/requirements.txt
export AVE_API_KEY=your_api_key_here
export API_PLAN=free # or normal, pro
```
### 8.2 Data REST API Examples
```bash
# Token search
python3 docs/scripts/ave_data_rest.py search --keyword PEPE --chain bsc
# Batch price (up to 200 tokens)
python3 docs/scripts/ave_data_rest.py price --token-ids "PEPE-bsc,TRUMP-bsc,SOL-bsc"
# Trending tokens
python3 docs/scripts/ave_data_rest.py trending --chain bsc --page-size 20
# Token details + top pairs
python3 docs/scripts/ave_data_rest.py token --token-id "PEPE-bsc"
# Risk assessment
python3 docs/scripts/ave_data_rest.py risk --token-id "PEPE-bsc"
# Top 100 holders
python3 docs/scripts/ave_data_rest.py holders --token-id "PEPE-bsc" --limit 50
# Kline data (1h intervals)
python3 docs/scripts/ave_data_rest.py klines --token-id "PEPE-bsc" --interval 1h --limit 100
# Wallet PnL
python3 docs/scripts/ave_data_rest.py wallet-pnl \
--wallet 0xd9c500dff816a1da21a48a732d3498bf09dc9aeb \
--chain bsc --token 0x55d398326f99059fF775485246999027B3197955
# Smart wallets (for copy trading)
python3 docs/scripts/ave_data_rest.py smart-wallets --chain bsc --sort total_profit
```
### 8.3 WebSocket Examples
```bash
# Requires API_PLAN=pro
# Subscribe to swap transactions by pair
python3 docs/scripts/ave_data_wss.py subscribe-tx \
--pair Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE \
--chain solana
# Subscribe to all txs involving a token
python3 docs/scripts/ave_data_wss.py subscribe-multi-tx \
--token 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c \
--chain bsc
# Subscribe to liquidity changes
python3 docs/scripts/ave_data_wss.py subscribe-liq \
--pair Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE \
--chain solana
# Subscribe to price changes
python3 docs/scripts/ave_data_wss.py subscribe-price \
--pairs "PEPE-bsc,TRUMP-bsc,SOL-bsc"
# Subscribe to kline data
python3 docs/scripts/ave_data_wss.py subscribe-kline \
--token "PEPE-bsc" --interval 1m
# Interactive REPL mode
python3 docs/scripts/ave_data_wss.py wss-repl
# Then type commands like:
# subscribe tx <pair_address> <chain>
# subscribe price PEPE-bsc,TRUMP-bsc
# list
# quit
```
### 8.4 Trading Examples
```bash
# Chain Wallet (self-custody) - Free tier OK
# Dry-run quote
python3 docs/scripts/ave_trade_rest.py chain-quote \
--chain bsc \
--in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy
# Actual swap (requires signing keys configured)
python3 docs/scripts/ave_trade_rest.py chain-swap \
--chain bsc \
--in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy
# Proxy Wallet (server-managed) - Requires normal/pro tier
export AVE_SECRET_KEY=your_secret_key_here
# Dry-run quote
python3 docs/scripts/ave_trade_rest.py proxy-quote \
--chain bsc \
--proxy-wallet 0x... \
--in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy
# Market order with TP/SL
python3 docs/scripts/ave_trade_rest.py proxy-market \
--chain bsc \
--proxy-wallet 0x... \
--in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy \
--tp-price 35.0 --sl-price 30.0
# Limit order
python3 docs/scripts/ave_trade_rest.py proxy-limit \
--chain bsc \
--proxy-wallet 0x... \
--in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy --price 35.5
# Get open orders
python3 docs/scripts/ave_trade_rest.py proxy-orders \
--chain bsc --proxy-wallet 0x...
# Cancel order
python3 docs/scripts/ave_trade_rest.py proxy-cancel \
--chain bsc --order-id xxx
# Create proxy wallet
python3 docs/scripts/ave_trade_rest.py create-proxy-wallet --chain bsc
# List proxy wallets
python3 docs/scripts/ave_trade_rest.py list-proxy-wallets --chain bsc
```
---
## 9. Security Guide
### 9.1 API Key Management
| Do | Don't |
|----|-------|
| Store in environment variables | Commit to git |
| Use `.env` file (add to `.gitignore`) | Share in Slack/Discord |
| Rotate keys periodically | Use in client-side code |
| Regenerate if compromised | Log API keys in errors |
```bash
# .env file (NEVER commit this)
AVE_API_KEY=your_api_key_here
AVE_SECRET_KEY=your_secret_key_here
AVE_EVM_PRIVATE_KEY=your_private_key_here
```
### 9.2 HMAC Signing for Proxy Wallet
Proxy wallet requests require HMAC-SHA256 signature:
```python
import hashlib
import hmac
import json
import time
def generate_signature(secret_key: str, timestamp: str, body: str = "") -> str:
message = timestamp + body
signature = hmac.new(
secret_key.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return signature
# Usage
timestamp = str(int(time.time() * 1000))
body = json.dumps({"chain": "bsc", "proxy_wallet": "0x..."}, separators=(",", ":"))
signature = generate_signature(AVE_SECRET_KEY, timestamp, body)
headers = {
"X-API-KEY": API_KEY,
"X-Signature": signature,
"X-Timestamp": timestamp,
"Content-Type": "application/json"
}
```
### 9.3 Chain Wallet Private Key Protection
| Option | Security Level | Use Case |
|--------|---------------|----------|
| Hardware wallet | Highest | Production trading |
| Encrypted keystore | High | Development |
| Mnemonic (never raw key) | Medium | Quick testing |
| Raw private key in env | Low | Temporary only |
```bash
# Use hardware wallet or encrypted key
# NEVER do this:
AVE_EVM_PRIVATE_KEY=0x1234567890abcdef...
# DO this instead:
# Import from encrypted keystore or hardware wallet
```
### 9.4 Webhook/Callback Verification
If implementing webhooks for order updates:
```python
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)
```
### 9.5 Security Checklist
- [ ] API key stored in environment variable, not code
- [ ] `.env` in `.gitignore`
- [ ] Proxy wallet HMAC signing implemented correctly
- [ ] Private keys never logged or error messages
- [ ] HTTPS only (all AVE Cloud endpoints use HTTPS)
- [ ] Timestamp validation (requests expire after ~30s)
- [ ] Input validation on all user-provided addresses/tokens
---
## 10. Testing Strategies
### 10.1 Dry-Run / Quote Mode
Always test with quotes first:
```bash
# Chain wallet quote (no actual trade)
python3 docs/scripts/ave_trade_rest.py chain-quote \
--chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy
# Proxy wallet quote (no actual trade)
python3 docs/scripts/ave_trade_rest.py proxy-quote \
--chain bsc --proxy-wallet 0x... \
--in-token 0x55d398326f99059fF775485246999027B3197955 \
--out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c \
--in-amount 10000000 --swap-type buy
```
### 10.2 Paper Trading Pattern
```python
import os
class PaperTradingBot:
def __init__(self):
self.mode = os.getenv("TRADING_MODE", "paper") # paper or live
def execute_trade(self, order):
if self.mode == "paper":
print(f"[PAPER] Would execute: {order}")
return {"status": "paper", "order_id": "paper_123"}
else:
return self.live_execute(order)
```
### 10.3 Testnet Considerations
| Chain | Testnet | Faucet |
|-------|---------|--------|
| BSC | https://testnet.bscscan.com | https://testnet.bnb.org |
| Solana | https://api.devnet.solana.com | https://faucet.solana.com |
| ETH | Sepolia testnet | https://sepoliafaucet.com |
| Base | Base Sepolia | https://www.coinbase.com/faucets |
### 10.4 Mocking API Responses
```python
import pytest
from unittest.mock import Mock, patch
def test_token_search():
mock_response = {
"status": 200,
"data": [{"symbol": "PEPE", "chain": "bsc", "current_price_usd": "0.00001"}]
}
with patch("requests.get") as mock_get:
mock_get.return_value = Mock(json=lambda: mock_response, status_code=200)
result = search_tokens("PEPE", "bsc")
assert result["data"][0]["symbol"] == "PEPE"
```
### 10.5 Testing WebSocket Reconnection
```python
def test_reconnect():
client = AveWssClient(API_KEY)
client.connect()
# Simulate disconnect
client.ws.close()
# Should auto-reconnect
assert client.running
time.sleep(6) # Wait for reconnect
assert client.ws is not None
```
---
## 11. Troubleshooting Guide
### 11.1 Common Errors and Fixes
| Error | HTTP Code | Business Code | Cause | Solution |
|-------|-----------|--------------|-------|---------|
| 401 Unauthorized | 401 | - | Invalid/missing API key | Regenerate at cloud.ave.ai |
| 403 Forbidden | 403 | 1022 | API key expired | Renew key or contact support |
| 403 Forbidden | 403 | 3104 | Free tier accessing proxy wallet | Upgrade to Level 1+ |
| 429 Rate Limited | 429 | - | TPS exceeded | Add delay, implement backoff |
| 3001 Send TX Failed | 200 | 3001 | Insufficient gas or wallet balance | Check RPC, fund wallet |
| 1021 Signature Failed | 200 | 1021 | HMAC signature incorrect | Check timestamp and signing logic |
| 2001 Parameter Error | 200 | 2001 | Invalid request parameters | Check API docs for required fields |
### 11.2 WebSocket Troubleshooting
**Connection refused:**
```bash
# Verify API plan is pro
echo $API_PLAN # Should be "pro"
```
**Not receiving messages:**
```python
# Enable debug mode
client = AveWssClient(api_key, debug=True)
```
**Auto-reconnect not working:**
```python
# Manual reconnect
client.disconnect()
time.sleep(5)
client.connect()
```
### 11.3 Rate Limit Handling
```python
import time
import requests
def call_with_retry(func, max_retries=3):
for attempt in range(max_retries):
result = func()
if result.status_code != 429:
return result
wait_time = 2 ** attempt # Exponential backoff
print(f"Rate limited, waiting {wait_time}s...")
time.sleep(wait_time)
raise Exception("Max retries exceeded")
```
### 11.4 Debugging Tips
1. **Check headers:**
```python
print(headers) # Verify X-API-KEY is present
```
2. **Verify token ID format:**
```python
# Correct
"PEPE-bsc"
"0x1234...-eth"
# Wrong
"PEPE" # Missing chain
"bsc:0x1234..." # Wrong separator
```
3. **Check timestamp for HMAC:**
```python
# Timestamp must be milliseconds
timestamp = str(int(time.time() * 1000))
```
4. **Amount format:**
```python
# Use string to avoid floating point precision issues
"10000000" # Correct
10000000 # Also works
10.0 # WRONG - precision loss
```
---
## 12. Competitive Analysis
### 12.1 AVE Cloud vs Alternatives
| Feature | AVE Cloud | DexScreener | Moralis | CoinGecko |
|---------|-----------|-------------|---------|-----------|
| Multi-chain support | 4 chains | 20+ chains | 10+ chains | 100+ chains |
| Trading API | ✅ Chain + Proxy wallet | ❌ | ✅ ETH/ERC-20 only | ❌ |
| WebSocket streams | ✅ (pro tier) | ✅ Free | ✅ Paid only | ❌ |
| TP/SL automation | ✅ Proxy wallet | ❌ | ❌ | ❌ |
| Copy trading support | ✅ Smart wallet list | ❌ | ✅ | ❌ |
| Self-custody option | ✅ Chain wallet | ❌ | ❌ | ❌ |
| CU-based pricing | ✅ | Free | Free tier limited | Free tier limited |
| Risk/honeypot detection | ✅ Built-in | Limited | ✅ | ✅ |
| API documentation | Chinese-focused | Basic | Comprehensive | Comprehensive |
| Community size | Very small (3 stars) | Large | Large | Very large |
### 12.2 Unique Selling Points of AVE Cloud
1. **TP/SL Automation** - Built into proxy wallet, no need to monitor
2. **Dual Wallet Options** - Self-custody (chain) or managed (proxy)
3. **Copy Trading Infrastructure** - Smart wallet tracking API built-in
4. **All-in-one** - Data + Trading in single platform
5. **Low fees** - 0.6% chain, 0.8% proxy with rebates
### 12.3 Weaknesses
1. **Small community** - Only 3 GitHub stars, limited tutorials
2. **Documentation** - Primarily Chinese, limited English examples
3. **New platform** - Early stage, potential instability
4. **Feature locks** - WebSocket requires pro tier
5. **Solana complexity** - Priority fees not well documented
### 12.4 When to Use Alternatives
| Use Case | Alternative |
|----------|-------------|
| Multi-chain analytics only | DexScreener API |
| ERC-20 trading on ETH | Moralis |
| Historical price data | CoinGecko API |
| Advanced charting | TradingView API |
| Social sentiment | LunarCrush |
### 12.5 AVE Cloud Best Fit
- **Hackathon projects** focused on automated trading with TP/SL
- **Copy trading bots** leveraging smart wallet tracking
- **Multi-chain trading bots** needing unified API
- **Real-time monitoring dashboards** with WebSocket feeds
---
## 13. AVE Cloud Agent Skills - User Insights
**GitHub Activity:** **GitHub Activity:**
- `ave-cloud-skill`: 3 stars, 46 commits (very early stage) - `ave-cloud-skill`: 3 stars, 46 commits (very early stage)
@@ -240,3 +838,69 @@ Example: `https://pro.ave.ai/token/0x1234...abcd-bsc`
- No YouTube tutorials, blog posts, or external reviews yet - No YouTube tutorials, blog posts, or external reviews yet
**Bottom line:** The skills system is very new (3 stars), primarily used for token research and proxy wallet trading. The self-custody chain-wallet is the least used due to complexity. **Bottom line:** The skills system is very new (3 stars), primarily used for token research and proxy wallet trading. The self-custody chain-wallet is the least used due to complexity.
---
## Appendix: Quick Reference
### Environment Variables
| Variable | Required For | Description |
|----------|-------------|-------------|
| `AVE_API_KEY` | All scripts | API key from cloud.ave.ai |
| `API_PLAN` | WSS, Proxy trading | free, normal, or pro |
| `AVE_SECRET_KEY` | Proxy wallet | HMAC signing secret |
| `AVE_EVM_PRIVATE_KEY` | Chain wallet (optional) | Hex private key for BSC/ETH/Base |
| `AVE_SOLANA_PRIVATE_KEY` | Chain wallet (optional) | Base58 private key for Solana |
| `AVE_MNEMONIC` | Chain wallet (optional) | BIP39 mnemonic |
### Script Quick Reference
```bash
# Data REST
python3 docs/scripts/ave_data_rest.py search --keyword <keyword>
python3 docs/scripts/ave_data_rest.py price --token-ids <comma-separated>
python3 docs/scripts/ave_data_rest.py trending --chain <chain>
python3 docs/scripts/ave_data_rest.py token --token-id <id>
python3 docs/scripts/ave_data_rest.py risk --token-id <id>
python3 docs/scripts/ave_data_rest.py holders --token-id <id>
python3 docs/scripts/ave_data_rest.py klines --token-id <id>
python3 docs/scripts/ave_data_rest.py wallet-pnl --wallet <addr> --chain <chain> --token <addr>
python3 docs/scripts/ave_data_rest.py wallet-info --wallet <addr> --chain <chain>
python3 docs/scripts/ave_data_rest.py smart-wallets --chain <chain>
# Data WebSocket
python3 docs/scripts/ave_data_wss.py subscribe-tx --pair <addr> --chain <chain>
python3 docs/scripts/ave_data_wss.py subscribe-multi-tx --token <addr> --chain <chain>
python3 docs/scripts/ave_data_wss.py subscribe-price --pairs <comma-separated>
python3 docs/scripts/ave_data_wss.py wss-repl
# Trading REST
python3 docs/scripts/ave_trade_rest.py chain-quote --chain <chain> --in-token <addr> --out-token <addr> --in-amount <amount> --swap-type <buy|sell>
python3 docs/scripts/ave_trade_rest.py chain-swap ...
python3 docs/scripts/ave_trade_rest.py proxy-quote ...
python3 docs/scripts/ave_trade_rest.py proxy-market ... [--tp-price <p>] [--sl-price <p>]
python3 docs/scripts/ave_trade_rest.py proxy-limit ... --price <p>
python3 docs/scripts/ave_trade_rest.py proxy-orders --chain <chain> --proxy-wallet <addr>
python3 docs/scripts/ave_trade_rest.py proxy-cancel --chain <chain> --order-id <id>
python3 docs/scripts/ave_trade_rest.py create-proxy-wallet --chain <chain>
python3 docs/scripts/ave_trade_rest.py list-proxy-wallets --chain <chain>
```
### Common Token Addresses (BSC Mainnet)
| Token | Address |
|-------|---------|
| BNB | (native) |
| USDT | 0x55d398326f99059fF775485246999027B3197955 |
| BUSD | 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56 |
| BTCB | 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c |
| ETH | 0x2170Ed0880ac9A755fd29C2681C0DBeD5aF88B2c |
### Common Token Addresses (Solana)
| Token | Address |
|-------|---------|
| SOL | So11111111111111111111111111111111111111112 |
| USDC | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |

View File

@@ -0,0 +1,494 @@
#!/usr/bin/env python3
"""
AVE Cloud Data REST API - Token Search, Prices, Klines, Holders, Risk
Usage:
export AVE_API_KEY=your_api_key_here
export API_PLAN=free # free, normal, pro
python3 docs/scripts/ave_data_rest.py search --keyword PEPE
python3 docs/scripts/ave_data_rest.py price --token-ids "PEPE-bsc,TRUMP-bsc"
python3 docs/scripts/ave_data_rest.py trending --chain bsc
python3 docs/scripts/ave_data_rest.py token --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py risk --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py holders --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py klines --token-id "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc"
python3 docs/scripts/ave_data_rest.py pairs --pair-id "0x16b9a82891338f9ba80e2d6970fdda79d1eb0dae-bsc"
python3 docs/scripts/ave_data_rest.py wallet-pnl --wallet "0xd9c500dff816a1da21a48a732d3498bf09dc9aeb" --chain bsc --token "0x55d398326f99059fF775485246999027B3197955"
python3 docs/scripts/ave_data_rest.py wallet-info --wallet "0xd9c500dff816a1da21a48a732d3498bf09dc9aeb" --chain bsc
python3 docs/scripts/ave_data_rest.py smart-wallets --chain bsc
"""
import argparse
import json
import os
import sys
import time
from dataclasses import dataclass
from typing import Optional
import requests
BASE_URL = "https://prod.ave-api.com"
API_KEY = os.getenv("AVE_API_KEY", "")
API_PLAN = os.getenv("API_PLAN", "free")
CU_COSTS = {
"search": 5,
"price": 100,
"trending": 5,
"token": 5,
"risk": 10,
"holders": 10,
"klines_token": 10,
"klines_pair": 10,
"pairs": 5,
"wallet_pnl": 5,
"wallet_info": 5,
"wallet_tokens": 10,
"smart_wallet": 5,
}
TIER_LIMITS = {
"free": {"tps": 1, "data_wss": False, "proxy_wallet": False},
"normal": {"tps": 5, "data_wss": False, "proxy_wallet": True},
"pro": {"tps": 20, "data_wss": True, "proxy_wallet": True},
}
@dataclass
class ApiResponse:
status: int
data: Optional[dict] = None
error: Optional[str] = None
def make_headers():
return {
"X-API-KEY": API_KEY,
"Content-Type": "application/json",
}
def handle_response(response: requests.Response) -> ApiResponse:
if response.status_code == 200:
return ApiResponse(status=200, data=response.json())
elif response.status_code == 401:
return ApiResponse(
status=401, error="Unauthorized - invalid or missing API key"
)
elif response.status_code == 403:
return ApiResponse(
status=403, error="Forbidden - API key expired or plan limits reached"
)
elif response.status_code == 429:
return ApiResponse(status=429, error="Rate limited - TPS exceeded")
else:
return ApiResponse(status=response.status_code, error=response.text)
def search_tokens(
keyword: str, chain: Optional[str] = None, limit: int = 100
) -> ApiResponse:
params = {"keyword": keyword, "limit": limit}
if chain:
params["chain"] = chain
response = requests.get(
f"{BASE_URL}/v2/tokens", headers=make_headers(), params=params
)
return handle_response(response)
def get_token_price(token_ids: list) -> ApiResponse:
data = {"token_ids": token_ids}
response = requests.post(
f"{BASE_URL}/v2/tokens/price", headers=make_headers(), json=data
)
return handle_response(response)
def get_trending_tokens(chain: str, page: int = 0, page_size: int = 50) -> ApiResponse:
params = {"chain": chain, "current_page": page, "page_size": page_size}
response = requests.get(
f"{BASE_URL}/v2/tokens/trending", headers=make_headers(), params=params
)
return handle_response(response)
def get_token_detail(token_id: str) -> ApiResponse:
response = requests.get(f"{BASE_URL}/v2/tokens/{token_id}", headers=make_headers())
return handle_response(response)
def get_token_risk(token_id: str) -> ApiResponse:
response = requests.get(
f"{BASE_URL}/v2/contracts/{token_id}", headers=make_headers()
)
return handle_response(response)
def get_top_holders(token_id: str, limit: int = 100) -> ApiResponse:
params = {"limit": limit} if limit != 100 else {}
response = requests.get(
f"{BASE_URL}/v2/tokens/top100/{token_id}", headers=make_headers(), params=params
)
return handle_response(response)
def get_klines_by_token(
token_id: str, interval: str = "1h", limit: int = 100
) -> ApiResponse:
params = {"interval": interval, "limit": limit}
response = requests.get(
f"{BASE_URL}/v2/klines/token/{token_id}", headers=make_headers(), params=params
)
return handle_response(response)
def get_klines_by_pair(
pair_id: str, interval: str = "1h", limit: int = 100
) -> ApiResponse:
params = {"interval": interval, "limit": limit}
response = requests.get(
f"{BASE_URL}/v2/klines/pair/{pair_id}", headers=make_headers(), params=params
)
return handle_response(response)
def get_pair_detail(pair_id: str) -> ApiResponse:
response = requests.get(f"{BASE_URL}/v2/pairs/{pair_id}", headers=make_headers())
return handle_response(response)
def get_wallet_pnl(
wallet_address: str,
chain: str,
token_address: str,
from_time: Optional[int] = None,
to_time: Optional[int] = None,
) -> ApiResponse:
params = {
"wallet_address": wallet_address,
"chain": chain,
"token_address": token_address,
}
if from_time:
params["from_time"] = from_time
if to_time:
params["to_time"] = to_time
response = requests.get(
f"{BASE_URL}/v2/address/pnl", headers=make_headers(), params=params
)
return handle_response(response)
def get_wallet_info(wallet_address: str, chain: str) -> ApiResponse:
params = {"wallet_address": wallet_address, "chain": chain}
response = requests.get(
f"{BASE_URL}/v2/address/walletinfo", headers=make_headers(), params=params
)
return handle_response(response)
def get_wallet_tokens(
wallet_address: str,
chain: str,
sort: str = "last_txn_time",
sort_dir: str = "desc",
hide_sold: int = 0,
hide_small: int = 0,
) -> ApiResponse:
params = {
"wallet_address": wallet_address,
"chain": chain,
"sort": sort,
"sort_dir": sort_dir,
"hide_sold": hide_sold,
"hide_small": hide_small,
}
response = requests.get(
f"{BASE_URL}/v2/address/walletinfo/tokens",
headers=make_headers(),
params=params,
)
return handle_response(response)
def get_smart_wallets(
chain: str, sort: str = "total_profit", sort_dir: str = "desc"
) -> ApiResponse:
params = {"chain": chain, "sort": sort, "sort_dir": sort_dir}
response = requests.get(
f"{BASE_URL}/v2/address/smart_wallet/list",
headers=make_headers(),
params=params,
)
return handle_response(response)
def format_json(data):
return json.dumps(data, indent=2, ensure_ascii=False)
def print_cu_warning(operation: str):
cu_cost = CU_COSTS.get(operation, "unknown")
print(f"[CU Cost: {cu_cost}]", file=sys.stderr)
def cmd_search(args):
result = search_tokens(args.keyword, args.chain, args.limit)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("search")
print(format_json(result.data))
def cmd_price(args):
token_ids = [t.strip() for t in args.token_ids.split(",")]
result = get_token_price(token_ids)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("price")
print(format_json(result.data))
def cmd_trending(args):
result = get_trending_tokens(args.chain, args.page, args.page_size)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("trending")
print(format_json(result.data))
def cmd_token(args):
result = get_token_detail(args.token_id)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("token")
print(format_json(result.data))
def cmd_risk(args):
result = get_token_risk(args.token_id)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("risk")
print(format_json(result.data))
def cmd_holders(args):
result = get_top_holders(args.token_id, args.limit)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("holders")
print(format_json(result.data))
def cmd_klines(args):
if args.pair_id:
result = get_klines_by_pair(args.pair_id, args.interval, args.limit)
print_cu_warning("klines_pair")
else:
result = get_klines_by_token(args.token_id, args.interval, args.limit)
print_cu_warning("klines_token")
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print(format_json(result.data))
def cmd_pairs(args):
result = get_pair_detail(args.pair_id)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("pairs")
print(format_json(result.data))
def cmd_wallet_pnl(args):
result = get_wallet_pnl(
args.wallet, args.chain, args.token, args.from_time, args.to_time
)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("wallet_pnl")
print(format_json(result.data))
def cmd_wallet_info(args):
result = get_wallet_info(args.wallet, args.chain)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("wallet_info")
print(format_json(result.data))
def cmd_wallet_tokens(args):
result = get_wallet_tokens(
args.wallet,
args.chain,
args.sort,
args.sort_dir,
args.hide_sold,
args.hide_small,
)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("wallet_tokens")
print(format_json(result.data))
def cmd_smart_wallets(args):
result = get_smart_wallets(args.chain, args.sort, args.sort_dir)
if result.error:
print(f"Error: {result.error}")
sys.exit(1)
print_cu_warning("smart_wallet")
print(format_json(result.data))
def main():
parser = argparse.ArgumentParser(description="AVE Cloud Data REST API")
parser.add_argument(
"--api-key", default=API_KEY, help="AVE API key (or set AVE_API_KEY env)"
)
parser.add_argument(
"--api-plan",
default=API_PLAN,
choices=["free", "normal", "pro"],
help="API plan",
)
subparsers = parser.add_subparsers(dest="command", help="Commands")
p_search = subparsers.add_parser("search", help="Search tokens by keyword")
p_search.add_argument("--keyword", required=True, help="Token symbol or address")
p_search.add_argument("--chain", help="Chain name (bsc, solana, eth, base)")
p_search.add_argument(
"--limit", type=int, default=100, help="Number of results (max 300)"
)
p_price = subparsers.add_parser("price", help="Get batch token prices")
p_price.add_argument(
"--token-ids",
required=True,
help="Comma-separated token IDs (e.g. PEPE-bsc,TRUMP-bsc)",
)
p_trending = subparsers.add_parser("trending", help="Get trending tokens")
p_trending.add_argument("--chain", required=True, help="Chain name")
p_trending.add_argument("--page", type=int, default=0, help="Page number")
p_trending.add_argument(
"--page-size", type=int, default=50, help="Results per page (max 100)"
)
p_token = subparsers.add_parser("token", help="Get token details and top pairs")
p_token.add_argument(
"--token-id", required=True, help="Token ID (address-chain format)"
)
p_risk = subparsers.add_parser("risk", help="Get token risk information")
p_risk.add_argument(
"--token-id", required=True, help="Token ID (address-chain format)"
)
p_holders = subparsers.add_parser("holders", help="Get top 100 token holders")
p_holders.add_argument(
"--token-id", required=True, help="Token ID (address-chain format)"
)
p_holders.add_argument(
"--limit", type=int, default=100, help="Number of holders (max 100)"
)
p_klines = subparsers.add_parser("klines", help="Get kline/candlestick data")
p_klines.add_argument("--token-id", help="Token ID (use OR --pair-id)")
p_klines.add_argument("--pair-id", help="Pair ID (use OR --token-id)")
p_klines.add_argument(
"--interval", default="1h", help="Interval (1m, 5m, 15m, 30m, 1h, 4h, 1d)"
)
p_klines.add_argument("--limit", type=int, default=100, help="Number of klines")
p_pairs = subparsers.add_parser("pairs", help="Get pair details")
p_pairs.add_argument(
"--pair-id", required=True, help="Pair ID (address-chain format)"
)
p_wallet_pnl = subparsers.add_parser(
"wallet-pnl", help="Get wallet PnL for a token"
)
p_wallet_pnl.add_argument("--wallet", required=True, help="Wallet address")
p_wallet_pnl.add_argument("--chain", required=True, help="Chain name")
p_wallet_pnl.add_argument("--token", required=True, help="Token address")
p_wallet_pnl.add_argument(
"--from-time", type=int, help="Unix epoch seconds (earliest 15 days ago)"
)
p_wallet_pnl.add_argument("--to-time", type=int, help="Unix epoch seconds")
p_wallet_info = subparsers.add_parser(
"wallet-info", help="Get wallet info (all tokens on chain)"
)
p_wallet_info.add_argument("--wallet", required=True, help="Wallet address")
p_wallet_info.add_argument("--chain", required=True, help="Chain name")
p_wallet_tokens = subparsers.add_parser(
"wallet-tokens", help="Get all tokens holding in wallet"
)
p_wallet_tokens.add_argument("--wallet", required=True, help="Wallet address")
p_wallet_tokens.add_argument("--chain", required=True, help="Chain name")
p_wallet_tokens.add_argument("--sort", default="last_txn_time", help="Sort field")
p_wallet_tokens.add_argument(
"--sort-dir", default="desc", help="Sort direction (desc/asc)"
)
p_wallet_tokens.add_argument(
"--hide-sold", type=int, default=0, help="Hide sold tokens (0/1)"
)
p_wallet_tokens.add_argument(
"--hide-small", type=int, default=0, help="Hide small balances (0/1)"
)
p_smart = subparsers.add_parser(
"smart-wallets", help="Get smart wallet list (for copy trading)"
)
p_smart.add_argument("--chain", required=True, help="Chain name")
p_smart.add_argument("--sort", default="total_profit", help="Sort field")
p_smart.add_argument("--sort-dir", default="desc", help="Sort direction (desc/asc)")
args = parser.parse_args()
if not args.api_key:
print("Error: API key required. Set AVE_API_KEY env or use --api-key")
sys.exit(1)
if not args.command:
parser.print_help()
sys.exit(1)
cmd_map = {
"search": cmd_search,
"price": cmd_price,
"trending": cmd_trending,
"token": cmd_token,
"risk": cmd_risk,
"holders": cmd_holders,
"klines": cmd_klines,
"pairs": cmd_pairs,
"wallet-pnl": cmd_wallet_pnl,
"wallet-info": cmd_wallet_info,
"wallet-tokens": cmd_wallet_tokens,
"smart-wallets": cmd_smart_wallets,
}
cmd_map[args.command](args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,459 @@
#!/usr/bin/env python3
"""
AVE Cloud Data WebSocket API - Real-time Streams
Usage:
export AVE_API_KEY=your_api_key_here
export API_PLAN=pro # REQUIRED for WebSocket (must be 'pro')
python3 docs/scripts/ave_data_wss.py subscribe-tx --pair "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE" --chain solana
python3 docs/scripts/ave_data_wss.py subscribe-multi-tx --token "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c" --chain bsc
python3 docs/scripts/ave_data_wss.py subscribe-liq --pair "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE" --chain solana
python3 docs/scripts/ave_data_wss.py subscribe-price --pairs "PEPE-bsc,TRUMP-bsc"
python3 docs/scripts/ave_data_wss.py subscribe-kline --token "0x6982508145454Ce325dDbE47a25d4ec3d2311933-bsc" --interval 1m
python3 docs/scripts/ave_data_wss.py wss-repl # Interactive REPL mode
Notes:
- WebSocket API requires API_PLAN=pro
- Max 5 concurrent WebSocket connections
- Auto-reconnect with exponential backoff on disconnect
"""
import argparse
import json
import os
import sys
import time
from dataclasses import dataclass, field
from typing import Optional
import websocket
WSS_URL = "wss://wss.ave-api.xyz"
API_KEY = os.getenv("AVE_API_KEY", "")
API_PLAN = os.getenv("API_PLAN", "")
@dataclass
class WssMessage:
id: int
method: str
params: list
result: Optional[dict] = None
@dataclass
class WssSubscription:
topic: str
address: str
chain: str
id: int
class AveWssClient:
def __init__(self, api_key: str, debug: bool = False):
self.api_key = api_key
self.debug = debug
self.ws: Optional[websocket.WebSocket] = None
self.subscription_id = 1
self.subscriptions: list[WssSubscription] = []
self.running = False
def connect(self):
if self.ws:
self.disconnect()
self.ws = websocket.WebSocketApp(
WSS_URL,
on_open=self._on_open,
on_message=self._on_message,
on_error=self._on_error,
on_close=self._on_close,
)
self.running = True
def disconnect(self):
self.running = False
if self.ws:
self.ws.close()
self.ws = None
def _on_open(self, ws):
print("[Connected to WebSocket]", file=sys.stderr)
def _on_message(self, ws, message):
try:
data = json.loads(message)
if self.debug:
print(f"[DEBUG] {json.dumps(data, indent=2)}", file=sys.stderr)
if "result" in data and data.get("id"):
for sub in self.subscriptions:
if sub.id == data["id"]:
sub.id = data["result"].get("id", data["id"])
print(
f"[Subscribed to {sub.topic}] {sub.address} on {sub.chain}",
file=sys.stderr,
)
break
elif "params" in data:
topic = data["params"].get("topic", "unknown")
if topic == "tx":
self._handle_tx(data["params"]["data"])
elif topic == "liq":
self._handle_liq(data["params"]["data"])
elif topic == "kline":
self._handle_kline(data["params"]["data"])
elif topic == "price":
self._handle_price(data["params"]["data"])
except json.JSONDecodeError:
print(f"[Error] Failed to parse message: {message}", file=sys.stderr)
def _on_error(self, ws, error):
print(f"[WebSocket Error] {error}", file=sys.stderr)
def _on_close(self, ws, close_status_code, close_msg):
print(f"[Disconnected] {close_status_code}: {close_msg}", file=sys.stderr)
self.running = False
def _handle_tx(self, tx: dict):
print(
f"[TX] {tx.get('chain')}: {tx.get('from_symbol')} -> {tx.get('to_symbol')} "
f"Amount: {tx.get('from_amount')} {tx.get('from_symbol')} | "
f"Sender: {tx.get('sender', 'unknown')[:10]}... | "
f"Pair: {tx.get('pair_address', 'unknown')[:15]}..."
)
def _handle_liq(self, liq: dict):
print(
f"[LIQ] {liq.get('chain')}: {liq.get('action')} "
f"Amount: {liq.get('amount')} {liq.get('symbol')} | "
f"Pair: {liq.get('pair_address', 'unknown')[:15]}..."
)
def _handle_kline(self, kline: dict):
print(
f"[KLINE] {kline.get('token_id', kline.get('pair_id'))} "
f"{kline.get('interval')}: O={kline.get('open')} H={kline.get('high')} "
f"L={kline.get('low')} C={kline.get('close')} V={kline.get('volume')}"
)
def _handle_price(self, price: dict):
print(
f"[PRICE] {price.get('token_id', price.get('pair_id'))}: "
f"{price.get('price')} USD (change: {price.get('price_change_24h', 'N/A')}%)"
)
def _send(self, method: str, params: list, timeout: int = 10) -> Optional[dict]:
if not self.ws:
return None
msg_id = self.subscription_id
self.subscription_id += 1
msg = {"jsonrpc": "2.0", "method": method, "params": params, "id": msg_id}
self.ws.send(json.dumps(msg))
return {"id": msg_id}
def subscribe_tx(self, pair_address: str, chain: str):
params = ["tx", pair_address, chain]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="tx", address=pair_address, chain=chain, id=result["id"]
)
)
def subscribe_multi_tx(self, token_address: str, chain: str):
params = ["multi_tx", token_address, chain]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="multi_tx",
address=token_address,
chain=chain,
id=result["id"],
)
)
def subscribe_liq(self, pair_address: str, chain: str):
params = ["liq", pair_address, chain]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="liq", address=pair_address, chain=chain, id=result["id"]
)
)
def subscribe_price(self, pairs: list):
params = ["price", pairs]
result = self._send("subscribe", params)
if result:
for pair in pairs:
self.subscriptions.append(
WssSubscription(
topic="price", address=pair, chain="multi", id=result["id"]
)
)
def subscribe_kline(self, token_or_pair_id: str, interval: str = "1m"):
params = ["kline", token_or_pair_id, interval]
result = self._send("subscribe", params)
if result:
self.subscriptions.append(
WssSubscription(
topic="kline",
address=token_or_pair_id,
chain=interval,
id=result["id"],
)
)
def unsubscribe(self, topic: str, address: str, chain: str):
params = (
["unsubscribe", topic, address, chain]
if chain != "multi"
else ["unsubscribe", topic, address]
)
self._send("unsubscribe", params)
self.subscriptions = [
s
for s in self.subscriptions
if not (s.topic == topic and s.address == address and s.chain == chain)
]
def run_forever(self, reconnect_delay: int = 5, max_reconnect_delay: int = 60):
delay = reconnect_delay
while self.running:
try:
self.ws.run_forever(ping_interval=30, ping_timeout=10)
except Exception as e:
print(f"[Error] {e}", file=sys.stderr)
if self.running:
print(f"[Reconnecting in {delay}s...]", file=sys.stderr)
time.sleep(delay)
delay = min(delay * 2, max_reconnect_delay)
self.connect()
def cmd_subscribe_tx(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_tx(args.pair, args.chain)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_multi_tx(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_multi_tx(args.token, args.chain)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_liq(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_liq(args.pair, args.chain)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_price(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
pairs = [p.strip() for p in args.pairs.split(",")]
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_price(pairs)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_subscribe_kline(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
client.subscribe_kline(args.token, args.interval)
print("[Press Ctrl+C to exit]", file=sys.stderr)
try:
client.run_forever()
except KeyboardInterrupt:
client.disconnect()
def cmd_wss_repl(args):
if API_PLAN != "pro":
print("Error: WebSocket requires API_PLAN=pro", file=sys.stderr)
sys.exit(1)
client = AveWssClient(args.api_key, debug=args.debug)
client.connect()
print(
"[WebSocket REPL - type 'help' for commands, 'quit' to exit]", file=sys.stderr
)
print(
"[Commands: subscribe tx <pair> <chain>, subscribe price <pairs>, unsubscribe <topic> <addr> <chain>]",
file=sys.stderr,
)
subscriptions = []
def print_help():
print("Commands:")
print(
" subscribe tx <pair_address> <chain> - Subscribe to swap transactions by pair"
)
print(
" subscribe multi_tx <token_address> <chain> - Subscribe to all txs involving a token"
)
print(
" subscribe liq <pair_address> <chain> - Subscribe to liquidity changes by pair"
)
print(" subscribe price <pair1,pair2,...> - Subscribe to price changes")
print(
" subscribe kline <token_id> <interval> - Subscribe to kline data (interval: 1m, 5m, etc.)"
)
print(" unsubscribe <topic> <address> <chain> - Unsubscribe")
print(" list - List subscriptions")
print(" help - Show this help")
print(" quit - Exit")
while True:
try:
user_input = input("wss> ").strip()
if not user_input:
continue
parts = user_input.split()
cmd = parts[0].lower()
if cmd == "quit":
break
elif cmd == "help":
print_help()
elif cmd == "list":
for s in client.subscriptions:
print(f" {s.topic}: {s.address} on {s.chain}")
elif cmd == "subscribe" and len(parts) >= 3:
sub_type = parts[1].lower()
if sub_type == "tx" and len(parts) >= 4:
client.subscribe_tx(parts[2], parts[3])
elif sub_type == "multi_tx" and len(parts) >= 4:
client.subscribe_multi_tx(parts[2], parts[3])
elif sub_type == "liq" and len(parts) >= 4:
client.subscribe_liq(parts[2], parts[3])
elif sub_type == "price" and len(parts) >= 3:
pairs = parts[2].split(",")
client.subscribe_price(pairs)
elif sub_type == "kline" and len(parts) >= 4:
client.subscribe_kline(parts[2], parts[3])
else:
print("Invalid subscribe command")
elif cmd == "unsubscribe" and len(parts) >= 4:
client.unsubscribe(parts[1], parts[2], parts[3])
else:
print("Unknown command. Type 'help' for commands.")
except KeyboardInterrupt:
break
except EOFError:
break
client.disconnect()
print("\n[Exited]")
def main():
parser = argparse.ArgumentParser(description="AVE Cloud Data WebSocket API")
parser.add_argument(
"--api-key", default=API_KEY, help="AVE API key (or set AVE_API_KEY env)"
)
parser.add_argument(
"--api-plan", default=API_PLAN, help="API plan (or set API_PLAN env)"
)
parser.add_argument("--debug", action="store_true", help="Enable debug output")
subparsers = parser.add_subparsers(dest="command", help="Commands")
p_tx = subparsers.add_parser(
"subscribe-tx", help="Subscribe to swap transactions by pair"
)
p_tx.add_argument("--pair", required=True, help="Pair address")
p_tx.add_argument(
"--chain", required=True, help="Chain name (solana, bsc, eth, base)"
)
p_multi = subparsers.add_parser(
"subscribe-multi-tx", help="Subscribe to all txs involving a token"
)
p_multi.add_argument("--token", required=True, help="Token address")
p_multi.add_argument("--chain", required=True, help="Chain name")
p_liq = subparsers.add_parser(
"subscribe-liq", help="Subscribe to liquidity changes by pair"
)
p_liq.add_argument("--pair", required=True, help="Pair address")
p_liq.add_argument("--chain", required=True, help="Chain name")
p_price = subparsers.add_parser(
"subscribe-price", help="Subscribe to price changes"
)
p_price.add_argument(
"--pairs", required=True, help="Comma-separated pairs (e.g. PEPE-bsc,TRUMP-bsc)"
)
p_kline = subparsers.add_parser("subscribe-kline", help="Subscribe to kline data")
p_kline.add_argument(
"--token", required=True, help="Token ID (address-chain format)"
)
p_kline.add_argument(
"--interval", default="1m", help="Interval (1m, 5m, 15m, 30m, 1h, 4h, 1d)"
)
subparsers.add_parser("wss-repl", help="Interactive WebSocket REPL")
args = parser.parse_args()
if not args.api_key:
print("Error: API key required. Set AVE_API_KEY env or use --api-key")
sys.exit(1)
if not args.command:
parser.print_help()
sys.exit(1)
cmd_map = {
"subscribe-tx": cmd_subscribe_tx,
"subscribe-multi-tx": cmd_subscribe_multi_tx,
"subscribe-liq": cmd_subscribe_liq,
"subscribe-price": cmd_subscribe_price,
"subscribe-kline": cmd_subscribe_kline,
"wss-repl": cmd_wss_repl,
}
cmd_map[args.command](args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,560 @@
#!/usr/bin/env python3
"""
AVE Cloud Trading REST API - Chain Wallet & Proxy Wallet Trading
Usage:
# Environment setup
export AVE_API_KEY=your_api_key_here
export API_PLAN=free # free for chain-wallet, normal/pro for proxy-wallet
export AVE_SECRET_KEY=your_secret_key_here # For proxy wallet HMAC signing
# Chain Wallet (Self-custody) - Free tier OK
python3 docs/scripts/ave_trade_rest.py chain-quote --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
python3 docs/scripts/ave_trade_rest.py chain-swap --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
# Proxy Wallet (Server-managed) - Requires normal/pro tier
python3 docs/scripts/ave_trade_rest.py proxy-quote --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
python3 docs/scripts/ave_trade_rest.py proxy-market --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy
python3 docs/scripts/ave_trade_rest.py proxy-limit --chain bsc --in-token 0x55d398326f99059fF775485246999027B3197955 --out-token 0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c --in-amount 10000000 --swap-type buy --price 35.5
python3 docs/scripts/ave_trade_rest.py proxy-orders --chain bsc
python3 docs/scripts/ave_trade_rest.py proxy-cancel --chain bsc --order-id xxx
# Wallet Management
python3 docs/scripts/ave_trade_rest.py create-proxy-wallet --chain bsc
python3 docs/scripts/ave_trade_rest.py list-proxy-wallets --chain bsc
Notes:
- Chain Wallet: Requires API_PLAN=free or higher
- Proxy Wallet: Requires API_PLAN=normal or pro
- All amount fields use string format to avoid floating point precision issues
- Proxy wallet uses HMAC-SHA256 signing with AVE_SECRET_KEY
"""
import argparse
import hashlib
import hmac
import json
import os
import sys
import time
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Optional
import requests
CHAIN_WALLET_URL = "https://bot-api.ave.ai"
PROXY_WALLET_URL = "https://bot-api.ave.ai"
API_KEY = os.getenv("AVE_API_KEY", "")
API_PLAN = os.getenv("API_PLAN", "free")
SECRET_KEY = os.getenv("AVE_SECRET_KEY", "")
EVM_PRIVATE_KEY = os.getenv("AVE_EVM_PRIVATE_KEY", "")
SOLANA_PRIVATE_KEY = os.getenv("AVE_SOLANA_PRIVATE_KEY", "")
@dataclass
class TradeResponse:
status: int
data: Optional[dict] = None
error: Optional[str] = None
business_code: Optional[int] = None
def make_headers(signed: bool = False):
headers = {
"X-API-KEY": API_KEY,
"Content-Type": "application/json",
}
return headers
def make_proxy_headers(timestamp: str, signature: str):
return {
"X-API-KEY": API_KEY,
"X-Signature": signature,
"X-Timestamp": timestamp,
"Content-Type": "application/json",
}
def generate_hmac_signature(timestamp: str, body: str = "") -> str:
message = timestamp + body
signature = hmac.new(
SECRET_KEY.encode(), message.encode(), hashlib.sha256
).hexdigest()
return signature
def handle_response(response: requests.Response) -> TradeResponse:
if response.status_code == 200:
data = response.json()
if data.get("code") == 200 or data.get("status") == 200:
return TradeResponse(status=200, data=data)
else:
return TradeResponse(
status=data.get("code", response.status_code),
data=data,
error=data.get("msg", "Unknown error"),
business_code=data.get("code"),
)
elif response.status_code == 401:
return TradeResponse(
status=401, error="Unauthorized - invalid or missing API key"
)
elif response.status_code == 403:
return TradeResponse(
status=403,
error="Forbidden - API key expired, plan limits, or insufficient permissions",
)
elif response.status_code == 429:
return TradeResponse(status=429, error="Rate limited - TPS exceeded")
else:
try:
data = response.json()
return TradeResponse(
status=response.status_code,
data=data,
error=data.get("msg", response.text),
business_code=data.get("code"),
)
except json.JSONDecodeError:
return TradeResponse(status=response.status_code, error=response.text)
def chain_quote(
chain: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
slippage: float = 0.5,
) -> TradeResponse:
endpoint = f"{CHAIN_WALLET_URL}/v1/chain/quote"
data = {
"chain": chain,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"slippage": slippage,
}
response = requests.post(endpoint, headers=make_headers(), json=data)
return handle_response(response)
def chain_swap(
chain: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
slippage: float = 0.5,
recipient: Optional[str] = None,
) -> TradeResponse:
endpoint = f"{CHAIN_WALLET_URL}/v1/chain/swap"
data = {
"chain": chain,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"slippage": slippage,
}
if recipient:
data["recipient"] = recipient
response = requests.post(endpoint, headers=make_headers(), json=data)
return handle_response(response)
def proxy_quote(
chain: str,
proxy_wallet: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
body = json.dumps(
{
"chain": chain,
"proxy_wallet": proxy_wallet,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
},
separators=(",", ":"),
)
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/quote"
response = requests.post(endpoint, headers=headers, json=json.loads(body))
return handle_response(response)
def proxy_market_order(
chain: str,
proxy_wallet: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
tp_price: Optional[str] = None,
sl_price: Optional[str] = None,
trailing_stop: Optional[dict] = None,
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {
"chain": chain,
"proxy_wallet": proxy_wallet,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"order_type": "market",
}
if tp_price:
data["tp_price"] = tp_price
if sl_price:
data["sl_price"] = sl_price
if trailing_stop:
data["trailing_stop"] = trailing_stop
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/market_order"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def proxy_limit_order(
chain: str,
proxy_wallet: str,
in_token: str,
out_token: str,
in_amount: str,
swap_type: str,
price: str,
tp_price: Optional[str] = None,
sl_price: Optional[str] = None,
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {
"chain": chain,
"proxy_wallet": proxy_wallet,
"in_token": in_token,
"out_token": out_token,
"in_amount": in_amount,
"swap_type": swap_type,
"price": price,
"order_type": "limit",
}
if tp_price:
data["tp_price"] = tp_price
if sl_price:
data["sl_price"] = sl_price
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/limit_order"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def proxy_cancel_order(chain: str, order_id: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {"chain": chain, "order_id": order_id}
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/cancel_order"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def proxy_get_orders(
chain: str, proxy_wallet: str, order_type: Optional[str] = None
) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
params = {"chain": chain, "proxy_wallet": proxy_wallet}
if order_type:
params["order_type"] = order_type
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = generate_hmac_signature(timestamp, query_string)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/orders"
response = requests.get(endpoint, headers=headers, params=params)
return handle_response(response)
def proxy_get_order_history(chain: str, proxy_wallet: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
params = {"chain": chain, "proxy_wallet": proxy_wallet}
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = generate_hmac_signature(timestamp, query_string)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/order_history"
response = requests.get(endpoint, headers=headers, params=params)
return handle_response(response)
def create_proxy_wallet(chain: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
data = {"chain": chain}
body = json.dumps(data, separators=(",", ":"))
signature = generate_hmac_signature(timestamp, body)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/create_proxy_wallet"
response = requests.post(endpoint, headers=headers, json=data)
return handle_response(response)
def list_proxy_wallets(chain: str) -> TradeResponse:
timestamp = str(int(time.time() * 1000))
params = {"chain": chain}
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = generate_hmac_signature(timestamp, query_string)
headers = make_proxy_headers(timestamp, signature)
endpoint = f"{PROXY_WALLET_URL}/v1/proxy_wallets"
response = requests.get(endpoint, headers=headers, params=params)
return handle_response(response)
def format_json(data):
return json.dumps(data, indent=2, ensure_ascii=False)
def print_trade_response(result: TradeResponse, success_msg: str = "Success"):
if result.error:
print(f"Error ({result.business_code or result.status}): {result.error}")
if result.data:
print(format_json(result.data))
sys.exit(1)
else:
print(f"{success_msg}")
if result.data:
print(format_json(result.data))
def cmd_chain_quote(args):
result = chain_quote(
chain=args.chain,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
slippage=args.slippage,
)
print_trade_response(result, "Quote retrieved (dry-run - no actual trade)")
def cmd_chain_swap(args):
result = chain_swap(
chain=args.chain,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
slippage=args.slippage,
recipient=args.recipient,
)
print_trade_response(result, "Swap executed!")
def cmd_proxy_quote(args):
result = proxy_quote(
chain=args.chain,
proxy_wallet=args.proxy_wallet,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
)
print_trade_response(result, "Quote retrieved (dry-run - no actual trade)")
def cmd_proxy_market(args):
result = proxy_market_order(
chain=args.chain,
proxy_wallet=args.proxy_wallet,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
tp_price=args.tp_price,
sl_price=args.sl_price,
)
print_trade_response(result, "Market order submitted!")
def cmd_proxy_limit(args):
result = proxy_limit_order(
chain=args.chain,
proxy_wallet=args.proxy_wallet,
in_token=args.in_token,
out_token=args.out_token,
in_amount=args.in_amount,
swap_type=args.swap_type,
price=args.price,
tp_price=args.tp_price,
sl_price=args.sl_price,
)
print_trade_response(result, "Limit order submitted!")
def cmd_proxy_cancel(args):
result = proxy_cancel_order(args.chain, args.order_id)
print_trade_response(result, "Order cancelled!")
def cmd_proxy_orders(args):
result = proxy_get_orders(args.chain, args.proxy_wallet, args.order_type)
print_trade_response(result)
def cmd_proxy_history(args):
result = proxy_get_order_history(args.chain, args.proxy_wallet)
print_trade_response(result)
def cmd_create_proxy_wallet(args):
result = create_proxy_wallet(args.chain)
print_trade_response(result, "Proxy wallet created!")
def cmd_list_proxy_wallets(args):
result = list_proxy_wallets(args.chain)
print_trade_response(result)
def main():
parser = argparse.ArgumentParser(description="AVE Cloud Trading REST API")
parser.add_argument(
"--api-key", default=API_KEY, help="AVE API key (or set AVE_API_KEY env)"
)
parser.add_argument(
"--api-plan", default=API_PLAN, help="API plan (or set API_PLAN env)"
)
parser.add_argument(
"--secret-key",
default=SECRET_KEY,
help="AVE SECRET_KEY for HMAC signing (or set AVE_SECRET_KEY env)",
)
subparsers = parser.add_subparsers(dest="command", help="Commands")
p_cquote = subparsers.add_parser(
"chain-quote", help="Chain wallet - get swap quote (dry-run)"
)
p_cquote.add_argument(
"--chain", required=True, help="Chain name (bsc, solana, eth, base)"
)
p_cquote.add_argument("--in-token", required=True, help="Input token address")
p_cquote.add_argument("--out-token", required=True, help="Output token address")
p_cquote.add_argument(
"--in-amount", required=True, help="Input amount (use string format)"
)
p_cquote.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_cquote.add_argument(
"--slippage", type=float, default=0.5, help="Slippage tolerance (default: 0.5)"
)
p_cswap = subparsers.add_parser("chain-swap", help="Chain wallet - execute swap")
p_cswap.add_argument("--chain", required=True, help="Chain name")
p_cswap.add_argument("--in-token", required=True, help="Input token address")
p_cswap.add_argument("--out-token", required=True, help="Output token address")
p_cswap.add_argument("--in-amount", required=True, help="Input amount")
p_cswap.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_cswap.add_argument(
"--slippage", type=float, default=0.5, help="Slippage tolerance"
)
p_cswap.add_argument("--recipient", help="Optional recipient address")
p_pquote = subparsers.add_parser(
"proxy-quote", help="Proxy wallet - get swap quote (dry-run)"
)
p_pquote.add_argument("--chain", required=True, help="Chain name")
p_pquote.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_pquote.add_argument("--in-token", required=True, help="Input token address")
p_pquote.add_argument("--out-token", required=True, help="Output token address")
p_pquote.add_argument("--in-amount", required=True, help="Input amount")
p_pquote.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_pmarket = subparsers.add_parser(
"proxy-market", help="Proxy wallet - submit market order"
)
p_pmarket.add_argument("--chain", required=True, help="Chain name")
p_pmarket.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_pmarket.add_argument("--in-token", required=True, help="Input token address")
p_pmarket.add_argument("--out-token", required=True, help="Output token address")
p_pmarket.add_argument("--in-amount", required=True, help="Input amount")
p_pmarket.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_pmarket.add_argument("--tp-price", help="Take-profit price")
p_pmarket.add_argument("--sl-price", help="Stop-loss price")
p_plimit = subparsers.add_parser(
"proxy-limit", help="Proxy wallet - submit limit order"
)
p_plimit.add_argument("--chain", required=True, help="Chain name")
p_plimit.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_plimit.add_argument("--in-token", required=True, help="Input token address")
p_plimit.add_argument("--out-token", required=True, help="Output token address")
p_plimit.add_argument("--in-amount", required=True, help="Input amount")
p_plimit.add_argument("--swap-type", required=True, help="Swap type (buy or sell)")
p_plimit.add_argument("--price", required=True, help="Limit price")
p_plimit.add_argument("--tp-price", help="Take-profit price")
p_plimit.add_argument("--sl-price", help="Stop-loss price")
p_cancel = subparsers.add_parser("proxy-cancel", help="Proxy wallet - cancel order")
p_cancel.add_argument("--chain", required=True, help="Chain name")
p_cancel.add_argument("--order-id", required=True, help="Order ID to cancel")
p_orders = subparsers.add_parser(
"proxy-orders", help="Proxy wallet - get open orders"
)
p_orders.add_argument("--chain", required=True, help="Chain name")
p_orders.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_orders.add_argument("--order-type", help="Filter by order type (market/limit)")
p_history = subparsers.add_parser(
"proxy-history", help="Proxy wallet - get order history"
)
p_history.add_argument("--chain", required=True, help="Chain name")
p_history.add_argument("--proxy-wallet", required=True, help="Proxy wallet address")
p_create = subparsers.add_parser(
"create-proxy-wallet", help="Create a new proxy wallet"
)
p_create.add_argument("--chain", required=True, help="Chain name")
p_list = subparsers.add_parser("list-proxy-wallets", help="List proxy wallets")
p_list.add_argument("--chain", required=True, help="Chain name")
args = parser.parse_args()
if not args.api_key:
print("Error: API key required. Set AVE_API_KEY env or use --api-key")
sys.exit(1)
if not args.command:
parser.print_help()
sys.exit(1)
cmd_map = {
"chain-quote": cmd_chain_quote,
"chain-swap": cmd_chain_swap,
"proxy-quote": cmd_proxy_quote,
"proxy-market": cmd_proxy_market,
"proxy-limit": cmd_proxy_limit,
"proxy-cancel": cmd_proxy_cancel,
"proxy-orders": cmd_proxy_orders,
"proxy-history": cmd_proxy_history,
"create-proxy-wallet": cmd_create_proxy_wallet,
"list-proxy-wallets": cmd_list_proxy_wallets,
}
cmd_map[args.command](args)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,2 @@
requests>=2.31.0
websocket-client>=1.7.0